1

There is a funnel diagram in the recently received request. Compared with the funnel of the chart library, it looks a little different. Although there is a funnel, the rest of the chart library cannot be combined to achieve it, so I think about implementing one by myself.
image.png

The right part is actually very simple. It is mainly realized by the funnel chart on the left. The funnel chart is actually assembled by several isosceles trapezoids. If you use div+css and think of using borders, then the assembly is a little troublesome, just use it. svg to do:

  1. polygon can draw isosceles trapezoid directly
  2. The method of fixed coordinates makes the stitching no problem

So how to get the coordinates of the trapezoid? What is the law with the data?

image.png
Generally speaking, the funnel is wide at the top and narrow at the bottom. The length of the top and bottom of each trapezoid actually corresponds to the comparison of each piece of node data.
As shown in the figure above, assuming it is the first grid data of the funnel, then the AB side length is the maximum width of the funnel, which also maps the first grid data, and the longer the bottom CD is mapped to the second grid data.
Then the ratio of the two sides can be determined, assuming that the funnel data is a1, a2, a3, a4
Then AB: CD = a1: a2

The coordinate of point A is the starting point, that is (0, 0). Assuming the width of the funnel is allWidth, then the coordinate of point B should be (allWidth, 0)
The coordinates of point C are calculated (CG, AG):

  • The height of the funnel block is fixed, so the length of AG is fixed, which is assumed to be h
  • CG = (AB-CD)/2; converted to calculation data ratio is CG = allWidth * (1-a2/a1)/2

The coordinates of point D use isosceles trapezoid symmetry, and the coordinates are (allWidth-CG, h)

Think about it carefully, the top coordinate of each trapezoid is the bottom coordinate of the previous trapezoid. As long as the bottom coordinate calculates the difference, the CG side length, the abscissa of the left and right coordinates can be obtained.

Based on these summarized relationships, suppose our data is like this list = [{number: 100}, {number: 60}, {number: 50}, {number: 10}], we press the following code to extract the drawing The coordinates (0,0) of the four vertices of the four polygons are the starting points

// BASE_WIDTH 为实际边宽, PER_HEIGHT为梯形高
// 取出顶边数据(对应BASE_WIDTH)
    const allWidth = list[0].number;
    // 先计算每一个差值
    const deltas = list
      .slice(1)// 排除掉第一个数据即基准值
      .concat(list[list.length - 1]) // 结尾补充一个,最后一个梯形没有下一个比较,所以是矩形
      .map((item) => {
        return ((1 - item.number / allWidth) / 2) * BASE_WIDTH;
      });
    // 遍历数据
    return list.map((item, index) => {
      let points;
      // 独立处理第一个数据
      if (index === 0) {
        points = [
          [0, 0],// 左上点
          [BASE_WIDTH, 0],// 右上点
          [BASE_WIDTH - deltas[index], PER_HEIGHT],// 右下点 横坐标即全长-差值
          [deltas[index], PER_HEIGHT], // 左下点 横坐标即为差值
        ];
      } else {
        points = [
          [deltas[index - 1], PER_HEIGHT * index], // 左上点,即上一个梯形的左下点,纵坐标为一个PER_HEIGHT
          [BASE_WIDTH - deltas[index - 1], PER_HEIGHT * index],// 右上点 即上一个梯形的右下点
          [BASE_WIDTH - deltas[index], PER_HEIGHT * (index + 1)],// 右下点
          [deltas[index], PER_HEIGHT * (index + 1)],// 左下点
        ];
      }
      return {
        ...item,
        points,
      };
    });

At this point, we have sorted out the vertex coordinates of several trapezoids. Next, just apply the polygon svg.

After the left part of the funnel is completed, only the back part is left. Obviously, polygons can also be used to draw, and it is more convenient to align with the left part.

For the overall effect, see codepen >> https://codepen.io/shellphon-the-encoder/pen/oNZMJaN

Update: The similar trapezoidal function can also be completed by turning to clip-path. Here is an example of funnel:

https://codepen.io/shellphon-the-encoder/pen/PopxpqV


Dont
7k 声望144 粉丝

学如逆水行舟不进则退