javascripthtmlcss

How can i divide a div to equal div parts without distorting the image?


myDiv

I have div and I want to slice it equal parts like in image. Then I want to animate this sliced divs one by one. My goal is adapt animation in this js fiddle:

https://jsfiddle.net/F5SbD/1/

<a href="#" class="toggle">Toggle</a>
<div class="grid">
    
    <div class="tile posone">
        <div class="front"><img src="http://placehold.it/250x175/00baff/ffffff" height="175" height="250" /></div>
        <div class="back"><img src="http://placehold.it/250x175/ffa800/ffffff" height="175" height="250" /></div>
    </div>

    <div class="tile posone">
        <div class="front"><img src="http://placehold.it/250x175/00baff/ffffff" height="175" height="250" /></div>
        <div class="back"><img src="http://placehold.it/250x175/ffa800/ffffff" height="175" height="250" /></div>
    </div>

    <div class="tile posone">
        <div class="front"><img src="http://placehold.it/250x175/00baff/ffffff" height="175" height="250" /></div>
        <div class="back"><img src="http://placehold.it/250x175/ffa800/ffffff" height="175" height="250" /></div>
    </div>
    
    <div class="tile posone">
        <div class="front"><img src="http://placehold.it/250x175/00baff/ffffff" height="175" height="250" /></div>
        <div class="back"><img src="http://placehold.it/250x175/ffa800/ffffff" height="175" height="250" /></div>
    </div>
    
</div>
* { font-family:Arial, Helvetica, sans-serif; }
.toggle { display:inline-block; padding:20px; background:#666; margin:0 0 10px 0; color:#fff; font-size:15px; text-decoration:none; }
.grid { overflow:hidden; }
.tile { width:250px; height:175px; position:relative; float:left; margin:0 1px 1px 0; cursor:pointer; -webkit-perspective:600px; }
.tile > div { position:absolute; top:0; left:0; right:0; bottom:0; -webkit-backface-visibility:hidden; -webkit-transition:-webkit-transform 0.2s ease-in-out; }

.tile .front { -webkit-transform:rotateX(0deg); }
.tile .back { -webkit-transform:rotateX(-180deg); }

.tile.postwo .front { -webkit-transform:rotateX(180deg); }
.tile.postwo .back { -webkit-transform:rotateX(0deg); }

jQuery 1.8.3 code:

    flip = { 
        init: function(){
            $('.toggle').on('click', flip.toggle);
            $('.tile').on('hover', flip.hover);
        },
        
        toggle: function(e){
            e.preventDefault();
            $('.tile').each(function(i, elm) {
                    setTimeout(function(){
                flip.autoFlip($(elm));
            }, i*40);
            });
        },
        
        hover: function(e){
            if (e.type === 'mouseenter'){
                var dir = flip.getDir($(this), { x:e.pageX, y:e.pageY });
            }
            flip.flipOver($(this), e.type, dir);
        },
        
        flipOver: function($elm, type, dir){
                
                switch (dir) {
                    case 0 :
                        $elm.addClass('top');   
                    break;
                    case 1 :
                        $elm.addClass('right'); 
                    break;
                    case 2 :
                        $elm.addClass('bottom');    
                    break;
                    case 3 :
                        $elm.addClass('left');  
                    break;
                    default :
                        $elm.removeClass('top right bottom left');
                }
                
                $elm.toggleClass('posone postwo');
            
        },
        
        autoFlip: function($elm){
            $elm.toggleClass('posone postwo');
        },
        
        getDir: function($elm, coord){
            var w = $elm.width(),
                h = $elm.height(),
                x = ( coord.x - $elm.offset().left - ( w/2 )) * ( w > h ? ( h/w ) : 1 ),
                y = ( coord.y - $elm.offset().top  - ( h/2 )) * ( h > w ? ( w/h ) : 1 ),
                direction = Math.round( ( ( ( Math.atan2(y, x) * (180 / Math.PI) ) + 180 ) / 90 ) + 3 )  % 4;
            return direction;
        }
        
    }
    
    $(document).ready(function() {
        flip.init();
    });
    

If I can slice this div into equal parts with pure js or a js library I think I can somehow get somewhere.

I did some research, but I couldn't find this kind of div slice on the internet.

Is there anyone who knows about this thing and can help?


Solution

  • You'd need to build a grid of elements, assign them all the same background image, but offset the background coordinates based on their position in the grid.

    Here's a quick example:

    const imgPath = "https://i.sstatic.net/B8aBx.png";
    const xParts = 6;
    const yParts = 5;
    
    /** Asynchronously loads an image from URL
     * @param {string} src */
    function loadImage(src) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.addEventListener("load", () => resolve(img));
            img.addEventListener("error", reject);
            img.src = src;
        });
    }
    
    async function main() {
        const img = await loadImage(imgPath);
        console.log(img.width, img.height);
        
        const container = document.getElementById("grid");
        container.style.width = img.width + "px";
        container.style.height = img.height + "px";
        
        for (let y = 1, nextY = 0, thisY = 0; y <= yParts; ++y, thisY = nextY) {
            nextY = Math.floor((y / yParts) * img.height);
            
            for (let x = 1, nextX = 0, thisX = 0; x <= xParts; ++x, thisX = nextX) {
                nextX = Math.floor((x / xParts) * img.width);
                
                const part = document.createElement("div");
                part.className = "flipPart";
                part.style.top = thisY + "px";
                part.style.left = thisX + "px";
                part.style.width = (nextX - thisX) + "px";
                part.style.height = (nextY - thisY) + "px";
                part.style.backgroundImage = `url(${imgPath})`;
                part.style.backgroundPosition = `left ${-thisX}px top ${-thisY}px`;
                container.appendChild(part);
            }
        }
    }
    
    main();
    #grid {
        border: 1px solid black;
        position: relative;
        perspective: 5000px;
        
        /* Example image is quite large */
        transform-origin: top left;
        transform: scale(0.5);
    }
    
    .flipPart {
        position: absolute;
        transition: transform 1s ease;
    }
    
    .flipPart:hover {
        transform: rotateY(180deg);
    }
    <div id="grid"></div>