Showing posts with label HTML5. Show all posts
Showing posts with label HTML5. Show all posts

Saturday, June 26, 2021

How to Get Video Thumbnails with Javascript

Hello,

In this blog we will see how you can generate thumbnail of video using JavaScript.  Let's assume you have file upload in your HTML as following.

<input type="file" id="uploadVideo" accept="video/mp4" />

Now let's add an onChange listener for this.

document.querySelector("#uploadVideo").addEventListener('change', function() {
    var inputFile = document.querySelector("#uploadVideo").files[0];
    getVideoThumbnail(inputFile)
});

Now when you upload video it will call this function and you can access this video by using files property. Now we got the file. First step we will do is get blob URL of video so we can access metadata of video. Check below function. 

Here first what we are doing is creating video element and assigning blob URL to it from input file using URL.createObjectURL method.

Then we have added event listener for meta data. This is necessary as we can't get video data till them time meta data is loaded. 

Then we seek video to 0.0 second. You can add your own time here in case if you need. Then we have added seeked listener. By this time we have video data is available. Now we are using canvas to drawImage from video frame data.

Then using toDataURL method we get the base64Data. Here 0.60 is value of quality. If you don't want to compromise quality of image then you can pass 1 here.  

function getVideoThumbnail(inputFile) {
  try {
    let video = document.createElement('video');
    let blobSrc = URL.createObjectURL(inputFile);
    video.setAttribute('src', blobSrc);
    video.addEventListener('error', () => {
        console.log("Error")
    });
    video.addEventListener('loadedmetadata', () => {
        setTimeout(() => {
          video.currentTime = 0.0;
        }, 200);
        video.addEventListener('seeked', () => {
            let canvas = document.createElement('canvas');
            video.pause();
            canvas.width = 400
            canvas.height = 400;
            let ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            var base64Data = ctx.canvas.toDataURL(
                'image/png',
                0.60
            );
            // SET this data in SRC of image tag or you can add your own logic.
        });
    });
     video.load();
  } catch (err) {
  
  }
}

Hope this helps you.

Sunday, February 25, 2018

Scroll Two Divs Together

Recently in one of my project there was a requirement to maintain scroll positions of two divs. In UI there are two divs side by side. If user scrolls on left DIV then right div should also be scrolled and if user scrolls on right DIV then left div should also be scrolled. So here is how to do this.

var leftPart = document.getElementById('leftPart');
var rightPart = document.getElementById('rightPart');

Now lets add scroll event on both.

leftPart.onscroll = function() {
    rightPart.scrollTop = this.scrollTop;
}

rightPart.onscroll = function() {
    leftPart.scrollTop = this.scrollTop;
}

That's it now both should scroll no but wait it makes your UI unresponsive because there is a deadlock. While right one is scrolling, it will also scroll left one and at the same time it will also fire event and will try  to scroll right one again and there is DEADLOCK.........

So to prevent it, we have to add flags to check if one is already scrolling then hold the event.

so lets have two flags.

var isSyncingLeftScroll = false;
var isSyncingRightScroll = false;

and use it in scroll event.

leftPart.onscroll = function() {
  if (!isSyncingLeftScroll) {
    isSyncingRightScroll = true;
    rightPart.scrollTop = this.scrollTop;
  }
  isSyncingLeftScroll = false;
}

rightPart.onscroll = function() {
  if (!isSyncingRightScroll) {
    isSyncingLeftScroll = true;
    leftPart.scrollTop = this.scrollTop;
  }
  isSyncingRightScroll = false;
}

That's it and now you will have smooth scrolling effect on both the DIVs. Hope this helps you.

Sunday, January 14, 2018

jQuery Close Modal Window When User Clicks Outside of It

Recently in my work we faced an issue due to some JavaScript conflict on a page where we have modal popups that were not closing when user clicks outside of it and anywhere on page. Normally it does automatically in jQuery pop up. So here we have to add custom code to handle this situation. In this blog I am going to explain how to do it.

