当前位置: 首页 > news >正文

官方在家做兼职的网站赣县企业网站建设

官方在家做兼职的网站,赣县企业网站建设,有动效网站,凡科网免费网站怎么样本章开始补充一些基础的图形绘制#xff0c;比如绘制#xff1a;直线、曲线、圆/椭形、矩形。这一章主要分享一下本示例是如何开始绘制一个图形的#xff0c;并以绘制圆/椭形为实现目标。 请大家动动小手#xff0c;给我一个免费的 Star 吧~ 大家如果发现了 Bug#xff0c…本章开始补充一些基础的图形绘制比如绘制直线、曲线、圆/椭形、矩形。这一章主要分享一下本示例是如何开始绘制一个图形的并以绘制圆/椭形为实现目标。 请大家动动小手给我一个免费的 Star 吧~ 大家如果发现了 Bug欢迎来提 Issue 哟~ github源码 gitee源码 示例地址 接下来主要说说 UIGraph图形canvas2svg 打补丁拐点旋转修复 UI - 图形绘制类型切换 先找几个图标增加按钮分别代表绘制图形直线、曲线、圆/椭形、矩形 选中图形类型后即可通过拖动绘制图形绘制完成后清空选择 定义图形类型 // src/Render/types.ts /*** 图形类型*/ export enum GraphType {Line Line, // 直线Curve Curve, // 曲线Rect Rect, // 矩形Circle Circle // 圆/椭圆形 }在 Render 中记录当前图形类型并提供修改方法与事件 // src/Render/index.ts // 略// 画图类型graphType: Types.GraphType | undefined undefined// 略// 改变画图类型changeGraphType(type?: Types.GraphType) {this.graphType typethis.emit(graph-type-change, this.graphType)}工具栏按钮通讯 // src/components/main-header/index.vue // 略const emit defineEmits([/* 略 */, update:graphType])const props withDefaults(defineProps{// 略graphType?: Types.GraphType }(), {// 略 });// 略watch(() props.render, () {if (props.render) {// 略props.render?.on(graph-type-change, (value) {emit(update:graphType, value)})}}, {immediate: true })// 略function onGraph(type: Types.GraphType) {emit(update:graphType, props.graphType type ? undefined : type) 以上就是绘制图形的工具栏入口。 Graph - 图形定义及其相关实现 相关代码文件 1、src/Render/graphs/BaseGraph.ts - 抽象类定义通用属性、逻辑、外部接口定义。 2、src/Render/graphs/Circle.ts 继承 BaseGraph - 构造 圆/椭形 处理创建部分交互信息关键逻辑的实现。 3、src/Render/handlers/GraphHandlers.ts - 收集图形创建所需交互信息接着交给 Circle 静态处理方法处理。 4、src/Render/draws/GraphDraw.ts - 绘制图形、调整点 - 绘制 调整点 的锚点收集并处理交互信息接着并交给 Circle 静态处理方法处理。 BaseGraph 抽象类 // src/Render/graphs/BaseGraph.ts// 略/*** 图形类* 实例主要用于新建图形时含新建同时的大小拖动。* 静态方法主要用于新建之后通过 调整点 调整的逻辑定义*/ export abstract class BaseGraph {/*** 更新 图形 的 调整点 的 锚点位置* param width 图形 的 宽度* param height 图形 的 高度* param rotate 图形 的 旋转角度* param anchorShadows 图形 的 调整点 的 锚点*/static updateAnchorShadows(width: number,height: number,rotate: number,anchorShadows: Konva.Circle[]) {console.log(请实现 updateAnchorShadows, width, height, anchorShadows)}/*** 更新 图形 的 连接点 的 锚点位置* param width 图形 的 宽度* param height 图形 的 高度* param rotate 图形 的 旋转角度* param anchors 图形 的 调整点 的 锚点*/static updateLinkAnchorShadows(width: number,height: number,rotate: number,linkAnchorShadows: Konva.Circle[]) {console.log(请实现 updateLinkAnchorShadows, width, height, linkAnchorShadows)}/*** 生成 调整点* param render 渲染实例* param graph 图形* param anchor 调整点 定义* param anchorShadow 调整点 锚点* param adjustingId 正在操作的 调整点 id* returns*/static createAnchorShape(render: Render,graph: Konva.Group,anchor: Types.GraphAnchor,anchorShadow: Konva.Circle,adjustType: string,adjustGroupId: string): Konva.Shape {console.log(请实现 createAnchorShape, render, graph, anchor, anchorShadow, adjustingId, adjustGroupId)return new Konva.Shape()}/*** 调整 图形* param render 渲染实例* param graph 图形* param graphSnap 图形 的 备份* param rect 当前 调整点* param rects 所有 调整点* param startPoint 鼠标按下位置* param endPoint 鼠标拖动位置*/static adjust(render: Render,graph: Konva.Group,graphSnap: Konva.Group,rect: Types.GraphAnchorShape,rects: Types.GraphAnchorShape[],startPoint: Konva.Vector2d,endPoint: Konva.Vector2d) {console.log(请实现 updateAnchorShadows, render, graph, rect, startPoint, endPoint)}//protected render: Rendergroup: Konva.Groupid: string // 就是 group 的id/*** 鼠标按下位置*/protected dropPoint: Konva.Vector2d { x: 0, y: 0 }/*** 调整点 定义*/protected anchors: Types.GraphAnchor[] []/*** 调整点 的 锚点*/protected anchorShadows: Konva.Circle[] []/*** 调整点 定义*/protected linkAnchors: Types.LinkDrawPoint[] []/*** 连接点 的 锚点*/protected linkAnchorShadows: Konva.Circle[] []constructor(render: Render,dropPoint: Konva.Vector2d,config: {anchors: Types.GraphAnchor[]linkAnchors: Types.AssetInfoPoint[]}) {this.render renderthis.dropPoint dropPointthis.id nanoid()this.group new Konva.Group({id: this.id,name: asset,assetType: Types.AssetType.Graph})// 调整点 定义this.anchors config.anchors.map((o) ({...o,// 补充信息name: anchor,groupId: this.group.id()}))// 记录在 group 中this.group.setAttr(anchors, this.anchors)// 新建 调整点 的 锚点for (const anchor of this.anchors) {const circle new Konva.Circle({adjustType: anchor.adjustType,name: anchor.name,radius: 0// radius: this.render.toStageValue(1),// fill: red})this.anchorShadows.push(circle)this.group.add(circle)}// 连接点 定义this.linkAnchors config.linkAnchors.map((o) ({...o,id: nanoid(),groupId: this.group.id(),visible: false,pairs: [],direction: o.direction,alias: o.alias}) as Types.LinkDrawPoint)// 连接点信息this.group.setAttrs({points: this.linkAnchors})// 新建 连接点 的 锚点for (const point of this.linkAnchors) {const circle new Konva.Circle({name: link-anchor,id: point.id,x: point.x,y: point.y,radius: this.render.toStageValue(1),stroke: rgba(0,0,255,1),strokeWidth: this.render.toStageValue(2),visible: false,direction: point.direction,alias: point.alias})this.linkAnchorShadows.push(circle)this.group.add(circle)}this.group.on(mouseenter, () {// 显示 连接点this.render.linkTool.pointsVisible(true, this.group)})this.group.on(mouseleave, () {// 隐藏 连接点this.render.linkTool.pointsVisible(false, this.group)// 隐藏 hover 框this.group.findOne(#hoverRect)?.visible(false)})this.render.layer.add(this.group)this.render.redraw()}/*** 调整进行时* param point 鼠标位置 相对位置*/abstract drawMove(point: Konva.Vector2d): void/*** 调整结束*/abstract drawEnd(): void }这里的 静态方法相当定义了绘制图形必要的工具方法具体实现交给具体的图形类定义接着是绘制图形必要的属性及其初始化最后抽象方法约束了图形实例必要的方法。 绘制 圆/椭形 图形是可以调整的这里 圆/椭形 拥有 8 个 调整点 还要考虑图形被旋转后依然能合理调整 调整本身也是支持磁贴的 图形也支持 连接点 图形类 - Circle // src/Render/graphs/Circle.ts// 略/*** 图形 圆/椭圆*/ export class Circle extends BaseGraph {// 实现更新 图形 的 调整点 的 锚点位置static override updateAnchorShadows(width: number,height: number,rotate: number,anchorShadows: Konva.Circle[]): void {for (const shadow of anchorShadows) {switch (shadow.attrs.id) {case top:shadow.position({x: width / 2,y: 0})breakcase bottom:shadow.position({x: width / 2,y: height})breakcase left:shadow.position({x: 0,y: height / 2})breakcase right:shadow.position({x: width,y: height / 2})breakcase top-left:shadow.position({x: 0,y: 0})breakcase top-right:shadow.position({x: width,y: 0})breakcase bottom-left:shadow.position({x: 0,y: height})breakcase bottom-right:shadow.position({x: width,y: height})break}}}// 实现更新 图形 的 连接点 的 锚点位置static override updateLinkAnchorShadows(width: number,height: number,rotate: number,linkAnchorShadows: Konva.Circle[]): void {for (const shadow of linkAnchorShadows) {switch (shadow.attrs.alias) {case top:shadow.position({x: width / 2,y: 0})breakcase bottom:shadow.position({x: width / 2,y: height})breakcase left:shadow.position({x: 0,y: height / 2})breakcase right:shadow.position({x: width,y: height / 2})breakcase center:shadow.position({x: width / 2,y: height / 2})break}}}// 实现生成 调整点static createAnchorShape(render: Types.Render,graph: Konva.Group,anchor: Types.GraphAnchor,anchorShadow: Konva.Circle,adjustType: string,adjustGroupId: string): Konva.Shape {// stage 状态const stageState render.getStageState()const x render.toStageValue(anchorShadow.getAbsolutePosition().x - stageState.x),y render.toStageValue(anchorShadow.getAbsolutePosition().y - stageState.y)const offset render.pointSize 5const shape new Konva.Line({name: anchor,anchor: anchor,//// stroke: colorMap[anchor.id] ?? rgba(0,0,255,0.2),stroke:adjustType anchor.adjustType graph.id() adjustGroupId? rgba(0,0,255,0.8): rgba(0,0,255,0.2),strokeWidth: render.toStageValue(2),// 位置x,y,// 路径points:{top-left: _.flatten([[-offset, offset / 2],[-offset, -offset],[offset / 2, -offset]]),top: _.flatten([[-offset, -offset],[offset, -offset]]),top-right: _.flatten([[-offset / 2, -offset],[offset, -offset],[offset, offset / 2]]),right: _.flatten([[offset, -offset],[offset, offset]]),bottom-right: _.flatten([[-offset / 2, offset],[offset, offset],[offset, -offset / 2]]),bottom: _.flatten([[-offset, offset],[offset, offset]]),bottom-left: _.flatten([[-offset, -offset / 2],[-offset, offset],[offset / 2, offset]]),left: _.flatten([[-offset, -offset],[-offset, offset]])}[anchor.id] ?? [],// 旋转角度rotation: graph.getAbsoluteRotation()})shape.on(mouseenter, () {shape.stroke(rgba(0,0,255,0.8))document.body.style.cursor move})shape.on(mouseleave, () {shape.stroke(shape.attrs.adjusting ? rgba(0,0,255,0.8) : rgba(0,0,255,0.2))document.body.style.cursor shape.attrs.adjusting ? move : default})return shape}// 实现调整 图形static override adjust(render: Types.Render,graph: Konva.Group,graphSnap: Konva.Group,shapeRecord: Types.GraphAnchorShape,shapeRecords: Types.GraphAnchorShape[],startPoint: Konva.Vector2d,endPoint: Konva.Vector2d) {// 目标 圆/椭圆const circle graph.findOne(.graph) as Konva.Ellipse// 镜像const circleSnap graphSnap.findOne(.graph) as Konva.Ellipse// 调整点 锚点const anchors (graph.find(.anchor) ?? []) as Konva.Circle[]// 连接点 锚点const linkAnchors (graph.find(.link-anchor) ?? []) as Konva.Circle[]const { shape: adjustShape } shapeRecordif (circle circleSnap) {let [graphWidth, graphHeight] [graph.width(), graph.height()]const [graphRotation, anchorId, ex, ey] [Math.round(graph.rotation()),adjustShape.attrs.anchor?.id,endPoint.x,endPoint.y]let anchorShadow: Konva.Circle | undefined, anchorShadowAcross: Konva.Circle | undefinedswitch (anchorId) {case top:{anchorShadow graphSnap.findOne(#top)anchorShadowAcross graphSnap.findOne(#bottom)}breakcase bottom:{anchorShadow graphSnap.findOne(#bottom)anchorShadowAcross graphSnap.findOne(#top)}breakcase left:{anchorShadow graphSnap.findOne(#left)anchorShadowAcross graphSnap.findOne(#right)}breakcase right:{anchorShadow graphSnap.findOne(#right)anchorShadowAcross graphSnap.findOne(#left)}breakcase top-left:{anchorShadow graphSnap.findOne(#top-left)anchorShadowAcross graphSnap.findOne(#bottom-right)}breakcase top-right:{anchorShadow graphSnap.findOne(#top-right)anchorShadowAcross graphSnap.findOne(#bottom-left)}breakcase bottom-left:{anchorShadow graphSnap.findOne(#bottom-left)anchorShadowAcross graphSnap.findOne(#top-right)}breakcase bottom-right:{anchorShadow graphSnap.findOne(#bottom-right)anchorShadowAcross graphSnap.findOne(#top-left)}break}if (anchorShadow anchorShadowAcross) {const { x: sx, y: sy } anchorShadow.getAbsolutePosition()const { x: ax, y: ay } anchorShadowAcross.getAbsolutePosition()// anchorShadow它是当前操作的 调整点 锚点// anchorShadowAcross它是当前操作的 调整点 反方向对面的 锚点// 调整大小{// 略// 计算比较复杂不一定是最优方案详情请看工程代码。// 基本逻辑// 1、通过鼠标移动计算当前鼠标位置、当前操作的 调整点 锚点 位置原位置 分别与 anchorShadowAcross原位置的距离// 2、 保持 anchorShadowAcross 位置固定通过上面两距离的变化比例计算最新的宽高大小// 3、期间要约束不同角度不同方向的宽高处理有的只改变宽、有的只改变高、有的同时改变宽和高。}// 调整位置{// 略// 计算比较复杂不一定是最优方案详情请看工程代码。// 基本逻辑// 利用三角函数通过最新的宽高调整图形的坐标。}}// 更新 圆/椭圆 大小circle.x(graphWidth / 2)circle.radiusX(graphWidth / 2)circle.y(graphHeight / 2)circle.radiusY(graphHeight / 2)// 更新 调整点 的 锚点 位置Circle.updateAnchorShadows(graphWidth, graphHeight, graphRotation, anchors)// 更新 图形 的 连接点 的 锚点位置Circle.updateLinkAnchorShadows(graphWidth, graphHeight, graphRotation, linkAnchors)// stage 状态const stageState render.getStageState()// 更新 调整点 位置for (const anchor of anchors) {for (const { shape } of shapeRecords) {if (shape.attrs.anchor?.adjustType anchor.attrs.adjustType) {const anchorShadow graph.findOne(#${anchor.attrs.id})if (anchorShadow) {shape.position({x: render.toStageValue(anchorShadow.getAbsolutePosition().x - stageState.x),y: render.toStageValue(anchorShadow.getAbsolutePosition().y - stageState.y)})shape.rotation(graph.getAbsoluteRotation())}}}}}}/*** 默认图形大小*/static size 100/*** 圆/椭圆 对应的 Konva 实例*/private circle: Konva.Ellipseconstructor(render: Types.Render, dropPoint: Konva.Vector2d) {super(render, dropPoint, {// 定义了 8 个 调整点anchors: [{ adjustType: top },{ adjustType: bottom },{ adjustType: left },{ adjustType: right },{ adjustType: top-left },{ adjustType: top-right },{ adjustType: bottom-left },{ adjustType: bottom-right }].map((o) ({adjustType: o.adjustType, // 调整点 类型定义type: Types.GraphType.Circle // 记录所属 图形})),linkAnchors: [{ x: 0, y: 0, alias: top, direction: top },{ x: 0, y: 0, alias: bottom, direction: bottom },{ x: 0, y: 0, alias: left, direction: left },{ x: 0, y: 0, alias: right, direction: right },{ x: 0, y: 0, alias: center }] as Types.AssetInfoPoint[]})// 新建 圆/椭圆this.circle new Konva.Ellipse({name: graph,x: 0,y: 0,radiusX: 0,radiusY: 0,stroke: black,strokeWidth: 1})// 加入this.group.add(this.circle)// 鼠标按下位置 作为起点this.group.position(this.dropPoint)}// 实现拖动进行时override drawMove(point: Konva.Vector2d): void {// 鼠标拖动偏移量let offsetX point.x - this.dropPoint.x,offsetY point.y - this.dropPoint.y// 确保不翻转if (offsetX 1) {offsetX 1}if (offsetY 1) {offsetY 1}// 半径const radiusX offsetX / 2,radiusY offsetY / 2// 圆/椭圆 位置大小this.circle.x(radiusX)this.circle.y(radiusY)this.circle.radiusX(radiusX)this.circle.radiusY(radiusY)// group 大小this.group.size({width: offsetX,height: offsetY})// 更新 图形 的 调整点 的 锚点位置Circle.updateAnchorShadows(offsetX, offsetY, 1, this.anchorShadows)// 更新 图形 的 连接点 的 锚点位置Circle.updateLinkAnchorShadows(offsetX, offsetY, 1, this.linkAnchorShadows)// 重绘this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name])}// 实现拖动结束override drawEnd(): void {if (this.circle.radiusX() 1 this.circle.radiusY() 1) {// 加入只点击无拖动// 默认大小const width Circle.size,height widthconst radiusX Circle.size / 2,radiusY radiusX// 圆/椭圆 位置大小this.circle.x(radiusX)this.circle.y(radiusY)this.circle.radiusX(radiusX - this.circle.strokeWidth())this.circle.radiusY(radiusY - this.circle.strokeWidth())// group 大小this.group.size({width,height})// 更新 图形 的 调整点 的 锚点位置Circle.updateAnchorShadows(width, height, 1, this.anchorShadows)// 更新 图形 的 连接点 的 锚点位置Circle.updateLinkAnchorShadows(width, height, 1, this.linkAnchorShadows)// 对齐线清除this.render.attractTool.alignLinesClear()// 重绘this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name])}} }GraphHandlers // src/Render/handlers/GraphHandlers.ts // 略export class GraphHandlers implements Types.Handler {// 略/*** 新建图形中*/graphing false/*** 当前新建图形类型*/currentGraph: Graphs.BaseGraph | undefined/*** 获取鼠标位置并处理为 相对大小* param attract 含磁贴计算* returns*/getStagePoint(attract false) {const pos this.render.stage.getPointerPosition()if (pos) {const stageState this.render.getStageState()if (attract) {// 磁贴const { pos: transformerPos } this.render.attractTool.attractPoint(pos)return {x: this.render.toStageValue(transformerPos.x - stageState.x),y: this.render.toStageValue(transformerPos.y - stageState.y)}} else {return {x: this.render.toStageValue(pos.x - stageState.x),y: this.render.toStageValue(pos.y - stageState.y)}}}return null}handlers {stage: {mousedown: (e: Konva.KonvaEventObjectGlobalEventHandlersEventMap[mousedown]) {if (this.render.graphType) {// 选中图形类型开始if (e.target this.render.stage) {this.graphing truethis.render.selectionTool.selectingClear()const point this.getStagePoint()if (point) {if (this.render.graphType Types.GraphType.Circle) {// 新建 圆/椭圆 实例this.currentGraph new Graphs.Circle(this.render, point)}}}}},mousemove: () {if (this.graphing) {if (this.currentGraph) {const pos this.getStagePoint(true)if (pos) {// 新建并马上调整图形this.currentGraph.drawMove(pos)}}}},mouseup: () {if (this.graphing) {if (this.currentGraph) {// 调整结束this.currentGraph.drawEnd()}// 调整结束this.graphing false// 清空图形类型选择this.render.changeGraphType()// 对齐线清除this.render.attractTool.alignLinesClear()// 重绘this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name])}}}} }GraphDraw // src/Render/draws/GraphDraw.ts // 略export interface GraphDrawState {/*** 调整中*/adjusting: boolean/*** 调整中 id*/adjustType: string }// 略export class GraphDraw extends Types.BaseDraw implements Types.Draw {// 略state: GraphDrawState {adjusting: false,adjustType: }/*** 鼠标按下 调整点 位置*/startPoint: Konva.Vector2d { x: 0, y: 0 }/*** 图形 group 镜像*/graphSnap: Konva.Group | undefinedconstructor(render: Types.Render, layer: Konva.Layer, option: GraphDrawOption) {super(render, layer)this.option optionthis.group.name(this.constructor.name)}/*** 获取鼠标位置并处理为 相对大小* param attract 含磁贴计算* returns*/getStagePoint(attract false) {const pos this.render.stage.getPointerPosition()if (pos) {const stageState this.render.getStageState()if (attract) {// 磁贴const { pos: transformerPos } this.render.attractTool.attractPoint(pos)return {x: this.render.toStageValue(transformerPos.x - stageState.x),y: this.render.toStageValue(transformerPos.y - stageState.y)}} else {return {x: this.render.toStageValue(pos.x - stageState.x),y: this.render.toStageValue(pos.y - stageState.y)}}}return null}// 调整 预处理、定位静态方法adjusts(shapeDetailList: {graph: Konva.GroupshapeRecords: { shape: Konva.Shape; anchorShadow: Konva.Circle }[]}[]) {for (const { shapeRecords, graph } of shapeDetailList) {for (const { shape } of shapeRecords) {shape.setAttr(adjusting, false)}for (const shapeRecord of shapeRecords) {const { shape } shapeRecord// 鼠标按下shape.on(mousedown, () {this.state.adjusting truethis.state.adjustType shape.attrs.anchor?.adjustTypethis.state.adjustGroupId graph.id()shape.setAttr(adjusting, true)const pos this.getStagePoint()if (pos) {this.startPoint pos// 图形 group 镜像用于计算位置、大小的偏移this.graphSnap graph.clone()}})// 调整中this.render.stage.on(mousemove, () {if (this.state.adjusting this.graphSnap) {if (shape.attrs.anchor?.type Types.GraphType.Circle) {// 调整 圆/椭圆 图形if (shape.attrs.adjusting) {const pos this.getStagePoint(true)if (pos) {// 使用 圆/椭圆 静态处理方法Graphs.Circle.adjust(this.render,graph,this.graphSnap,shapeRecord,shapeRecords,this.startPoint,pos)// 重绘this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name])}}}}})// 调整结束this.render.stage.on(mouseup, () {this.state.adjusting falsethis.state.adjustType this.state.adjustGroupId // 恢复显示所有 调整点for (const { shape } of shapeRecords) {shape.opacity(1)shape.setAttr(adjusting, false)shape.stroke(rgba(0,0,255,0.2))document.body.style.cursor default}// 销毁 镜像this.graphSnap?.destroy()// 对齐线清除this.render.attractTool.alignLinesClear()})this.group.add(shape)}}}override draw() {this.clear()// 所有图形const graphs this.render.layer.find(.asset).filter((o) o.attrs.assetType Types.AssetType.Graph) as Konva.Group[]const shapeDetailList: {graph: Konva.GroupshapeRecords: { shape: Konva.Shape; anchorShadow: Konva.Circle }[]}[] []for (const graph of graphs) {// 非选中状态才显示 调整点if (!graph.attrs.selected) {const anchors (graph.attrs.anchors ?? []) as Types.GraphAnchor[]const shapeRecords: { shape: Konva.Shape; anchorShadow: Konva.Circle }[] []// 根据 调整点 信息创建for (const anchor of anchors) {// 调整点 的显示 依赖其隐藏的 锚点 位置、大小等信息const anchorShadow graph.findOne(#${anchor.id}) as Konva.Circleif (anchorShadow) {const shape Graphs.Circle.createAnchorShape(this.render,graph,anchor,anchorShadow,this.state.adjustingId,this.state.adjustGroupId)shapeRecords.push({ shape, anchorShadow })}}shapeDetailList.push({graph,shapeRecords})}}this.adjusts(shapeDetailList)} }稍显臃肿后面慢慢优化吧 -_- canvas2svg 打补丁 上面已经实现了绘制图形圆/椭形但是导出 svg 的时候报错了。经过错误定位以及源码阅读发现 1、当 Konva.Group 包含 Konva.Ellipse 的时候无法导出 svg 文件 2、对 Konva.Ellipse 调整如 radiusX、radiusY 属性时无法正确输出 path 路径 1、canvas2svg 尝试给 g 节点赋予 path 属性导致异常报错。 现通过 hack __applyCurrentDefaultPath 方法增加处理 nodeName ‘g’ 的场景 2、查看 Konva.Ellipse.prototype._sceneFunc 方法源码Konva 绘制 Ellipse 是通过 canvas 的 arc scale 实现的对应代码注释 A。 实际效果无法仿照 canvas 的平均 scale会出现 stroke 粗细不一。 因此尝试通过识别 scale 修改 path 特征修复此问题。 // src/Render/tools/ImportExportTool.ts C2S.prototype.__applyCurrentDefaultPath function () {// 补丁修复以下问题// 1、当 Konva.Group 包含 Konva.Ellipse 的时候无法导出 svg 文件// 2、对 Konva.Ellipse 调整如 radiusX、radiusY 属性时无法正确输出 path 路径//// PS:// 1、canvas2svg 尝试给 g 节点赋予 path 属性导致异常报错。// 现通过 hack __applyCurrentDefaultPath 方法增加处理 nodeName g 的场景//// 2、查看 Konva.Ellipse.prototype._sceneFunc 方法源码// Konva 绘制 Ellipse 是通过 canvas 的 arc scale 实现的对应代码注释 A// 实际效果无法仿照 canvas 的平均 scale会出现 stroke 粗细不一。// 因此尝试通过识别 scale 修改 path 特征修复此问题。//// 以上 hack 仅针对示例绘制 图形 时的特征进行处理并未深入研究 canvas2svg 为何会进入错误的逻辑if (this.__currentElement.nodeName g) {const g this.__currentElement.querySelector(g)if (g) {// 注释 A// const d this.__currentDefaultPath// const path document.createElementNS(http://www.w3.org/2000/svg, path) as SVGElement// path.setAttribute(d, d)// path.setAttribute(fill, none)// g.append(path)const scale g.getAttribute(transform)if (scale) {const match scale.match(/scale\(([^),]),([^)])\)/)if (match) {const [sx, sy] [parseFloat(match[1]), parseFloat(match[2])]let d this.__currentDefaultPathconst reg /A ([^ ]) ([^ ]) /const match2 d.match(reg)if (match2) {const [rx, ry] [parseFloat(match2[1]), parseFloat(match2[2])]d d.replace(reg, A ${rx * sx} ${ry * sy} )const path document.createElementNS(http://www.w3.org/2000/svg,path) as SVGElementpath.setAttribute(d, d)path.setAttribute(fill, none)this.__currentElement.append(path)}}} else {const d this.__currentDefaultPathconst path document.createElementNS(http://www.w3.org/2000/svg, path) as SVGElementpath.setAttribute(d, d)path.setAttribute(fill, none)this.__currentElement.append(path)}}console.warn([Hacked] Attempted to apply path command to node this.__currentElement.nodeName)return}// 原逻辑if (this.__currentElement.nodeName path) {const d this.__currentDefaultPaththis.__currentElement.setAttribute(d, d)} else {throw new Error(Attempted to apply path command to node this.__currentElement.nodeName)} }以上 hack 仅针对示例绘制 图形 时的特征进行处理并未深入研究 canvas2svg 为何会进入错误的逻辑 拐点旋转修复 测试发现连接线 的 拐点 并没有能跟随旋转角度调整坐标因此补充一个修复 // src/Render/handlers/SelectionHandlers.ts // 略/*** 矩阵变换坐标系中的一个点围绕着另外一个点进行旋转* - - - - - - - -* |x| |cos -sin| |x-a| |a|* | | | | | | * |y| |sin cos| |y-b| |b|* - - - - - - - -* param x 目标节点坐标 x* param y 目标节点坐标 y* param centerX 围绕的点坐标 x* param centerY 围绕的点坐标 y* param angle 旋转角度* returns*/rotatePoint(x: number, y: number, centerX: number, centerY: number, angle: number) {// 将角度转换为弧度const radians (angle * Math.PI) / 180// 计算旋转后的坐标const newX Math.cos(radians) * (x - centerX) - Math.sin(radians) * (y - centerY) centerXconst newY Math.sin(radians) * (x - centerX) Math.cos(radians) * (y - centerY) centerYreturn { x: newX, y: newY }}lastRotation 0// 略handlers { // 略transformer: {transform: () {// 旋转时拐点也要跟着动const back this.render.transformer.findOne(.back)if (back) {// stage 状态const stageState this.render.getStageState()const { x, y, width, height } back.getClientRect()const rotation back.getAbsoluteRotation() - this.lastRotationconst centerX x width / 2const centerY y height / 2const groups this.render.transformer.nodes()const points groups.reduce((ps, group) {return ps.concat(Array.isArray(group.getAttr(points)) ? group.getAttr(points) : [])}, [] as Types.LinkDrawPoint[])const pairs points.reduce((ps, point) {return ps.concat(point.pairs ? point.pairs.filter((o) !o.disabled) : [])}, [] as Types.LinkDrawPair[])for (const pair of pairs) {const fromGroup groups.find((o) o.id() pair.from.groupId)const toGroup groups.find((o) o.id() pair.to.groupId)// 必须成对移动才记录if (fromGroup toGroup) {// 移动if (fromGroup.attrs.manualPointsMap fromGroup.attrs.manualPointsMapBefore) {let manualPoints fromGroup.attrs.manualPointsMap[pair.id]const manualPointsBefore fromGroup.attrs.manualPointsMapBefore[pair.id]if (Array.isArray(manualPoints) Array.isArray(manualPointsBefore)) {manualPoints manualPointsBefore.map((o: Types.ManualPoint) {const { x, y } this.rotatePoint(this.render.toBoardValue(o.x) stageState.x,this.render.toBoardValue(o.y) stageState.y,centerX,centerY,rotation)return {x: this.render.toStageValue(x - stageState.x),y: this.render.toStageValue(y - stageState.y)}})fromGroup.setAttr(manualPointsMap, {...fromGroup.attrs.manualPointsMap,[pair.id]: manualPoints})}}}}}// 重绘this.render.redraw([Draws.GraphDraw.name, Draws.LinkDraw.name, Draws.PreviewDraw.name])}} // 略}Thanks watching~ More Stars please勾勾手指~ 源码 gitee源码 示例地址
http://www.tj-hxxt.cn/news/139636.html

