前端: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.rhkb.cn/news/300552.html

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

相关文章

1、java语法入门(找工作版)

文章目录 一、Java简介二、Java常量与变量1、标识符2、关键字3、变量4、类的命名规则5、数据类型6、基本数据类型字面值7、变量的定义与初始化8、ASCII码和Unicode编码9、转义字符10、类型转换11、常量 三、Java运算符1、算术运算符2、赋值运算符3、关系运算符4、逻辑运算符5、…

东莞酷得智能 AC63系列单片机

目前AC63芯片系列有下型号&#xff1a; AC6323A2&#xff1a;封装QFN20 AC6366C4&#xff1a;封装QFN32 AC6368A2&#xff1a;封装SOP8 AC63系列 SoC 芯片支持以下特性 蓝牙双模&#xff08;支持蓝牙EDR、蓝牙BLE5.2) 超低功耗处理器 数传透传智能设备 支持低功耗R…

Day16_学点儿JavaEE_理论知识_Tomcat、JSP、Servlet

1 软件的结构 C/S (Client - Server 客户端-服务器端) 典型应用&#xff1a;QQ软件 &#xff0c;飞秋&#xff0c;印象笔记。 特点&#xff1a; 必须下载特定的客户端程序。服务器端升级&#xff0c;客户端升级。 B/S &#xff08;Broswer -Server 浏览器端- 服务器端&…

尚硅谷html5+css3(2)CSS5基本知识

1.网页分为三个部分&#xff1a; 结构&#xff1a;HTML 表现&#xff1a;CSS 行为JavaScript CSS:层叠样式表&#xff0c;网页实际上是一个多层结构&#xff0c;通过CSS可以分别为网页的每一个层来设置样式&#xff0c;最终用户只看最上面的一层&#xff0c;总之&#xff0…

《MATLAB科研绘图与学术图表绘制从入门到精通》

解锁MATLAB科研绘图魅力&#xff0c;让数据可视化成为你的科研利器&#xff01; 1.零基础快速入门&#xff1a;软件操作实战案例图文、代码结合讲解&#xff0c;从入门到精通快速高效。 2.多种科研绘图方法&#xff1a;科研绘图基础变量图形极坐标图形3D图形地理信息可视化等&a…

4月7号总结

java学习 一.正则表达式 定义&#xff1a;正则表达式是一种用于描述字符串模式的表达式&#xff0c;通常被用于文本搜索、匹配和替换。它是一种强大的工具&#xff0c;可以在文本处理和文本分析中进行复杂的匹配和操作。 通过字符串引用里面的方法matches&#xff0c;然后执行…

转让名称带中国的金融控股集团公司要多少钱

随着公司的发展和市场竞争的影响&#xff0c;越来越多的创业者希望注册一家好名称的公司&#xff0c;以提高企业知名度和竞争力。但是&#xff0c;注册中字头无地域公司需要满足一定的条件和流程。本文将对中字头无地域公司注册条件及流程进行详细的介绍。可以致电咨询我或者来…

Linux IO:打开数据之窗的魔法

Linux I/O&#xff08;输入/输出&#xff09;是操作系统中一个至关重要的组成部分&#xff0c;它涉及到数据在内存&#x1f9e0;、存储设备&#x1f4be;、网络接口&#x1f310;等之间的传输过程。在Linux中&#xff0c;I/O操作不仅仅是文件读写那么简单&#xff0c;它包括了一…

蓝桥杯 历届真题 杨辉三角形【第十二届】【省赛】【C组】

资源限制 内存限制&#xff1a;256.0MB C/C时间限制&#xff1a;1.0s Java时间限制&#xff1a;3.0s Python时间限制&#xff1a;5.0s 思路&#xff1a; 由于我第一写没考虑到大数据的原因&#xff0c;直接判断导致只得了40分&#xff0c;下面是我的代码&#xff1a; #…

三防笔记本丨加固笔记本丨三防笔记本电脑赋能车辆检修

随着汽车数量的不断增加和交通运输行业的发展&#xff0c;车辆检修行业成为了保障交通安全和延长车辆寿命的重要领域。在车辆检修过程中&#xff0c;需要使用各种工具和设备来进行检测、维修和保养&#xff0c;而信息化技术的应用正逐渐渗透到这一行业中&#xff0c;为检修工作…

