从零实现2D绘图引擎:5.5.简单图表demo

MiniRender仓库地址参考

这正是检验"轮子"是否圆润的最佳时刻。我们将利用目前 MiniRender 已经具备的图形能力(Rect, Text)层级管理(Group, z-index)交互能力(Hover, Click) ,构建一个经典的柱状图(Bar Chart)

虽然我们还没有 ECharts 那样的高级配置项,但通过原生绘图指令,我们完全可以"手搓"一个出来。

功能点:

  1. 坐标轴:绘制 X 轴和 Y 轴(使用细长的 Rect 模拟线条)。
  2. 数据可视化:根据数据生成柱子。
  3. 交互反馈:鼠标悬停时,柱子高亮变色。
  4. 数据提示:悬停时,在柱子上方显示具体数值(简单的 Tooltip)。

代码实现 (index.ts)

请将以下代码放入你的入口文件。

typescript 复制代码
import { init } from './core/MiniRender';
import { Group } from './graphic/Group';
import { Rect } from './graphic/shape/Rect';
import { Text } from './graphic/Text';

// 1. 初始化引擎
const dom = document.getElementById('main')!;
const miniRender = init(dom);

// --- 配置数据 ---
const data = [120, 200, 150, 80, 70, 110, 130];
const categories = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

// --- 图表布局配置 ---
const chartConfig = {
    x: 50,          // 图表左边距
    y: 50,          // 图表上边距
    width: 500,     // 绘图区宽度
    height: 300,    // 绘图区高度
    barWidth: 30,   // 柱子宽度
    barColor: '#5470C6', // 默认颜色
    hoverColor: '#91CC75' // 高亮颜色
};

// 创建一个组来容纳整个图表,方便整体移动
const chartGroup = new Group({
    position: [chartConfig.x, chartConfig.y]
});

// --- 第一步:绘制坐标轴 (使用 Rect 模拟线) ---

// Y轴 (左侧竖线)
const yAxis = new Rect({
    shape: {
        x: 0, 
        y: 0, 
        width: 1, 
        height: chartConfig.height
    },
    style: { fill: '#333' }
});

// X轴 (底部横线)
const xAxis = new Rect({
    shape: {
        x: 0, 
        y: chartConfig.height, 
        width: chartConfig.width, 
        height: 1
    },
    style: { fill: '#333' }
});

chartGroup.add(yAxis);
chartGroup.add(xAxis);

// --- 第二步:准备 Tooltip (浮动提示文字) ---
// 我们创建一个共享的 Text 对象,默认隐藏,悬停时移动位置并显示
const tooltip = new Text({
    style: {
        text: '',
        fill: '#000',
        fontSize: 14,
        fontWeight: 'bold',
        textAlign: 'center',
        textBaseline: 'bottom'
    },
    z: 10,       // 保证在最上层
    invisible: true, // 初始隐藏
    silent: true // 关键:让 Tooltip 不阻挡鼠标,防止闪烁
});
// Tooltip 不加到 chartGroup,而是直接加到 miniRender,防止受 group 变换影响(虽然这里 chartGroup 没旋转)
// 但为了坐标方便,加到 chartGroup 里更容易计算相对坐标
chartGroup.add(tooltip);


// --- 第三步:绘制柱子与标签 ---

// 计算每个柱子的间隔
const step = chartConfig.width / data.length;
const maxVal = Math.max(...data);

data.forEach((value, index) => {
    // 1. 数据映射计算
    // 高度比例:value / maxVal
    const barHeight = (value / maxVal) * (chartConfig.height - 40); // 留40px顶部余量
    
    // 柱子左上角坐标 (相对于 chartGroup)
    // x = 间隔 * 索引 + 居中偏移
    const x = index * step + (step - chartConfig.barWidth) / 2;
    // y = 底部Y - 柱子高度
    const y = chartConfig.height - barHeight;

    // 2. 创建柱子
    const bar = new Rect({
        shape: {
            x: x,
            y: y,
            width: chartConfig.barWidth,
            height: barHeight
        },
        style: {
            fill: chartConfig.barColor
        }
    });

    // 3. 创建 X 轴分类文本
    const label = new Text({
        style: {
            text: categories[index],
            fill: '#666',
            fontSize: 12,
            textAlign: 'center',
            textBaseline: 'top'
        },
        position: [x + chartConfig.barWidth / 2, chartConfig.height + 10],
        silent: true // 文本不响应交互
    });

    // 4. 绑定交互事件
    bar.on('mouseover', () => {
        // 柱子变色
        bar.style.fill = chartConfig.hoverColor;
        
        // 显示 Tooltip
        tooltip.invisible = false;
        tooltip.style.text = `${value}`; // 设置数值
        // 移动 Tooltip 到柱子顶部中间
        tooltip.x = x + chartConfig.barWidth / 2;
        tooltip.y = y - 5; // 往上飘一点

        miniRender.refresh();
    });

    bar.on('mouseout', () => {
        // 颜色复原
        bar.style.fill = chartConfig.barColor;
        
        // 隐藏 Tooltip
        tooltip.invisible = true;

        miniRender.refresh();
    });

    chartGroup.add(bar);
    chartGroup.add(label);
});

// 将整个图表组添加到引擎
miniRender.add(chartGroup);

// 渲染第一帧
miniRender.refresh();

相关推荐
Howie Zphile37 分钟前
NEXTJS/REACT有哪些主流的UI可选
前端·react.js·ui
fruge38 分钟前
React Server Components 实战:下一代 SSR 开发指南
前端·javascript·react.js
lichong95139 分钟前
harmonyos 大屏设备怎么弹出 u 盘
前端·macos·华为·typescript·android studio·harmonyos·大前端
irises39 分钟前
从零实现2D绘图引擎:5.鼠标悬停事件
前端·数据可视化
青莲84340 分钟前
Android Lifecycle 完全指南:从设计原理到生产实践
android·前端
irises41 分钟前
从零实现2D绘图引擎:4.矩形与文本的实现
前端·数据可视化
前端_逍遥生41 分钟前
Vue 2 vs React 18 深度对比指南
前端·vue.js·react.js
irises42 分钟前
从零实现2D绘图引擎:2.Storage和Painter的实现
前端·数据可视化
irises1 小时前
从零实现2D绘图引擎:3.交互系统(Handle)的实现
前端·数据可视化