Konva 实现指示框

Konva 实现指示框

还是先上效果图

封装

封装成了hooks,可以在vue或者react中使用,也是一份学习资料

代码

从左到右的渐变背景和边框
我采用的是线性渐变,通过createLinearGradient传递两个像素点分别为开始像素点和结束像素点,
然后按照addColorStop来添加各个位置的颜色。
通过moveTo方法来绘制边框

customShape.js

import * as Konva from 'konva'
export class CustomShape extends Konva.Shape {
    constructor(config) {
        super(config);
        this.config = config
        const {width, height} = this.config
        const rightToLeft = {
            x0: width,
            y0: height,
            x1: 0,
            y1: 0,
        }
        const leftToRight = {
            x0: 0,
            y0: 0,
            x1: width,
            y1: height,
        }
        const length = width >= height ? height * 0.3 : width * 0.3
        this.pathConfig = {
            RT: [
                [0, 0],
                [width - length, 0],
                [width, length],
                [width, height],
                [0, height]
            ],
            RB: [
                [0, 0],
                [width, 0],
                [width, height - length],
                [width - length, height],
                [0, height]
            ],
            LT: [
                [length, 0],
                [width, 0],
                [width, height],
                [width, height],
                [0, height],
                [0, length]
            ],
            LB: [
                [0, 0],
                [width, 0],
                [width, height],
                [length, height],
                [0, height - length]
            ],
            LR: [
                [0, 0],
                [width, 0],
                [width, height],
                [width, height],
                [0, height],

            ],
            RL: [
                [0, 0],
                [width, 0],
                [width, height],
                [width, height],
                [0, height],
            ]

        }
        this.linearGradientConfig = {
            RT: rightToLeft,
            RL: rightToLeft,
            RB: rightToLeft,
            LT: leftToRight,
            LB: leftToRight,
            LR: leftToRight
        }
        this.drawShape()
    }

    drawShape() {
        const {borderWidth, width, height, placement} = this.config
        const path = this.pathConfig[placement];
        const gradientConfig = this.linearGradientConfig[placement]
        if (!path || !gradientConfig) throw 'placement值不正确'
        const {x0, y0, x1, y1} = gradientConfig
        this.sceneFunc(context => {
            context.beginPath();
            context.moveTo(path[0][0], path[0][1]);
            path.slice(1).forEach((item) => {
                context.lineTo(item[0], item[1]);
            })
            context.lineTo(path[0][0], path[0][1]);
            context.closePath();
            const gradient = context.createLinearGradient(x0, y0, x1, y1);
            gradient.addColorStop(0, 'rgba(87,255,236,0.8)');
            //  gradient.addColorStop(0.5, 'rgba(87,255,236,0.4)');
            gradient.addColorStop(1, 'rgba(87,255,236,0)');
            // 应用渐变填充
            context.fillStyle = gradient;
            context.fill();
            // 设置边框颜色
            // 创建从上到下的线性渐变用于边框
            const borderGradient = context.createLinearGradient(x0, y0, x1, y1);
            borderGradient.addColorStop(0, 'rgba(90, 255, 236, 1)');
            borderGradient.addColorStop(0.9, 'rgba(90, 255, 236, 0.1)');
            borderGradient.addColorStop(1, 'rgba(147, 255, 247, 0)');

            // 应用渐变边框
            context.strokeStyle = borderGradient;
            context.lineWidth = borderWidth; // 使用传入的borderWidth
            context.stroke(); // 绘制边框

        });
    }
}

通过在useBox中的计算使得基准点为圆点的左上角坐标点,
绘制所有图形的时候都以此机基准点

看代码的时候可能有点绕,因为我里面建了一个分组,
分组内部的图形的位置0,0像素点,是相Group的左上角的点位置。
明白这一点代码就比较好懂了

最后返回的boxGroup 可以在外部调用konva中原有的方法实现,修改图形属性
useBox.js

import * as Konva from 'konva'
import {CustomShape} from "./hooks/customShape.js";

/**
 *
 * @param layer 图层
 * @param baseConfig  基础配置
 * @param styleConfig 样式配置
 * @return {Konva.Group}
 *
 * 注意 组里面图形的位置都是相对于组的位置,而我传入的baseX,baseY 的位置都是圆点的坐标,
 */