珠海华发实业股份有限公司副总毛冰清莅临天府锋巢直播产业基地考察调研

3月19日&#xff0c;珠海华发实业股份有限公司副总毛冰清拜访天府锋巢直播产业基地&#xff08;以下简称天府锋巢&#xff09;&#xff0c;由产业招商总负责人姜国东进行接待。 基地建设情况 姜国东负责人介绍到&#xff0c;天府锋巢是由德商产投携手无锋科技于兴隆湖落地的成都…

Hive3.0.0建库表命令测试

Hive创建表格格式如下&#xff1a; create [external] table [if not exists] table_name [(col_name data_type [comment col_comment],)] [comment table_comment] [partitioned by(col_name data_type [comment col_comment],)] [clustered by (col_name,col_name,...)…

Python程序设计 字符类型及其操作

1. 提取身份证号性别 通过身份证的第17位也就是倒数第二位的数字可以辨别该身份证所属人的性别,奇数为男性,偶数为女性。 输入身份证号&#xff0c;第17位若是偶数&#xff0c;输出性别女&#xff0c;否则输出性别男 1.通过input()函数接收用户输入的身份证号&#xff0c;将其…

第7章 数据安全

思维导图 7.1 引言 数据安全包括安全策略和过程的规划、建立与执行&#xff0c;为数据和信息资产提供正确的身份验证、授权、访问和审计。虽然数据安全的详细情况(如哪些数据需要保护)因行业和国家有所不同&#xff0c;但是数据安全实践的目标是相同的&#xff0c;即根据隐私和…

SQL Sever 2008 安装教程

先从官网下载程序&#xff1a;下载地址 打开上述链接后&#xff0c;点击下载按钮。 就会跳出下面这个界面&#xff0c;如果你的电脑是64位的请选择下图中这两个程序。 下载完成后&#xff0c;在电脑磁盘中找到这两个文件&#xff0c;注意安装的顺序&#xff0c;先安装 SQLEXPR…

pdf操作器(图片转文字、PDF转word、PDF拆分、图片jpg、png互转)

pdf操作器&#xff08;不用联网图片转文字、PDF转word、PDF拆分、图片jpg、png互转&#xff09;介绍目前该软件实现了以下功能 pdf转wordpdf拆分图片&#xff0c;图片导出在桌面的一个文件夹里图片合并为pdf压缩、转换图片格式&#xff08;jpg和png&#xff09;OCR图片转文字&…

uniapp中uni.navigateTo传递变量

效果展示&#xff1a; 核心代码&#xff1a; uniapp中uni.navigateTo传递变量 methods: {changePages(item) {setDatas("maintenanceFunName", JSON.stringify(item)).then((res) > {uni.navigateTo({url: /pages/PMS/maintenance/maintenanceTypes/maintenanceT…

[图像处理] MFC载入图片并绘制ROI矩形

上一篇&#xff1a; [图像处理] MFC载入图片并进行二值化处理和灰度处理及其效果显示 文章目录 前言完整代码重要代码效果 前言 上一篇实现了MFC通过Picture控件载入图片。 这一篇实现ROI功能的第一部分&#xff0c;在Picture控件中&#xff0c;通过鼠标拖拽画出一个矩形。 完…

积木报表Excel数据量大导出慢导不出问题、大量数据导不出问题优化方案和分析解决思路(优化前一万多导出失败,优化后支持百万级跨库表导出)

文章目录 积木报表Excel数据量大导出慢导不出问题、大量数据导不出问题优化方案和分析解决思路&#xff08;优化前一万多导出失败&#xff0c;优化后支持百万级跨库表导出&#xff09;优化结果需求背景和解决方案的思考解决方案流程描述&#xff1a;关键代码引入easy excel新建…

景区云旅游/视频慢直播方案设计与平台搭建

一、行业背景 经文化和旅游部数据中心测算&#xff0c;今年清明节假期3天全国国内旅游出游1.19亿人次&#xff0c;按可比口径较2019年同期增长11.5%&#xff1b;国内游客出游花费539.5亿元&#xff0c;较2019年同期增长12.7%。踏青赏花和户外徒步成为假期的热门出游主题。随着…