Skip to content

使用 SVG 在 Taro 小程序中简单作图

alt text

如图,就这么简单个东西。要在 Taro 的小程序上画个曲线。

一开始研究的方向是给小程序里内置 ECharts,问了 AI,搜了 Github,最后找到了 echarts4taro3。鼓捣半天,死活都报错。

后来换了研究方向,我干嘛不直接生成 svg,当成图片画上去呢。

js
import Taro from '@tarojs/taro'

export const generateSvgCurve = (dataList) => {
    // 1. 定义画布基础尺寸
    const width = 300;
    const height = 120;
    const padding = 15; 

    // 2. 映射 X 轴和 Y 轴的坐标
    const xStep = (width - padding * 2) / 6; 
    
    const amounts = dataList.map(item => item.amount || 0);
    const maxAmount = Math.max(...amounts, 1); 
    const minAmount = Math.min(...amounts, 0);
    const range = maxAmount - minAmount;

    const points = dataList.map((item, index) => {
        const x = padding + index * xStep;
        const ratio = range === 0 ? 0.5 : (item.amount - minAmount) / range;
        const y = height - padding - ratio * (height - padding * 2);
        return { x, y };
    });

    // 3. 使用贝塞尔控制点让折线变弯
    let pathData = `M ${points[0].x} ${points[0].y}`;
    for (let i = 0; i < points.length - 1; i++) {
        const p0 = points[i];
        const p1 = points[i + 1];
        
        const cpX1 = p0.x + xStep / 2;
        const cpY1 = p0.y;
        const cpX2 = p1.x - xStep / 2;
        const cpY2 = p1.y;

        pathData += ` C ${cpX1} ${cpY1}, ${cpX2} ${cpY2}, ${p1.x} ${p1.y}`;
    }

    const lastPoint = points[points.length - 1];

    // 4. 🌟 核心修改:把里面的 %23 全部恢复成标准的 # 号
    // 在 Base64 方案下,标准的 # 号才是对的,并且不需要任何正则压缩处理
    const svgHtml = `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${width} ${height}' width='100%' height='100%'><path d='${pathData}' fill='none' stroke='#9bc88d' stroke-width='3' stroke-linecap='round' /><circle cx='${lastPoint.x}' cy='${lastPoint.y}' r='5' fill='#ff9244' /></svg>`;

    // 5. 传入 Taro 原生转换
    const uint8Array = new TextEncoder().encode(svgHtml);
    const base64Data = Taro.arrayBufferToBase64(uint8Array.buffer);

    return `data:image/svg+xml;base64,${base64Data}`;
};
vue
<script setup>
const svgSrc = ref('')
const initChart = (originData = [{ amount: 0 }, { amount: 0 }, { amount: 0 }, { amount: 0 }, { amount: 0 }, { amount: 0 }, { amount: 0 }]) => {

    const isAllZero = originData.every(item => item.amount === 0);
    
    let renderData = [...originData];
    if (isAllZero) {

        const mockWaves = [10, 11, 13, 12, 11, 12, 10];
        renderData = originData.map((item, index) => ({
            ...item,
            amount: mockWaves[index] 
        }));
    }

    // 生成 SVG 链接
    svgSrc.value = generateSvgCurve(renderData);
};
</script>
<template>
    <image class="recently7-graph" :src="svgSrc" mode="contain"></image>
</template>

完事。

alt text

最后更新于:

评论区
评论区空空如也
发送评论
名字
0 / 20
邮箱
0 / 100
评论内容
0 / 140
由于是非实名评论,所以不提供删除功能。如果你需要删除你发送的评论,或者是其他人的评论对你造成了困扰,请 发邮件给我 。同时评论区会使用 AI + 人工的方式进行审核,以达到合规要求。