export function useBox(layer, baseConfig, styleConfig) {
    const {baseWidth, baseHeight, baseX, baseY, placement, Cl} = {
        Cl: true,
        ...baseConfig
    }
    console.log(!placement)
    if (!['LT', 'LR', 'LB', 'RT', 'RL', 'RB'].includes(placement)) {
        throw new Error('placement must be in \'LT\', \'LR\', \'LB\', \'RT\', \'RL\', \'RB\'')
    }
    const {fs, px, lineStyle, customShapeStyle, textStyle, circleStyle} = {
        fs: 20,
        px: 20,
        lineStyle: {
            strokeWidth: 2
        },
        customShapeStyle: {},
        textStyle: {},
        ...styleConfig
    }
    //基础图形起点坐标
    let x = baseX
    let y = baseY
    // 组图形七点坐标
    let gx = baseX
    let gy = baseY
    // 圆形坐标
    let cx = baseX
    let cy = baseY
    // 文字坐标
    let tx = baseX
    let ty = baseY
    let points = []
    if (['LT', 'LR', 'LB'].includes(placement)) {
        x = baseX + 2 * px
        y = y + px
        tx = x + fs
        ty = y + 2 + ((baseHeight - fs) / 2)
        points = [baseX, baseY, x - px, y + baseHeight / 2, x, y + baseHeight / 2]
    }
    if (['RT', 'RL', 'RB'].includes(placement)) {
        gx = baseX - 2 * px
        gy = baseY
        x = 0 - baseWidth
        y = baseY + px
        cx = 2 * px
        cy = baseY
        tx = 0
        ty = y + 2 + ((baseHeight - fs) / 2)
        points = [cx, cy, cx - px, y + baseHeight / 2, baseWidth + x, y + baseHeight / 2]
    }
    //创建分组
    const boxGroup = new Konva.Group({
        width: baseWidth,
        height: baseHeight,
        x: gx,
        y: gy
    });
    if (Cl) {
        //创建圆点
        const circle = new Konva.Circle({
            x: cx, // 设置圆心 x 坐标
            y: cy, // 设置圆心 y 坐标
            radius: 7, // 设置圆的半径
            fill: 'rgba(87,255,236,1)', // 设置填充颜色
            strokeWidth: 0, // 设置描边宽度
            ...circleStyle
        });
        boxGroup.add(circle)
    }
    // 创建基础图形
    const customShape = new CustomShape({
        x: x,
        y: y,
        borderWidth: 2,
        borderColor: "#FFFFFF",
        placement,
        ...customShapeStyle,
        width: baseWidth,
        height: baseHeight,
    });
    boxGroup.add(customShape);

    const addText = new Konva.Text({
        x: tx,
        y: ty,
        text: '呼吸 20次/min',
        fontSize: fs,
        fill: '#FFFFFF',
        ...textStyle
    });
    if (['RT', 'RL', 'RB'].includes(placement)) {
        addText.x(-addText.textWidth - fs)
    }
    boxGroup.add(addText);
    if (Cl) {
        const line = new Konva.Line({
            points: points,
            stroke: 'rgba(87,255,236,1)',
            strokeWidth: 5,
            lineCap: 'round',
            lineJoin: 'round',
            ...lineStyle,
        });
        boxGroup.add(line)
    }

    layer.add(boxGroup);
    return boxGroup
}

使用

useBox函数支持三个参数,

  • 第一参数为建立的图层,

  • 第二个参数为整体图形的配置包括长方形的宽baseWidthbaseWidth,
    起点像素(圆点的像素点)横坐标baseX竖坐标baseY
    以及Cl 是否显示圆圈和长方形和圆圈的连线,
    placement参数属性如下
    placement一共支持六个属性值,分别为

    LT透明度从左到右变透明,左上角缺口、

    LR透明度从左到右变透明,无缺口、

    LB透明度从左到右变透明,左下角缺口、

    RT透明度从右到左变透明,右上角缺口、

    RL透明度从右到左变透明,无缺口 、

    RB透明度从右到左变透明,右下角缺口

  • 第三个参数 fs 为字体大小(默认20) px 为圆点距离长方形的位置(默认20)
    lineStyle 为一个对象其属性Konvaline图形所自有的属性
    textStyle 为一个对象其属性Konvatext图形所自有的属性
    circleStyle 为一个对象其属性Konvacircle图形所自有的属性
    customShapeStyle 为一个对象其属性KonvacustomShape图形所自有的属性

init.js

import * as Konva from 'konva'
import {useBox} from "./hooks/useBox.js";

function init() {
  const layer = new Konva.Layer();
  const stage = new Konva.Stage({
    container: 'canvas',
    width: 1000,
    height: 700,
  });
  console.log(stage)
  stage.add(layer);
  const boxLT = useBox(layer, {
    baseWidth: 200,
    baseHeight: 40,
    baseX:260,
    baseY: 80,
    placement: 'LT',

  })
  const boxLR = useBox(layer, {
    baseWidth: 200,
    baseHeight: 40,
    baseX:260,
    baseY: 105,
    placement: 'LR',

  })
  const boxLB = useBox(layer, {
    baseWidth: 200,
    baseHeight: 40,
    baseX:260,
    baseY:130,
    placement: 'LB',

  })

  const boxRT = useBox(layer, {
    baseWidth: 200,
    baseHeight: 40,
    baseX:400,
    baseY: 80,
    placement: 'RT',

  })
  const boxRL = useBox(layer, {
    baseWidth: 200,
    baseHeight: 40,
    baseX:400,
    baseY: 105,
    placement: 'RL',

  })
  const boxRB = useBox(layer, {
    baseWidth: 200,
    baseHeight: 40,
    baseX:400,
    baseY:130,
    placement: 'RB',
  })
  layer.draw()
}
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万水千山走遍TML

您的鼓励,将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值