使用zrender(canvas) + d3绘制关系图谱

3,507 阅读3分钟

在这个dome中d3只用于位置计算和缩放,在关系图谱中,大量节点的情况下,对比与svg,canvas有着性能优势,因为它不需要频繁操作dom节点,不需要创建深层次的dom结构。 使用原生的canvas api比较复杂,很多第三方库提供了更加方便操作canvas的库,这里选用的是zrender。 canvas的一些比较复杂的东西比如事件,层级在zrender中也可以很好地实现。

zrender

api文档:ecomfe.github.io/zrender-doc… 仓库地址:github.com/ecomfe/zren… demo:github.com/ecomfe/zren… 由于目前最新版本对一些功能的支持和文档不一样(图形文字),所以当前demo采用4.3.2版本。

核心api

初始化

选择html中对应存在的dom作为容器,返回一个实例对象,用于创建图形,这里要记得给#main设置宽高

const zr = zrender.init(document.querySelector('#main'));

创建一个圆形

<body>
    <div id="main" style="width:100vw;height:100vh"></div>
    <script src="../lib/zrender.v4.3.2.js"></script>
    <script>
        const zr = new zrender.init(document.querySelector('#main'));
        console.log(zr);
        const circle = new zrender.Circle({
            shape: {
                // 圆中心点x坐标
                cx: 100,
                // 圆中心点y坐标
                cy: 100,
                // 圆半径
                r: 100
            },
            style: {
                // 设置圆样式
                fill: 'blue',
                stroke: 'black',

                // 设置圆内文本样式
                text: '圆内文本',
                textFill: 'white',
                fontSize: 20,
                // 缩放文本大小跟随
                transformText: true
            }
        })
        zr.add(circle)
    </script>
</body>

image.png

创建一条直线

    const line = new zrender.Line({
            shape: {
                // 起始x坐标
                x1: 100,
                // 起始y坐标
                y1: 300,
                // 结束x坐标
                x2: 100,
                // 结束y坐标
                y2: 500
            },
            style: {
                // 线条颜色
                stroke: 'blue',
                // 线条粗细
                lineWidth: 2,

                text: '直线中间的文本',
                // 文字的包围矩形背景色
                textBackgroundColor: '#fff',
            }
        })
    zr.add(line);

image.png

绘制三角形

  const polygon = new zrender.Polygon({
        shape: {
            // 填充图形的坐标
            points: [[x3, y3], [x4, y4], [x2, y2]],
        },
        style: {
            fill: '填充颜色',
            opacity
        },
        z
  })

创建带箭头的直线

箭头的位置需要一些三角函数的运算,下面代码为封装好的绘制函数,offset为0的时候尖端是个矩形,可以调整为负数实现更好的效果,当前这个dome中,由于箭头指向圆变,所以要偏移圆半径的距离。

    const zr = new zrender.init(document.querySelector('#main'));
    /*
        x1,y1:起点坐标
        x2,y2:终点坐标
        offset:箭头距离终点偏移量
        l:箭头大小控制参数
    */
    function drawArrow(zr, x1, y1, x2, y2, offset = 0, l = 10) {
        const line = new zrender.Line({
            shape: {
                x1,
                y1,
                x2,
                y2
            },
            style: {
                // 线条颜色
                stroke: 'blue',
                // 线条粗细
                lineWidth: 2,

                text: '直线中间的文本',
                // 文字的包围矩形背景色
                textBackgroundColor: '#fff',
            }
        })

        const a = Math.atan2((y2 - y1), (x2 - x1));
        let tx = x2;
        let ty = y2
        // 偏移长度
        let totalLength = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
        x2 = x1 + (totalLength - offset) * Math.cos(a)
        y2 = y1 + (totalLength - offset) * Math.sin(a)
        // D点x轴坐标
        const x3 = x2 - l * Math.cos(a + 30 * Math.PI / 180);
        // D点y轴坐标
        const y3 = y2 - l * Math.sin(a + 30 * Math.PI / 180);
        // C点x轴坐标
        const x4 = x2 - l * Math.cos(a - 30 * Math.PI / 180);
        // C点y轴坐标
        const y4 = y2 - l * Math.sin(a - 30 * Math.PI / 180);
        const polygon = new zrender.Polygon({
            shape: {
                // 填充图形的坐标
                points: [[x3, y3], [x4, y4], [x2, y2]],
            },
            style: {
                fill: '填充颜色',
                opacity: 1
            },
            z: 1
        })
        zr.add(line);
        zr.add(polygon)
    }
    drawArrow(zr, 200, 200, 300, 300);

image.png

d3.js

这是一个强大的可视化库,感兴趣更多细节可以查看文档或者我之前的文章,这个demo中主要使用了d3的Force布局。