简体   繁体   中英

Animate HTML5 canvas elements to change shape (on scroll or rollover) without gaps between them (the elements must be vertically connected)

How can I modify the shape of all elements (one by one) while scrolling on canvas or by rollover each element (to get random shape, but with some boundaries for the text to be in section more/less) and also to keep the elements vertically connected together? (no gaps in between to follow each other). I guess this can be done with coordinates?

Screenshot

I've done some research and I haven't found a similar example. I am open also to other solutions, javascript libraries, SCSS, skew() CSS function , clip-path CSS property , SVG or mask or anything else for the web (I mean, there is no special reason to use only one specific way).

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <style type="text/css">
    #myCanvas {
      border: 1px solid black;
      width: 100%;
      height: auto;
    }
  </style>
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
</head>
<body>

    <canvas id="myCanvas"></canvas>

    <script>
    $(function() {

        var canvas = document.getElementById('myCanvas'),
        width = window.innerWidth,
        height = window.innerHeight,
        elemWidth = window.innerWidth - 20,
        lineheight = 30,
        txt1 = 'Lorem 1 ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula\neget dolor. Aenean massa. Cum sociis natoque penatibus et',
        txt2 = 'Lorem 2 ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula\neget dolor. Aenean massa. Cum sociis natoque penatibus et',
        txt3 = 'Lorem 3 ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula\neget dolor. Aenean massa. Cum sociis natoque penatibus et',
        lines1 = txt1.split('\n'),
        lines2 = txt2.split('\n'),
        lines3 = txt3.split('\n');

        window.addEventListener('resize', resizeCanvas, false);

        function resizeCanvas() {
            canvas.width = width;
            canvas.height = height;
            drawStuff();
        }

        resizeCanvas();

        function drawStuff() {

            // element 1
            var poly1 = [5,100, (elemWidth-100),5, elemWidth,400, 5,300 ];
            var ctx1 = canvas.getContext('2d');
            ctx1.fillStyle = '#ff8080';
            ctx1.beginPath();
            ctx1.moveTo(poly1[0], poly1[1]);
            for(item = 2 ; item < poly1.length - 1 ; item += 2) {
                ctx1.lineTo(poly1[item], poly1[item + 1]);
            }
            ctx1.closePath();
            ctx1.fill();
            ctx1.fillStyle = "Black";
            ctx1.font = '70px Arial';
            ctx1.fillText("Some title 1",300,180);
            ctx1.font = '30px Arial';
            for (var i = 0; i<lines1.length; i++) {
                ctx1.fillText(lines1[i], 300, 220 + (i*lineheight) );
            }

            // element 2
            var poly2 = [5,300, elemWidth,400, (elemWidth-100),800, 50,600];
            var ctx2 = canvas.getContext('2d');
            ctx2.fillStyle = '#e9afaf';
            ctx2.beginPath();
            ctx2.moveTo(poly2[0], poly2[1]);
            for(item = 2 ; item < poly2.length - 1 ; item += 2) {
                ctx2.lineTo(poly2[item], poly2[item + 1]);
            }
            ctx2.closePath();
            ctx2.fill();
            ctx2.fillStyle = "Black";
            ctx2.font = '70px Arial';
            ctx2.fillText("Some title 2",300,480);
            ctx2.font = '30px Arial';
            for (var i = 0; i<lines2.length; i++) {
                ctx2.fillText(lines2[i], 300, 520 + (i*lineheight) );
            }

            // element 3
            var poly3 = [50,600, (elemWidth-100),800, elemWidth,940, 5,900];
            var ctx3 = canvas.getContext('2d');
            ctx3.fillStyle = '#c8b7b7';
            ctx3.beginPath();
            ctx3.moveTo(poly3[0], poly3[1]);
            for(item = 2 ; item < poly3.length - 1 ; item += 2) {
                ctx3.lineTo(poly3[item], poly3[item + 1]);
            }
            ctx3.closePath();
            ctx3.fill();
            ctx3.fillStyle = "Black";
            ctx3.font = '70px Arial';
            ctx3.fillText("Some title 3",300,780);
            ctx3.font = '30px Arial';
            for (var i = 0; i<lines3.length; i++) {
                ctx3.fillText(lines3[i], 300, 820 + (i*lineheight) );
            }

        }

    });
    </script>
