上一次加入了鼠标拖拽功能,这回加入我来加入一个区域框,并且框内数据的阴影,效果如下

具体实现思路就是,可以响应鼠标事件来移动和调整大小,并且获取覆盖的数据,画出阴影.
响应鼠标事件可以改造上次写的鼠标移动的功能
区域框的设计为2部分,一部分是上下的区域,用来移动整个区域框,一部分为左右的线,用来改变区域框的大小.
鼠标在这两个部分上点击时才会捕获鼠标事件.
具体实现如下
class VerticalRangeNavigation extends MouseNavigation {
constructor() {
super()
this.start = []
this.draging = false
this.screen = []
this.range = []
this._area = {
"topBar":"topBar",
"bottomBar":"bottomBar",
"left":"left",
"right":"right",
"none":"none"
}
this.barSize = 20
this.hitTarget = this._area.none
this.color = "#FF00FF"
}
setRange(from, to){
this.range = [from , to]
}
hit(mouseEventArgs) {
if (this.draging) return true
let e = mouseEventArgs
if (e.area != this.area) return false
if(this._getHitArea(mouseEventArgs) != this._area.none)
return true
return false
}
onMouseDown(mouseEventArgs) {
let e = mouseEventArgs
e.prevent()
let ieLeftDown = this._isLeftDown(e)
if (ieLeftDown) {
this._startDrag(e)
this.hitTarget = this._getHitArea(mouseEventArgs)
}
}
_getHitArea(mouseEventArgs){
let e = mouseEventArgs
let x1 = this.viewport.transformX(this.range[0],e.screen)
let x2 = this.viewport.transformX(this.range[1],e.screen)
let offset = 5
if(e.x > Math.min(x1 ,x2) && e.x < Math.max( x1 ,x2) && e.y > e.screen[1] && e.y < e.screen[1] + this.barSize) return this._area.topBar
if(e.x > Math.min(x1 ,x2) && e.x < Math.max( x1 ,x2) && e.y > e.screen[1] + e.screen[3] - this.barSize && e.y < e.screen[1] + e.screen[3] ) return this._area.bottomBar
if (Math.abs(e.x - x1) < offset) return this._area.left
if (Math.abs(e.x - x2) < offset) return this._area.right
return this._area.none
}
_startDrag(e) {
this.start = [e.x, e.y]
this.draging = true
this.screen = e.screen
}
_stopDrag() {
this.start = [0, 0]
this.draging = false
}
_isLeftDown(e) {
return e.event.button == 0
}
onMouseMove(mouseEventArgs) {
let e = mouseEventArgs
if (this.draging && this._isLeftDown(e)) {
e.prevent()
let startX = this.start[0]
let width = this.screen[2]
let height = this.screen[3]
var deltaX = e.x - startX
let visibleLeft = this.viewport.visible[0]
let visibleWidth = this.viewport.visible[2] - visibleLeft
var offsetX = deltaX / width * visibleWidth
switch (this.hitTarget){
case this._area.left:
this.range[0] += offsetX
break;
case this._area.right:
this.range[1] += offsetX
break;
case this._area.topBar:
case this._area.bottomBar:
this.range[0] += offsetX
this.range[1] += offsetX
break;
default:
break;
}
this.start = [e.x, e.y]
}
let target = this.hitTarget
if (target == this._area.none){
target = this._getHitArea(mouseEventArgs)
}
switch (target){
case this._area.left:
mouseEventArgs.cursor = "w-resize"
break;
case this._area.right:
mouseEventArgs.cursor = "e-resize"
break;
case this._area.topBar:
case this._area.bottomBar:
mouseEventArgs.cursor = "move"
break;
default:
break;
}
}
onMouseUp(mouseEventArgs) {
let e = mouseEventArgs
if (this.draging) {
e.prevent()
this._stopDrag()
this.hitTarget = this._area.none
}
}
}
基本上就是完全拷贝了之前的 MouseNavigationDrawing .加入了鼠标捕获区域的判定.鼠标移动时改变区域的位置.
但是现在的区域框是看不到的.所以还要实现显示的功能,
之前我有 CanvasDrawingElement 类型,所以继承它的类都有 render 方法进行绘图,可是js并不支持多继承,也没有接口.
不过并不妨碍我们使用 render , 我们稍稍改造一下绘制的逻辑,在里面判断有没有 render 方法,只要有 render 都进行绘制就可以了.
一下是实现绘制的方法,这样区域框就可以被显示出来了.
class VerticalRangeNavigation extends MouseNavigation {
...
render(context, [left, top, width, height]) {
context.strokeStyle = this.color
let x1 = this.viewport.transformX( this.range[0],[left, top, width, height])
let x2 = this.viewport.transformX( this.range[1],[left, top, width, height])
context.beginPath()
context.moveTo(x1, top)
context.lineTo(x1 , top + height)
context.stroke()
context.beginPath()
context.moveTo(x2, top)
context.lineTo(x2 , top + height)
context.stroke()
context.fillStyle = this.color
context.fillRect(x1, top, x2 - x1,this.barSize)
context.fillRect(x1, top + height - this.barSize , x2 - x1, this.barSize)
}
}
鸭子万岁.
现在已经可以实现移动的功能了,再加入数据阴影的功能.
class VerticalRangeNavigation extends MouseNavigation {
...
_getAreaData(){
let elements = [...this.chart.getElements()] || []
let result = []
for (let element of elements.filter(e => Array.isArray(e.data) )) {
let rangeData = []
for (let i = 0; i < element.data.length / 2; i++) {
let x = element.data[2 * i]
let y = element.data[2 * i + 1]
let x1 = this.range[0]
let x2 = this.range[1]
if(x > Math.min(x1,x2) && x < Math.max(x1,x2) ){
rangeData.push(x)
rangeData.push(y)
}
}
result.push({data:rangeData,color:element.color})
}
return result
}
render(context, [left, top, width, height]) {
let rangeDatas = this._getAreaData()
for (let index = 0; index < rangeDatas.length; index++) {
const rangeData = rangeDatas[index]
let points = this.viewport.transform(rangeData.data, [left, top, width, height])
let centerY = this.viewport.transformY(0, [left, top, width, height])
for (let j = 0; j < points.length / 2; j++) {
const x = points[j * 2];
const y = points[j * 2 + 1];
context.strokeStyle = rangeData.color || "#FF0000"
context.beginPath()
context.moveTo(x, y)
context.lineTo(x , centerY)
context.stroke()
}
}
...
}
}
最后的效果

收工
来源:https://www.cnblogs.com/cuifeipeng/p/11156384.html