相关文章:

  • 优化网站制作方法大全flash型网站网址
  • 华为企业建设网站的目的免费的logo设计
  • 红杭州网站建设asp网站后台密码文件
  • 中国建设网站上报名塔吊司索工王烨诡异复苏的漫画叫什么
  • 门户网站html内江市住房和城乡建设局网站电话号码
  • cocos2d-js可以做网站吗两学一做纪实评价系统网站
  • wordpress 网页编辑淘宝怎么优化关键词排名
  • 建设银行激活网站大学生网络推广实训报告
  • 上海网站建设招聘免费物流公司网站模板
  • 网站建设解决恩问题桂林生活网官网首页
  • 北京建设教育协会网站首页网站代码 上传 wordpress 空间
  • 西安模板建站定制淘宝代运营1个月多少钱
  • 北京创意网站建设如何建设自己网站
  • 网站开发者不给源代码怎么办图片制作工具
  • ps企业网站模板做网站 工资高吗
  • 关于asp sql网站开发的书籍东莞seo
  • 垂直电商网站建设绵阳网站建设优化
  • 网站开发软件系统科技类网站
  • 江苏省网站建设与管理历年自考试题车网站模板预览
  • 加强网站政务服务建设方案汽油价格最新调整最新消息
  • 周口网站制作公司哪家好广西住房和城乡建设厅
  • 织梦网站建设选项卡教程好的公众号
  • 网站公告建设方案wordpress分类目录网址优化
  • 红旗渠建设集团网站wordpress转帝国cms
  • 一个完整网站制作的实例网站中图片加水印
  • 陕西四通建设工程有限责任公司网站东营 网站建设公司
  • 网站制作需要哪些东西企业网站开发设计
  • j2ee网站开发开题报告wordpress 内网 插件
  • python做网站 不适合淘宝网站建设素材
  • wordpress的地址在本地seo权重优化