学习站点:
https://www.w3school.com.cn/svg
https://svgjs.dev/docs/ svg编辑常用方法
1.text 文字标签
x 右起点
y 下起点
text-anchor 文字左右居中
dominant-baseline="central" 上下居中
x,y要选中心点坐标
<text x="200" y="0" style="font-size:24px; writing-mode: tb;">垂直文字</text>
<text class="title" x="20" y="27.5" dx="-14 -14 -14 -14 -14 -14" dy="0 15 15 15 15 15">
响应率︵%︶
</text>
text{
font-size: 14px;
fill: rgb(232, 239, 244);
text-anchor: middle;
}
默认<text>从起始位置(x,y)开始展示
fill的默认为black,stroke默认为none
text-anchor="middle"
start|middle|end(起始坐标|中轴坐标|结束坐标)
tspan 文本分行
<text x="240" y="120">
<tspan>SVG</tspan>
<tspan>SVG</tspan>
</text>
文字排列沿线
<defs>
<path id="MyPath"
d="M 100 200
C 200 100 300 0 400 100
C 500 200 600 300 700 200
C 800 100 900 100 900 100" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5">
<textPath xlink:href="#MyPath">
We go up, then we go down, then up again
</textPath>
</text>
2. image 图片标签
x y width height
xlink:href 图片位置
3.circle 圆标签
cx cy r
fill stroke stroke-width transparent
4.rect 柱形标签
width height x y
5.line 线标签
x1 y1 x2 y2
stroke-opacity 透明度
6.marker 箭头标签
<svg>
<defs>
<marker id="arrow"
markerUnits="strokeWidth"
markerWidth="4"
markerHeight="4"
viewBox="0 0 10 4"
refX="0"
refY="3"
orient="auto">
<path d="M0,0 L9,3 L0,6 Z" style="fill: #00ff00;" />
</marker>
</defs>
<!-- 实箭头的使用-->
<polyline
points="0,15 50,15"
fill="none"
stroke="#00ff00"
stroke-width="10"
marker-end="url(#arrow)"
></polyline>
</svg>
双向箭头
<svg class="page-map">
<defs>
<marker id="mar-success"
markerUnits="strokeWidth"
markerWidth="5"
markerHeight="5"
viewBox="0 0 12 12"
refX="6"
refY="6"
orient="auto">
<path d="M2,2 L10,6 L2,10 L6,6 L2,2" style="fill: grey;" />
</marker>
<marker id="mar1-success"
markerUnits="strokeWidth"
markerWidth="5"
markerHeight="5"
viewBox="0 0 12 12"
refX="6"
refY="6"
orient="auto">
<path d="M10,2 L2,6 L10,10 L6,6 L10,2" style="fill: grey;" />
</marker>
</defs>
<line x1="50" y1="50" x2="100" y2="50" id="montoser" stroke="grey" stroke-width="8" marker-start="url(#mar1-success)" marker-end="url(#mar-success)" />
</svg>
7.linearGradient 线性渐变
树的阴影效果
<svg width="400" height="600">
<defs>
<pattern id="grap" patternUnits="userSpaceOnUse" x="0" y="0" width="100" height="67" viewBox="0 0 102 76">
<image x="0" y="0" width="102" height="76" xlink:href="http://pic27.nipic.com/20130324/9148618_153134223000_2.jpg"></image>
</pattern>
<linearGradient id="TrunkGrad">
<stop offset="0%" stop-color="#663300"></stop>
<stop offset="40%" stop-color="#996600"></stop>
<stop offset="100%" stop-color="#552200"></stop>
</linearGradient>
<rect x="-5" y="-50" width="10" height="50" id="Trunk"></rect>
<path d="M-25,-50L-10,-80L-20,-80L-5,-110L-15,-110L0,-140L15,-110L5,-110L20,-80L10,-80L25,-50Z" fill="#f00" id="can">
</path>
<linearGradient id="shadow" x=0 y=0 x2=0 y2=100%>
<stop offset="0%" stop-color="#000" stop-opacity=".5"></stop>
<stop offset="20%" stop-color="#996600" stop-opacity="0"></stop>
</linearGradient>
<g id="tree">
<use xlink:href="#Trunk" fill="url(#TrunkGrad)"/>
<use xlink:href="#Trunk" fill="url(#shadow)"/>
<use xlink:href="#can" fill="none" stroke="#663300" stroke-linejoin="round" stroke-width="4px" />
<use xlink:href="#can" fill="#339900" stroke="none"/>
</g>
<g id="treeShadow">
<use xlink:href="#Trunk" fill="#000"/>
<use xlink:href="#can" fill="#000" stroke="none"/>
</g>
</defs>
<text y=60 x=200 font-family="Arial" font-size="60px" fill="#996600" text-anchor="middle">tree</text>
<text y=90 x=200 font-family="Arial" font-size="20px" fill="#996600" text-anchor="middle" id="treeCounter"></text>
<text y=550 x=20 font-family="Arial" font-size="20px" fill="#996600" text-anchor="left">
<tspan>点击一颗树或树的影子</tspan>
<tspan>并移除掉它。。。</tspan>
</text>
<g transform="translate(-10,350)" stroke-width="20" stroke="url(#grap)" stroke-linejoin="round">
<path d="M0,0Q170,-50 260,-190Q310,-250 410,-250" fill="none">
</path>
</g>
<!--skewX() x轴方向向右扭曲25像素-->
<use xlink:href="#treeShadow" transform="translate(130,250) scale(1,.6) skewX(-25)" opacity="0.4" />
<use xlink:href="#tree" transform="translate(130,250)" />
<use xlink:href="#treeShadow" transform="translate(260,500) scale(2,1.2) skewX(-25)" opacity="0.4" />
<use xlink:href="#tree" transform="translate(260,500) scale(2)" />
</svg>
8.g 组合标签
可将字体、颜色、边框等样式等放到g上使用,组合后可结合 defs可多处使用
9.path 标签
画拆线时用line效果可能不好,结合处放大可能会有断开处
M = moveto
L = lineto
H = horizontal lineto
V = vertical lineto
C = curveto
S = smooth curveto
Q = quadratic Bézier curve
T = smooth quadratic Bézier curveto
A = elliptical Arc
Z = closepath
注意:以上所有命令均允许小写字母。大写表示绝对定位,小写表示相对定位。
1.直线命令
<svg width="100px" height="100px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 10 H 90 V 90 H 10 L 10 10"/>
<!-- Points -->
<circle cx="10" cy="10" r="2" fill="red"/>
<circle cx="90" cy="90" r="2" fill="red"/>
<circle cx="90" cy="10" r="2" fill="red"/>
<circle cx="10" cy="90" r="2" fill="red"/>
</svg>
2.曲线命令
<!--三次贝塞尔曲线-->
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M130 110 C 120 140, 180 140, 170 110" stroke="black" fill="transparent"/>
<circle cx="130" cy="110" r="2" fill="red"/>
<circle cx="120" cy="140" r="2" fill="red"/>
<line x1="130" y1="110" x2="120" y2="140" style="stroke:rgb(255,0,0);stroke-width:2"/>
<circle cx="180" cy="140" r="2" fill="red"/>
<circle cx="170" cy="110" r="2" fill="red"/>
<line x1="180" y1="140" x2="170" y2="110" style="stroke:rgb(255,0,0);stroke-width:2"/>
</svg>
<!--三次贝塞尔曲线简写-->
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/>
<circle cx="10" cy="80" r="2" fill="red"/>
<circle cx="40" cy="10" r="2" fill="red"/>
<line x1="10" y1="80" x2="40" y2="10" style="stroke:rgb(255,0,0);stroke-width:1"/>
<circle cx="65" cy="10" r="2" fill="red"/>
<circle cx="95" cy="80" r="2" fill="red"/>
<line x1="65" y1="10" x2="95" y2="80" style="stroke:rgb(255,0,0);stroke-width:1"/>
<circle cx="125" cy="150" r="2" fill="blue"/>
<circle cx="180" cy="80" r="2" fill="red"/>
<circle cx="150" cy="150" r="2" fill="red"/>
<line x1="95" y1="80" x2="125" y2="150" style="stroke:blue;stroke-width:1"/>
<line x1="180" y1="80" x2="150" y2="150" style="stroke:rgb(255,0,0);stroke-width:1"/>
</svg>
<!--二次贝塞尔曲线-->
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
<!--Points-->
<circle cx="10" cy="80" r="2" fill="red"/>
<circle cx="95" cy="10" r="2" fill="red"/>
<circle cx="180" cy="80" r="2" fill="red"/>
<line x1="10" y1="80" x2="95" y2="10" style="stroke:rgb(255,0,0);stroke-width:1"/>
<line x1="95" y1="10" x2="180" y2="80" style="stroke:rgb(255,0,0);stroke-width:1"/>
</svg>
10.js编辑svg元素属性
两种方式:
1)style样式只能这样修改才会生效
document.getElementById("mycircle").style.fill='red';
2)其他属性修改
document.getElementById("mycircle").setAttribute("r",r);
11.围绕中心转动
<style>
svg {
border:1px solid blue;
margin:100px;
}
</style>
<svg width="500" height="250" >
<rect
x="50" y="50"
width="50" height="50"
fill="red">
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
from="0 75 75"
to="360 75 75"
begin="0"
dur="2"
repeatCount="indefinite" />
</rect>
</svg>
12.文字沿着指定的曲线运动
<svg width="100%" height="100%" viewBox="0 0 1000 300"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path id="MyPath"
d="M 100 200
C 200 100 300 0 400 100
C 500 200 600 300 700 200
C 800 100 900 100 900 100" />
</defs>
<use xlink:href="#MyPath" fill="none" stroke="red" />
<text font-family="Verdana" font-size="42.5">
<textPath xlink:href="#MyPath">
优快云-叶常落
<animate attributeName="startOffset" from="0" to ="830" begin="0s" dur="10s" repeatCount="indefinite"/>
</textPath>
</text>
<!-- Show outline of the viewport using 'rect' element -->
</svg>
13.js制作的小圆柱
<div id="main" style="width: 100%; height: 800px"></div>
<script>
var svgNS = "http://www.w3.org/2000/svg";
var toolTip;
function initSvg(myDiv, array) {
document.getElementById(myDiv).innerHTML = '';
var oParent = document.getElementById(myDiv);
var oWidth = oParent.clientWidth;
var oHight = oParent.clientHeight;
var count = array.length;
var avg = (oWidth - 100) / (array.length + 1);
var maxCapacity = 0;
for (var i = 0; i < count; i++) {
var item = array[i];
maxCapacity = Math.max(maxCapacity, item.capacity);
}
for (var i = 0; i < count; i++) {
var item = array[i];
var oSvg = createSvg(avg, oHight, maxCapacity, item);
oParent.appendChild(oSvg);
}
}
function createSvg(oWidth, oHight, maxCapacity, item) {
var oSvg = createTag('svg', {'xmlns': svgNS, 'width': oWidth, 'height': oHight, x: 0});
var btmY = oHight * 0.7;
var leftX = oWidth * 0.1;
var rightX = oWidth * 0.9;
var rx = (leftX + rightX) / 2;
var ry = rx / 5;
var topY = 20 + ry + (btmY - 20 - ry) * (1 - (item.capacity / maxCapacity));
var costPencent = (item.remain / item.capacity) > 1 ? 1 : (item.remain / item.capacity);
var midY = topY + (btmY - topY) * (1 - costPencent);
var textY = (btmY + 25);
var oG = createTag('g', {'style': 'cursor:pointer; padding:0px 10px;'});
var iName = item.name;
if (item.name && item.name.length > 12) {
iName = item.name.substring(0, 12) + "...";
}
var oText = createTag('text', {
'x': rx,
'y': textY,
width: oWidth,
'text-anchor': 'middle',
'fill': '#0dc59f',
}, iName);
var emptyPath = createTag('path', {
'd': 'M' + leftX + ',' + topY + ' A' + rx + ',' + ry + ' 0 0,0 ' + rightX + ',' + topY + ' A' + rx + ',' + ry + ' 0 0,0 ' + leftX + ',' + topY + ' L' + leftX + ',' + midY + ' A' + rx + ',' + ry + ',0 0,0 ' + rightX + ',' + midY + ' L' + rightX + ',' + topY,
'style': 'stroke:#660000; fill: #fff',
});
var remainPath = createTag('path', {
'd': 'M' + leftX + ',' + midY + ' A' + rx + ',' + ry + ' 0 0,0 ' + rightX + ',' + midY + ' A' + rx + ',' + ry + ' 0 0,0 ' + leftX + ',' + midY + ' L' + leftX + ',' + btmY + ' A' + rx + ',' + ry + ',0 0,0 ' + rightX + ',' + btmY + ' L' + rightX + ',' + midY,
'style': 'stroke:#660000; fill: #c23531',
});
var remainAni = createTag('animate', {
attributeName: 'd',
dur: '0.5',
from: 'M' + leftX + ',' + topY + ' A' + rx + ',' + ry + ' 0 0,0 ' + rightX + ',' + topY + ' A' + rx + ',' + ry + ' 0 0,0 ' + leftX + ',' + topY + ' L' + leftX + ',' + btmY + ' A' + rx + ',' + ry + ',0 0,0 ' + rightX + ',' + btmY + ' L' + rightX + ',' + topY,
to: 'M' + leftX + ',' + midY + ' A' + rx + ',' + ry + ' 0 0,0 ' + rightX + ',' + midY + ' A' + rx + ',' + ry + ' 0 0,0 ' + leftX + ',' + midY + ' L' + leftX + ',' + btmY + ' A' + rx + ',' + ry + ',0 0,0 ' + rightX + ',' + btmY + ' L' + rightX + ',' + midY
});
oSvg.appendChild(oG);
oG.appendChild(emptyPath);
remainPath.appendChild(remainAni);
oG.appendChild(remainPath);
oG.appendChild(oText);
oG.onmousemove = function (ev) {
if (toolTip) {
toolTip.remove();
}
var ev = ev || window.event;
toolTip = document.createElement("div");
toolTip.setAttribute("style", "position: absolute; border-style: solid; white-space: nowrap; z-index: 9999999; transition: left 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s, top 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s; background-color: rgba(50, 50, 50, 0.7); border-width: 0px; border-color: rgb(51, 51, 51); border-radius: 4px; color: rgb(255, 255, 255); font: 14px / 21px "Microsoft YaHei"; padding: 5px; left: 694px; top: 392px; pointer-events: none;");
toolTip.style.left = (ev.clientX + 25) + 'px';
toolTip.style.top = (ev.clientY + 25) + 'px';
var rPencent = item.remain / item.capacity * 100;
rPencent = rPencent.toFixed(2) + "%";
var iHtml = item.name + "<br><span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:#c23531;\"></span>总容量:" + item.capacity
+ "<br><span style=\"display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:#2f4554;\"></span>剩余量:" + item.remain + " (" + rPencent + ")";
toolTip.innerHTML = iHtml;
document.body.appendChild(toolTip);
};
oG.onmouseleave = function (ev) {
if (toolTip) {
toolTip.remove();
}
}
return oSvg;
}
function createTag(tag, params, innerHtml) {
var oTag = document.createElementNS(svgNS, tag);
for (var attr in params) {
oTag.setAttribute(attr, params[attr]);
}
if (innerHtml) {
oTag.innerHTML = innerHtml;
}
return oTag;
}
function initData() {
initSvg('main', data.data);
}
var data = {
"code": 200,
"msg": null,
"count": "0",
"data": [{
"name": "柱子1",
"capacity": 20000.00,
"total": 466.00,
"cost": 0,
"remain": 466.00
}, {
"name": "柱子2",
"capacity": 10200.00,
"total": 11041.00,
"cost": 0,
"remain": 11041.00
}, {
"name": "柱子3",
"capacity": 16300.00,
"total": 0,
"cost": 0,
"remain": 0
}, {
"name": "柱子4",
"capacity": 12400.00,
"total": 971.00,
"cost": 0,
"remain": 971.00
}, {
"name": "柱子5",
"capacity": 12000.00,
"total": 3000.00,
"cost": 0,
"remain": 3000.00
}, {
"name": "柱子6",
"capacity": 10400.00,
"total": 485.00,
"cost": 0,
"remain": 485.00
}, {
"name": "柱子7",
"capacity": 12000.00,
"total": 0,
"cost": 0,
"remain": 0
}, {
"name": "柱子8",
"capacity": 10000.00,
"total": 0,
"cost": 0,
"remain": 0
}, {
"name": "柱子9",
"capacity": 10000.00,
"total": 548.00,
"cost": 0,
"remain": 548.00
}, {
"name": "柱子10",
"capacity": 10000.00,
"total": 0,
"cost": 0,
"remain": 0
}]
}
window.onload = function() {
initData();
}
</script>
14、 svg.js使用
<!DOCTYPE html>
<html>
<head>
<title>SVG.js画图Demo</title>
<link rel="stylesheet" href="svg/svg.select.css" media="all">
<script src="svg/svg.js"></script>
<script src="svg/svg.draggable.js"></script>
<script src="svg/svg.select.js"></script>
<script src="svg/svg.resize.js"></script>
<script src="svg/svg.panzoom.js"></script>
<script src="svg/jquery-1.10.2.js"></script>
</head>
<body>
<div class="layui-fluid">
<div class="left" style="width: 210px">
<div class="buttons">
<img id="imgYard" nodeType="yard" class="controls" src="image/yard.svg" />
</div>
<div class="buttons">
<img id="imgFactory" nodeType="factory" class="controls" src="image/factory.svg" />
</div>
<div class="buttons">
<img id="imgSource" nodeType="source" class="controls" src="image/source.svg" />
</div>
<div class="buttons">
<img id="imgPoint" nodeType="point" class="controls" src="image/point.svg" />
</div>
</div>
<div class="main" style="width: calc(100% - 30px);border-left: none;">
<svg id="mSvg" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<defs>
<image id="yard" xlink:href="image/yard.svg"></image>
<image id="factory" xlink:href="image/factory.svg"></image>
<image id="source" xlink:href="image/source.svg"></image>
<image id="point" xlink:href="image/point.svg"></image>
</defs>
</svg>
</div>
<div class="right"></div>
</div>
<style>
.layui-fluid {
padding: 10px 15px;
/* height: calc(100% - 24px); */
height: calc(100vh - 36px);
display: flex;
}
.left,
.main {
box-shadow: rgb(13 197 159 / 10%) 0px 0px 40px 0px inset;
border-width: 1px;
border-style: solid;
border-color: rgba(13, 197, 159, 0.4);
border-image: initial;
height: 100%;
}
.main {
cursor: url("image/openhand.cur"), default;
}
.drag {
cursor: url("image/closedhand.cur"), default;
}
.controls {
width: 170px;
height: 85px;
cursor: pointer;
}
.buttons {
margin: auto;
line-height: 90px;
text-align: center;
}
</style>
<script>
var joinLines = [];
const lineMap = {
"yard": "factory",
"factory": "point",
"source": "point",
}
const draw = SVG('mSvg').size('100%', '100%').panZoom({ zoomMin: 0.5, zoomMax: 2 });
const rootGroup = draw.group().id('rootGroup');
// draw.defs().pattern(10, 10, function (add) {
// add.path('M 10 0 L 0 0 0 10').fill('none').stroke({color: '#eee', width: 0.5})
// add.pattern(10, 10, function (add) {
// add.rect().attr({width: 10, height: 10, fill: 'url(#smallGrid)'})
// add.path('M 100 0 L 0 0 0 100').fill('none').stroke({color: '#eee', width: 1})
// }).attr({'id': 'grid'})
// }).attr({'id': 'smallGrid'})
// const gridRect = rootGroup.rect().size('100%', '100%').fill('url(#grid)').id('gridrect') // 网格
// rootGroup.add(gridRect)
$('.controls').off('mousedown').on('mousedown', function () {
console.log($(this).attr('nodeType'))
let nodeType = $(this).attr('nodeType')
draw.remember('addNode', nodeType);
})
function addNewNode(nodeType) {
let selectNode = rootGroup.use(nodeType).attr('nodeType', nodeType);
draw.remember('selectNode', selectNode)
selectNode.on('selectNode mousedown', function (e) {
console.log('selectNode mousedown')
let startNode = draw.remember('startNode');
if (startNode && this !== startNode) {
startNode.selectize(false).resize(false).draggable(false);
}
this.selectize().resize().draggable();
addJoinLine(this);
draw.remember('startNode', this);
e.stopPropagation();
})
selectNode.on('dragend', function (e) {
console.log('dragend')
updateJoinLine(this);
// e.stopPropagation();
});
selectNode.on('resizing', function (e) {
console.log('resizing')
updateJoinLine(this);
// e.stopPropagation();
});
return selectNode;
}
$('.main').on('mouseover', function (e) {
// console.log('mouseover', e)
let addNode = draw.remember('addNode');
if (addNode) {
let selectNode = draw.remember('selectNode');
if (!selectNode) {
selectNode = addNewNode(addNode);
}
let rbox = selectNode.rbox();
let point = draw.point(e.pageX - rbox.width / 2, e.pageY - rbox.height / 2);
selectNode.move(point.x, point.y);
selectNode.on('mouseup', function (e) {
// console.log('mouseup', e)
//鼠标左键保留
if (e.which === 1) {
console.log('save')
draw.forget('addNode');
draw.forget('selectNode');
}
this.off('mouseup');
})
}
}).on('mousedown', function (e) {
console.log('main.mousedown', e)
$('.main').addClass('drag');
let startNode = draw.remember('startNode');
if (startNode) {
let rbox = startNode.rbox();
if (rbox.x <= e.pageX && rbox.x + rbox.width >= e.pageX && rbox.y <= e.pageY && rbox.y + rbox.height >= e.pageY) {
console.log('inner')
draw.forget('startDrag');
} else {
console.log('outer')
draw.remember('startDrag', e);
draw.forget('startNode');
startNode.selectize(false).resize(false).draggable(false);
}
} else {
draw.remember('startDrag', e);
}
}).on('mouseup', function (e) {
console.log('main.mouseup', e)
let selectNode = draw.remember('selectNode');
if (selectNode) {
console.log('delete')
draw.forget('addNode');
draw.forget('selectNode');
selectNode.remove();
e.stopPropagation();
}
let startNode = draw.remember('startNode');
if (startNode) {
draw.forget('startNode');
startNode.selectize(false).resize(false).draggable(false);
startNode.remove();
}
$('.main').removeClass('drag');
})
$(document).on('keydown', function (e) {
let startNode = draw.remember('startNode');
console.log('document.keydown', e, startNode)
if (startNode) {
if (e.key == 'Delete') {
deleteSelectNode(startNode);
} else if (e.key == 'ArrowLeft') {
let x = startNode.x();
x -= 3;
startNode.x(x);
updateJoinLine(startNode);
} else if (e.key == 'ArrowRight') {
let x = startNode.x();
x += 3;
startNode.x(x);
updateJoinLine(startNode);
} else if (e.key == 'ArrowUp') {
let y = startNode.y();
y -= 3;
startNode.y(y);
updateJoinLine(startNode);
} else if (e.key == 'ArrowDown') {
let y = startNode.y();
y += 3;
startNode.y(y);
updateJoinLine(startNode);
}
}
}).on('contextmenu', function(){
return false;
})
function deleteSelectNode(node) {
console.log('deleteNode', node.attr('nodeId'))
if (node.attr('nodeId')) {
top.layer.confirm('确定删除吗?', function (index) {
deleteNode(node);
top.layer.close(index);
});
} else {
deleteNode(node);
}
}
function deleteNode(node) {
//删除连接线
joinLines.forEach((joinLine, index) => {
if (node === joinLine.startNode || node === joinLine.endNode) {
joinLine.path.remove();
joinLines.splice(index, 1);
}
});
node.selectize(false).resize(false).draggable(false);
node.remove();
draw.forget('startNode')
}
//两个节点间添加连接线
function addJoinLine(endNode) {
let startNode = draw.remember('startNode');
if (!startNode) return;
if (startNode === endNode) {
// console.log('节点之间才相互连线');
return;
}
let repeat = false;
joinLines.forEach(joinLine => {
if (startNode === joinLine.startNode && endNode === joinLine.endNode) {
// console.log('不允许重复添加连线');
repeat = true;
return;
}
})
let startNodeType = startNode.attr('nodeType');
let endNodeType = endNode.attr('nodeType');
if (endNodeType !== lineMap[startNodeType]) {
console.log('不允许添加连线', startNodeType, endNodeType);
return;
}
if (!repeat) {
let path = drawLine(startNode, endNode);
let joinLine = { path, startNode, endNode };
joinLines.push(joinLine);
draw.remember('startNode', endNode);
}
}
//更新连接线位置
function updateJoinLine(node) {
joinLines.forEach(joinLine => {
if (node === joinLine.startNode || node === joinLine.endNode) {
let path = drawLine(joinLine.startNode, joinLine.endNode, joinLine.path);
joinLine.path = path;
}
})
}
function drawLine(startNode, endNode, path) {
let srb = startNode.rbox();
let erb = endNode.rbox();
let start;
let end;
//x轴距离较长,取左右边缘中点
if (Math.abs(srb.cx - erb.cx) > Math.abs(srb.cy - erb.cy)) {
if (srb.cx < erb.x) {
start = startNode.point(srb.x + srb.width, srb.y + srb.height / 2);
end = endNode.point(erb.x, erb.y + erb.height / 2);
} else {
start = startNode.point(srb.x, srb.y + srb.height / 2);
end = endNode.point(erb.x + erb.width, erb.y + erb.height / 2);
}
} else { //y轴距离较远,取上下边缘中点
if (srb.cy < erb.y) {
start = startNode.point(srb.x + srb.width / 2, srb.y + srb.height);
end = endNode.point(erb.x + erb.width / 2, erb.y);
} else {
start = startNode.point(srb.x + srb.width / 2, srb.y);
end = endNode.point(erb.x + erb.width / 2, erb.y + erb.height);
}
}
let mid = { x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 };
let pathArray = new SVG.PathArray([
['M', start.x, start.y]
, ['L', mid.x, mid.y]
, ['L', end.x, end.y]
]);
// console.log(pathArray);
if (path) {
path.reference('marker-mid').remove();
path.remove();
}
let nodeTypes = [startNode.attr('nodeType'), endNode.attr('nodeType')]
path = draw.path(pathArray).attr('nodeType', nodeTypes.join('-'));
rootGroup.add(path);
path.marker('mid', 12, 12, function (add) {
add.path('M2,2 L2,11 L10,6 L2,2').fill('#0dc59f')
}).stroke({ width: 3, color: '#0dc59f' }).fill('none').back();
path.on('click', function (e) {
console.log('path.click')
let startNode = draw.remember('startNode');
if (startNode && this !== startNode) {
startNode.selectize(false).resize(false).draggable(false);
}
this.selectize().resize().draggable();
draw.remember('startNode', this);
// e.stopPropagation();
})
return path;
}
window.onresize = function () {
heightAdaptive();
}
heightAdaptive()
function heightAdaptive() {
$(document).trigger('mouseup');
}
</script>
</body>
</html>
15.流动的铁路线
<!DOCTYPE html>
<html>
<body>
<style style="text/css">
.svgLineDL{
animation:move2 1s infinite;
}
@keyframes move2{
0%{
stroke-dashoffset: 100;
}
100%{
stroke-dashoffset: 0;
}
}
</style>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<defs>
<symbol id="sym">
<polyline points="100 100 250 90 400 80 500 90 550 100 600 110"/>
</symbol>
</defs>
<g >
<use xlink:href="#sym" style="fill:none;stroke:black;stroke-width:20"/>
<use xlink:href="#sym" style="fill:none;stroke:rgb(128,128,128);stroke-width:18;
stroke-dasharray:50 50;stroke-dashoffset :50" class="svgLineDL"/>
</g>
</svg>
</body>
</html>