In above picture I explained how to do it. So basic trick is to track click event on entire web page and to check it it's X and Y coordinates are inside the BOX of modal window. If yes then do not close it. But if it's out side of it, close the modal popup. Here is the code for the same.

  var rect = $('.modalSelector')[0].getBoundingClientRect();
  clientX1 = rect.x
  clientX2 = rect.x + rect.width;

  clientY1 = rect.y
  clientY2 = rect.y + rect.height;

  if((e.clientX >= clientX1 && e.clientX <= clientX2) && (e.clientY >= clientY1 && e.clientY <= clientY2)){
    return;
  }

  if($('#modalSelector').hasClass('active')){
    $('#modalSelector').removeClass('active');
    $('. modalSelector').hide();
  }

That's it and it will close if you click anywhere on web page outside of modal popup.

Saturday, August 13, 2016

JavaScript parseInt('08') Returns Zero

Recently in one of our product we faced strange issue related to date display.  We were passing date components to display like this.

1st August 2016

Everything was working fine, till we faced the issue since start of Month of August. Instead of displaying correct date it was displaying 1 year old date or any random date.

It took sometime for me to figure out issue. Issue was number system. When we parse as following

parseInt("08")

In some browser or some android phones, it is considered as octal number and octal number system is used to parse. So "08" is "0" in octal so it gives wrong number.

So to fix this issue you can either use radix parameter in parseInt

parseInt("08", 10);

Here radix 10 represent decimal number system so "08" is parsed as "8" Other solution is to use Number function to parse the string.

Number("08");

And it gives you correct result. Octal system is deprecated in most of the browser now but still some old browser and some android phones are still using it so we have to to use above methods to avoid any issue.

Hope this helps you.

Thursday, May 5, 2016

Create Dynamic Half Circular Progress Bar With HTML 5 CSS 3 - Create Gauge Chart In HTML 5

Recently in one of my project there was a requirement to create half circle gauge chart to show progress of some actions. Something like below image


So first of all I decided to use some charts library to create UI like this but since this was mobile application I do not find any suitable chart library. So I decided to build UI from scratch. So here is the step by step guide. 

First our basic HTML and CSS

<div style="visibility: hidden" class="container" id="container">
                       <div id="border" class="active-border">
                            <div id="circle" class="circle">
                               <div id="needle" class="needle"></div> 
                            </div>
                        </div>
                      </div>

Now the basic CSS.

.container{
    width: 100%;
    height: 100%;
    overflow: hidden;
    position: relative;
    top: -25%;
}

.circle{
    position: relative;
    top: 5px;
    left: 5px;
    text-align: center;
    width: 200px;
    height: 200px;
    border-radius: 100%;
    background-color: rgba(0,0,0,1);
}

.border{
    position: relative;
    text-align: center;
    width: 210px;
    height: 210px;
    border-radius: 100%;
    top : 50%;
    background-color:#00a651;
}

.needle {
    position: absolute;
    background-color: #f0566f;
    height: 100%;
    width: 0.5%;
    left: 50%;
}

.needle:before {
    content: "";
    position: absolute;
    top: 0px;
    left: -10px;
    width: 0px;
    height: 0px;
    border-top: 10px solid transparent;
    border-right: 20px solid #f0566f;
    border-bottom: 10px solid transparent;
    -webkit-transform: rotate(90deg);
}

Now here comes the dynamic things. first of we have to set height and width of all the elements inside container to screen width and height.

var containerWidth = 0;

if(document.getElementById('container').clientHeight > document.getElementById('container').clientWidth){
containerWidth = document.getElementById('container').clientWidth;
}
else{
containerWidth = document.getElementById('container').clientHeight;
}

var circleWidth =  containerWidth - 10;
var activeBorderWidth =  containerWidth;
var padding = (document.getElementById('container').clientWidth - document.getElementById('container').clientHeight) / 2;

document.getElementById('circle').style.width = circleWidth + 'px';
document.getElementById('circle').style.height = circleWidth + 'px';
document.getElementById('container').style.paddingLeft = padding + 'px';

document.getElementById('border').style.width = activeBorderWidth + 'px';
document.getElementById('border').style.height = activeBorderWidth + 'px';

So as you can see we are setting border with to container width and make it fit inside container and setting inner circle width to bit less than border width to create circular progress bar. Now we calculate transform degrees to set up liner gradient to show progress. 

