需求
主要内容:
- 静态绘制
- 缩放/拖拽联动
- 选中效果/扩大点击区域/曲线可被选中而svg画布其他部分鼠标穿透
- 悬浮效果+获取tooltip数据
静态绘制曲线集
svg
1 | <svg class="home-broadband-chart-line" version="1.1" xmlns="http://www.w3.org/2000/svg"> |
css
1 | .home-broadband-chart-line { |
参考: visiblepainted
动态绘制曲线集
获得每一条线的起始坐标,输入svg绘制即可。
曲线
1 | <svg |
起点位置
起点是四个DOM定点,只需获取四个DOM元素的中心位置(简单DOM操作,根据实际情况而定)1
2
3
4
5
6
7
8
9
10
11
12// 该示例不通用
getPos = () => {
const { id } = this.props;
const { offsetLeft, offsetTop } = this[id].offsetParent; // 位置
const ball = this[id].children[0];
const xCenter = (this[id].clientWidth - ball.clientWidth) / 2; // 中心
const yCenter = ball.clientHeight / 2;
return {
x: offsetLeft + this[id].offsetLeft + xCenter,
y: (offsetTop + this[id].offsetTop) + yCenter,
};
};
终点位置
终点是echarts图结点,需要获取echarts点位置1
2
3
4
5
6
7getPixel(info) {
const { pos, geo = 'geo' } = info;
const { lng, lat } = pos;
const { chart } = this;
const pixel = chart.convertToPixel(geo, [lng, lat]); // 经纬度转平面坐标
return pixel;
}
resize(拖拽/缩放)
echarts图形变动——重新获取地图各点平面坐标(终点位置)
1 | setDataZoom(func) { |
窗口变动——重新更新四个DOM元素平面坐标(起点位置)
1 | window.addEventListener('resize', this.resize);。 |
判断鼠标“是否在同一条连线上连续移动”
鼠标在同一条连线上连续移动,不应重新调取tooltip接口,而应直接采用原有tooltip接口数据。
已知鼠标方法:
- 鼠标落在连线: onmouseover
- 鼠标离开连线: onmouseout
鼠标在曲线上移动过程中,视觉上虽然是连续的,但其实在一瞬间先经历了onmouseout又onmouseover的过程。
思路: 利用定时器setTimeout,来延缓onmouseout。即在200ms内,再次onmouseover,则不再执行onmouseout的方法。
1 | onLinkOut = () => { |
定时器有广泛的应用意义:
- 为了防止用户鼠标不经意划过链接,腾讯网首页几乎所有鼠标经过事件都进行了【延时处理】,即 鼠标经过后200毫秒,才执行鼠标经过事件。
该方案是节流、防抖的思想之一。
节流、防抖
描述
因频繁执行DOM操作,资源加载等行为,导致UI停顿甚至浏览器崩溃。
常见导致原因如以下持续触发的事件——
- 浏览器的 onresize / onscroll 等事件。
- 鼠标的 mousemove / mousedown 等事件。
- 键盘的 keydown / keyup 等事件。
- 地图的 zoomend / dragend / moveend 等事件。
功能
节流throttle
作用:
以一定的频率执行后续处理。
让水龙头每隔200毫秒流出一滴水。源源不断的流出水而又不浪费。
场景:
拖拽DOM。在一定时间内多次执行,会感觉流畅。(如果使用防抖,一定时间内执行一次,会感觉卡顿)。
分类:
- 时间戳
- 定时版本
防抖debounce
作用:
停止n毫秒后,执行后续处理
场景:
搜索。当联想搜索时,用户连续不断输入字符keyup,不应立即发送请求,而应等一段时间不输入了,才发送一次请求
分类:
- 非立即防抖
- 立即防抖
非立即防抖
触发事件后函数不会立即执行,而是在n秒之后执行,如果n秒之内又触发了事件,则会重新计算函数执行时间。1
2
3
4
5
6
7
8
9
10
11
12
13function debounce(func, wait) {
var timer = null; // 定义计时器
var context = this;
var args = arguments;
return function () {
if (timer) {
clearTimeout(timer); // 在n时间内,又被执行,则清除计时器,重新计时
}
timer = setTimeout(function () {
func.apply(context, args)
}, wait); // 触发事件后,等待n时间后才执行
}
}
立即防抖
触发事件后函数会立即执行,然后n秒内不触发事件才会执行函数的效果。1
2
3
4
5
6
7
8
9
10
11
12
13function debounce(func, wait) {
var timeout = null;
var context = this;
var args = arguments;
return function () {
if (timeout) clearTimeout(timeout);
var callNow = !timeout;
timeout = setTimeout(function () {
timeout = null;
}, wait)
if (callNow) func.apply(context, args)
}
}