配置项如下
var uploadedDataURL = "/asset/get/s/data-1618453297000-coRLtNeB2.PNG";
var bgPatternImg = new Image();
bgPatternImg.setAttribute("crossOrigin", 'Anonymous');
bgPatternImg.src = "/asset/get/s/data-1618453297000-coRLtNeB2.PNG";
let pointList = [{
name: '中心节点',
position: [500, 150],
color: 'green',
items: [{
name: '中心节点',
}, ],
shape: {
r: 20 // 半径
}
},
{
name: '节点1',
position: [380, 110],
color: 'skyblue',
items: [{
name: '节点1',
}, ],
shape: {
r: 15 // 半径
}
},
{
name: '节点2',
position: [380, 190],
color: 'skyblue',
items: [{
name: '节点2',
}, ],
shape: {
r: 15 // 半径
}
},
{
name: '节点3',
position: [620, 110],
color: 'skyblue',
items: [{
name: '节点3',
}, ],
shape: {
r: 15 // 半径
}
},
{
name: '节点4',
position: [620, 190],
color: 'skyblue',
items: [{
name: '节点4',
}, ],
shape: {
r: 15 // 半径
}
},
{
name: '1-1',
position: [420, 30],
color: 'red',
items: [{
name: '1-1',
}, ],
shape: {
r: 10 // 半径
}
},
{
name: '1-2',
position: [260, 90],
color: 'red',
items: [{
name: '1-2',
}, ],
shape: {
r: 10 // 半径
}
}, {
name: '2-1',
position: [320, 250],
color: 'red',
items: [{
name: '2-1',
}, ],
shape: {
r: 10 // 半径
}
}, {
name: '2-2',
position: [450, 250],
color: 'red',
items: [{
name: '2-2',
}, ],
shape: {
r: 10 // 半径
}
},
{
name: '3-1',
position: [700, 110],
color: 'red',
items: [{
name: '3-1',
}, ],
shape: {
r: 10 // 半径
}
},
{
name: '4-1',
position: [700, 250],
color: 'red',
items: [{
name: '4-1',
}, ],
shape: {
r: 10 // 半径
}
},
];
let lineList = [{
name: '1',
nodes: [{
name: '中心节点'
}, {
name: '节点1'
}]
},
{
name: '2',
nodes: [{
name: '中心节点'
},
{
name: '节点2'
},
]
}, {
name: '3',
nodes: [{
name: '中心节点'
},
{
name: '节点3'
},
]
}, {
name: '4',
nodes: [{
name: '中心节点'
},
{
name: '节点4'
},
]
},
{
name: '5',
nodes: [{
name: '节点1'
},
{
name: '1-1'
},
]
},
{
name: '6',
nodes: [{
name: '节点1'
},
{
name: '1-2'
},
]
},
{
name: '7',
nodes: [{
name: '节点2'
},
{
name: '2-1'
},
]
},
{
name: '8',
nodes: [{
name: '节点2'
},
{
name: '2-2'
},
{
name: '4-1'
},
]
},
{
name: '9',
nodes: [{
name: '节点3'
},
{
name: '3-1'
},
]
},
{
name: '10',
nodes: [{
name: '节点4'
},
{
name: '4-1'
},
]
},
];
option = {
graphic: [{
// 拖拽的透明面板
id: 'toolPan',
type: 'rect',
z: 2, // z 方向上的高度
position: [200, 0],
invisible: true, // 节点不可见,不然会挡住底图
style: {
fill: '#ccc'
},
//draggable: true,
cursor: 'all-scroll',
shape: {
height: 300,
width: 600,
},
//ondrag: groupCanDrag(), // 拖动组
onmousedown: dragPanStart(),
onmouseup: dragPanEnd(),
onmousemove: dragPan(),
onmouseout: dragPanEnd(),
onmousewheel: groupCanZoom('group1', 'toolPan'), // 缩放组
onclick: e => {
//const curPos = vecSub([e.offsetX, e.offsetY])
// console.log(curPos)
panPosition = myChart.getOption().graphic[0].elements[0].position;
console.log(panPosition)
},
},
{
type: 'group',
id: 'group1',
scale: [1, 1],
position: [0, 0],
children: [{
// 背景图
type: 'image',
id: 'bg',
position: [200, 0],
//bounding: 'raw',
// origin: [75, 75],
z: 1,
style: {
image: bgPatternImg
},
shape: {
height: 300,
width: 600,
}
},
// },
{
type: 'group',
id: 'tooltip',
ignore: true,
children: [{
type: 'rect',
id: 'tooltip-bg',
z: 100,
left: 'center',
shape: {
width: 190,
height: 90
},
style: {
fill: 'rgba(22,50,79,0.7)',
stroke: '#555',
lineWidth: 0,
shadowBlur: 8,
shadowOffsetX: 0,
shadowOffsetY: 2,
shadowColor: 'rgba(0,0,0,0.15)'
}
}, {
type: 'text',
id: 't-text',
z: 100,
left: 'center',
top: 10,
style: {
fill: 'rgba(174,238,238,0.7)',
textAlign: 'center',
}
},
{
type: 'text',
id: 't-text0',
z: 100,
left: 'center',
top: 10,
style: {
fill: '#fff',
textAlign: 'center',
}
},
{
type: 'text',
id: 't-text1',
z: 100,
left: 'center',
top: 30,
style: {
fill: '#fff',
textAlign: 'center',
}
}
]
}
]
}
]
};
/*
let dragMoveV = [0, 0]; // 拖动产生的偏移
let pointListCopy
// 拖动组
function groupCanDrag() {
return e => {
const curPosition = e.target.position; // 拖拽面板的位置
dragMoveV = curPosition;
//移动背景图
myChart.setOption({
graphic: [{
id: 'group1',
$action: 'merge',
position: vecSub(curPosition, scaleMoveV)
},
]
});
};
}*/
let isDrag // 是否在拖动
let dragOrigin //拖动的起始点
let panPosition = [0, 0]; // 拖拽盘的位置
function dragPanStart() {
return e => {
isDrag = true;
dragOrigin = [e.offsetX, e.offsetY];
panPosition = myChart.getOption().graphic[0].elements[0].position;
}
}
let pointListCopy;
function dragPan() {
return e => {
if (!isDrag) return;
const curPos = [e.offsetX, e.offsetY]
const moveV = vecSub(curPos, dragOrigin);
pointListCopy = JSON.parse(JSON.stringify(pointList));
pointListCopy.forEach(point => {
point.position = vecAdd(point.position, moveV)
})
updatePoints(pointListCopy);
drawLine(lineList, pointListCopy);
myChart.setOption({
graphic: [{
id: 'toolPan',
$action: 'merge',
position: vecAdd(moveV, panPosition),
},
{
id: 'bg',
$action: 'merge',
position: vecAdd(moveV, panPosition),
}
],
})
}
}
function dragPanEnd() {
return e => {
isDrag = false;
dragOrigin = undefined;
if (!pointListCopy) return
pointList = pointListCopy;
panPosition = myChart.getOption().graphic[0].elements[0].position;
}
}
let curScale = 1.00;
// 缩放 group
function groupCanZoom(groupId, dragPanId) {
return e => {
let curPointerPos = [e.offsetX, e.offsetY];
const minScale = 0.5; // 最小缩小尺寸
const maxScale = 5; // 最大放大尺寸
const scaleStep = 1.25; // 每次滚轮滑动改变的尺寸
const isWheelUp = e.wheelDelta > 0;
scale = isWheelUp ? scaleStep : (1 / scaleStep);
if (curScale * scale < minScale || curScale * scale > maxScale) return;
curScale = curScale * scale;
//const pointListCopy = JSON.parse(JSON.stringify(pointList)); // 深拷贝
pointList.forEach(point => {
const tmp1 = vecSub(point.position, curPointerPos);
const tmp2 = vecScale(tmp1, scale);
point.position = vecAdd(tmp2, curPointerPos);
})
updatePoints(pointList);
drawLine(lineList, pointList)
panPosition = myChart.getOption().graphic[0].elements[0].position;
// 计算背景图原点的偏移
const temp1 = vecSub(panPosition, curPointerPos);
const temp2 = vecScale(temp1, scale);
panPosition = vecAdd(temp2, curPointerPos)
myChart.setOption({
graphic: [{
id: 'bg',
$action: 'merge',
scale: [curScale, curScale],
shape: {
height: 300 * curScale,
width: 600 * curScale,
},
position: panPosition,
},
{
id: 'toolPan',
$action: 'merge',
shape: {
height: 300 * curScale,
width: 600 * curScale,
},
position: panPosition
}
]
});
};
}
// 画点
function drawPoint(points) {
const pointsInGroup = [];
// 给每个点设置 circle 的配置
points.forEach(point => {
const pointOpt = {
id: point.name,
name: point.name,
type: 'circle',
items: point.items,
position: point.position,
draggable: true,
z: 3,
style: {
fill: point.color || 'black'
},
shape: point.shape,
ondrag: onDragPoint(lineList, pointList),
onclick: onPointClick(),
onmouseover: showTooltip(),
onmousemove: showTooltip(),
onmouseout: hideTooltip(),
};
pointsInGroup.push(pointOpt);
});
myChart.setOption({
graphic: [{
id: 'group1',
type: 'group',
$action: 'merge',
children: pointsInGroup
}]
});
}
// 更新点
function updatePoints(points) {
const pointsOpt = [];
points.forEach(point => {
pointsOpt.push({
id: point.name,
$action: 'merge',
position: point.position
})
});
myChart.setOption({
graphic: pointsOpt
})
}
// 画线
function drawLine(lines, points) {
const linesInGroup = [];
lines.forEach(line => {
const pointsInLine = [];
line.nodes.forEach(item => {
points.forEach(point => {
if (item.name === point.name) pointsInLine.push(point.position)
})
});
const lineOpt = {
id: line.name,
type: 'polyline',
z: 2,
style: {
stroke: '#838A9D',
lineWidth: 2,
},
shape: {
points: pointsInLine,
},
onclick: onClickLine()
};
linesInGroup.push(lineOpt);
});
myChart.setOption({
graphic: [{
id: 'group1',
type: 'group',
$action: 'merge',
children: linesInGroup
}]
});
}
// 当移动点时,重新画线
function onDragPoint(lines, points) {
return e => {
const curPointName = e.target.__ecGraphicId;
const curPointPosition = [e.offsetX, e.offsetY];
pointList.forEach(point => {
if (point.name === curPointName) {
point.position = curPointPosition;
}
});
// 只从新画该测点的测线
const linesNeedDraw = lines.filter(line => {
if (line.nodes.filter(item => item.name === curPointName).length) return true;
});
updatePoints(pointList);
drawLine(linesNeedDraw, pointList);
};
}
let lastClickedPoint = '';
// 鼠标点击测点,测点放大和加上阴影
function onPointClick() {
// 放大后的scale
magnifyScale = 1.2;
return e => {
const curPoint = e.target;
const curPointName = curPoint.__ecGraphicId;
const curScale = curPoint.scale[0];
const curColor = curPoint.style.fill;
const scale = curScale === magnifyScale ? 1 : magnifyScale;
optList = [{
id: curPointName,
$action: 'merge',
scale: [scale, scale],
style: {
shadowBlur: curScale === magnifyScale ? 0 : 4,
shadowColor: curColor
}
}];
// 取消上次的选中
if (lastClickedPoint && lastClickedPoint !== curPointName) {
optList.push({
id: lastClickedPoint,
$action: 'merge',
scale: [1, 1],
style: {
shadowBlur: 0,
}
});
lastClickedPoint = '';
}
myChart.setOption({
graphic: optList
});
lastClickedPoint = curPointName;
}
}
lastClickedLine = ''
// 点击线后放大线
function onClickLine() {
// 放大后的线宽
magnifyWidth = 4.5;
return e => {
const curLine = e.target;
const curLineName = curLine.__ecGraphicId;
const curLineWidth = curLine.style.lineWidth;
optList = [{
id: curLineName,
$action: 'merge',
style: {
lineWidth: curLineWidth === magnifyWidth ? 2 : magnifyWidth,
}
}];
// 取消上次的选中
if (lastClickedLine && lastClickedLine !== curLineName) {
optList.push({
id: lastClickedLine,
$action: 'merge',
style: {
lineWidth: 2,
}
});
lastClickedLine = '';
}
myChart.setOption({
graphic: optList
});
lastClickedLine = curLineName;
}
}
// 还原上次放大的点
/*
function resizeLastPoint() {
if (!lastClickedPoint) return;
console.log(lastClickedPoint);
optList = [{
id: lastClickedPoint,
$action: 'merge',
scale: [1, 1],
}];
myChart.setOption({
graphic: optList
});
lastClickedPoint = '';
}
*/
// 显示 tooltip
function showTooltip() {
return e => {
const point = e.target;
let maxLen = 0; // 最长字符数
point.items.forEach(item => {
const str = item.name + item.value;
maxLen = str.length > maxLen ? str.length : maxLen;
});
const width = maxLen * 14 + 20;
const height = point.items ? point.items.length * 20 + 40 : 40;
const position = point.position;
let tipX;
let tipY;
if (position[0] < width + 10) {
// x 坐标过小,tooltip 在右方
tipX = position[0] + width / 2 + 10;
} else {
tipX = position[0] - width / 2 - 10;
}
if (position[1] < height + 10) {
// y 坐标过小,tooltip 在下方
tipY = position[1] + 10;
} else {
tipY = position[1] - height - 10;
}
const textList = [{
type: 'text',
id: 't-text',
$action: 'merge',
top: 10,
style: {
text: point.name,
}
}]
point.items.forEach((item, i) => {
textOpt = {
type: 'text',
id: 't-text' + i,
$action: 'merge',
top: 10 + (i + 1) * 20,
style: {
fill: '#fff',
textAlign: 'center',
font: '400 14px Microsoft YaHei'
}
}
textList.push(textOpt)
})
// 先把 tooltip 内容置空
myChart.setOption({
graphic: [{
id: 't-text',
$action: 'merge',
style: {
text: '',
}
},
{
id: 't-text0',
$action: 'merge',
style: {
text: '',
}
},
{
id: 't-text1',
$action: 'merge',
style: {
text: '',
}
}
]
});
myChart.setOption({
graphic: [{
id: 'tooltip',
ignore: false,
$action: 'merge',
position: [tipX, tipY],
}, {
id: 'tooltip-bg',
$action: 'merge',
shape: {
height,
width
}
},
...textList
]
});
}
}
//隐藏 tooltip
function hideTooltip() {
return e => {
myChart.setOption({
graphic: {
id: 'tooltip',
ignore: true,
$action: 'merge',
}
});
}
}
function vecAdd(vec1, vec2) {
if (vec1.length < 2 || vec2.length < 2) return
return [vec1[0] + vec2[0], vec1[1] + vec2[1]]
}
function vecSub(vec1, vec2) {
if (vec1.length < 2 || vec2.length < 2) return
return [vec1[0] - vec2[0], vec1[1] - vec2[1]]
}
function vecScale(vec, size) {
if (vec.length < 2) return
return [vec[0] * size, vec[1] * size]
}
// 取反向量
function vecNegate(vec) {
if (vec.length < 2) return
return [-vec[0], -vec[1]]
}
// 画图例
function drawLegend() {
const legendOpt = pointList.map((point, i) => {
return {
id: 'legend' + i,
type: 'group',
position: [10, 25 * i],
children: [{
// 点击的透明面板
id: 'legend' + i + '-pan',
pId: point.name,
legendId: 'legend' + i,
color: point.color,
type: 'rect',
z: 67, // z 方向上的高度
position: [0, 0],
invisible: true, // 节点不可见,不然会挡住底图
shape: {
height: 20,
width: 100,
},
onclick: onLegendClick()
},
{
id: 'legend' + i + '-c',
type: 'circle',
position: [10, 10], // 圆心的坐标位置
z: 66,
silent: true,
style: {
fill: point.color
},
shape: {
r: 10 // 半径
}
},
{
id: 'legend' + i + '-t',
type: 'text',
position: [30, 10 - 5], // 圆心的坐标位置
z: 66,
silent: true,
style: {
text: point.name,
font: 'bolder 14px "Microsoft YaHei", sans-serif',
fill: point.color
},
},
]
}
});
myChart.setOption({
graphic: [{
id: 'legend',
type: 'group',
$action: 'merge',
children: legendOpt
}]
});
}
// 点击图例
function onLegendClick() {
return e => {
const legend = e.target;
const pId = legend.pId;
const legendId = legend.legendId
if (!legend.isHide) {
myChart.setOption({
graphic: [{
id: legendId + '-c',
style: {
fill: 'rgba(230,233,239,1)',
}
},
{
id: legendId + '-t',
style: {
fill: 'rgba(230,233,239,1)',
}
},
{
id: pId,
ignore: true,
}
]
});
legend.isHide = true;
} else {
myChart.setOption({
graphic: [{
id: legendId + '-c',
style: {
fill: legend.color,
}
},
{
id: legendId + '-t',
style: {
fill: legend.color,
}
},
{
id: pId,
ignore: false,
}
]
});
legend.isHide = false;
}
}
}
setTimeout(function() {
drawPoint(pointList);
drawLine(lineList, pointList);
drawLegend();
}, 100);