从零实现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();

相关推荐
爱上好庆祝36 分钟前
学习js的第五天
前端·css·学习·html·css3·js
C澒1 小时前
IntelliPro 产研协作平台:基于 AI Agent 的低代码智能化配置方案设计与实现
前端·低代码·ai编程
一袋米扛几楼981 小时前
【Git】规范化协作:详解 GitHub 工作流中的 Issue、Branch 与 Pull Request 最佳实践
前端·git·github·issue
网络点点滴1 小时前
前端与后端的区别与联系
前端
EnCi Zheng2 小时前
M5-markconv自定义CSS样式指南 [特殊字符]
前端·css·python
kyriewen2 小时前
你的网页慢,用户不说直接走——前端性能监控教你“读心术”
前端·性能优化·监控
广州华水科技2 小时前
北斗GNSS变形监测在大坝安全监测中的应用与优势分析
前端
前端老石人2 小时前
前端开发中的 URL 完全指南
开发语言·前端·javascript·css·html
CAE虚拟与现实2 小时前
五一假期闲来无事,来个前段、后端的说明吧
前端·后端·vtk·three.js·前后端
Sarvartha2 小时前
三目运算符
linux·服务器·前端