Search code examples
csshtml5-canvasdemo

Use html5 canvas or CSS3 animation to demo app snapshots


I want to create an animated app demo: load the sceenshot1 -> button click -> switch to sceenshot2 -> typing 2 lines of text. I saw a site doing similar animation (https://www.pixelapse.com/).

Is html5 canvas or CSS3 the right tool to create this animation? I found this library. https://github.com/GwennaelBuchet/SceneGraph.js. Are there any other tools to create this kind of animation?

enter image description here

enter image description here


Solution

  • Here's an example and Demo to get you started:

    One comment:

    enter image description here

    Multiple comments:

    enter image description here

    • Draw the image associated with the comment: context.drawImage

    • Draw the text part of the comment and wrap it onto multiple lines as required: see the wrapText function in the example below.

    • Draw the rounded rectangle around the images+comments: see the roundedRect function in the example below.

    Example code and Demo to get you started:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var cw = canvas.width;
    var ch = canvas.height;
    
    var x = 25;
    var y = 25;
    var width = 350;
    var height = 0;
    var radius = 10;
    var padding = 10;
    
    var comments = [];
    var commentDisplayCount = 1;
    comments.push({
      imgIndex: 0,
      name: 'jennifer',
      comment: 'Lacking contrast in the colors around this blue thing on top of the swan origami. What do you think we can do to punch it up a bit?'
    });
    comments.push({
      imgIndex: 1,
      name: 'Richard',
      comment: 'Maybe we try a darker shade of blue in the sides of that blue thing?'
    });
    comments.push({
      imgIndex: 0,
      name: 'jennifer',
      comment: 'Blah, Blah, Blah'
    });
    comments.push({
      imgIndex: 1,
      name: 'Richard',
      comment: 'Yep, Yep, Yep'
    });
    
    // preload images
    // put the paths to your images in imageURLs[]
    var imageURLs = [];
    // push all your image urls!
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/face1.png");
    imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/face2.png");
    
    // the loaded images will be placed in imgs[]
    var imgs = [];
    var imagesOK = 0;
    loadAllImages(start);
    
    function loadAllImages(callback) {
      for (var i = 0; i < imageURLs.length; i++) {
        var img = new Image();
        imgs.push(img);
        img.onload = function() {
          imagesOK++;
          if (imagesOK >= imageURLs.length) {
            callback();
          }
        };
        img.onerror = function() {
          alert("image load failed");
        }
        img.crossOrigin = "anonymous";
        img.src = imageURLs[i];
      }
    }
    
    function start() {
    
      // the imgs[] array now holds fully loaded images
      // the imgs[] are in the same order as imageURLs[]
    
      draw();
    }
    
    
    function draw() {
      var accumHeight = 0;
      var imageWidth = 35;
    
      ctx.clearRect(0, 0, cw, ch);
      for (var i = 0; i < commentDisplayCount; i++) {
    
        ctx.drawImage(imgs[comments[i].imgIndex], x + padding, y + accumHeight + padding, 25, 25);
    
        accumHeight = wrapText(
          comments[i].comment,
          x + padding + imageWidth,
          y + padding + accumHeight,
          width - padding * 2 - imageWidth, 12, "verdana"
        );
    
      }
      roundedRect(x, y, width, accumHeight, radius);
    }
    
    
    function roundedRect(x, y, w, h, r) {
      ctx.beginPath();
      ctx.moveTo(x + r, y);
      ctx.lineTo(x + w - r, y);
      ctx.quadraticCurveTo(x + w, y, x + w, y + r);
      ctx.lineTo(x + w, y + h - r);
      ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
      ctx.lineTo(x + r, y + h);
      ctx.quadraticCurveTo(x, y + h, x, y + h - r);
      ctx.lineTo(x, y + r);
      ctx.quadraticCurveTo(x, y, x + r, y);
      ctx.closePath();
      ctx.strokeStyle = 'black';
      ctx.fillStyle = 'white';
      ctx.stroke();
      ctx.globalCompositeOperation = 'destination-over';
      ctx.fill();
      ctx.globalCompositeOperation = 'source-over';
    }
    
    
    function wrapText(text, x, y, maxWidth, fontSize, fontFace) {
      var words = text.split(' ');
      var line = '';
      var lineHeight = fontSize;
      y += fontSize;
      ctx.font = fontSize + " " + fontFace;
      ctx.fillStyle = 'black';
      for (var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = ctx.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth) {
          ctx.fillText(line, x, y);
          line = words[n] + ' ';
          y += lineHeight;
        } else {
          line = testLine;
        }
      }
      ctx.fillText(line, x, y);
      return (y);
    }
    
    
    
    $("#test").click(function() {
      if (++commentDisplayCount > comments.length) {
        commentDisplayCount = comments.length;
      }
      draw();
    });
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <button id="test">Add a Comment</button>
    <br>
    <canvas id="canvas" width=400 height=400></canvas>