var degree = (180 * Number(count)) / (Number(total));

document.getElementById('border').style.background = '-webkit-linear-gradient('+degree+'deg, #9a9a9a 50%, #00a651 50%)';

As you can see since we have half circle we are calculating degrees by 180. If you want full circle progress bar then calculate it with 360 degree.                 

Now set needle transformation.

var needleTransformDegree = 180 - degree;

document.getElementById('needle').style.webkitTransform = 'rotate('+needleTransformDegree+'deg)';
               
document.getElementById('container').style.visibility = 'visible'

That's it and end result look something like below.


Hope this helps you.

CSS Border Radius Not Working in Android WebView or Chrome

Recently while working on mobile app project which was cross platform application we were creating pie shaped menu where we faced a very strange issue.

Actually I was trying to create following menu and I created that successfully while I was working in Xcode and iPhone simulator.



And it worked fine but as soon as I checked it in Android phone it came up like following.


Now that was so embarrassing. Off course, after spending couple of days to make such menu and it came up like this, that is so disappointing. How ever after spending some time over it I found out a solution, in this blog I am going to explain this. There more than one solutions so I posting each one. 

1) Some older version does not support percentage value. 

Some older version of chrome does not support percentage values for border radius. So instead of percentage give pixel values.

Use border-radius : 50px in stead of border-radius : 10%

2) Specify top, left right and bottom property separately. 

some Chrome does understand single value like border-radius : 50px. So here you have to specify each border radius saperately.


Use 
border-top-left-radius: 50px;border-top-right-radius: 50px;border-bottom-right-radius: 50px;border-bottom-left-radius: 50px;


In stead of 

border-radius : 50px

3) Now here comes the issue which I have faced,  background-color "leaking" outside of a border when border-radius is present. In my case there were few div tags which was having background color and was going out side of main container because of transformation.  So here are the two solutions you can do.

Apply overflow: hidden property to main container

If that does not work apply following CSS property to main container.

-webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box;

This should solve your all border radius related problem in all the versions of Chrome. Hope this helps you.

Saturday, February 20, 2016

Laravel 4.2 Using Custom View for Pagination

Recently in one of my project we used laravel pagination and we have to use custom pagination as the theme we used were having different CSS classes for pagination which were not compatible with laravel default views. So in this blog I am going to explain how to do this. 

First of all open app/config/view.php file. Here remove pagination key and add following key. 

'pagination' => 'paging'

Now go to your views folder and add new file and name it paging.blade.php and add following content to it.

<?php
$presenter = new Illuminate\Pagination\BootstrapPresenter($paginator);
?>

<?php if ($paginator->getLastPage() > 1): ?>
    <ul class="pagination">
        <?php echo $presenter->render(); ?>
        <li>
            <?php
            echo Form::open(array('url' => $paginator->getUrl(0), 'method' => 'GET'));
            ?>
            <?php echo Form::close(); ?>
        </li>
    </ul>
<?php endif; ?>

Above is your custom view so you can make changes as per your requirements and add custom code. 

Now add following code where you want to display paging. First of all in controller file. 

$pagedData = Model::where('company_id',$companyId)->paginate(5);

Now in view add following code.

{{ $pagedData->links(); }}

That's it now you have custom paging view in your laravel app.


Friday, January 22, 2016

jQuery JSTree Tips and Tricks Like Expand All Nodes, Get Selected Node, Get Extra Information

Hello,

Recently in one my project I used jQuery JSTree for display data in tree format and while working with I faced certain issues so here I am sharing some tips and tricks you can use with JSTree.

1) Expand All Nodes on Page Load


If you have dynamic dataset in JSTree and you want to expand it when tree is created here is what you can do. First call AJAX service to get data.

$.ajax({
            url: "cat-tree",
            cache: false
        }).done(function( json ) {
            //init js tree here
         
        });

For example in above service I am calling url cat-tree and get my JSON data. Now add following code to initialize JSTree.

$('#categoryTree').jstree({
                'plugins': ["wholerow", "types"],
                'core': {
                    "themes" : {
                        "responsive": false
                    },
                    'data': json
                },
                "types" : {
                    "default" : {
                        "icon" : "fa fa-folder icon-state-warning icon-lg"
                    },
                    "file" : {
                        "icon" : "fa fa-file icon-state-warning icon-lg"
                    }
                }
            });

