当前位置:首页 > 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实现验证码

js实现验证码

实现验证码的JavaScript方法 生成随机验证码 使用Math.random()生成随机字符串,结合数字和字母: function generateCaptcha() { const cha…

js实现vue路由

js实现vue路由

Vue路由基础实现 使用Vue Router实现前端路由需要先安装并配置路由库。Vue Router是Vue.js官方的路由管理器。 安装Vue Router: npm install vue…

js 实现vue模板

js 实现vue模板

实现 Vue 模板的 JavaScript 方法 通过原生 JavaScript 可以实现类似 Vue 的模板渲染功能,主要包括数据绑定、指令处理和模板解析。以下是核心实现思路: 数据绑定与响应式…

js实现

js实现

实现 JavaScript 功能的方法 在 JavaScript 中实现特定功能通常涉及多个步骤。以下是常见的实现方法: 基础语法和变量声明 使用 let 或 const 声明变量: let co…

js实现轮播

js实现轮播

实现轮播图的基本思路 轮播图的核心逻辑是通过定时切换展示的图片或内容,通常结合左右滑动按钮和指示器(小圆点)增强交互性。以下是基于原生JavaScript的实现方法。 HTML结构 构建轮播图的H…

js实现动画

js实现动画

使用 CSS 动画与 JavaScript 控制 通过 JavaScript 动态添加或移除 CSS 类来触发动画。CSS 定义关键帧(@keyframes),JavaScript 通过 classL…