Spaces:
Running
Running
| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one | |
| * or more contributor license agreements. See the NOTICE file | |
| * distributed with this work for additional information | |
| * regarding copyright ownership. The ASF licenses this file | |
| * to you under the Apache License, Version 2.0 (the | |
| * "License"); you may not use this file except in compliance | |
| * with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, | |
| * software distributed under the License is distributed on an | |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the | |
| * specific language governing permissions and limitations | |
| * under the License. | |
| */ | |
| import DataZoomView from './DataZoomView'; | |
| import sliderMove from '../helper/sliderMove'; | |
| import * as roams from './roams'; | |
| import InsideZoomModel from './InsideZoomModel'; | |
| import GlobalModel from '../../model/Global'; | |
| import ExtensionAPI from '../../core/ExtensionAPI'; | |
| import { bind } from 'zrender/src/core/util'; | |
| import RoamController, {RoamEventParams} from '../helper/RoamController'; | |
| import { AxisBaseModel } from '../../coord/AxisBaseModel'; | |
| import Polar from '../../coord/polar/Polar'; | |
| import SingleAxis from '../../coord/single/SingleAxis'; | |
| import { DataZoomCoordSysMainType, DataZoomReferCoordSysInfo } from './helper'; | |
| class InsideZoomView extends DataZoomView { | |
| static type = 'dataZoom.inside'; | |
| type = 'dataZoom.inside'; | |
| /** | |
| * 'throttle' is used in this.dispatchAction, so we save range | |
| * to avoid missing some 'pan' info. | |
| */ | |
| range: number[]; | |
| render(dataZoomModel: InsideZoomModel, ecModel: GlobalModel, api: ExtensionAPI) { | |
| super.render.apply(this, arguments as any); | |
| if (dataZoomModel.noTarget()) { | |
| this._clear(); | |
| return; | |
| } | |
| // Hence the `throttle` util ensures to preserve command order, | |
| // here simply updating range all the time will not cause missing | |
| // any of the the roam change. | |
| this.range = dataZoomModel.getPercentRange(); | |
| // Reset controllers. | |
| roams.setViewInfoToCoordSysRecord( | |
| api, | |
| dataZoomModel, | |
| { | |
| pan: bind(getRangeHandlers.pan, this), | |
| zoom: bind(getRangeHandlers.zoom, this), | |
| scrollMove: bind(getRangeHandlers.scrollMove, this) | |
| } | |
| ); | |
| } | |
| dispose() { | |
| this._clear(); | |
| super.dispose.apply(this, arguments as any); | |
| } | |
| private _clear() { | |
| roams.disposeCoordSysRecordIfNeeded(this.api, this.dataZoomModel as InsideZoomModel); | |
| this.range = null; | |
| } | |
| } | |
| interface DataZoomGetRangeHandler< | |
| T extends RoamEventParams['zoom'] | RoamEventParams['scrollMove'] | RoamEventParams['pan'] | |
| > { | |
| ( | |
| coordSysInfo: DataZoomReferCoordSysInfo, | |
| coordSysMainType: DataZoomCoordSysMainType, | |
| controller: RoamController, | |
| e: T | |
| ): [number, number] | |
| } | |
| const getRangeHandlers: { | |
| pan: DataZoomGetRangeHandler<RoamEventParams['pan']> | |
| zoom: DataZoomGetRangeHandler<RoamEventParams['zoom']> | |
| scrollMove: DataZoomGetRangeHandler<RoamEventParams['scrollMove']> | |
| } & ThisType<InsideZoomView> = { | |
| zoom(coordSysInfo, coordSysMainType, controller, e: RoamEventParams['zoom']) { | |
| const lastRange = this.range; | |
| const range = lastRange.slice() as [number, number]; | |
| // Calculate transform by the first axis. | |
| const axisModel = coordSysInfo.axisModels[0]; | |
| if (!axisModel) { | |
| return; | |
| } | |
| const directionInfo = getDirectionInfo[coordSysMainType]( | |
| null, [e.originX, e.originY], axisModel, controller, coordSysInfo | |
| ); | |
| const percentPoint = ( | |
| directionInfo.signal > 0 | |
| ? (directionInfo.pixelStart + directionInfo.pixelLength - directionInfo.pixel) | |
| : (directionInfo.pixel - directionInfo.pixelStart) | |
| ) / directionInfo.pixelLength * (range[1] - range[0]) + range[0]; | |
| const scale = Math.max(1 / e.scale, 0); | |
| range[0] = (range[0] - percentPoint) * scale + percentPoint; | |
| range[1] = (range[1] - percentPoint) * scale + percentPoint; | |
| // Restrict range. | |
| const minMaxSpan = this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan(); | |
| sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan); | |
| this.range = range; | |
| if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) { | |
| return range; | |
| } | |
| }, | |
| pan: makeMover(function (range, axisModel, coordSysInfo, coordSysMainType, controller, e: RoamEventParams['pan']) { | |
| const directionInfo = getDirectionInfo[coordSysMainType]( | |
| [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordSysInfo | |
| ); | |
| return directionInfo.signal | |
| * (range[1] - range[0]) | |
| * directionInfo.pixel / directionInfo.pixelLength; | |
| }), | |
| scrollMove: makeMover( | |
| function (range, axisModel, coordSysInfo, coordSysMainType, controller, e: RoamEventParams['scrollMove'] | |
| ) { | |
| const directionInfo = getDirectionInfo[coordSysMainType]( | |
| [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordSysInfo | |
| ); | |
| return directionInfo.signal * (range[1] - range[0]) * e.scrollDelta; | |
| }) | |
| }; | |
| export type DataZoomGetRangeHandlers = typeof getRangeHandlers; | |
| function makeMover( | |
| getPercentDelta: ( | |
| range: [number, number], | |
| axisModel: AxisBaseModel, | |
| coordSysInfo: DataZoomReferCoordSysInfo, | |
| coordSysMainType: DataZoomCoordSysMainType, | |
| controller: RoamController, | |
| e: RoamEventParams['scrollMove']| RoamEventParams['pan'] | |
| ) => number | |
| ) { | |
| return function ( | |
| this: InsideZoomView, | |
| coordSysInfo: DataZoomReferCoordSysInfo, | |
| coordSysMainType: DataZoomCoordSysMainType, | |
| controller: RoamController, | |
| e: RoamEventParams['scrollMove']| RoamEventParams['pan'] | |
| ): [number, number] { | |
| const lastRange = this.range; | |
| const range = lastRange.slice() as [number, number]; | |
| // Calculate transform by the first axis. | |
| const axisModel = coordSysInfo.axisModels[0]; | |
| if (!axisModel) { | |
| return; | |
| } | |
| const percentDelta = getPercentDelta( | |
| range, axisModel, coordSysInfo, coordSysMainType, controller, e | |
| ); | |
| sliderMove(percentDelta, range, [0, 100], 'all'); | |
| this.range = range; | |
| if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) { | |
| return range; | |
| } | |
| }; | |
| } | |
| interface DirectionInfo { | |
| pixel: number | |
| pixelLength: number | |
| pixelStart: number | |
| signal: -1 | 1 | |
| } | |
| interface GetDirectionInfo { | |
| ( | |
| oldPoint: number[], | |
| newPoint: number[], | |
| axisModel: AxisBaseModel, | |
| controller: RoamController, | |
| coordSysInfo: DataZoomReferCoordSysInfo | |
| ): DirectionInfo | |
| } | |
| const getDirectionInfo: Record<'grid' | 'polar' | 'singleAxis', GetDirectionInfo> = { | |
| grid(oldPoint, newPoint, axisModel, controller, coordSysInfo) { | |
| const axis = axisModel.axis; | |
| const ret = {} as DirectionInfo; | |
| const rect = coordSysInfo.model.coordinateSystem.getRect(); | |
| oldPoint = oldPoint || [0, 0]; | |
| if (axis.dim === 'x') { | |
| ret.pixel = newPoint[0] - oldPoint[0]; | |
| ret.pixelLength = rect.width; | |
| ret.pixelStart = rect.x; | |
| ret.signal = axis.inverse ? 1 : -1; | |
| } | |
| else { // axis.dim === 'y' | |
| ret.pixel = newPoint[1] - oldPoint[1]; | |
| ret.pixelLength = rect.height; | |
| ret.pixelStart = rect.y; | |
| ret.signal = axis.inverse ? -1 : 1; | |
| } | |
| return ret; | |
| }, | |
| polar(oldPoint, newPoint, axisModel, controller, coordSysInfo) { | |
| const axis = axisModel.axis; | |
| const ret = {} as DirectionInfo; | |
| const polar = coordSysInfo.model.coordinateSystem as Polar; | |
| const radiusExtent = polar.getRadiusAxis().getExtent(); | |
| const angleExtent = polar.getAngleAxis().getExtent(); | |
| oldPoint = oldPoint ? polar.pointToCoord(oldPoint) : [0, 0]; | |
| newPoint = polar.pointToCoord(newPoint); | |
| if (axisModel.mainType === 'radiusAxis') { | |
| ret.pixel = newPoint[0] - oldPoint[0]; | |
| // ret.pixelLength = Math.abs(radiusExtent[1] - radiusExtent[0]); | |
| // ret.pixelStart = Math.min(radiusExtent[0], radiusExtent[1]); | |
| ret.pixelLength = radiusExtent[1] - radiusExtent[0]; | |
| ret.pixelStart = radiusExtent[0]; | |
| ret.signal = axis.inverse ? 1 : -1; | |
| } | |
| else { // 'angleAxis' | |
| ret.pixel = newPoint[1] - oldPoint[1]; | |
| // ret.pixelLength = Math.abs(angleExtent[1] - angleExtent[0]); | |
| // ret.pixelStart = Math.min(angleExtent[0], angleExtent[1]); | |
| ret.pixelLength = angleExtent[1] - angleExtent[0]; | |
| ret.pixelStart = angleExtent[0]; | |
| ret.signal = axis.inverse ? -1 : 1; | |
| } | |
| return ret; | |
| }, | |
| singleAxis(oldPoint, newPoint, axisModel, controller, coordSysInfo) { | |
| const axis = axisModel.axis as SingleAxis; | |
| const rect = coordSysInfo.model.coordinateSystem.getRect(); | |
| const ret = {} as DirectionInfo; | |
| oldPoint = oldPoint || [0, 0]; | |
| if (axis.orient === 'horizontal') { | |
| ret.pixel = newPoint[0] - oldPoint[0]; | |
| ret.pixelLength = rect.width; | |
| ret.pixelStart = rect.x; | |
| ret.signal = axis.inverse ? 1 : -1; | |
| } | |
| else { // 'vertical' | |
| ret.pixel = newPoint[1] - oldPoint[1]; | |
| ret.pixelLength = rect.height; | |
| ret.pixelStart = rect.y; | |
| ret.signal = axis.inverse ? -1 : 1; | |
| } | |
| return ret; | |
| } | |
| }; | |
| export default InsideZoomView; | |