That's it now wait for sometime to get it rendered in DOM and then expand it.

setTimeout(function(){
                $('#categoryTree').jstree("open_all");
            },500);

2) Add select event and get Selected Node in JSTree

Add following code to add select event.

$('#categoryTree').on('select_node.jstree', function(e,data) {
                    //Your code here
                });

Use following code to get single selected node of JSTree.

var selectedNode = $('#categoryTree').jstree().get_selected(true)[0];

Use following code to get single multiple selected nodes of JSTree.

var selectedNode = $('#categoryTree').jstree().get_selected(true);

3) Deselect all the Nodes in JSTree

Use following code to deselect all the nodes in JSTree.

$('#categoryTree').jstree("deselect_all");

4) Access Additional Data of Selected Node

We know that there is a standard format of data used with JSTree. For example.

[
       'Simple root node',
       {
         'text' : 'Root node 2',
         'state' : {
           'opened' : true,
           'selected' : true
         },
         'children' : [
           { 'text' : 'Child 1' },
           'Child 2'
         ]
      }
    ]

What if you want to have extra data like this.

[
       'Simple root node',
       {
         'text' : 'Root node 2',
         'key1': 'value1',
         'key2': 'value2'
         'state' : {
           'opened' : true,
           'selected' : true
         },
         'children' : [
           { 'text' : 'Child 1' , 'key1': 'value1', 'key2': 'value2'},
           'Child 2'
         ]
      }
    ]

You can pass any number of extra data buy how will you access it. Check the following code.

First get selected node.

var selectedNode = $('#categoryTree').jstree().get_selected(true)[0];

Extra data is available in key  called original.

var value1 = selectedNode.original.key1;
var value2 = selectedNode.original.key2;

Hope this helps you.

Sunday, January 17, 2016

Passing and Retrieving Data from Booststrap Modal

Recently in one my project I was using a theme which is using boostrap modal. Basically I was using modal for confirmation of delete and once user click on confirm process the delete action. I was using laravel REST API so we have to pass the id of object to be destroyed. So I have to pass id of object to modal and confirmation call API to delete. In this blog I will explain how to do this.

First of all add following modal code to your HTML.

<div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button>
                <h4 class="modal-title">Confirmation</h4>
            </div>
            <div class="modal-body">
                <p> Are you sure you want to delete? </p>
                <input type="hidden" id="objectId"/>
            </div>
            <div class="modal-footer">
                <button type="button" data-dismiss="modal" class="btn dark btn-outline">Cancel</button>
                <button id="confirmDelete" type="button" data-dismiss="modal" class="btn green">Continue</button>
            </div>
        </div>
    </div>

As you can in above code I have added one hidden field in modal where we will store object id.

Now following will your code of delete button.

<a id="deleteButton" data-id="{{$object->id}}" data-toggle="modal" href="#deleteConfirmation" class="btn btn-danger btn-sm">

As soon as you click on delete button modal will be displayed.

Now add following code to your JavaScript.

    $(document).on("click", "#deleteButton", function () {
        var id = $(this).data('id');
        jQuery('#deleteConfirmation .modal-body #objectId').val( id );
    });

    $('#deleteConfirmation .modal-footer button').on('click', function (e) {
        var $target = $(e.target); // Clicked button element
        $(this).closest('.modal').on('hidden.bs.modal', function () {
            if($target[0].id == 'confirmDelete'){
                $id = $('#deleteConfirmation .modal-body #objectId').val();
            }
        });
    });

As you can in above code we have added click event on delete button and setting id in modal hidden field.

Then we are adding event for confirm button in modal window and getting value stored in hidden field and then you can call the APIs or submit form whatever you want.

Hope this helps you.

Wednesday, January 6, 2016

HTML Fit Content to Available Space - Dynamic Font Size

Hello,

Recently in one of my project we have to fit content to available screen height. Basically it was cross platform mobile application built in HTML 5 and JavaScript. On screen there was a card with content. Card height and width as set to screen height and width. Now the problem was content can big or small and there should not be scrollbar. So what I did is I reduced the size of font till the content fits available width and height. This I did in JavaScript. So here in blog I am going to explain how to do this.

