这几天写链路图,边写边想写这东西这么消耗体力,就想写个小工具出来能加快效率,但奈何比较懒,想着链路图应该很快能调好,可发现调了一个多小时,线还没开始,麻了!
思考了下,工具写起来应该比较简单,然后花了点时间写了这个PointsBuild,废话不多说,上代码::
import React, { useState, useRef } from 'react';
import Clipboard from 'clipboard';
/**
* 链路图点位工具
* @param {number} cartesianMaxY y轴最大值,默认为0,表示DOM定位方式
* @param {number} width 占位宽度
* @param {number} height 占位高度
* @param {url} background 占位背景
* @param {json} style 占位style
* @param {bool} notice 是否提示复制信息
* @param {string} formatter 数据输出格式,使用${x}${y}占位
* @param {bool} multi 多点连续输出,默认单点输出
*/
const listenerCatch = (obj, e, hander) => {
if (obj.addEventListener) {
obj.addEventListener(e, hander, false);
} else if (obj.attachEvent) {
e = 'on' + e;
obj.attachEvent(e, hander);
}
};
const cancelEvent = (e) => {
if (e.preventDefault) {
e.preventDefault();
e.stopPropagation();
} else {
e.returnValue = false;
e.cancelBubble = true;
}
};
const PointsBuild = ({
cartesianMaxY = 0,
width = 100,
height = 100,
background = null,
style = {},
notice = true,
formatter = '',
multi = false,
}) => {
const [top, setTop] = useState(0);
const [left, setLeft] = useState(0);
const [mesWidth, setWidth] = useState(0);
const [pointer, points, ref] = [useRef({ x: 0, y: 0 }), useRef(''), useRef(null)];
const drag = (e) => {
!pointer.current.x && !pointer.current.y && listenerCatch(document, 'mousemove', mousemove);
pointer.current = { x: e.pageX, y: e.pageY };
};
const mousemove = (e) => {
cancelEvent(e);
let [x, y] = [e.pageX, e.pageY];
if (ref.current.offsetLeft <= 5 && ref.current.offsetTop <= 5) points.current = '';
setLeft((l) => l + x - pointer.current.x);
setTop((t) => t + y - pointer.current.y);
pointer.current = { x: x, y: y };
};
const copy = (e) => {
let text;
if (formatter) {
let [x, y] = cartesianMaxY ? [left + width / 2, cartesianMaxY - top - height / 2] : [left, top];
if (points.current.indexOf('${x}') == -1) multi ? (points.current += formatter) : (points.current = formatter);
points.current = points.current.replace('${x}', x).replace('${y}', y);
text = points.current;
} else {
cartesianMaxY && (points.current += `[${left + width / 2}, ${cartesianMaxY - top - height / 2}],`);
text = cartesianMaxY ? points.current : `left: '${left}px', top: '${top}px',`;
}
const clipboard = new Clipboard('.btn', {
text: function () {
return text;
},
});
clipboard.on('success', () => {
clipboard.destroy();
});
clipboard.on('error', function () {
clipboard.destroy();
});
clipboard.onClick(e);
if (notice) {
const mes = document.createElement('div');
mes.className = `mes-mark`;
document.body.appendChild(mes);
mes.textContent = `复制坐标${text}成功`;
setWidth(mes.clientWidth);
setTimeout(() => {
mes.remove();
}, 1500);
}
};
return (
<div onMouseDown={(e) => drag(e)} onClick={(e) => copy(e)} ref={ref} style={style} className="pointsbuild-mark">
<style jsx="true">
{`
.pointsbuild-mark {
width: ${width}px;
height: ${height}px;
background: url(${background}) center no-repeat;
position: absolute;
top: ${top}px;
left: ${left}px;
border: 1px solid red;
z-index: 100000;
}
.mes-mark {
position: fixed;
top: 50px;
font-size: 18px;
padding: 0 20px;
border-radius: 8px;
line-height: 30px;
height: 30px;
background: rgba(255, 255, 255, 1);
left: calc(50% - ${mesWidth / 2}px);
}
`}
</style>
</div>
);
};
export default PointsBuild;
代码是react的,vue就不写了,其实一样的,先来看看这东西怎么用的:
替代了原先在代码上一个个写定位然后在浏览器上面调坐标的方式,直接写好格式化输出语句,直接在浏览器上取点直接复制到代码上即可。现在来说说怎么使用:
/**
* 链路图点位工具
* @param {number} cartesianMaxY y轴最大值,默认为0,表示DOM定位方式
* @param {number} width 占位宽度
* @param {number} height 占位高度
* @param {url} background 占位背景
* @param {json} style 占位style
* @param {bool} notice 是否提示复制信息
* @param {string} formatter 数据输出格式,使用${x}${y}占位
* @param {bool} multi 多点连续输出,默认单点输出
*/
cartesianMaxY区分是DOM定位还是坐标系定位,为0是dom定位,坐标系定位时,这里要填入最大纵坐标值,width、height、background、style是定位框的大小样式,可以直接用需要定位的元素替代。notice是否弹出提示框,formatter是输出格式, x {x} x{y}是占位符,输出时会替换为对应坐标值。multi设置多点输出还是单点输出,没有设置formatter在坐标系模式下默认多点输出。示例如下:
<PointsBuild
cartesianMaxY={1445}
width={25}
height={17}
multi={true}
//formatter是string格式,这里为了方便展示,用了``格式
formatter={`{
lineStyle: {
color: '#fff',
type: 'solid',
opacity: 1,
},
coords: [
[${'${x}'}, ${'${y}'}],
[${'${x}'}, ${'${y}'}],
[${'${x}'}, ${'${y}'}],
],
},`}
/>
DOM定位配置比较简单,把这个组件扔到需要定位的元素同一父节点(为了定位一致)下就行,坐标系定位的话需要另外将坐标系展示范围设置和父节点一致,cartesianMaxY设为y轴最大值,具体配置如下:
<ReactEcharts
// 父节点大小
style={{ width: 3500, height: 1445 }}
option={options}
/>
// 设置展示区域为100%以及x、y轴的最大值与父节点分辨率一致
const options = {
grid: {
left: 0,
right: 0,
top: 0,
bottom: 0,
},
xAxis: {
min: 0,
max: 3500,
},
yAxis: {
min: 0,
max: 1445,
}
}
以上配置都是为了获取范围的坐标系与应用的坐标系保持一致,好了设置好这些就能食用了。
安装方式
npm install pointsbuild -D
有兴趣的同学可以改成读取地图点位的,需要考虑比例尺以及原点位置。
本文原创,未经授权,谢绝转载!