</body>
</html>

Update: I've created the suggested SVGs, since my target is the animation, any suggestions/ideas on updating those polygon points values (for example on rollover, I can use jquery) that the next polygons can follow (update points) dynamically and also staying connected?

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style type="text/css">
  svg {
    width: 100%;
    height: auto;
  }
</style>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
</head>
<body>
<svg width="100%" viewBox="0 0 100 100" preserveAspectRatio="none">
  <polygon fill="#99bde5" points="0,5 95,0 100,35, 0,20" id="testElem"/>
  <text x="10" y="12" text-anchor="left" fill="black" font-size="6">Some title 1</text>
  <text x="10" y="15" text-anchor="left" fill="black" font-size="3">
      <tspan>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</tspan>
      <tspan x="10" dy="3">Aenean commodo ligula eget dolor. Aenean massa.</tspan>
  </text>

  <polygon fill="#c9e599" points="0,20 100,35 100,55, 5,50" id="testElem"/>
  <text x="10" y="36" text-anchor="left" fill="black" font-size="6">Some title 1</text>
  <text x="10" y="40" text-anchor="left" fill="black" font-size="3">
      <tspan>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</tspan>
      <tspan x="10" dy="3">Aenean commodo ligula eget dolor. Aenean massa.</tspan>
  </text>

  <polygon fill="#a5e599" points="5,50 100,55 94,75, 5,80" id="testElem"/>
  <text x="10" y="63" text-anchor="left" fill="black" font-size="6">Some title 1</text>
  <text x="10" y="67" text-anchor="left" fill="black" font-size="3">
      <tspan>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</tspan>
      <tspan x="10" dy="3">Aenean commodo ligula eget dolor. Aenean massa.</tspan>
  </text>

  <polygon fill="#99e5ca" points="5,80 94,74 100,100, 0,100" id="testElem"/>
  <text x="10" y="89" text-anchor="left" fill="black" font-size="6">Some title 1</text>
  <text x="10" y="92" text-anchor="left" fill="black" font-size="3">
      <tspan>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</tspan>
      <tspan x="10" dy="3">Aenean commodo ligula eget dolor. Aenean massa.</tspan>
  </text>
</svg>
</body>
</html>

PS. The SVG points are x,y and clock-wise starting from top-left to bottom-left.

I think your best bet is going to be with an svg . Here's an example of someone doing something pretty similar: https://codepen.io/erikdkennedy/pen/ygpwZg

The key is the points of the polygon added within the svg which creates a triangular section added to the rectangular header. The svg here has no background so it's actually cutting a section out of the the header. This is basically removing a section from the parent element. You can change it to div instead of header or whatever element you need it to be.

<polygon fill="white" points="0,100 100,0 100,100"/>

From the documentation , points are pairs of (x,y) coordinates. SVGs are very flexible and open to whatever customization you need. Setting up the points will be the only tricky part as you'll have to experiment till you get the shape(s) you need. You'll need your parent elements to be large enough that you can cut sections out to fit your design.

Update

I haven't seen it confirmed in documentation, but the points appear to be percentages of the space provided. And, for some reason, y is flipped. So using that last example, 0,100 100,0 100,100 translates to bottom left, upper right, bottom right.

Update (animation)

As far as animating your points, here's another helpful example on that. This boils down to creating an animate tag within the svg with an ID to reference, ( documentation here ). You set your animation properties on the animate tag. To trigger it call the id of the reference and then trigger it with beginElement :

var animationToStar = document.getElementById("animation-to-star")
animationToStar.beginElement();

Note that the properties for to on the animate tag. This dictates what the shape should be at the end of the animation. For your use case you'll want to set up event listeners for mouseover , mouseleave , and scroll to fire off the animations per your design.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM