前端:SVG绘制流程图

效果

代码

html代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>SVG流程图示例</title><style>/* CSS 样式 */</style><script src="js/index.js"></script> <!-- 引入外部JS文件 -->
</head><body><svg id="workflow-svg" width="1000" height="800"><!-- SVG图形内容... --></svg></body></html>

js/index.js

// 定义矩形框
class FlowChartShape {// 定义一个类的构造函数。svgElement容纳新创建的矩形框、initialX,initialY分别代表矩形框左上角的初始X轴和Y轴坐标、width和height:这两个参数表示矩形框的宽度和高度constructor(svgElement, initialX, initialY, width, height) {//是在当前类的实例(FlowChartShape)内部设置一个成员变量。意味着每个FlowChartShape实例都将与特定的SVG元素关联起来this.svgElement = svgElement;// 创建一个新的SVG < rect > 元素(图形)。this.rectElement = document.createElementNS("http://www.w3.org/2000/svg", 'rect');// 设定矩形元素在其父SVG容器中的X坐标位置this.rectElement.setAttribute('x', initialX);// 设定矩形元素在其父SVG容器中的y坐标位置this.rectElement.setAttribute('y', initialY);// 设定矩形元素在其父SVG容器中的宽度this.rectElement.setAttribute('width', width);// 设定矩形元素在其父SVG容器中的高度this.rectElement.setAttribute('height', height);// 设置矩形的圆角半径设置为10个单位this.rectElement.setAttribute('rx', 10);// 设置当前SVG矩形元素的内部填充颜色为纯白色。this.rectElement.setAttribute('fill', '#fff');// 设置了矩形元素的描边颜色为黑色this.rectElement.setAttribute('stroke', '#1d6ee7');// 矩形元素的描边宽度为2个单位this.rectElement.setAttribute('stroke-width', 2);// 创建了一个新的SVG文本元素。let textElement = document.createElementNS("http://www.w3.org/2000/svg", 'text');// 'x' 属性设置文本元素在水平方向上的起始位置:为矩形容器的起始x坐标加上宽度的一半textElement.setAttribute('x', initialX + width / 2);// 'y' 属性设置文本元素在竖直方向上的起始位置:为矩形容器的起始y坐标加上高度的一半textElement.setAttribute('y', initialY + height / 2);// 设置SVG文本元素的对齐方式:居中textElement.setAttribute('text-anchor', 'middle'); // 这会让文本水平居中textElement.setAttribute('dominant-baseline', 'middle'); // 竖直居中,在某些浏览器中可能需要其他值,比如 'central'// 将先前创建的SVG矩形元素(this.rectElement) 添加为 this.svgElement 的子元素this.svgElement.appendChild(this.rectElement);// 将先前创建的SVG矩形元素(this.textElement) 添加为 this.svgElement 的子元素this.svgElement.appendChild(textElement);// 将文本元素引用赋值给了类的成员变量 this.textElement,这样后续可以通过 this.textElement 直接访问和操作这个文本元素,比如设置文本内容、更改样式等。this.textElement = textElement;}// 设置SVG文本元素的内容setText(textContent) {this.textElement.textContent = textContent;}// 添加创建和连接直线箭头的方法createArrow(x1, y1, x2, y2, color = '#1d6ee7', strokeWidth = 2) {// 创建的SVG元素类型——这里是线段元素const line = document.createElementNS("http://www.w3.org/2000/svg", 'line');// 为刚创建的SVG线段元素设置 x1 属性,表示线段起点的X坐标,这里的 x1 是一个变量,存储了所需的数值。line.setAttribute('x1', x1);// 为线段元素设置 y1 属性,表示线段起点的Y坐标,这里的 y1 是一个变量,存储了所需的数值。line.setAttribute('y1', y1);// 为线段元素设置 x2 属性,表示线段终点的X坐标,这里的 x2 是一个变量,存储了所需的数值。line.setAttribute('x2', x2);// 为线段元素设置 y2 属性,表示线段终点的Y坐标,这里的 y2 是一个变量,存储了所需的数值。line.setAttribute('y2', y2);// 设置线段的颜色line.setAttribute('stroke', color);//设置线段的粗细line.setAttribute('stroke-width', strokeWidth);// 创建箭头头部// 创建一个名为 arrowHead 的SVG多边形元素,这里是创建一个三角形作为箭头头部const arrowHead = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');// 计算向量的差分和长度//计算线段从起点 x1 到终点 x2 在X轴上的位移。const dx = x2 - x1;//计算线段在Y轴上的位移。const dy = y2 - y1;//计算线段的长度(欧几里得距离)const len = Math.sqrt(dx * dx + dy * dy);//计算线段的方向角,即从起点指向终点的角度,使用 Math.atan2 函数得到弧度值const angle = Math.atan2(dy, dx);//定义箭头头部的大小,这是一个常量,用来决定箭头三角形两边的长度const arrowHeadSize = 10;// 计算箭头三角形的两个顶点坐标//根据角度减去π/6(30度),计算箭头左侧顶点相对于线段终点的X坐标。const headX1 = x2 - arrowHeadSize * Math.cos(angle - Math.PI / 6);// 计算箭头左侧顶点相对于线段终点的Y坐标。const headY1 = y2 - arrowHeadSize * Math.sin(angle - Math.PI / 6);// 根据角度加上π/6(30度),计算箭头右侧顶点相对于线段终点的X坐标。const headX2 = x2 - arrowHeadSize * Math.cos(angle + Math.PI / 6);// 计算箭头右侧顶点相对于线段终点的Y坐标。const headY2 = y2 - arrowHeadSize * Math.sin(angle + Math.PI / 6);// 设置SVG多边形元素的points属性,该属性接受一系列顶点坐标,此处定义了一个等腰三角形作为箭头头部,三个顶点分别为线段终点和刚刚计算出的两侧顶点。arrowHead.setAttribute('points', [`${x2},${y2}`, `${headX1},${headY1}`, `${headX2},${headY2}`].join(' '));//设置箭头头部多边形的填充颜色,使其与线段颜色一致。arrowHead.setAttribute('fill', color);//将之前创建的线段元素添加到一个假设存在的SVG容器元素 this.svgElement 中。this.svgElement.appendChild(line);//将创建好的箭头头部(多边形)元素也添加到相同的SVG容器元素中,这样就形成了一个带有箭头的线段图形。this.svgElement.appendChild(arrowHead);}//定义了一个名为connectTo的方法,用于连接两个SVG图形connectTo(otherShape, startAnchor = { side: 'right', verticalAlign: 'center' }, endAnchor = { side: 'left', verticalAlign: 'center' }) {const myBBox = this.rectElement.getBBox();const otherBBox = otherShape.rectElement.getBBox();let startX, startY, endX, endY;switch (startAnchor.side) {case 'left':startX = myBBox.x;startY = startAnchor.verticalAlign === 'top' ? myBBox.y : myBBox.y + myBBox.height / 2;break;case 'right':startX = myBBox.x + myBBox.width;startY = startAnchor.verticalAlign === 'top' ? myBBox.y : myBBox.y + myBBox.height / 2;break;case 'top':startX = startAnchor.horizontalAlign === 'left' ? myBBox.x : myBBox.x + myBBox.width / 2;startY = myBBox.y;break;case 'bottom':startX = startAnchor.horizontalAlign === 'left' ? myBBox.x : myBBox.x + myBBox.width / 2;startY = myBBox.y + myBBox.height;break;default: // 默认为中心点startX = myBBox.x + myBBox.width / 2;startY = myBBox.y + myBBox.height / 2;break;}switch (endAnchor.side) {case 'left':endX = otherBBox.x;endY = endAnchor.verticalAlign === 'top' ? otherBBox.y : otherBBox.y + otherBBox.height / 2;break;case 'right':endX = otherBBox.x + otherBBox.width;endY = endAnchor.verticalAlign === 'top' ? otherBBox.y : otherBBox.y + otherBBox.height / 2;break;case 'top':endX = endAnchor.horizontalAlign === 'left' ? otherBBox.x : otherBBox.x + otherBBox.width / 2;endY = otherBBox.y;break;case 'bottom':endX = endAnchor.horizontalAlign === 'left' ? otherBBox.x : otherBBox.x + otherBBox.width / 2;endY = otherBBox.y + otherBBox.height;break;default: // 默认为中心点endX = otherBBox.x + otherBBox.width / 2;endY = otherBBox.y + otherBBox.height / 2;break;}this.createArrow(startX, startY, endX, endY);}// 新增setLink方法,处理超链接逻辑setLink(url) {const linkElement = document.createElementNS("http://www.w3.org/2000/svg", 'a');linkElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url);// 如果矩形框和文本不在同一个父节点下,或者不在linkElement内if (this.rectElement.parentNode !== linkElement && this.textElement.parentNode !== linkElement) {// 移除它们原先所在的位置this.rectElement.parentNode.removeChild(this.rectElement);this.textElement.parentNode.removeChild(this.textElement);// 将矩形和文本都添加到链接元素内部linkElement.appendChild(this.rectElement);linkElement.appendChild(this.textElement);// 确保链接元素被添加到SVG容器内this.svgElement.appendChild(linkElement);// 更新类的成员变量引用为链接元素this.linkElement = linkElement;} else if (this.linkElement) {// 如果linkElement已经存在但href需要更新this.linkElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url);} else {// 如果linkElement不存在但在同一父节点下,可以直接将它们包裹进新的linkElementthis.rectElement.parentNode.insertBefore(linkElement, this.rectElement);linkElement.appendChild(this.rectElement);linkElement.appendChild(this.textElement);this.linkElement = linkElement;}}
}// 示例:创建三个矩形框并连接它们
window.onload = function () {var svgElement = document.getElementById('workflow-svg');// 初始化三个矩形框并设置链接(x轴,y轴,宽,高)let shape1Ref = new FlowChartShape(svgElement, 50, 150, 120, 40);let shape2Ref = new FlowChartShape(svgElement, 250, 150, 120, 40);let shape3Ref = new FlowChartShape(svgElement, 450, 150, 120, 40);let shape4Ref = new FlowChartShape(svgElement, 650, 150, 120, 40);let shape5Ref = new FlowChartShape(svgElement, 350, 50, 120, 40);let shape6Ref = new FlowChartShape(svgElement, 250, 250, 120, 40);let shape7Ref = new FlowChartShape(svgElement, 450, 250, 120, 40);let shape8Ref = new FlowChartShape(svgElement, 650, 250, 120, 40);let shape9Ref = new FlowChartShape(svgElement, 850, 250, 120, 40);let shape10Ref = new FlowChartShape(svgElement, 850, 350, 120, 40);let shape11Ref = new FlowChartShape(svgElement, 850, 450, 120, 40);let shape12Ref = new FlowChartShape(svgElement, 350, 350, 120, 40);let shape13Ref = new FlowChartShape(svgElement, 550, 350, 120, 40);setTimeout(() => {//设置名称shape1Ref.setText('销售订单');shape2Ref.setText('报价申请');shape3Ref.setText('报价单签核');shape4Ref.setText('报价单回复');shape5Ref.setText('报价单修改');shape6Ref.setText('订单建立');shape7Ref.setText('订单审核');shape8Ref.setText('订单出货');shape9Ref.setText('销售退货');shape10Ref.setText('出货对账');shape11Ref.setText('出货对账取消');shape12Ref.setText('订单修改');shape13Ref.setText('订单反审核');// 连接矩形框shape1Ref.connectTo(shape2Ref);shape2Ref.connectTo(shape3Ref);shape3Ref.connectTo(shape4Ref);//2的顶部中点到5的底部中点shape2Ref.connectTo(shape5Ref, {side: 'top',verticalAlign: 'center'}, {side: 'left',verticalAlign: 'center'});// 从shape1Ref的左上角到shape2Ref的右下角:// shape1Ref.connectTo(shape2Ref, {//     side: 'left',//     verticalAlign: 'top'// }, {//     side: 'right',//     verticalAlign: 'bottom'// });shape5Ref.connectTo(shape3Ref, {side: 'right',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape1Ref.connectTo(shape6Ref);shape6Ref.connectTo(shape7Ref);shape7Ref.connectTo(shape8Ref);shape8Ref.connectTo(shape9Ref);shape9Ref.connectTo(shape10Ref, {side: 'bottom',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape10Ref.connectTo(shape11Ref, {side: 'bottom',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape7Ref.connectTo(shape13Ref, {side: 'bottom',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape13Ref.connectTo(shape12Ref, {side: 'left',verticalAlign: 'center'}, {side: 'right',verticalAlign: 'center'});shape12Ref.connectTo(shape7Ref, {side: 'top',verticalAlign: 'center'}, {side: 'bottom',verticalAlign: 'center'});//添加超链接shape1Ref.setLink('page1.html'); // 为第一个矩形框设置链接到“page1.html”shape2Ref.setLink('page2.html'); // 为第二个矩形框设置链接到“page2.html”shape3Ref.setLink('page3.html'); // 为第三个矩形框设置链接到“page3.html”}, 0);
};

把实现图形的部分写在html页面

html

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>SVG流程图示例</title><style>/* CSS 样式 */</style><script src="js/index.js"></script><!-- 引入外部JS文件 --><script>// 示例:创建三个矩形框并连接它们window.onload = function () {var svgElement = document.getElementById('workflow-svg');// 初始化三个矩形框并设置链接(x轴,y轴,宽,高)let shape1Ref = new FlowChartShape(svgElement, 50, 150, 120, 40);let shape2Ref = new FlowChartShape(svgElement, 250, 150, 120, 40);let shape3Ref = new FlowChartShape(svgElement, 450, 150, 120, 40);let shape4Ref = new FlowChartShape(svgElement, 650, 150, 120, 40);let shape5Ref = new FlowChartShape(svgElement, 350, 50, 120, 40);let shape6Ref = new FlowChartShape(svgElement, 250, 250, 120, 40);let shape7Ref = new FlowChartShape(svgElement, 450, 250, 120, 40);let shape8Ref = new FlowChartShape(svgElement, 650, 250, 120, 40);let shape9Ref = new FlowChartShape(svgElement, 850, 250, 120, 40);let shape10Ref = new FlowChartShape(svgElement, 850, 350, 120, 40);let shape11Ref = new FlowChartShape(svgElement, 850, 450, 120, 40);let shape12Ref = new FlowChartShape(svgElement, 350, 350, 120, 40);let shape13Ref = new FlowChartShape(svgElement, 550, 350, 120, 40);setTimeout(() => {//设置名称shape1Ref.setText('销售订单');shape2Ref.setText('报价申请');shape3Ref.setText('报价单签核');shape4Ref.setText('报价单回复');shape5Ref.setText('报价单修改');shape6Ref.setText('订单建立');shape7Ref.setText('订单审核');shape8Ref.setText('订单出货');shape9Ref.setText('销售退货');shape10Ref.setText('出货对账');shape11Ref.setText('出货对账取消');shape12Ref.setText('订单修改');shape13Ref.setText('订单反审核');// 连接矩形框shape1Ref.connectTo(shape2Ref);shape2Ref.connectTo(shape3Ref);shape3Ref.connectTo(shape4Ref);//2的顶部中点到5的底部中点shape2Ref.connectTo(shape5Ref, {side: 'top',verticalAlign: 'center'}, {side: 'left',verticalAlign: 'center'});// 从shape1Ref的左上角到shape2Ref的右下角:// shape1Ref.connectTo(shape2Ref, {//     side: 'left',//     verticalAlign: 'top'// }, {//     side: 'right',//     verticalAlign: 'bottom'// });shape5Ref.connectTo(shape3Ref, {side: 'right',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape1Ref.connectTo(shape6Ref);shape6Ref.connectTo(shape7Ref);shape7Ref.connectTo(shape8Ref);shape8Ref.connectTo(shape9Ref);shape9Ref.connectTo(shape10Ref, {side: 'bottom',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape10Ref.connectTo(shape11Ref, {side: 'bottom',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape7Ref.connectTo(shape13Ref, {side: 'bottom',verticalAlign: 'center'}, {side: 'top',verticalAlign: 'center'});shape13Ref.connectTo(shape12Ref, {side: 'left',verticalAlign: 'center'}, {side: 'right',verticalAlign: 'center'});shape12Ref.connectTo(shape7Ref, {side: 'top',verticalAlign: 'center'}, {side: 'bottom',verticalAlign: 'center'});//添加超链接shape1Ref.setLink('page1.html'); // 为第一个矩形框设置链接到“page1.html”shape2Ref.setLink('page2.html'); // 为第二个矩形框设置链接到“page2.html”shape3Ref.setLink('page3.html'); // 为第三个矩形框设置链接到“page3.html”}, 0);};</script>
</head><body><svg id="workflow-svg" width="1000" height="800"><!-- SVG图形内容... --></svg></body></html>

