7

Building a line graph with CSS clip-mask

 1 year ago
source link: https://benfrain.com/building-a-line-graph-with-css-clip-mask/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Building a line graph with CSS clip-mask

23.06.2023 0 comments
0 days since last revision. Content should be accurate.

This isn’t a substitute for d3 or chart.js. It is however, a surprisingly simple and effective way of creating a line graph.

I’ve used this clip-path technique when I want to show a basic updating worm of data but don’t want to add an extra library.

I’m using a bunch of stubbed data here to illustrate, and JavaScript to render some of the UI but the crucial thing to understand is CSS. With a little calc() and the use of clip-mask you can easily create a line graph (or worm as they are sometimes known). The premise is simple, a clip-mask clips a rectangle with a series of X/Y coordinates. Each bringing the shape ‘in’ from it’s edges. The best way to understand how the syntax works is to take a look at Bennet Feely’s excellent clippy.

Here is a basic implementation:

Example

Specifics of the technique

And here is the clip-mask creating that line chart:

clip-path: polygon(
  0% 60%,
  20% 90%,
  40% 43.33%,
  60% 61.67%,
  80% 23.33%,
  100% 18.33%,
  100% calc(18.33% - 1px),
  80% calc(23.33% - 1px),
  60% calc(61.67% - 1px),
  40% calc(43.33% - 1px),
  20% calc(90% - 1px),
  0% calc(60% - 1px)
);

The key thing to achieve this effect is understanding that to create a ‘line’, we want to run once along our data to bring our mask in from the top, and then, assuming we want a line and not a filled shape (also possible), we want to bring our mask in from the bottom by going over the positions again, exactly the same in reverse, albeit 1px shorter, made easy with calc(), in the vertical axis. You can see this clearly when looking at the mask above, where it is laid out one position at a time.

Implementation

How you manipulate your data to create this string is up to you. For this basic example, from a basic array of data shaped like this:

let values = [
  {
    time: 1,
    value: 144,
  },
  {
    time: 2,
    value: 126,
  },
  // ... more
];

I have used a function like so:

function makeWorm() {
  let duration = 150;
  let generatePointX = (data) => (100 / duration) * data.time;
  let generatePointY = (data) => ((data.value - 120) * 100) / (180 - 120);

  let maskString = `clip-path: polygon(`;
  values.map((data) => {
    maskString += `${generatePointX(data).toFixed(2)}% ${(
      100 - generatePointY(data)
    ).toFixed(2)}%, `;
  });
  values.toReversed().map((data, i, { length }) => {
    maskString += `${generatePointX(data).toFixed(2)}% calc(${(
      100 - generatePointY(data)
    ).toFixed(2)}% - 1px)`;
    if (i + 1 !== length) {
      maskString += `, `;
    }
  });

  maskString += `);`;
  return maskString;
}

worm.style = makeWorm();

There are a couple of hard coded values in there for the vertical points, based upon the values I have in my data. You would likely want to compute the bottom and top extremes of your chart based upon the highest and lowest values in your own data.

There are likely cleaner ways of generating the string too but this works; looping over the array of data, first one way for the ‘top’ positions of the mask, and then reversing through the array to generate the ‘bottom’ coordinates.

Summary

This way of creating a line chart is very basic but very light. Sure, we can do this kind of thing with the more suitable SVG but I found it a fun application of clip-mask. It also isn’t ‘transition-able’, so if you were hoping of getting it cleanly animating in this manner, I’m afraid you’re out of luck.

Improvements? Examples of clip-mask graphs you’ve made yourself? Let me know in the comments below.

If you enjoyed this post and/or it was useful, Say thanks with a coffee. 🙏


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK