当前位置:首页 > JavaScript

js实现漏斗

2026-02-02 08:14:56JavaScript

使用 Canvas 绘制漏斗图

Canvas 提供了灵活的绘图能力,适合实现自定义漏斗效果。以下是一个基础实现示例:

js实现漏斗

const canvas = document.getElementById('funnelCanvas');
const ctx = canvas.getContext('2d');

function drawFunnel(data) {
  const width = canvas.width;
  const height = canvas.height;
  const segmentCount = data.length;
  const segmentHeight = height / segmentCount;

  data.forEach((item, index) => {
    const ratio = 1 - (index * 0.15); // 每层宽度递减比例
    const segmentWidth = width * ratio;
    const x = (width - segmentWidth) / 2;
    const y = index * segmentHeight;

    ctx.fillStyle = `hsl(${index * 30}, 70%, 60%)`;
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x + segmentWidth, y);
    ctx.lineTo(x + segmentWidth * 0.9, y + segmentHeight);
    ctx.lineTo(x + segmentWidth * 0.1, y + segmentHeight);
    ctx.closePath();
    ctx.fill();

    ctx.fillStyle = '#fff';
    ctx.textAlign = 'center';
    ctx.fillText(item.label, width/2, y + segmentHeight/2 + 5);
  });
}

drawFunnel([
  { label: 'Visits', value: 1000 },
  { label: 'Signups', value: 800 },
  { label: 'Purchases', value: 400 }
]);

使用 SVG 创建漏斗图

SVG 方案更适合需要动态交互的场景:

js实现漏斗

function createSVGFunnel(data, containerId) {
  const container = document.getElementById(containerId);
  const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  svg.setAttribute('viewBox', '0 0 200 300');

  const total = Math.max(...data.map(d => d.value));
  const segmentHeight = 300 / data.length;

  data.forEach((item, i) => {
    const width = 200 * (item.value / total);
    const y = i * segmentHeight;
    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");

    const d = `
      M ${100 - width/2} ${y}
      L ${100 + width/2} ${y}
      L ${100 + width/2 * 0.9} ${y + segmentHeight}
      L ${100 - width/2 * 0.9} ${y + segmentHeight}
      Z
    `;

    path.setAttribute('d', d);
    path.setAttribute('fill', `hsl(${i * 40}, 80%, 65%)`);
    svg.appendChild(path);

    const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.setAttribute('x', '100');
    text.setAttribute('y', y + segmentHeight/2);
    text.setAttribute('fill', 'white');
    text.setAttribute('text-anchor', 'middle');
    text.textContent = `${item.label}: ${item.value}`;
    svg.appendChild(text);
  });

  container.appendChild(svg);
}

使用 D3.js 高级方案

对于复杂数据可视化,D3.js 提供了更专业的解决方案:

import * as d3 from 'd3';

function renderD3Funnel(data, container) {
  const width = 600;
  const height = 400;
  const margin = { top: 20, right: 20, bottom: 60, left: 20 };

  const svg = d3.select(container)
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  const maxValue = d3.max(data, d => d.value);
  const yScale = d3.scaleLinear()
    .domain([0, data.length])
    .range([margin.top, height - margin.bottom]);

  const xScale = d3.scaleLinear()
    .domain([0, maxValue])
    .range([0, width - margin.left - margin.right]);

  const color = d3.scaleOrdinal()
    .domain(data.map((d,i) => i))
    .range(d3.schemeTableau10);

  const funnel = svg.append('g')
    .attr('transform', `translate(${margin.left},0)`);

  data.forEach((d, i) => {
    const currentWidth = xScale(d.value);
    const nextWidth = i < data.length - 1 ? xScale(data[i+1].value) : 0;

    funnel.append('path')
      .attr('d', `
        M ${(width - currentWidth)/2} ${yScale(i)}
        L ${(width + currentWidth)/2} ${yScale(i)}
        L ${(width + nextWidth)/2} ${yScale(i+1)}
        L ${(width - nextWidth)/2} ${yScale(i+1)}
        Z
      `)
      .attr('fill', color(i))
      .attr('stroke', '#fff');

    funnel.append('text')
      .attr('x', width/2)
      .attr('y', yScale(i) + (yScale(1) - yScale(0))/2)
      .attr('text-anchor', 'middle')
      .attr('fill', 'white')
      .text(`${d.label} (${d.value})`);
  });
}

响应式设计注意事项

实现响应式漏斗图需要考虑以下要点:

  • 使用百分比宽度而非固定像素值
  • 添加 resize 事件监听器重新计算尺寸
  • 设置适当的 viewBox 保持 SVG 比例
  • 使用 CSS media queries 调整文字大小
window.addEventListener('resize', function() {
  const containerWidth = document.getElementById('chartContainer').clientWidth;
  const aspectRatio = 2/3; // 宽高比
  const newHeight = containerWidth * aspectRatio;

  d3.select('#funnelSVG')
    .attr('width', containerWidth)
    .attr('height', newHeight);
});

以上方案可根据具体需求选择,Canvas 适合性能敏感场景,SVG 适合需要交互的场景,D3.js 则提供最完整的数据可视化功能。实际项目中可结合 CSS 动画和过渡效果增强用户体验。

标签: 漏斗js
分享给朋友:

相关文章

js实现pdf在线预览

js实现pdf在线预览

使用PDF.js实现PDF在线预览 PDF.js是由Mozilla开发的一个开源JavaScript库,可以在网页中直接渲染PDF文件。以下是实现PDF在线预览的步骤: 引入PDF.js库 在HT…

js钟表实现

js钟表实现

实现JavaScript钟表的基本方法 创建一个简单的JavaScript钟表可以通过以下步骤完成,涵盖数字和模拟两种形式。 数字钟表实现 HTML结构只需一个显示时间的容器: <div i…

js怎么实现异步

js怎么实现异步

异步实现方法 JavaScript中实现异步操作主要通过以下几种方式: Promise Promise是ES6引入的异步解决方案,用于处理异步操作的成功或失败状态。 const promise =…

js 实现图片 放大

js 实现图片 放大

使用 CSS transform 实现图片放大 通过 CSS 的 transform: scale() 属性可以实现图片的平滑放大效果。结合 JavaScript 监听鼠标事件控制放大状态: con…

js 实现全选

js 实现全选

实现全选功能的方法 使用 JavaScript 实现全选功能通常需要操作复选框(checkbox)的状态。以下是几种常见的实现方式。 通过 DOM 操作实现全选 // 获取全选复选框和子复选框 co…

js实现复选框

js实现复选框

实现复选框的基本方法 使用HTML的<input type="checkbox">元素创建复选框,并通过JavaScript监听其状态变化。 <input type="checkb…