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

相关推荐
GISer_Jing6 小时前
Taro跨端开发实战:核心原理与关键差异解析
前端·javascript·taro
无心使然云中漫步6 小时前
vant实现自定义日期时间选择器(年月日时分秒)
前端·vue
极客先躯6 小时前
EasyUI + jQuery 自定义组件封装规范与项目结构最佳实践
前端·jquery·easyui
❀͜͡傀儡师6 小时前
docker部署Docker Compose文件Web管理工具Dockman
java·前端·docker·dockman
karshey7 小时前
【前端】sort:js按照固定顺序排序
开发语言·前端·javascript
MyBFuture7 小时前
索引器实战:对象数组访问技巧及命名空间以及项目文件规范
开发语言·前端·c#·visual studio
IT_陈寒7 小时前
Redis性能提升50%的7个实战技巧,连官方文档都没讲全!
前端·人工智能·后端
打小就很皮...7 小时前
React 富文本图片上传 OSS 并防止 Base64 图片粘贴
前端·react.js·base64·oss
咬人喵喵7 小时前
告别无脑 <div>:HTML 语义化标签入门
前端·css·编辑器·html·svg