SliderZoomView.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  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.js';
  42. import * as eventTool from 'zrender/lib/core/event.js';
  43. import * as graphic from '../../util/graphic.js';
  44. import * as throttle from '../../util/throttle.js';
  45. import DataZoomView from './DataZoomView.js';
  46. import { linearMap, asc, parsePercent } from '../../util/number.js';
  47. import * as layout from '../../util/layout.js';
  48. import sliderMove from '../helper/sliderMove.js';
  49. import { getAxisMainType, collectReferCoordSysModelInfo } from './helper.js';
  50. import { enableHoverEmphasis } from '../../util/states.js';
  51. import { createSymbol, symbolBuildProxies } from '../../util/symbol.js';
  52. import { deprecateLog } from '../../util/log.js';
  53. import { createTextStyle } from '../../label/labelStyle.js';
  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 oldSize = this._shadowSize || [];
  249. var seriesModel = info.series;
  250. var data = seriesModel.getRawData();
  251. var otherDim = seriesModel.getShadowDim ? seriesModel.getShadowDim() // @see candlestick
  252. : info.otherDim;
  253. if (otherDim == null) {
  254. return;
  255. }
  256. var polygonPts = this._shadowPolygonPts;
  257. var polylinePts = this._shadowPolylinePts; // Not re-render if data doesn't change.
  258. if (data !== this._shadowData || otherDim !== this._shadowDim || size[0] !== oldSize[0] || size[1] !== oldSize[1]) {
  259. var otherDataExtent_1 = data.getDataExtent(otherDim); // Nice extent.
  260. var otherOffset = (otherDataExtent_1[1] - otherDataExtent_1[0]) * 0.3;
  261. otherDataExtent_1 = [otherDataExtent_1[0] - otherOffset, otherDataExtent_1[1] + otherOffset];
  262. var otherShadowExtent_1 = [0, size[1]];
  263. var thisShadowExtent = [0, size[0]];
  264. var areaPoints_1 = [[size[0], 0], [0, 0]];
  265. var linePoints_1 = [];
  266. var step_1 = thisShadowExtent[1] / (data.count() - 1);
  267. var thisCoord_1 = 0; // Optimize for large data shadow
  268. var stride_1 = Math.round(data.count() / size[0]);
  269. var lastIsEmpty_1;
  270. data.each([otherDim], function (value, index) {
  271. if (stride_1 > 0 && index % stride_1) {
  272. thisCoord_1 += step_1;
  273. return;
  274. } // FIXME
  275. // Should consider axis.min/axis.max when drawing dataShadow.
  276. // FIXME
  277. // 应该使用统一的空判断?还是在list里进行空判断?
  278. var isEmpty = value == null || isNaN(value) || value === ''; // See #4235.
  279. var otherCoord = isEmpty ? 0 : linearMap(value, otherDataExtent_1, otherShadowExtent_1, true); // Attempt to draw data shadow precisely when there are empty value.
  280. if (isEmpty && !lastIsEmpty_1 && index) {
  281. areaPoints_1.push([areaPoints_1[areaPoints_1.length - 1][0], 0]);
  282. linePoints_1.push([linePoints_1[linePoints_1.length - 1][0], 0]);
  283. } else if (!isEmpty && lastIsEmpty_1) {
  284. areaPoints_1.push([thisCoord_1, 0]);
  285. linePoints_1.push([thisCoord_1, 0]);
  286. }
  287. areaPoints_1.push([thisCoord_1, otherCoord]);
  288. linePoints_1.push([thisCoord_1, otherCoord]);
  289. thisCoord_1 += step_1;
  290. lastIsEmpty_1 = isEmpty;
  291. });
  292. polygonPts = this._shadowPolygonPts = areaPoints_1;
  293. polylinePts = this._shadowPolylinePts = linePoints_1;
  294. }
  295. this._shadowData = data;
  296. this._shadowDim = otherDim;
  297. this._shadowSize = [size[0], size[1]];
  298. var dataZoomModel = this.dataZoomModel;
  299. function createDataShadowGroup(isSelectedArea) {
  300. var model = dataZoomModel.getModel(isSelectedArea ? 'selectedDataBackground' : 'dataBackground');
  301. var group = new graphic.Group();
  302. var polygon = new graphic.Polygon({
  303. shape: {
  304. points: polygonPts
  305. },
  306. segmentIgnoreThreshold: 1,
  307. style: model.getModel('areaStyle').getAreaStyle(),
  308. silent: true,
  309. z2: -20
  310. });
  311. var polyline = new graphic.Polyline({
  312. shape: {
  313. points: polylinePts
  314. },
  315. segmentIgnoreThreshold: 1,
  316. style: model.getModel('lineStyle').getLineStyle(),
  317. silent: true,
  318. z2: -19
  319. });
  320. group.add(polygon);
  321. group.add(polyline);
  322. return group;
  323. } // let dataBackgroundModel = dataZoomModel.getModel('dataBackground');
  324. for (var i = 0; i < 3; i++) {
  325. var group = createDataShadowGroup(i === 1);
  326. this._displayables.sliderGroup.add(group);
  327. this._displayables.dataShadowSegs.push(group);
  328. }
  329. };
  330. SliderZoomView.prototype._prepareDataShadowInfo = function () {
  331. var dataZoomModel = this.dataZoomModel;
  332. var showDataShadow = dataZoomModel.get('showDataShadow');
  333. if (showDataShadow === false) {
  334. return;
  335. } // Find a representative series.
  336. var result;
  337. var ecModel = this.ecModel;
  338. dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
  339. var seriesModels = dataZoomModel.getAxisProxy(axisDim, axisIndex).getTargetSeriesModels();
  340. each(seriesModels, function (seriesModel) {
  341. if (result) {
  342. return;
  343. }
  344. if (showDataShadow !== true && indexOf(SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')) < 0) {
  345. return;
  346. }
  347. var thisAxis = ecModel.getComponent(getAxisMainType(axisDim), axisIndex).axis;
  348. var otherDim = getOtherDim(axisDim);
  349. var otherAxisInverse;
  350. var coordSys = seriesModel.coordinateSystem;
  351. if (otherDim != null && coordSys.getOtherAxis) {
  352. otherAxisInverse = coordSys.getOtherAxis(thisAxis).inverse;
  353. }
  354. otherDim = seriesModel.getData().mapDimension(otherDim);
  355. result = {
  356. thisAxis: thisAxis,
  357. series: seriesModel,
  358. thisDim: axisDim,
  359. otherDim: otherDim,
  360. otherAxisInverse: otherAxisInverse
  361. };
  362. }, this);
  363. }, this);
  364. return result;
  365. };
  366. SliderZoomView.prototype._renderHandle = function () {
  367. var thisGroup = this.group;
  368. var displayables = this._displayables;
  369. var handles = displayables.handles = [null, null];
  370. var handleLabels = displayables.handleLabels = [null, null];
  371. var sliderGroup = this._displayables.sliderGroup;
  372. var size = this._size;
  373. var dataZoomModel = this.dataZoomModel;
  374. var api = this.api;
  375. var borderRadius = dataZoomModel.get('borderRadius') || 0;
  376. var brushSelect = dataZoomModel.get('brushSelect');
  377. var filler = displayables.filler = new Rect({
  378. silent: brushSelect,
  379. style: {
  380. fill: dataZoomModel.get('fillerColor')
  381. },
  382. textConfig: {
  383. position: 'inside'
  384. }
  385. });
  386. sliderGroup.add(filler); // Frame border.
  387. sliderGroup.add(new Rect({
  388. silent: true,
  389. subPixelOptimize: true,
  390. shape: {
  391. x: 0,
  392. y: 0,
  393. width: size[0],
  394. height: size[1],
  395. r: borderRadius
  396. },
  397. style: {
  398. // deprecated option
  399. stroke: dataZoomModel.get('dataBackgroundColor') || dataZoomModel.get('borderColor'),
  400. lineWidth: DEFAULT_FRAME_BORDER_WIDTH,
  401. fill: 'rgba(0,0,0,0)'
  402. }
  403. })); // Left and right handle to resize
  404. each([0, 1], function (handleIndex) {
  405. var iconStr = dataZoomModel.get('handleIcon');
  406. if (!symbolBuildProxies[iconStr] && iconStr.indexOf('path://') < 0 && iconStr.indexOf('image://') < 0) {
  407. // Compatitable with the old icon parsers. Which can use a path string without path://
  408. iconStr = 'path://' + iconStr;
  409. if (process.env.NODE_ENV !== 'production') {
  410. deprecateLog('handleIcon now needs \'path://\' prefix when using a path string');
  411. }
  412. }
  413. var path = createSymbol(iconStr, -1, 0, 2, 2, null, true);
  414. path.attr({
  415. cursor: getCursor(this._orient),
  416. draggable: true,
  417. drift: bind(this._onDragMove, this, handleIndex),
  418. ondragend: bind(this._onDragEnd, this),
  419. onmouseover: bind(this._showDataInfo, this, true),
  420. onmouseout: bind(this._showDataInfo, this, false),
  421. z2: 5
  422. });
  423. var bRect = path.getBoundingRect();
  424. var handleSize = dataZoomModel.get('handleSize');
  425. this._handleHeight = parsePercent(handleSize, this._size[1]);
  426. this._handleWidth = bRect.width / bRect.height * this._handleHeight;
  427. path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());
  428. path.style.strokeNoScale = true;
  429. path.rectHover = true;
  430. path.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'handleStyle']).getItemStyle();
  431. enableHoverEmphasis(path);
  432. var handleColor = dataZoomModel.get('handleColor'); // deprecated option
  433. // Compatitable with previous version
  434. if (handleColor != null) {
  435. path.style.fill = handleColor;
  436. }
  437. sliderGroup.add(handles[handleIndex] = path);
  438. var textStyleModel = dataZoomModel.getModel('textStyle');
  439. thisGroup.add(handleLabels[handleIndex] = new graphic.Text({
  440. silent: true,
  441. invisible: true,
  442. style: createTextStyle(textStyleModel, {
  443. x: 0,
  444. y: 0,
  445. text: '',
  446. verticalAlign: 'middle',
  447. align: 'center',
  448. fill: textStyleModel.getTextColor(),
  449. font: textStyleModel.getFont()
  450. }),
  451. z2: 10
  452. }));
  453. }, this); // Handle to move. Only visible when brushSelect is set true.
  454. var actualMoveZone = filler;
  455. if (brushSelect) {
  456. var moveHandleHeight = parsePercent(dataZoomModel.get('moveHandleSize'), size[1]);
  457. var moveHandle_1 = displayables.moveHandle = new graphic.Rect({
  458. style: dataZoomModel.getModel('moveHandleStyle').getItemStyle(),
  459. silent: true,
  460. shape: {
  461. r: [0, 0, 2, 2],
  462. y: size[1] - 0.5,
  463. height: moveHandleHeight
  464. }
  465. });
  466. var iconSize = moveHandleHeight * 0.8;
  467. var moveHandleIcon = displayables.moveHandleIcon = createSymbol(dataZoomModel.get('moveHandleIcon'), -iconSize / 2, -iconSize / 2, iconSize, iconSize, '#fff', true);
  468. moveHandleIcon.silent = true;
  469. moveHandleIcon.y = size[1] + moveHandleHeight / 2 - 0.5;
  470. moveHandle_1.ensureState('emphasis').style = dataZoomModel.getModel(['emphasis', 'moveHandleStyle']).getItemStyle();
  471. var moveZoneExpandSize = Math.min(size[1] / 2, Math.max(moveHandleHeight, 10));
  472. actualMoveZone = displayables.moveZone = new graphic.Rect({
  473. invisible: true,
  474. shape: {
  475. y: size[1] - moveZoneExpandSize,
  476. height: moveHandleHeight + moveZoneExpandSize
  477. }
  478. });
  479. actualMoveZone.on('mouseover', function () {
  480. api.enterEmphasis(moveHandle_1);
  481. }).on('mouseout', function () {
  482. api.leaveEmphasis(moveHandle_1);
  483. });
  484. sliderGroup.add(moveHandle_1);
  485. sliderGroup.add(moveHandleIcon);
  486. sliderGroup.add(actualMoveZone);
  487. }
  488. actualMoveZone.attr({
  489. draggable: true,
  490. cursor: getCursor(this._orient),
  491. drift: bind(this._onDragMove, this, 'all'),
  492. ondragstart: bind(this._showDataInfo, this, true),
  493. ondragend: bind(this._onDragEnd, this),
  494. onmouseover: bind(this._showDataInfo, this, true),
  495. onmouseout: bind(this._showDataInfo, this, false)
  496. });
  497. };
  498. SliderZoomView.prototype._resetInterval = function () {
  499. var range = this._range = this.dataZoomModel.getPercentRange();
  500. var viewExtent = this._getViewExtent();
  501. this._handleEnds = [linearMap(range[0], [0, 100], viewExtent, true), linearMap(range[1], [0, 100], viewExtent, true)];
  502. };
  503. SliderZoomView.prototype._updateInterval = function (handleIndex, delta) {
  504. var dataZoomModel = this.dataZoomModel;
  505. var handleEnds = this._handleEnds;
  506. var viewExtend = this._getViewExtent();
  507. var minMaxSpan = dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();
  508. var percentExtent = [0, 100];
  509. 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);
  510. var lastRange = this._range;
  511. var range = this._range = asc([linearMap(handleEnds[0], viewExtend, percentExtent, true), linearMap(handleEnds[1], viewExtend, percentExtent, true)]);
  512. return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];
  513. };
  514. SliderZoomView.prototype._updateView = function (nonRealtime) {
  515. var displaybles = this._displayables;
  516. var handleEnds = this._handleEnds;
  517. var handleInterval = asc(handleEnds.slice());
  518. var size = this._size;
  519. each([0, 1], function (handleIndex) {
  520. // Handles
  521. var handle = displaybles.handles[handleIndex];
  522. var handleHeight = this._handleHeight;
  523. handle.attr({
  524. scaleX: handleHeight / 2,
  525. scaleY: handleHeight / 2,
  526. // This is a trick, by adding an extra tiny offset to let the default handle's end point align to the drag window.
  527. // NOTE: It may affect some custom shapes a bit. But we prefer to have better result by default.
  528. x: handleEnds[handleIndex] + (handleIndex ? -1 : 1),
  529. y: size[1] / 2 - handleHeight / 2
  530. });
  531. }, this); // Filler
  532. displaybles.filler.setShape({
  533. x: handleInterval[0],
  534. y: 0,
  535. width: handleInterval[1] - handleInterval[0],
  536. height: size[1]
  537. });
  538. var viewExtent = {
  539. x: handleInterval[0],
  540. width: handleInterval[1] - handleInterval[0]
  541. }; // Move handle
  542. if (displaybles.moveHandle) {
  543. displaybles.moveHandle.setShape(viewExtent);
  544. displaybles.moveZone.setShape(viewExtent); // Force update path on the invisible object
  545. displaybles.moveZone.getBoundingRect();
  546. displaybles.moveHandleIcon && displaybles.moveHandleIcon.attr('x', viewExtent.x + viewExtent.width / 2);
  547. } // update clip path of shadow.
  548. var dataShadowSegs = displaybles.dataShadowSegs;
  549. var segIntervals = [0, handleInterval[0], handleInterval[1], size[0]];
  550. for (var i = 0; i < dataShadowSegs.length; i++) {
  551. var segGroup = dataShadowSegs[i];
  552. var clipPath = segGroup.getClipPath();
  553. if (!clipPath) {
  554. clipPath = new graphic.Rect();
  555. segGroup.setClipPath(clipPath);
  556. }
  557. clipPath.setShape({
  558. x: segIntervals[i],
  559. y: 0,
  560. width: segIntervals[i + 1] - segIntervals[i],
  561. height: size[1]
  562. });
  563. }
  564. this._updateDataInfo(nonRealtime);
  565. };
  566. SliderZoomView.prototype._updateDataInfo = function (nonRealtime) {
  567. var dataZoomModel = this.dataZoomModel;
  568. var displaybles = this._displayables;
  569. var handleLabels = displaybles.handleLabels;
  570. var orient = this._orient;
  571. var labelTexts = ['', '']; // FIXME
  572. // date型,支持formatter,autoformatter(ec2 date.getAutoFormatter)
  573. if (dataZoomModel.get('showDetail')) {
  574. var axisProxy = dataZoomModel.findRepresentativeAxisProxy();
  575. if (axisProxy) {
  576. var axis = axisProxy.getAxisModel().axis;
  577. var range = this._range;
  578. var dataInterval = nonRealtime // See #4434, data and axis are not processed and reset yet in non-realtime mode.
  579. ? axisProxy.calculateDataWindow({
  580. start: range[0],
  581. end: range[1]
  582. }).valueWindow : axisProxy.getDataValueWindow();
  583. labelTexts = [this._formatLabel(dataInterval[0], axis), this._formatLabel(dataInterval[1], axis)];
  584. }
  585. }
  586. var orderedHandleEnds = asc(this._handleEnds.slice());
  587. setLabel.call(this, 0);
  588. setLabel.call(this, 1);
  589. function setLabel(handleIndex) {
  590. // Label
  591. // Text should not transform by barGroup.
  592. // Ignore handlers transform
  593. var barTransform = graphic.getTransform(displaybles.handles[handleIndex].parent, this.group);
  594. var direction = graphic.transformDirection(handleIndex === 0 ? 'right' : 'left', barTransform);
  595. var offset = this._handleWidth / 2 + LABEL_GAP;
  596. var textPoint = graphic.applyTransform([orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset), this._size[1] / 2], barTransform);
  597. handleLabels[handleIndex].setStyle({
  598. x: textPoint[0],
  599. y: textPoint[1],
  600. verticalAlign: orient === HORIZONTAL ? 'middle' : direction,
  601. align: orient === HORIZONTAL ? direction : 'center',
  602. text: labelTexts[handleIndex]
  603. });
  604. }
  605. };
  606. SliderZoomView.prototype._formatLabel = function (value, axis) {
  607. var dataZoomModel = this.dataZoomModel;
  608. var labelFormatter = dataZoomModel.get('labelFormatter');
  609. var labelPrecision = dataZoomModel.get('labelPrecision');
  610. if (labelPrecision == null || labelPrecision === 'auto') {
  611. labelPrecision = axis.getPixelPrecision();
  612. }
  613. var valueStr = value == null || isNaN(value) ? '' // FIXME Glue code
  614. : axis.type === 'category' || axis.type === 'time' ? axis.scale.getLabel({
  615. value: Math.round(value)
  616. }) // param of toFixed should less then 20.
  617. : value.toFixed(Math.min(labelPrecision, 20));
  618. return isFunction(labelFormatter) ? labelFormatter(value, valueStr) : isString(labelFormatter) ? labelFormatter.replace('{value}', valueStr) : valueStr;
  619. };
  620. /**
  621. * @param showOrHide true: show, false: hide
  622. */
  623. SliderZoomView.prototype._showDataInfo = function (showOrHide) {
  624. // Always show when drgging.
  625. showOrHide = this._dragging || showOrHide;
  626. var displayables = this._displayables;
  627. var handleLabels = displayables.handleLabels;
  628. handleLabels[0].attr('invisible', !showOrHide);
  629. handleLabels[1].attr('invisible', !showOrHide); // Highlight move handle
  630. displayables.moveHandle && this.api[showOrHide ? 'enterEmphasis' : 'leaveEmphasis'](displayables.moveHandle, 1);
  631. };
  632. SliderZoomView.prototype._onDragMove = function (handleIndex, dx, dy, event) {
  633. this._dragging = true; // For mobile device, prevent screen slider on the button.
  634. eventTool.stop(event.event); // Transform dx, dy to bar coordination.
  635. var barTransform = this._displayables.sliderGroup.getLocalTransform();
  636. var vertex = graphic.applyTransform([dx, dy], barTransform, true);
  637. var changed = this._updateInterval(handleIndex, vertex[0]);
  638. var realtime = this.dataZoomModel.get('realtime');
  639. this._updateView(!realtime); // Avoid dispatch dataZoom repeatly but range not changed,
  640. // which cause bad visual effect when progressive enabled.
  641. changed && realtime && this._dispatchZoomAction(true);
  642. };
  643. SliderZoomView.prototype._onDragEnd = function () {
  644. this._dragging = false;
  645. this._showDataInfo(false); // While in realtime mode and stream mode, dispatch action when
  646. // drag end will cause the whole view rerender, which is unnecessary.
  647. var realtime = this.dataZoomModel.get('realtime');
  648. !realtime && this._dispatchZoomAction(false);
  649. };
  650. SliderZoomView.prototype._onClickPanel = function (e) {
  651. var size = this._size;
  652. var localPoint = this._displayables.sliderGroup.transformCoordToLocal(e.offsetX, e.offsetY);
  653. if (localPoint[0] < 0 || localPoint[0] > size[0] || localPoint[1] < 0 || localPoint[1] > size[1]) {
  654. return;
  655. }
  656. var handleEnds = this._handleEnds;
  657. var center = (handleEnds[0] + handleEnds[1]) / 2;
  658. var changed = this._updateInterval('all', localPoint[0] - center);
  659. this._updateView();
  660. changed && this._dispatchZoomAction(false);
  661. };
  662. SliderZoomView.prototype._onBrushStart = function (e) {
  663. var x = e.offsetX;
  664. var y = e.offsetY;
  665. this._brushStart = new graphic.Point(x, y);
  666. this._brushing = true;
  667. this._brushStartTime = +new Date(); // this._updateBrushRect(x, y);
  668. };
  669. SliderZoomView.prototype._onBrushEnd = function (e) {
  670. if (!this._brushing) {
  671. return;
  672. }
  673. var brushRect = this._displayables.brushRect;
  674. this._brushing = false;
  675. if (!brushRect) {
  676. return;
  677. }
  678. brushRect.attr('ignore', true);
  679. var brushShape = brushRect.shape;
  680. var brushEndTime = +new Date(); // console.log(brushEndTime - this._brushStartTime);
  681. if (brushEndTime - this._brushStartTime < 200 && Math.abs(brushShape.width) < 5) {
  682. // Will treat it as a click
  683. return;
  684. }
  685. var viewExtend = this._getViewExtent();
  686. var percentExtent = [0, 100];
  687. this._range = asc([linearMap(brushShape.x, viewExtend, percentExtent, true), linearMap(brushShape.x + brushShape.width, viewExtend, percentExtent, true)]);
  688. this._handleEnds = [brushShape.x, brushShape.x + brushShape.width];
  689. this._updateView();
  690. this._dispatchZoomAction(false);
  691. };
  692. SliderZoomView.prototype._onBrush = function (e) {
  693. if (this._brushing) {
  694. // For mobile device, prevent screen slider on the button.
  695. eventTool.stop(e.event);
  696. this._updateBrushRect(e.offsetX, e.offsetY);
  697. }
  698. };
  699. SliderZoomView.prototype._updateBrushRect = function (mouseX, mouseY) {
  700. var displayables = this._displayables;
  701. var dataZoomModel = this.dataZoomModel;
  702. var brushRect = displayables.brushRect;
  703. if (!brushRect) {
  704. brushRect = displayables.brushRect = new Rect({
  705. silent: true,
  706. style: dataZoomModel.getModel('brushStyle').getItemStyle()
  707. });
  708. displayables.sliderGroup.add(brushRect);
  709. }
  710. brushRect.attr('ignore', false);
  711. var brushStart = this._brushStart;
  712. var sliderGroup = this._displayables.sliderGroup;
  713. var endPoint = sliderGroup.transformCoordToLocal(mouseX, mouseY);
  714. var startPoint = sliderGroup.transformCoordToLocal(brushStart.x, brushStart.y);
  715. var size = this._size;
  716. endPoint[0] = Math.max(Math.min(size[0], endPoint[0]), 0);
  717. brushRect.setShape({
  718. x: startPoint[0],
  719. y: 0,
  720. width: endPoint[0] - startPoint[0],
  721. height: size[1]
  722. });
  723. };
  724. /**
  725. * This action will be throttled.
  726. */
  727. SliderZoomView.prototype._dispatchZoomAction = function (realtime) {
  728. var range = this._range;
  729. this.api.dispatchAction({
  730. type: 'dataZoom',
  731. from: this.uid,
  732. dataZoomId: this.dataZoomModel.id,
  733. animation: realtime ? REALTIME_ANIMATION_CONFIG : null,
  734. start: range[0],
  735. end: range[1]
  736. });
  737. };
  738. SliderZoomView.prototype._findCoordRect = function () {
  739. // Find the grid coresponding to the first axis referred by dataZoom.
  740. var rect;
  741. var coordSysInfoList = collectReferCoordSysModelInfo(this.dataZoomModel).infoList;
  742. if (!rect && coordSysInfoList.length) {
  743. var coordSys = coordSysInfoList[0].model.coordinateSystem;
  744. rect = coordSys.getRect && coordSys.getRect();
  745. }
  746. if (!rect) {
  747. var width = this.api.getWidth();
  748. var height = this.api.getHeight();
  749. rect = {
  750. x: width * 0.2,
  751. y: height * 0.2,
  752. width: width * 0.6,
  753. height: height * 0.6
  754. };
  755. }
  756. return rect;
  757. };
  758. SliderZoomView.type = 'dataZoom.slider';
  759. return SliderZoomView;
  760. }(DataZoomView);
  761. function getOtherDim(thisDim) {
  762. // FIXME
  763. // 这个逻辑和getOtherAxis里一致,但是写在这里是否不好
  764. var map = {
  765. x: 'y',
  766. y: 'x',
  767. radius: 'angle',
  768. angle: 'radius'
  769. };
  770. return map[thisDim];
  771. }
  772. function getCursor(orient) {
  773. return orient === 'vertical' ? 'ns-resize' : 'ew-resize';
  774. }
  775. export default SliderZoomView;