SliderZoomView.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import { __extends } from "tslib";
  41. import { bind, each, isFunction, isString, indexOf } from 'zrender/lib/core/util';
  42. import * as eventTool from 'zrender/lib/core/event';
  43. import * as graphic from '../../util/graphic';
  44. import * as throttle from '../../util/throttle';
  45. import DataZoomView from './DataZoomView';
  46. import { linearMap, asc, parsePercent } from '../../util/number';
  47. import * as layout from '../../util/layout';
  48. import sliderMove from '../helper/sliderMove';
  49. import { getAxisMainType, collectReferCoordSysModelInfo } from './helper';
  50. import { enableHoverEmphasis } from '../../util/states';
  51. import { createSymbol, symbolBuildProxies } from '../../util/symbol';
  52. import { deprecateLog } from '../../util/log';
  53. import { createTextStyle } from '../../label/labelStyle';
  54. var Rect = graphic.Rect; // Constants
  55. var DEFAULT_LOCATION_EDGE_GAP = 7;
  56. var DEFAULT_FRAME_BORDER_WIDTH = 1;
  57. var DEFAULT_FILLER_SIZE = 30;
  58. var DEFAULT_MOVE_HANDLE_SIZE = 7;
  59. var HORIZONTAL = 'horizontal';
  60. var VERTICAL = 'vertical';
  61. var LABEL_GAP = 5;
  62. var SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];
  63. var REALTIME_ANIMATION_CONFIG = {
  64. easing: 'cubicOut',
  65. duration: 100,
  66. delay: 0
  67. };
  68. var SliderZoomView =
  69. /** @class */
  70. function (_super) {
  71. __extends(SliderZoomView, _super);
  72. function SliderZoomView() {
  73. var _this = _super !== null && _super.apply(this, arguments) || this;
  74. _this.type = SliderZoomView.type;
  75. _this._displayables = {};
  76. return _this;
  77. }
  78. SliderZoomView.prototype.init = function (ecModel, api) {
  79. this.api = api; // A unique handler for each dataZoom component
  80. this._onBrush = bind(this._onBrush, this);
  81. this._onBrushEnd = bind(this._onBrushEnd, this);
  82. };
  83. SliderZoomView.prototype.render = function (dataZoomModel, ecModel, api, payload) {
  84. _super.prototype.render.apply(this, arguments);
  85. throttle.createOrUpdate(this, '_dispatchZoomAction', dataZoomModel.get('throttle'), 'fixRate');
  86. this._orient = dataZoomModel.getOrient();
  87. if (dataZoomModel.get('show') === false) {
  88. this.group.removeAll();
  89. return;
  90. }
  91. if (dataZoomModel.noTarget()) {
  92. this._clear();
  93. this.group.removeAll();
  94. return;
  95. } // Notice: this._resetInterval() should not be executed when payload.type
  96. // is 'dataZoom', origin this._range should be maintained, otherwise 'pan'
  97. // or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,
  98. if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {
  99. this._buildView();
  100. }
  101. this._updateView();
  102. };
  103. SliderZoomView.prototype.dispose = function () {
  104. this._clear();
  105. _super.prototype.dispose.apply(this, arguments);
  106. };
  107. SliderZoomView.prototype._clear = function () {
  108. throttle.clear(this, '_dispatchZoomAction');
  109. var zr = this.api.getZr();
  110. zr.off('mousemove', this._onBrush);
  111. zr.off('mouseup', this._onBrushEnd);
  112. };
  113. SliderZoomView.prototype._buildView = function () {
  114. var thisGroup = this.group;
  115. thisGroup.removeAll();
  116. this._brushing = false;
  117. this._displayables.brushRect = null;
  118. this._resetLocation();
  119. this._resetInterval();
  120. var barGroup = this._displayables.sliderGroup = new graphic.Group();
  121. this._renderBackground();
  122. this._renderHandle();
  123. this._renderDataShadow();
  124. thisGroup.add(barGroup);
  125. this._positionGroup();
  126. };
  127. SliderZoomView.prototype._resetLocation = function () {
  128. var dataZoomModel = this.dataZoomModel;
  129. var api = this.api;
  130. var showMoveHandle = dataZoomModel.get('brushSelect');
  131. var moveHandleSize = showMoveHandle ? DEFAULT_MOVE_HANDLE_SIZE : 0; // If some of x/y/width/height are not specified,
  132. // auto-adapt according to target grid.
  133. var coordRect = this._findCoordRect();
  134. var ecSize = {
  135. width: api.getWidth(),
  136. height: api.getHeight()
  137. }; // Default align by coordinate system rect.
  138. var positionInfo = this._orient === HORIZONTAL ? {
  139. // Why using 'right', because right should be used in vertical,
  140. // and it is better to be consistent for dealing with position param merge.
  141. right: ecSize.width - coordRect.x - coordRect.width,
  142. top: ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP - moveHandleSize,
  143. width: coordRect.width,
  144. height: DEFAULT_FILLER_SIZE
  145. } : {
  146. right: DEFAULT_LOCATION_EDGE_GAP,
  147. top: coordRect.y,
  148. width: DEFAULT_FILLER_SIZE,
  149. height: coordRect.height
  150. }; // Do not write back to option and replace value 'ph', because
  151. // the 'ph' value should be recalculated when resize.
  152. var layoutParams = layout.getLayoutParams(dataZoomModel.option); // Replace the placeholder value.
  153. each(['right', 'top', 'width', 'height'], function (name) {
  154. if (layoutParams[name] === 'ph') {
  155. layoutParams[name] = positionInfo[name];
  156. }
  157. });
  158. var layoutRect = layout.getLayoutRect(layoutParams, ecSize);
  159. this._location = {
  160. x: layoutRect.x,
  161. y: layoutRect.y
  162. };
  163. this._size = [layoutRect.width, layoutRect.height];
  164. this._orient === VERTICAL && this._size.reverse();
  165. };
  166. SliderZoomView.prototype._positionGroup = function () {
  167. var thisGroup = this.group;
  168. var location = this._location;
  169. var orient = this._orient; // Just use the first axis to determine mapping.
  170. var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();
  171. var inverse = targetAxisModel && targetAxisModel.get('inverse');
  172. var sliderGroup = this._displayables.sliderGroup;
  173. var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse; // Transform barGroup.
  174. sliderGroup.attr(orient === HORIZONTAL && !inverse ? {
  175. scaleY: otherAxisInverse ? 1 : -1,
  176. scaleX: 1
  177. } : orient === HORIZONTAL && inverse ? {
  178. scaleY: otherAxisInverse ? 1 : -1,
  179. scaleX: -1
  180. } : orient === VERTICAL && !inverse ? {
  181. scaleY: otherAxisInverse ? -1 : 1,
  182. scaleX: 1,
  183. rotation: Math.PI / 2
  184. } // Dont use Math.PI, considering shadow direction.
  185. : {
  186. scaleY: otherAxisInverse ? -1 : 1,
  187. scaleX: -1,
  188. rotation: Math.PI / 2
  189. }); // Position barGroup
  190. var rect = thisGroup.getBoundingRect([sliderGroup]);
  191. thisGroup.x = location.x - rect.x;
  192. thisGroup.y = location.y - rect.y;
  193. thisGroup.markRedraw();
  194. };
  195. SliderZoomView.prototype._getViewExtent = function () {
  196. return [0, this._size[0]];
  197. };
  198. SliderZoomView.prototype._renderBackground = function () {
  199. var dataZoomModel = this.dataZoomModel;
  200. var size = this._size;
  201. var barGroup = this._displayables.sliderGroup;
  202. var brushSelect = dataZoomModel.get('brushSelect');
  203. barGroup.add(new Rect({
  204. silent: true,
  205. shape: {
  206. x: 0,
  207. y: 0,
  208. width: size[0],
  209. height: size[1]
  210. },
  211. style: {
  212. fill: dataZoomModel.get('backgroundColor')
  213. },
  214. z2: -40
  215. })); // Click panel, over shadow, below handles.
  216. var clickPanel = new Rect({
  217. shape: {
  218. x: 0,
  219. y: 0,
  220. width: size[0],
  221. height: size[1]
  222. },
  223. style: {
  224. fill: 'transparent'
  225. },
  226. z2: 0,
  227. onclick: bind(this._onClickPanel, this)
  228. });
  229. var zr = this.api.getZr();
  230. if (brushSelect) {
  231. clickPanel.on('mousedown', this._onBrushStart, this);
  232. clickPanel.cursor = 'crosshair';
  233. zr.on('mousemove', this._onBrush);
  234. zr.on('mouseup', this._onBrushEnd);
  235. } else {
  236. zr.off('mousemove', this._onBrush);
  237. zr.off('mouseup', this._onBrushEnd);
  238. }
  239. barGroup.add(clickPanel);
  240. };
  241. SliderZoomView.prototype._renderDataShadow = function () {
  242. var info = this._dataShadowInfo = this._prepareDataShadowInfo();
  243. this._displayables.dataShadowSegs = [];
  244. if (!info) {
  245. return;
  246. }
  247. var size = this._size;
  248. var seriesModel = info.series;
  249. var data = seriesModel.getRawData();
  250. var otherDim = seriesModel.getShadowDim ? seriesModel.getShadowDim() // @see candlestick
  251. : info.otherDim;
  252. if (otherDim == null) {
  253. return;
  254. }
  255. var otherDataExtent = data.getDataExtent(otherDim); // Nice extent.
  256. var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;
  257. otherDataExtent = [otherDataExtent[0] - otherOffset, otherDataExtent[1] + otherOffset];
  258. var otherShadowExtent = [0, size[1]];
  259. var thisShadowExtent = [0, size[0]];
  260. var areaPoints = [[size[0], 0], [0, 0]];
  261. var linePoints = [];
  262. var step = thisShadowExtent[1] / (data.count() - 1);
  263. var thisCoord = 0; // Optimize for large data shadow
  264. var stride = Math.round(data.count() / size[0]);
  265. var lastIsEmpty;
  266. data.each([otherDim], function (value, index) {
  267. if (stride > 0 && index % stride) {
  268. thisCoord += step;
  269. return;
  270. } // FIXME
  271. // Should consider axis.min/axis.max when drawing dataShadow.
  272. // FIXME
  273. // 应该使用统一的空判断?还是在list里进行空判断?
  274. var isEmpty = value == null || isNaN(value) || value === ''; // See #4235.
  275. var otherCoord = isEmpty ? 0 : linearMap(value, otherDataExtent, otherShadowExtent, true); // Attempt to draw data shadow precisely when there are empty value.
  276. if (isEmpty && !lastIsEmpty && index) {
  277. areaPoints.push([areaPoints[areaPoints.length - 1][0], 0]);
  278. linePoints.push([linePoints[linePoints.length - 1][0], 0]);
  279. } else if (!isEmpty && lastIsEmpty) {
  280. areaPoints.push([thisCoord, 0]);
  281. linePoints.push([thisCoord, 0]);
  282. }
  283. areaPoints.push([thisCoord, otherCoord]);
  284. linePoints.push([thisCoord, otherCoord]);
  285. thisCoord += step;
  286. lastIsEmpty = isEmpty;
  287. });
  288. var dataZoomModel = this.dataZoomModel;
  289. function createDataShadowGroup(isSelectedArea) {
  290. var model = dataZoomModel.getModel(isSelectedArea ? 'selectedDataBackground' : 'dataBackground');
  291. var group = new graphic.Group();
  292. var polygon = new graphic.Polygon({
  293. shape: {
  294. points: areaPoints
  295. },
  296. segmentIgnoreThreshold: 1,
  297. style: model.getModel('areaStyle').getAreaStyle(),
  298. silent: true,
  299. z2: -20
  300. });
  301. var polyline = new graphic.Polyline({
  302. shape: {
  303. points: linePoints
  304. },
  305. segmentIgnoreThreshold: 1,
  306. style: model.getModel('lineStyle').getLineStyle(),
  307. silent: true,
  308. z2: -19
  309. });
  310. group.add(polygon);
  311. group.add(polyline);
  312. return group;
  313. } // let dataBackgroundModel = dataZoomModel.getModel('dataBackground');
  314. for (var i = 0; i < 3; i++) {
  315. var group = createDataShadowGroup(i === 1);
  316. this._displayables.sliderGroup.add(group);
  317. this._displayables.dataShadowSegs.push(group);
  318. }
  319. };
  320. SliderZoomView.prototype._prepareDataShadowInfo = function () {
  321. var dataZoomModel = this.dataZoomModel;
  322. var showDataShadow = dataZoomModel.get('showDataShadow');
  323. if (showDataShadow === false) {
  324. return;
  325. } // Find a representative series.
  326. var result;
  327. var ecModel = this.ecModel;
  328. dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
  329. var seriesModels = dataZoomModel.getAxisProxy(axisDim, axisIndex).getTargetSeriesModels();
  330. each(seriesModels, function (seriesModel) {
  331. if (result) {
  332. return;
  333. }
  334. if (showDataShadow !== true && indexOf(SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')) < 0) {
  335. return;
  336. }
  337. var thisAxis = ecModel.getComponent(getAxisMainType(axisDim), axisIndex).axis;
  338. var otherDim = getOtherDim(axisDim);
  339. var otherAxisInverse;
  340. var coordSys = seriesModel.coordinateSystem;
  341. if (otherDim != null && coordSys.getOtherAxis) {
  342. otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;
  343. }
  344. otherDim = seriesModel.getData().mapDimension(otherDim);
  345. result = {
  346. thisAxis: thisAxis,
  347. series: seriesModel,
  348. thisDim: axisDim,
  349. otherDim: otherDim,
  350. otherAxisInverse: otherAxisInverse
  351. };
  352. }, this);
  353. }, this);
  354. return result;
  355. };
  356. SliderZoomView.prototype._renderHandle = function () {
  357. var thisGroup = this.group;
  358. var displayables = this._displayables;
  359. var handles = displayables.handles = [null, null];
  360. var handleLabels = displayables.handleLabels = [null, null];
  361. var sliderGroup = this._displayables.sliderGroup;
  362. var size = this._size;
  363. var dataZoomModel = this.dataZoomModel;
  364. var api = this.api;
  365. var borderRadius = dataZoomModel.get('borderRadius') || 0;
  366. var brushSelect = dataZoomModel.get('brushSelect');
  367. var filler = displayables.filler = new Rect({
  368. silent: brushSelect,
  369. style: {
  370. fill: dataZoomModel.get('fillerColor')
  371. },
  372. textConfig: {
  373. position: 'inside'
  374. }
  375. });
  376. sliderGroup.add(filler); // Frame border.
  377. sliderGroup.add(new Rect({
  378. silent: true,
  379. subPixelOptimize: true,
  380. shape: {
  381. x: 0,
  382. y: 0,
  383. width: size[0],
  384. height: size[1],
  385. r: borderRadius
  386. },
  387. style: {
  388. stroke: dataZoomModel.get('dataBackgroundColor') // deprecated option
  389. || dataZoomModel.get('borderColor'),
  390. lineWidth: DEFAULT_FRAME_BORDER_WIDTH,
  391. fill: 'rgba(0,0,0,0)'
  392. }
  393. })); // Left and right handle to resize
  394. each([0, 1], function (handleIndex) {
  395. var iconStr = dataZoomModel.get('handleIcon');
  396. if (!symbolBuildProxies[iconStr] && iconStr.indexOf('path://') < 0 && iconStr.indexOf('image://') < 0) {
  397. // Compatitable with the old icon parsers. Which can use a path string without path://
  398. iconStr = 'path://' + iconStr;
  399. if (process.env.NODE_ENV !== 'production') {
  400. deprecateLog('handleIcon now needs \'path://\' prefix when using a path string');
  401. }
  402. }
  403. var path = createSymbol(iconStr, -1, 0, 2, 2, null, true);
  404. path.attr({
  405. cursor: getCursor(this._orient),
  406. draggable: true,
  407. drift: bind(this._onDragMove, this, handleIndex),
  408. ondragend: bind(this._onDragEnd, this),
  409. onmouseover: bind(this._showDataInfo, this, true),
  410. onmouseout: bind(this._showDataInfo, this, false),
  411. z2: 5
  412. });
  413. var bRect = path.getBoundingRect();
  414. var handleSize = dataZoomModel.get('handleSize');
  415. this._handleHeight = parsePercent(handleSize, this._size[1]);
  416. this._handleWidth = bRect.width / bRect.height * this._handleHeight;
  417. path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());
  418. path.style.strokeNoScale = true;
  419. path.rectHover = true;
  420. path.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'handleStyle']).getItemStyle();
  421. enableHoverEmphasis(path);
  422. var handleColor = dataZoomModel.get('handleColor'); // deprecated option
  423. // Compatitable with previous version
  424. if (handleColor != null) {
  425. path.style.fill = handleColor;
  426. }
  427. sliderGroup.add(handles[handleIndex] = path);
  428. var textStyleModel = dataZoomModel.getModel('textStyle');
  429. thisGroup.add(handleLabels[handleIndex] = new graphic.Text({
  430. silent: true,
  431. invisible: true,
  432. style: createTextStyle(textStyleModel, {
  433. x: 0,
  434. y: 0,
  435. text: '',
  436. verticalAlign: 'middle',
  437. align: 'center',
  438. fill: textStyleModel.getTextColor(),
  439. font: textStyleModel.getFont()
  440. }),
  441. z2: 10
  442. }));
  443. }, this); // Handle to move. Only visible when brushSelect is set true.
  444. var actualMoveZone = filler;
  445. if (brushSelect) {
  446. var moveHandleHeight = parsePercent(dataZoomModel.get('moveHandleSize'), size[1]);
  447. var moveHandle_1 = displayables.moveHandle = new graphic.Rect({
  448. style: dataZoomModel.getModel('moveHandleStyle').getItemStyle(),
  449. silent: true,
  450. shape: {
  451. r: [0, 0, 2, 2],
  452. y: size[1] - 0.5,
  453. height: moveHandleHeight
  454. }
  455. });
  456. var iconSize = moveHandleHeight * 0.8;
  457. var moveHandleIcon = displayables.moveHandleIcon = createSymbol(dataZoomModel.get('moveHandleIcon'), -iconSize / 2, -iconSize / 2, iconSize, iconSize, '#fff', true);
  458. moveHandleIcon.silent = true;
  459. moveHandleIcon.y = size[1] + moveHandleHeight / 2 - 0.5;
  460. moveHandle_1.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'moveHandleStyle']).getItemStyle();
  461. var moveZoneExpandSize = Math.min(size[1] / 2, Math.max(moveHandleHeight, 10));
  462. actualMoveZone = displayables.moveZone = new graphic.Rect({
  463. invisible: true,
  464. shape: {
  465. y: size[1] - moveZoneExpandSize,
  466. height: moveHandleHeight + moveZoneExpandSize
  467. }
  468. });
  469. actualMoveZone.on('mouseover', function () {
  470. api.enterEmphasis(moveHandle_1);
  471. }).on('mouseout', function () {
  472. api.leaveEmphasis(moveHandle_1);
  473. });
  474. sliderGroup.add(moveHandle_1);
  475. sliderGroup.add(moveHandleIcon);
  476. sliderGroup.add(actualMoveZone);
  477. }
  478. actualMoveZone.attr({
  479. draggable: true,
  480. cursor: getCursor(this._orient),
  481. drift: bind(this._onDragMove, this, 'all'),
  482. ondragstart: bind(this._showDataInfo, this, true),
  483. ondragend: bind(this._onDragEnd, this),
  484. onmouseover: bind(this._showDataInfo, this, true),
  485. onmouseout: bind(this._showDataInfo, this, false)
  486. });
  487. };
  488. SliderZoomView.prototype._resetInterval = function () {
  489. var range = this._range = this.dataZoomModel.getPercentRange();
  490. var viewExtent = this._getViewExtent();
  491. this._handleEnds = [linearMap(range[0], [0, 100], viewExtent, true), linearMap(range[1], [0, 100], viewExtent, true)];
  492. };
  493. SliderZoomView.prototype._updateInterval = function (handleIndex, delta) {
  494. var dataZoomModel = this.dataZoomModel;
  495. var handleEnds = this._handleEnds;
  496. var viewExtend = this._getViewExtent();
  497. var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();
  498. var percentExtent = [0, 100];
  499. sliderMove(delta, handleEnds, viewExtend, dataZoomModel.get('zoomLock') ? 'all' : handleIndex, minMaxSpan.minSpan != null ? linearMap(minMaxSpan.minSpan, percentExtent, viewExtend, true) : null, minMaxSpan.maxSpan != null ? linearMap(minMaxSpan.maxSpan, percentExtent, viewExtend, true) : null);
  500. var lastRange = this._range;
  501. var range = this._range = asc([linearMap(handleEnds[0], viewExtend, percentExtent, true), linearMap(handleEnds[1], viewExtend, percentExtent, true)]);
  502. return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];
  503. };
  504. SliderZoomView.prototype._updateView = function (nonRealtime) {
  505. var displaybles = this._displayables;
  506. var handleEnds = this._handleEnds;
  507. var handleInterval = asc(handleEnds.slice());
  508. var size = this._size;
  509. each([0, 1], function (handleIndex) {
  510. // Handles
  511. var handle = displaybles.handles[handleIndex];
  512. var handleHeight = this._handleHeight;
  513. handle.attr({
  514. scaleX: handleHeight / 2,
  515. scaleY: handleHeight / 2,
  516. // This is a trick, by adding an extra tiny offset to let the default handle's end point align to the drag window.
  517. // NOTE: It may affect some custom shapes a bit. But we prefer to have better result by default.
  518. x: handleEnds[handleIndex] + (handleIndex ? -1 : 1),
  519. y: size[1] / 2 - handleHeight / 2
  520. });
  521. }, this); // Filler
  522. displaybles.filler.setShape({
  523. x: handleInterval[0],
  524. y: 0,
  525. width: handleInterval[1] - handleInterval[0],
  526. height: size[1]
  527. });
  528. var viewExtent = {
  529. x: handleInterval[0],
  530. width: handleInterval[1] - handleInterval[0]
  531. }; // Move handle
  532. if (displaybles.moveHandle) {
  533. displaybles.moveHandle.setShape(viewExtent);
  534. displaybles.moveZone.setShape(viewExtent); // Force update path on the invisible object
  535. displaybles.moveZone.getBoundingRect();
  536. displaybles.moveHandleIcon && displaybles.moveHandleIcon.attr('x', viewExtent.x + viewExtent.width / 2);
  537. } // update clip path of shadow.
  538. var dataShadowSegs = displaybles.dataShadowSegs;
  539. var segIntervals = [0, handleInterval[0], handleInterval[1], size[0]];
  540. for (var i = 0; i < dataShadowSegs.length; i++) {
  541. var segGroup = dataShadowSegs[i];
  542. var clipPath = segGroup.getClipPath();
  543. if (!clipPath) {
  544. clipPath = new graphic.Rect();
  545. segGroup.setClipPath(clipPath);
  546. }
  547. clipPath.setShape({
  548. x: segIntervals[i],
  549. y: 0,
  550. width: segIntervals[i + 1] - segIntervals[i],
  551. height: size[1]
  552. });
  553. }
  554. this._updateDataInfo(nonRealtime);
  555. };
  556. SliderZoomView.prototype._updateDataInfo = function (nonRealtime) {
  557. var dataZoomModel = this.dataZoomModel;
  558. var displaybles = this._displayables;
  559. var handleLabels = displaybles.handleLabels;
  560. var orient = this._orient;
  561. var labelTexts = ['', '']; // FIXME
  562. // date型,支持formatter,autoformatter(ec2 date.getAutoFormatter)
  563. if (dataZoomModel.get('showDetail')) {
  564. var axisProxy = dataZoomModel.findRepresentativeAxisProxy();
  565. if (axisProxy) {
  566. var axis = axisProxy.getAxisModel().axis;
  567. var range = this._range;
  568. var dataInterval = nonRealtime // See #4434, data and axis are not processed and reset yet in non-realtime mode.
  569. ? axisProxy.calculateDataWindow({
  570. start: range[0],
  571. end: range[1]
  572. }).valueWindow : axisProxy.getDataValueWindow();
  573. labelTexts = [this._formatLabel(dataInterval[0], axis), this._formatLabel(dataInterval[1], axis)];
  574. }
  575. }
  576. var orderedHandleEnds = asc(this._handleEnds.slice());
  577. setLabel.call(this, 0);
  578. setLabel.call(this, 1);
  579. function setLabel(handleIndex) {
  580. // Label
  581. // Text should not transform by barGroup.
  582. // Ignore handlers transform
  583. var barTransform = graphic.getTransform(displaybles.handles[handleIndex].parent, this.group);
  584. var direction = graphic.transformDirection(handleIndex === 0 ? 'right' : 'left', barTransform);
  585. var offset = this._handleWidth / 2 + LABEL_GAP;
  586. var textPoint = graphic.applyTransform([orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset), this._size[1] / 2], barTransform);
  587. handleLabels[handleIndex].setStyle({
  588. x: textPoint[0],
  589. y: textPoint[1],
  590. verticalAlign: orient === HORIZONTAL ? 'middle' : direction,
  591. align: orient === HORIZONTAL ? direction : 'center',
  592. text: labelTexts[handleIndex]
  593. });
  594. }
  595. };
  596. SliderZoomView.prototype._formatLabel = function (value, axis) {
  597. var dataZoomModel = this.dataZoomModel;
  598. var labelFormatter = dataZoomModel.get('labelFormatter');
  599. var labelPrecision = dataZoomModel.get('labelPrecision');
  600. if (labelPrecision == null || labelPrecision === 'auto') {
  601. labelPrecision = axis.getPixelPrecision();
  602. }
  603. var valueStr = value == null || isNaN(value) ? '' // FIXME Glue code
  604. : axis.type === 'category' || axis.type === 'time' ? axis.scale.getLabel({
  605. value: Math.round(value)
  606. }) // param of toFixed should less then 20.
  607. : value.toFixed(Math.min(labelPrecision, 20));
  608. return isFunction(labelFormatter) ? labelFormatter(value, valueStr) : isString(labelFormatter) ? labelFormatter.replace('{value}', valueStr) : valueStr;
  609. };
  610. /**
  611. * @param showOrHide true: show, false: hide
  612. */
  613. SliderZoomView.prototype._showDataInfo = function (showOrHide) {
  614. // Always show when drgging.
  615. showOrHide = this._dragging || showOrHide;
  616. var displayables = this._displayables;
  617. var handleLabels = displayables.handleLabels;
  618. handleLabels[0].attr('invisible', !showOrHide);
  619. handleLabels[1].attr('invisible', !showOrHide); // Highlight move handle
  620. displayables.moveHandle && this.api[showOrHide ? 'enterEmphasis' : 'leaveEmphasis'](displayables.moveHandle, 1);
  621. };
  622. SliderZoomView.prototype._onDragMove = function (handleIndex, dx, dy, event) {
  623. this._dragging = true; // For mobile device, prevent screen slider on the button.
  624. eventTool.stop(event.event); // Transform dx, dy to bar coordination.
  625. var barTransform = this._displayables.sliderGroup.getLocalTransform();
  626. var vertex = graphic.applyTransform([dx, dy], barTransform, true);
  627. var changed = this._updateInterval(handleIndex, vertex[0]);
  628. var realtime = this.dataZoomModel.get('realtime');
  629. this._updateView(!realtime); // Avoid dispatch dataZoom repeatly but range not changed,
  630. // which cause bad visual effect when progressive enabled.
  631. changed && realtime && this._dispatchZoomAction(true);
  632. };
  633. SliderZoomView.prototype._onDragEnd = function () {
  634. this._dragging = false;
  635. this._showDataInfo(false); // While in realtime mode and stream mode, dispatch action when
  636. // drag end will cause the whole view rerender, which is unnecessary.
  637. var realtime = this.dataZoomModel.get('realtime');
  638. !realtime && this._dispatchZoomAction(false);
  639. };
  640. SliderZoomView.prototype._onClickPanel = function (e) {
  641. var size = this._size;
  642. var localPoint = this._displayables.sliderGroup.transformCoordToLocal(e.offsetX, e.offsetY);
  643. if (localPoint[0] < 0 || localPoint[0] > size[0] || localPoint[1] < 0 || localPoint[1] > size[1]) {
  644. return;
  645. }
  646. var handleEnds = this._handleEnds;
  647. var center = (handleEnds[0] + handleEnds[1]) / 2;
  648. var changed = this._updateInterval('all', localPoint[0] - center);
  649. this._updateView();
  650. changed && this._dispatchZoomAction(false);
  651. };
  652. SliderZoomView.prototype._onBrushStart = function (e) {
  653. var x = e.offsetX;
  654. var y = e.offsetY;
  655. this._brushStart = new graphic.Point(x, y);
  656. this._brushing = true;
  657. this._brushStartTime = +new Date(); // this._updateBrushRect(x, y);
  658. };
  659. SliderZoomView.prototype._onBrushEnd = function (e) {
  660. if (!this._brushing) {
  661. return;
  662. }
  663. var brushRect = this._displayables.brushRect;
  664. this._brushing = false;
  665. if (!brushRect) {
  666. return;
  667. }
  668. brushRect.attr('ignore', true);
  669. var brushShape = brushRect.shape;
  670. var brushEndTime = +new Date(); // console.log(brushEndTime - this._brushStartTime);
  671. if (brushEndTime - this._brushStartTime < 200 && Math.abs(brushShape.width) < 5) {
  672. // Will treat it as a click
  673. return;
  674. }
  675. var viewExtend = this._getViewExtent();
  676. var percentExtent = [0, 100];
  677. this._range = asc([linearMap(brushShape.x, viewExtend, percentExtent, true), linearMap(brushShape.x + brushShape.width, viewExtend, percentExtent, true)]);
  678. this._handleEnds = [brushShape.x, brushShape.x + brushShape.width];
  679. this._updateView();
  680. this._dispatchZoomAction(false);
  681. };
  682. SliderZoomView.prototype._onBrush = function (e) {
  683. if (this._brushing) {
  684. // For mobile device, prevent screen slider on the button.
  685. eventTool.stop(e.event);
  686. this._updateBrushRect(e.offsetX, e.offsetY);
  687. }
  688. };
  689. SliderZoomView.prototype._updateBrushRect = function (mouseX, mouseY) {
  690. var displayables = this._displayables;
  691. var dataZoomModel = this.dataZoomModel;
  692. var brushRect = displayables.brushRect;
  693. if (!brushRect) {
  694. brushRect = displayables.brushRect = new Rect({
  695. silent: true,
  696. style: dataZoomModel.getModel('brushStyle').getItemStyle()
  697. });
  698. displayables.sliderGroup.add(brushRect);
  699. }
  700. brushRect.attr('ignore', false);
  701. var brushStart = this._brushStart;
  702. var sliderGroup = this._displayables.sliderGroup;
  703. var endPoint = sliderGroup.transformCoordToLocal(mouseX, mouseY);
  704. var startPoint = sliderGroup.transformCoordToLocal(brushStart.x, brushStart.y);
  705. var size = this._size;
  706. endPoint[0] = Math.max(Math.min(size[0], endPoint[0]), 0);
  707. brushRect.setShape({
  708. x: startPoint[0],
  709. y: 0,
  710. width: endPoint[0] - startPoint[0],
  711. height: size[1]
  712. });
  713. };
  714. /**
  715. * This action will be throttled.
  716. */
  717. SliderZoomView.prototype._dispatchZoomAction = function (realtime) {
  718. var range = this._range;
  719. this.api.dispatchAction({
  720. type: 'dataZoom',
  721. from: this.uid,
  722. dataZoomId: this.dataZoomModel.id,
  723. animation: realtime ? REALTIME_ANIMATION_CONFIG : null,
  724. start: range[0],
  725. end: range[1]
  726. });
  727. };
  728. SliderZoomView.prototype._findCoordRect = function () {
  729. // Find the grid coresponding to the first axis referred by dataZoom.
  730. var rect;
  731. var coordSysInfoList = collectReferCoordSysModelInfo(this.dataZoomModel).infoList;
  732. if (!rect && coordSysInfoList.length) {
  733. var coordSys = coordSysInfoList[0].model.coordinateSystem;
  734. rect = coordSys.getRect && coordSys.getRect();
  735. }
  736. if (!rect) {
  737. var width = this.api.getWidth();
  738. var height = this.api.getHeight();
  739. rect = {
  740. x: width * 0.2,
  741. y: height * 0.2,
  742. width: width * 0.6,
  743. height: height * 0.6
  744. };
  745. }
  746. return rect;
  747. };
  748. SliderZoomView.type = 'dataZoom.slider';
  749. return SliderZoomView;
  750. }(DataZoomView);
  751. function getOtherDim(thisDim) {
  752. // FIXME
  753. // 这个逻辑和getOtherAxis里一致,但是写在这里是否不好
  754. var map = {
  755. x: 'y',
  756. y: 'x',
  757. radius: 'angle',
  758. angle: 'radius'
  759. };
  760. return map[thisDim];
  761. }
  762. function getCursor(orient) {
  763. return orient === 'vertical' ? 'ns-resize' : 'ew-resize';
  764. }
  765. export default SliderZoomView;