First of all add onload method to your body tag.

<body onload="resizeFontSizeInit()">

   <div id="contentContainer" style="width:100%;height:100%;overflow:hidden;">
       <div id="content">
        Dynamic Content Here
       </div>
   </div>

</body>

Now add following function to JavaScript

function resizeFontSizeInit(){
   resizeFont(0.1);
}

function resizeFont(emSize){
      //first get the screen height
      var screenHeight = document.documentElement.clientHeight;
   
      //Now set the font size to content div
      var contentDiv = document.getElementById('content');
      contentDiv.style.fontSize = String(emSize)+"em";

      //Now check the height of screen to height of content div
      var contentHeight = contentDiv.clientHeight;

      //Check if content height is less than screen height.
      if(contentHeight < screenHeight){
           //Increase font size and call the same function recursively.
           emSize = emSize + 0.1;
           resizeFont(emSize);
      }else{
           //content height is greater than screen size so time to stop recursion.
          //set fontsize to previous size.
          revertFontSizeToPreviousSize(emSize);
      }
}

function revertFontSizeToPreviousSize(emSize){
      emSize = emSize - 0.1;
      var contentDiv = document.getElementById('content');
      contentDiv.style.fontSize = String(emSize)+"em";
}

So basically we start with 0.1 em font size and keep increasing it till the content height is greater than screen height. As soon as it's bigger we have to stop and reset it to previous size. This way no matter what your content is, it will fit to screen without scroll bar.

Monday, March 10, 2014

Sencha Touch List Find Top Visible Item Index

Recently in one of my project we have a Sencha Touch list and top banner. Each list item have certain banner text to show. When user scrolls up or down we have to show the banner text of list item which is on top position in the top banner panel. It should change as user moves up or down.  For that we have to find top visible item index or record of list. So here is my logic for that. 

As we know that all the list item have certain fix height that we can specify with itemHeight config. Each list is scrollable with scroll view. We can simply calculate top visible item by dividing y offset of scrollview with item height of the list. This will give us top visible item index. Here is the logic to do that. Add reference of your list to controller and bind initialize event of the list.

myList:{
                initialize: 'onMyListInit'
 },

No we will bind scroll event to this list scroller.

onMyListInit: function(list){
          var listItemHeight = 53;
          var scroller = list.getScrollable().getScroller();
          scroller.on({
            scroll: function(scroller, x, y, e){
                          var currentVisibleItemOnTopIndex = parseInt(y/listItemHeight);
                }
          });
}

This logic will give us top visible item index. You can find record from index using getAt method of list store. In my case I get the record and use it's banner text to display on top banner above the list. It keeps changing as you scroll up or down the list. Please note that this trick will only work if you have simple list with fixed height of the item. If you have variable heights or group list.  This trick will not work. As in group list we have items arranged in groups so their indexes changed. We might have to find some other solution for that. If you have any idea post a comment.

Sunday, May 26, 2013

Capture CSS3 Animations Event in JavaScript

Hello,

This is my first blog on CSS 3 animations. Recently I was working on project where I created some CSS 3 animation. It was a sencha touch project, so we have some requirements like when animation ends we have to switch active item on view port. This we can only do in JavaScript and for that we have to capture CSS 3 animations events in JavaScript. So how to do it?

Basically we are going to add event handler. In case of web kit browser this is webkitAnimationEnd and webkitAnimationStart events. Please note that this event will only work if you have used -webkit-animation on the target. If you are using Transitions, there are some other events. I will cover that in next blogs. Check the code below. This shows exact syntax of adding animation start and end events.

Suppose you have html element with id box1 on which you are applying some CSS 3 animation.

document.getElementById("box1").addEventListener('webkitAnimationStart',function(event){

},false);

Above code will capture animation start event.

document.getElementById("box1").addEventListener('webkitAnimationEnd',function(event){

},false);

Above code will capture animation end event.

If you have infinite animation above functions be invoked every time when animation starts or ends. You also get event object as a parameter to callback function. It contains the target which invoked this event. You can get it using event.srcElement

Please note that above code will only work on web kit browsers.