网站关键词分隔符,深圳网站搜索排名,阿里云主机 wordpress,设计开发上海网站设计开发公司本章响应小伙伴的反馈#xff0c;除了算法自动画连接线#xff08;仍需优化完善#xff09;#xff0c;实现了可以手动绘制直线、折线连接线功能。 请大家动动小手#xff0c;给我一个免费的 Star 吧~ 大家如果发现了 Bug#xff0c;欢迎来提 Issue 哟~ github源码 gitee…本章响应小伙伴的反馈除了算法自动画连接线仍需优化完善实现了可以手动绘制直线、折线连接线功能。 请大家动动小手给我一个免费的 Star 吧~ 大家如果发现了 Bug欢迎来提 Issue 哟~ github源码 gitee源码 示例地址 模式切换 前置工作
连接线 模式种类
// src/Render/types.ts
export enum LinkType {auto auto,straight straight, // 直线manual manual // 手动折线
}连接线 模式状态
// src/Render/draws/LinkDraw.ts// 连接线临时
export interface LinkDrawState {// 略linkType: Types.LinkType // 连接线类型linkManualing: boolean // 是否 正在操作拐点
}连接线 模式切换方法
// src/Render/draws/LinkDraw.ts/*** 修改当前连接线类型* param linkType Types.LinkType*/changeLinkType(linkType: Types.LinkType) {this.state.linkType linkTypethis.render.config?.on?.linkTypeChange?.(this.state.linkType)}连接线 模式切换按钮
!-- src/App.vue --button clickonLinkTypeChange(Types.LinkType.auto):disabledcurrentLinkType Types.LinkType.auto连接线自动/button
button clickonLinkTypeChange(Types.LinkType.straight):disabledcurrentLinkType Types.LinkType.straight连接线直线/button
button clickonLinkTypeChange(Types.LinkType.manual):disabledcurrentLinkType Types.LinkType.manual连接线手动/button连接线 模式切换事件
// src/App.vue
const currentLinkType ref(Types.LinkType.auto)function onLinkTypeChange(linkType: Types.LinkType) {(render?.draws[Draws.LinkDraw.name] as Draws.LinkDraw).changeLinkType(linkType)
}当前 连接对pair 记录当前 连接线 模式
// src/Render/draws/LinkDraw.tsexport class LinkDraw extends Types.BaseDraw implements Types.Draw {// 略override draw() {// 略// 连接点for (const point of points) {// 略// 非 选择中if (group !group.getAttr(selected)) {// 略const anchor this.render.layer.findOne(#${point.id})if (anchor) {// 略circle.on(mouseup, () {if (this.state.linkingLine) {// 略// 不同连接点if (line.circle.id() ! circle.id()) {// 略if (toGroup) {// 略if (fromPoint) {// 略if (toPoint) {if (Array.isArray(fromPoint.pairs)) {fromPoint.pairs [...fromPoint.pairs,{// 略linkType: this.state.linkType // 记录 连接线 类型}]}// 略}}}}// 略}})// 略}}}}
}直线 绘制直线相对简单通过判断 连接对pair记录的 连接线 模式从起点绘制一条 Line 到终点即可
// src/Render/draws/LinkDraw.tsexport class LinkDraw extends Types.BaseDraw implements Types.Draw {// 略override draw() {// 略// 连接线for (const pair of pairs) {if (pair.linkType Types.LinkType.manual) {// 略手动折线} else if (pair.linkType Types.LinkType.straight) {// 直线if (fromGroup toGroup fromPoint toPoint) {const fromAnchor fromGroup.findOne(#${fromPoint.id})const toAnchor toGroup.findOne(#${toPoint.id})// 锚点信息const fromAnchorPos this.getAnchorPos(fromAnchor)const toAnchorPos this.getAnchorPos(toAnchor)const linkLine new Konva.Line({name: link-line,// 用于删除连接线groupId: fromGroup.id(),pointId: fromPoint.id,pairId: pair.id,linkType: pair.linkType,points: _.flatten([[this.render.toStageValue(fromAnchorPos.x),this.render.toStageValue(fromAnchorPos.y)],[this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)]]),stroke: red,strokeWidth: 2})this.group.add(linkLine)}} else {// 略原算法画连接线逻辑}}}
}折线 绘制折线先人为定义 3 种“点” 1、连接点就是原来就有的。 2、拐点待拐蓝色的从未拖动过的一旦拖动会新增拐点记录。 3、拐点已拐绿色的已经拖动过的依然可以拖动但不会新增拐点记录。 请留意下方代码的注释关键
fromGroup 会记录 拐点 manualPoints。连接线 的绘制是从 起点 - 拐点们- 终点linkPoints。拐点正在拖动时绘制临时的虚线 Line。分别处理 拐点待拐和 拐点已拐两种情况。
处理 拐点待拐和 拐点已拐主要区别是
处理 拐点待拐遍历 linkPoints 的时候是成对遍历的。处理 拐点已拐遍历 linkPoints 的时候是跳过 起点 和 终点 的。拖动 拐点待拐会新增拐点记录。拖动 拐点已拐不会新增拐点记录。
// src/Render/draws/LinkDraw.tsexport class LinkDraw extends Types.BaseDraw implements Types.Draw {// 略override draw() {// 略// 连接线for (const pair of pairs) {if (pair.linkType Types.LinkType.manual) {// 手动折线if (fromGroup toGroup fromPoint toPoint) {const fromAnchor fromGroup.findOne(#${fromPoint.id})const toAnchor toGroup.findOne(#${toPoint.id})// 锚点信息const fromAnchorPos this.getAnchorPos(fromAnchor)const toAnchorPos this.getAnchorPos(toAnchor)// 拐点已拐记录const manualPoints: Array{ x: number; y: number } Array.isArray(fromGroup.getAttr(manualPoints))? fromGroup.getAttr(manualPoints): []// 连接点 拐点const linkPoints [[this.render.toStageValue(fromAnchorPos.x),this.render.toStageValue(fromAnchorPos.y)],...manualPoints.map((o) [o.x, o.y]),[this.render.toStageValue(toAnchorPos.x), this.render.toStageValue(toAnchorPos.y)]]// 连接线const linkLine new Konva.Line({name: link-line,// 用于删除连接线groupId: fromGroup.id(),pointId: fromPoint.id,pairId: pair.id,linkType: pair.linkType,points: _.flatten(linkPoints),stroke: red,strokeWidth: 2})this.group.add(linkLine)// 正在拖动效果const manualingLine new Konva.Line({stroke: #ff0000,strokeWidth: 2,points: [],dash: [4, 4]})this.group.add(manualingLine)// 拐点// 拐点待拐for (let i 0; i linkPoints.length - 1; i) {const circle new Konva.Circle({id: nanoid(),pairId: pair.id,x: (linkPoints[i][0] linkPoints[i 1][0]) / 2,y: (linkPoints[i][1] linkPoints[i 1][1]) / 2,radius: this.render.toStageValue(this.render.bgSize / 2),stroke: rgba(0,0,255,0.1),strokeWidth: this.render.toStageValue(1),name: link-manual-point,// opacity: 0,linkManualIndex: i // 当前拐点位置})// hover 效果circle.on(mouseenter, () {circle.stroke(rgba(0,0,255,0.8))document.body.style.cursor pointer})circle.on(mouseleave, () {if (!circle.attrs.dragStart) {circle.stroke(rgba(0,0,255,0.1))document.body.style.cursor default}})// 拐点操作circle.on(mousedown, () {const pos circle.getAbsolutePosition()// 记录操作开始状态circle.setAttrs({// 开始坐标dragStartX: pos.x,dragStartY: pos.y,// 正在操作dragStart: true})// 标记状态 - 正在操作拐点this.state.linkManualing true})this.render.stage.on(mousemove, () {if (circle.attrs.dragStart) {// 正在操作const pos this.render.stage.getPointerPosition()if (pos) {// 磁贴const { pos: transformerPos } this.render.attractTool.attract({x: pos.x,y: pos.y,width: 1,height: 1})// 移动拐点circle.setAbsolutePosition(transformerPos)// 正在拖动效果const tempPoints [...linkPoints]tempPoints.splice(circle.attrs.linkManualIndex 1, 0, [this.render.toStageValue(transformerPos.x - stageState.x),this.render.toStageValue(transformerPos.y - stageState.y)])manualingLine.points(_.flatten(tempPoints))}}})circle.on(mouseup, () {const pos circle.getAbsolutePosition()if (Math.abs(pos.x - circle.attrs.dragStartX) this.option.size ||Math.abs(pos.y - circle.attrs.dragStartY) this.option.size) {// 操作移动距离达到阈值// stage 状态const stageState this.render.getStageState()// 记录插入拐点manualPoints.splice(circle.attrs.linkManualIndex, 0, {x: this.render.toStageValue(pos.x - stageState.x),y: this.render.toStageValue(pos.y - stageState.y)})fromGroup.setAttr(manualPoints, manualPoints)}// 操作结束circle.setAttrs({dragStart: false})// state 操作结束this.state.linkManualing false// 销毁circle.destroy()manualingLine.destroy()// 更新历史this.render.updateHistory()// 重绘this.render.redraw()})this.group.add(circle)}// 拐点已拐for (let i 1; i linkPoints.length - 1; i) {const circle new Konva.Circle({id: nanoid(),pairId: pair.id,x: linkPoints[i][0],y: linkPoints[i][1],radius: this.render.toStageValue(this.render.bgSize / 2),stroke: rgba(0,100,0,0.1),strokeWidth: this.render.toStageValue(1),name: link-manual-point,// opacity: 0,linkManualIndex: i // 当前拐点位置})// hover 效果circle.on(mouseenter, () {circle.stroke(rgba(0,100,0,1))document.body.style.cursor pointer})circle.on(mouseleave, () {if (!circle.attrs.dragStart) {circle.stroke(rgba(0,100,0,0.1))document.body.style.cursor default}})// 拐点操作circle.on(mousedown, () {const pos circle.getAbsolutePosition()// 记录操作开始状态circle.setAttrs({dragStartX: pos.x,dragStartY: pos.y,dragStart: true})// 标记状态 - 正在操作拐点this.state.linkManualing true})this.render.stage.on(mousemove, () {if (circle.attrs.dragStart) {// 正在操作const pos this.render.stage.getPointerPosition()if (pos) {// 磁贴const { pos: transformerPos } this.render.attractTool.attract({x: pos.x,y: pos.y,width: 1,height: 1})// 移动拐点circle.setAbsolutePosition(transformerPos)// 正在拖动效果const tempPoints [...linkPoints]tempPoints[circle.attrs.linkManualIndex] [this.render.toStageValue(transformerPos.x - stageState.x),this.render.toStageValue(transformerPos.y - stageState.y)]manualingLine.points(_.flatten(tempPoints))}}})circle.on(mouseup, () {const pos circle.getAbsolutePosition()if (Math.abs(pos.x - circle.attrs.dragStartX) this.option.size ||Math.abs(pos.y - circle.attrs.dragStartY) this.option.size) {// 操作移动距离达到阈值// stage 状态const stageState this.render.getStageState()// 记录更新拐点manualPoints[circle.attrs.linkManualIndex - 1] {x: this.render.toStageValue(pos.x - stageState.x),y: this.render.toStageValue(pos.y - stageState.y)}fromGroup.setAttr(manualPoints, manualPoints)}// 操作结束circle.setAttrs({dragStart: false})// state 操作结束this.state.linkManualing false// 销毁circle.destroy()manualingLine.destroy()// 更新历史this.render.updateHistory()// 重绘this.render.redraw()})this.group.add(circle)}}} else if (pair.linkType Types.LinkType.straight) {// 略直线} else {// 略原算法画连接线逻辑}}}
}最后关于 linkManualing 状态会用在 2 个地方避免和其它交互产生冲突
// src/Render/handlers/DragHandlers.ts// 略export class DragHandlers implements Types.Handler {// 略 handlers {stage: {mousedown: (e: Konva.KonvaEventObjectGlobalEventHandlersEventMap[mousedown]) {// 拐点操作中防止异常拖动if (!(this.render.draws[Draws.LinkDraw.name] as Draws.LinkDraw).state.linkManualing) {// 略}},// 略}}
}
// src/Render/tools/LinkTool.ts// 略
export class LinkTool {// 略pointsVisible(visible: boolean, group?: Konva.Group) {// 略// 拐点操作中此处不重绘if (!(this.render.draws[Draws.LinkDraw.name] as Draws.LinkDraw).state.linkManualing) {// 重绘this.render.redraw()}}// 略
}
Done! More Stars please勾勾手指~ 源码 gitee源码 示例地址