js

增加linkElement.setAttribute('target', '_blank'); // 使链接在新窗口打开

// 定义矩形框
class FlowChartShape {// 定义一个类的构造函数。svgElement容纳新创建的矩形框、initialX,initialY分别代表矩形框左上角的初始X轴和Y轴坐标、width和height:这两个参数表示矩形框的宽度和高度constructor(svgElement, initialX, initialY, width, height) {//是在当前类的实例(FlowChartShape)内部设置一个成员变量。意味着每个FlowChartShape实例都将与特定的SVG元素关联起来this.svgElement = svgElement;// 创建一个新的SVG < rect > 元素(图形)。this.rectElement = document.createElementNS("http://www.w3.org/2000/svg", 'rect');// 设定矩形元素在其父SVG容器中的X坐标位置this.rectElement.setAttribute('x', initialX);// 设定矩形元素在其父SVG容器中的y坐标位置this.rectElement.setAttribute('y', initialY);// 设定矩形元素在其父SVG容器中的宽度this.rectElement.setAttribute('width', width);// 设定矩形元素在其父SVG容器中的高度this.rectElement.setAttribute('height', height);// 设置矩形的圆角半径设置为10个单位this.rectElement.setAttribute('rx', 10);// 设置当前SVG矩形元素的内部填充颜色为纯白色。this.rectElement.setAttribute('fill', '#fff');// 设置了矩形元素的描边颜色为黑色this.rectElement.setAttribute('stroke', '#1d6ee7');// 矩形元素的描边宽度为2个单位this.rectElement.setAttribute('stroke-width', 2);// 创建了一个新的SVG文本元素。let textElement = document.createElementNS("http://www.w3.org/2000/svg", 'text');// 'x' 属性设置文本元素在水平方向上的起始位置:为矩形容器的起始x坐标加上宽度的一半textElement.setAttribute('x', initialX + width / 2);// 'y' 属性设置文本元素在竖直方向上的起始位置:为矩形容器的起始y坐标加上高度的一半textElement.setAttribute('y', initialY + height / 2);// 设置SVG文本元素的对齐方式:居中textElement.setAttribute('text-anchor', 'middle'); // 这会让文本水平居中textElement.setAttribute('dominant-baseline', 'middle'); // 竖直居中,在某些浏览器中可能需要其他值,比如 'central'// 将先前创建的SVG矩形元素(this.rectElement) 添加为 this.svgElement 的子元素this.svgElement.appendChild(this.rectElement);// 将先前创建的SVG矩形元素(this.textElement) 添加为 this.svgElement 的子元素this.svgElement.appendChild(textElement);// 将文本元素引用赋值给了类的成员变量 this.textElement,这样后续可以通过 this.textElement 直接访问和操作这个文本元素,比如设置文本内容、更改样式等。this.textElement = textElement;}// 设置SVG文本元素的内容setText(textContent) {this.textElement.textContent = textContent;}// 添加创建和连接直线箭头的方法createArrow(x1, y1, x2, y2, color = '#1d6ee7', strokeWidth = 2) {// 创建的SVG元素类型——这里是线段元素const line = document.createElementNS("http://www.w3.org/2000/svg", 'line');// 为刚创建的SVG线段元素设置 x1 属性,表示线段起点的X坐标,这里的 x1 是一个变量,存储了所需的数值。line.setAttribute('x1', x1);// 为线段元素设置 y1 属性,表示线段起点的Y坐标,这里的 y1 是一个变量,存储了所需的数值。line.setAttribute('y1', y1);// 为线段元素设置 x2 属性,表示线段终点的X坐标,这里的 x2 是一个变量,存储了所需的数值。line.setAttribute('x2', x2);// 为线段元素设置 y2 属性,表示线段终点的Y坐标,这里的 y2 是一个变量,存储了所需的数值。line.setAttribute('y2', y2);// 设置线段的颜色line.setAttribute('stroke', color);//设置线段的粗细line.setAttribute('stroke-width', strokeWidth);// 创建箭头头部// 创建一个名为 arrowHead 的SVG多边形元素,这里是创建一个三角形作为箭头头部const arrowHead = document.createElementNS("http://www.w3.org/2000/svg", 'polygon');// 计算向量的差分和长度//计算线段从起点 x1 到终点 x2 在X轴上的位移。const dx = x2 - x1;//计算线段在Y轴上的位移。const dy = y2 - y1;//计算线段的长度(欧几里得距离)const len = Math.sqrt(dx * dx + dy * dy);//计算线段的方向角,即从起点指向终点的角度,使用 Math.atan2 函数得到弧度值const angle = Math.atan2(dy, dx);//定义箭头头部的大小,这是一个常量,用来决定箭头三角形两边的长度const arrowHeadSize = 10;// 计算箭头三角形的两个顶点坐标//根据角度减去π/6(30度),计算箭头左侧顶点相对于线段终点的X坐标。const headX1 = x2 - arrowHeadSize * Math.cos(angle - Math.PI / 6);// 计算箭头左侧顶点相对于线段终点的Y坐标。const headY1 = y2 - arrowHeadSize * Math.sin(angle - Math.PI / 6);// 根据角度加上π/6(30度),计算箭头右侧顶点相对于线段终点的X坐标。const headX2 = x2 - arrowHeadSize * Math.cos(angle + Math.PI / 6);// 计算箭头右侧顶点相对于线段终点的Y坐标。const headY2 = y2 - arrowHeadSize * Math.sin(angle + Math.PI / 6);// 设置SVG多边形元素的points属性,该属性接受一系列顶点坐标,此处定义了一个等腰三角形作为箭头头部,三个顶点分别为线段终点和刚刚计算出的两侧顶点。arrowHead.setAttribute('points', [`${x2},${y2}`, `${headX1},${headY1}`, `${headX2},${headY2}`].join(' '));//设置箭头头部多边形的填充颜色,使其与线段颜色一致。arrowHead.setAttribute('fill', color);//将之前创建的线段元素添加到一个假设存在的SVG容器元素 this.svgElement 中。this.svgElement.appendChild(line);//将创建好的箭头头部(多边形)元素也添加到相同的SVG容器元素中,这样就形成了一个带有箭头的线段图形。this.svgElement.appendChild(arrowHead);}//定义了一个名为connectTo的方法,用于连接两个SVG图形connectTo(otherShape, startAnchor = { side: 'right', verticalAlign: 'center' }, endAnchor = { side: 'left', verticalAlign: 'center' }) {const myBBox = this.rectElement.getBBox();const otherBBox = otherShape.rectElement.getBBox();let startX, startY, endX, endY;switch (startAnchor.side) {case 'left':startX = myBBox.x;startY = startAnchor.verticalAlign === 'top' ? myBBox.y : myBBox.y + myBBox.height / 2;break;case 'right':startX = myBBox.x + myBBox.width;startY = startAnchor.verticalAlign === 'top' ? myBBox.y : myBBox.y + myBBox.height / 2;break;case 'top':startX = startAnchor.horizontalAlign === 'left' ? myBBox.x : myBBox.x + myBBox.width / 2;startY = myBBox.y;break;case 'bottom':startX = startAnchor.horizontalAlign === 'left' ? myBBox.x : myBBox.x + myBBox.width / 2;startY = myBBox.y + myBBox.height;break;default: // 默认为中心点startX = myBBox.x + myBBox.width / 2;startY = myBBox.y + myBBox.height / 2;break;}switch (endAnchor.side) {case 'left':endX = otherBBox.x;endY = endAnchor.verticalAlign === 'top' ? otherBBox.y : otherBBox.y + otherBBox.height / 2;break;case 'right':endX = otherBBox.x + otherBBox.width;endY = endAnchor.verticalAlign === 'top' ? otherBBox.y : otherBBox.y + otherBBox.height / 2;break;case 'top':endX = endAnchor.horizontalAlign === 'left' ? otherBBox.x : otherBBox.x + otherBBox.width / 2;endY = otherBBox.y;break;case 'bottom':endX = endAnchor.horizontalAlign === 'left' ? otherBBox.x : otherBBox.x + otherBBox.width / 2;endY = otherBBox.y + otherBBox.height;break;default: // 默认为中心点endX = otherBBox.x + otherBBox.width / 2;endY = otherBBox.y + otherBBox.height / 2;break;}this.createArrow(startX, startY, endX, endY);}// 新增setLink方法,处理超链接逻辑setLink(url) {const linkElement = document.createElementNS("http://www.w3.org/2000/svg", 'a');linkElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url);linkElement.setAttribute('target', '_blank'); // 使链接在新窗口打开// 如果矩形框和文本不在同一个父节点下,或者不在linkElement内if (this.rectElement.parentNode !== linkElement && this.textElement.parentNode !== linkElement) {// 移除它们原先所在的位置this.rectElement.parentNode.removeChild(this.rectElement);this.textElement.parentNode.removeChild(this.textElement);// 将矩形和文本都添加到链接元素内部linkElement.appendChild(this.rectElement);linkElement.appendChild(this.textElement);// 确保链接元素被添加到SVG容器内this.svgElement.appendChild(linkElement);// 更新类的成员变量引用为链接元素this.linkElement = linkElement;} else if (this.linkElement) {// 如果linkElement已经存在但href需要更新this.linkElement.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url);} else {// 如果linkElement不存在但在同一父节点下,可以直接将它们包裹进新的linkElementthis.rectElement.parentNode.insertBefore(linkElement, this.rectElement);linkElement.appendChild(this.rectElement);linkElement.appendChild(this.textElement);this.linkElement = linkElement;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/798794.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浪潮信息边缘服务器NE5260G7焕新升级 算力系统更开放、更强大

随着边缘计算场景的增加&#xff0c;再加上用户需求的升级&#xff0c;边缘服务器市场亦迎来了新的挑战&#xff0c;紧跟需求&#xff0c;浪潮信息亦有序通过技术创新提升服务器性能。日前&#xff0c;浪潮信息边缘服务器NE5260G7焕新升级&#xff0c;完成第五代英特尔至强处理…

JVM 全景图

今天我重新复习了一下 jvm 的一些知识点。我以前觉得 jvm 的知识点很多很碎&#xff0c;而且记起来很困难&#xff0c;但是今天我重新复习了一下&#xff0c;对这些知识点进行了简单的梳理之后&#xff0c;产生了不一样的看法。虽然 jvm 的知识点很碎&#xff0c;但是如果你真的…

基于R语言、MaxEnt模型融合技术的物种分布模拟、参数优化方法、结果分析制图与论文写作

第一章、理论篇&#xff1a;以问题导入的方式&#xff0c;深入掌握原理基础 什么是MaxEnt模型&#xff1f; MaxEnt模型的原理是什么&#xff1f;有哪些用途&#xff1f; MaxEnt运行需要哪些输入文件&#xff1f;注意那些事项&#xff1f; 融合R语言的MaxEnt模型的优势&…

科技云报道:卷完参数卷应用,大模型落地有眉目了?

科技云报道原创。 国内大模型战场的比拼正在进入新的阶段。 随着产业界对模型落地的态度逐渐回归理性&#xff0c;企业客户的认知从原来的“觉得大模型什么都能做”的阶段&#xff0c;已经收敛到“大模型能够给自身业务带来什么价值上了”。 2023 年下半年&#xff0c;不少企…

[羊城杯 2020]Easyphp2 ---不会编程的崽

摆烂一周了&#xff0c;继续更&#xff01;&#xff01;题目还是简单哦。 提示明显要我们修改数据包&#xff0c;第一反应是修改referer。试了一下不太对。url很可能存在文件包含 使用伪协议读取一下源码吧。它过滤了base64关键字。尝试url编码绕过&#xff0c;这里可以使用二…

uniApp移动端安卓中使用webview打开pdf文件是下载而不是预览解决方案

关键 使用到 pdf.js 第一步&#xff1a; 下载pdf.js 文件到项目根目录 也就是这个文件 附下载地址&#xff1a;uni-app-pdf: 在uni-app中使用pdf.js实现在手机上打开pdf 也可通过其他方法下载 如npm 第二步&#xff1a; 拷贝hybrid文件到项目根目录 第三步&#xff1a;…

HarmonyOS实战开发-通过screenshot模块实现屏幕截图 。

介绍 本示例展示全屏截图和屏幕局部截图。 本示例通过screenshot模块实现屏幕截图 &#xff0c;通过window模块实现隐私窗口切换&#xff0c;通过display模块查询当前隐私窗口。 效果预览 使用说明&#xff1a; 点击右上角图标打开弹窗&#xff0c;选择截屏&#xff0c;展示…

stable-diffusion-webui安装教程

现在AI开始进入绘画领域,并且能自动根据文本来创建图片出来,这是一个划时代的进步。 这时候,我也不能落后,要紧跟上时代的步伐,那么也来学习一下stable-diffusion的使用,这样也算多一项对技术的认识,提高对AI的认知。 从网上看到很多stable-diffusion-webui的安装,其…

为什么苹果 Mac 电脑需要使用清理软件?

尽管 Apple Mac 电脑因其卓越的性能、简洁高效的 macOS 操作系统及独特的美学设计备受全球用户青睐&#xff0c;但任何电子设备在长期使用后都难以避免面临系统资源日渐累积的问题。其中一个重要维护需求在于&#xff0c;随着使用时间的增长&#xff0c;Mac电脑可能会由于系统垃…

element-ui 在Popover弹框中使用Select选择器,Vue3

bug描述&#xff1a; 当选择完select的时候,popover也会退出。 解决&#xff1a; popover组件的的关闭是当点击组件外的元素时会关闭&#xff0c;select虽然是写在组件内的&#xff0c;但是select有一个默认属性teleported“true” 会把它默认插到 body 元素&#xff0c;我…

Docker容器(五)Docker Compose

一、概述 1.1介绍 Docker Compose是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排。Compose 是 Docker 公司推出的一个工具软件&#xff0c;可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml&#xff0c;…

分布式主键ID生成策略

业务系统对分布式ID的要求 唯一性&#xff1a;在分布式系统中&#xff0c;每个节点都需要生成唯一的标识符来确保数据的唯一性。传统的单点生成ID方式无法满足分布式环境下的需求&#xff0c;而分布式ID能够在整个系统中保证每个节点生成的ID都是唯一的。 顺序性&#xff1a;某…

Svg Flow Editor 原生svg流程图编辑器(五)

系列文章 Svg Flow Editor 原生svg流程图编辑器&#xff08;一&#xff09; Svg Flow Editor 原生svg流程图编辑器&#xff08;二&#xff09; Svg Flow Editor 原生svg流程图编辑器&#xff08;三&#xff09; Svg Flow Editor 原生svg流程图编辑器&#xff08;四&#xf…

使用tomcat里的API - servlet 写动态网页

一、创建一个新的Maven空项目 首次创建maven项目的时候&#xff0c;会自动从maven网站上下载一些依赖组件&#xff08;这个过程需要保证网络稳定&#xff0c;否则后续打包一些操作会出现一些问题&#xff09; ps:校园网可能会屏蔽一些网站&#xff0c;可能会导致maven的依赖…

FPGA + 图像处理(三)生成3x3像素矩阵

前言 生成NxN的像素矩阵是对图像进行各类滤波操作的基本前提&#xff0c;本文介绍一种通过bram生成3x3矩阵的方法。 程序 生成bram核 因为本文介绍的是基于bram生成的3x3像素矩阵&#xff0c;所以要先生成两个bram核&#xff0c;用于缓存前两行图像数据 在 IP catalog中选…

刷代码随想录有感(24)

有时候我会怀疑努力的意义&#xff0c;因为我总是花人家好几倍的时间去理解一个狗看了都觉得弱智的问题&#xff0c;思考过后我知道&#xff0c;努力本没有意义&#xff0c;是在未来可能十年内取得成就时突然回想起来之前做过一些事情&#xff0c;未来的成就赋予曾经的意义&…

说说虚拟化上部署Oracle RAC的那点注意事项

0.概述 目前在虚拟化上部署RAC主要是以下3个场景 1是VMWARE的虚拟化&#xff08;私有云&#xff09;&#xff1b; 2是国产厂商基于KVM的虚拟化&#xff08;私有云&#xff09;&#xff1b; 3是公有云&#xff0c;由云厂商给你提供虚拟主机和虚拟磁盘。 这里我只对前2个熟悉一些…

【微服务】面试题(一)

最近进行了一些面试&#xff0c;这几个问题分享给大家 一、分别介绍一下微服务、分布式以及两者的区别 微服务&#xff08;Microservices&#xff09;和分布式系统&#xff08;Distributed Systems&#xff09;是两种不同的软件架构风格&#xff0c;虽然它们之间有些重叠&#…

SpriingBoot整合MongoDB多数据源

背景&#xff1a; MongoDB多数据源&#xff1a;springboot为3以上版本&#xff0c;spring-boot-starter-data-mongodb低版本MongoDBFactory已过时&#xff0c; 改为MongoDatabaseFactory。 1、pom引入&#xff1a; <dependency><groupId>org.springframework.boo…

汇编基础----mov基本操作

汇编基础----mov基本操作 下载VS2022 这个网上教程很多,自行下载安装即可 新建项目 选择空项目,如何点击下一步 在源文件下创建这二个文件 修改配置使asm文件能被解析,右击项目名(demo)->生成依赖项->生成自定义->勾选如下图所示选项->确定 立即数寻址 main…