BarView.js 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012
  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 Path from 'zrender/lib/graphic/Path';
  42. import Group from 'zrender/lib/graphic/Group';
  43. import { extend, each, map } from 'zrender/lib/core/util';
  44. import { Rect, Sector, updateProps, initProps, removeElementWithFadeOut } from '../../util/graphic';
  45. import { getECData } from '../../util/innerStore';
  46. import { enableHoverEmphasis, setStatesStylesFromModel } from '../../util/states';
  47. import { setLabelStyle, getLabelStatesModels, setLabelValueAnimation } from '../../label/labelStyle';
  48. import { throttle } from '../../util/throttle';
  49. import { createClipPath } from '../helper/createClipPathFromCoordSys';
  50. import Sausage from '../../util/shape/sausage';
  51. import ChartView from '../../view/Chart';
  52. import { isCoordinateSystemType } from '../../coord/CoordinateSystem';
  53. import { getDefaultLabel, getDefaultInterpolatedLabel } from '../helper/labelHelper';
  54. import { warn } from '../../util/log';
  55. import { createSectorCalculateTextPosition, setSectorTextRotation } from '../../label/sectorLabel';
  56. import { saveOldStyle } from '../../animation/basicTrasition';
  57. var _eventPos = [0, 0];
  58. var mathMax = Math.max;
  59. var mathMin = Math.min;
  60. function getClipArea(coord, data) {
  61. var coordSysClipArea = coord.getArea && coord.getArea();
  62. if (isCoordinateSystemType(coord, 'cartesian2d')) {
  63. var baseAxis = coord.getBaseAxis(); // When boundaryGap is false or using time axis. bar may exceed the grid.
  64. // We should not clip this part.
  65. // See test/bar2.html
  66. if (baseAxis.type !== 'category' || !baseAxis.onBand) {
  67. var expandWidth = data.getLayout('bandWidth');
  68. if (baseAxis.isHorizontal()) {
  69. coordSysClipArea.x -= expandWidth;
  70. coordSysClipArea.width += expandWidth * 2;
  71. } else {
  72. coordSysClipArea.y -= expandWidth;
  73. coordSysClipArea.height += expandWidth * 2;
  74. }
  75. }
  76. }
  77. return coordSysClipArea;
  78. }
  79. var BarView =
  80. /** @class */
  81. function (_super) {
  82. __extends(BarView, _super);
  83. function BarView() {
  84. var _this = _super.call(this) || this;
  85. _this.type = BarView.type;
  86. _this._isFirstFrame = true;
  87. return _this;
  88. }
  89. BarView.prototype.render = function (seriesModel, ecModel, api, payload) {
  90. this._model = seriesModel;
  91. this._removeOnRenderedListener(api);
  92. this._updateDrawMode(seriesModel);
  93. var coordinateSystemType = seriesModel.get('coordinateSystem');
  94. if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') {
  95. this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api, payload);
  96. } else if (process.env.NODE_ENV !== 'production') {
  97. warn('Only cartesian2d and polar supported for bar.');
  98. }
  99. };
  100. BarView.prototype.incrementalPrepareRender = function (seriesModel) {
  101. this._clear();
  102. this._updateDrawMode(seriesModel); // incremental also need to clip, otherwise might be overlow.
  103. // But must not set clip in each frame, otherwise all of the children will be marked redraw.
  104. this._updateLargeClip(seriesModel);
  105. };
  106. BarView.prototype.incrementalRender = function (params, seriesModel) {
  107. // Do not support progressive in normal mode.
  108. this._incrementalRenderLarge(params, seriesModel);
  109. };
  110. BarView.prototype._updateDrawMode = function (seriesModel) {
  111. var isLargeDraw = seriesModel.pipelineContext.large;
  112. if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) {
  113. this._isLargeDraw = isLargeDraw;
  114. this._clear();
  115. }
  116. };
  117. BarView.prototype._renderNormal = function (seriesModel, ecModel, api, payload) {
  118. var group = this.group;
  119. var data = seriesModel.getData();
  120. var oldData = this._data;
  121. var coord = seriesModel.coordinateSystem;
  122. var baseAxis = coord.getBaseAxis();
  123. var isHorizontalOrRadial;
  124. if (coord.type === 'cartesian2d') {
  125. isHorizontalOrRadial = baseAxis.isHorizontal();
  126. } else if (coord.type === 'polar') {
  127. isHorizontalOrRadial = baseAxis.dim === 'angle';
  128. }
  129. var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
  130. var realtimeSortCfg = shouldRealtimeSort(seriesModel, coord);
  131. if (realtimeSortCfg) {
  132. this._enableRealtimeSort(realtimeSortCfg, data, api);
  133. }
  134. var needsClip = seriesModel.get('clip', true) || realtimeSortCfg;
  135. var coordSysClipArea = getClipArea(coord, data); // If there is clipPath created in large mode. Remove it.
  136. group.removeClipPath(); // We don't use clipPath in normal mode because we needs a perfect animation
  137. // And don't want the label are clipped.
  138. var roundCap = seriesModel.get('roundCap', true);
  139. var drawBackground = seriesModel.get('showBackground', true);
  140. var backgroundModel = seriesModel.getModel('backgroundStyle');
  141. var barBorderRadius = backgroundModel.get('borderRadius') || 0;
  142. var bgEls = [];
  143. var oldBgEls = this._backgroundEls;
  144. var isInitSort = payload && payload.isInitSort;
  145. var isChangeOrder = payload && payload.type === 'changeAxisOrder';
  146. function createBackground(dataIndex) {
  147. var bgLayout = getLayout[coord.type](data, dataIndex);
  148. var bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout);
  149. bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius.
  150. if (coord.type === 'cartesian2d') {
  151. bgEl.setShape('r', barBorderRadius);
  152. }
  153. bgEls[dataIndex] = bgEl;
  154. return bgEl;
  155. }
  156. ;
  157. data.diff(oldData).add(function (dataIndex) {
  158. var itemModel = data.getItemModel(dataIndex);
  159. var layout = getLayout[coord.type](data, dataIndex, itemModel);
  160. if (drawBackground) {
  161. createBackground(dataIndex);
  162. } // If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy".
  163. if (!data.hasValue(dataIndex) || !isValidLayout[coord.type](layout)) {
  164. return;
  165. }
  166. var isClipped = false;
  167. if (needsClip) {
  168. // Clip will modify the layout params.
  169. // And return a boolean to determine if the shape are fully clipped.
  170. isClipped = clip[coord.type](coordSysClipArea, layout);
  171. }
  172. var el = elementCreator[coord.type](seriesModel, data, dataIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, false, roundCap);
  173. updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
  174. if (isInitSort) {
  175. el.attr({
  176. shape: layout
  177. });
  178. } else if (realtimeSortCfg) {
  179. updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, dataIndex, isHorizontalOrRadial, false, false);
  180. } else {
  181. initProps(el, {
  182. shape: layout
  183. }, seriesModel, dataIndex);
  184. }
  185. data.setItemGraphicEl(dataIndex, el);
  186. group.add(el);
  187. el.ignore = isClipped;
  188. }).update(function (newIndex, oldIndex) {
  189. var itemModel = data.getItemModel(newIndex);
  190. var layout = getLayout[coord.type](data, newIndex, itemModel);
  191. if (drawBackground) {
  192. var bgEl = void 0;
  193. if (oldBgEls.length === 0) {
  194. bgEl = createBackground(oldIndex);
  195. } else {
  196. bgEl = oldBgEls[oldIndex];
  197. bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius.
  198. if (coord.type === 'cartesian2d') {
  199. bgEl.setShape('r', barBorderRadius);
  200. }
  201. bgEls[newIndex] = bgEl;
  202. }
  203. var bgLayout = getLayout[coord.type](data, newIndex);
  204. var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord);
  205. updateProps(bgEl, {
  206. shape: shape
  207. }, animationModel, newIndex);
  208. }
  209. var el = oldData.getItemGraphicEl(oldIndex);
  210. if (!data.hasValue(newIndex) || !isValidLayout[coord.type](layout)) {
  211. group.remove(el);
  212. return;
  213. }
  214. var isClipped = false;
  215. if (needsClip) {
  216. isClipped = clip[coord.type](coordSysClipArea, layout);
  217. if (isClipped) {
  218. group.remove(el);
  219. }
  220. }
  221. if (!el) {
  222. el = elementCreator[coord.type](seriesModel, data, newIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, !!el, roundCap);
  223. } else {
  224. saveOldStyle(el);
  225. } // Not change anything if only order changed.
  226. // Especially not change label.
  227. if (!isChangeOrder) {
  228. updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
  229. }
  230. if (isInitSort) {
  231. el.attr({
  232. shape: layout
  233. });
  234. } else if (realtimeSortCfg) {
  235. updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, newIndex, isHorizontalOrRadial, true, isChangeOrder);
  236. } else {
  237. updateProps(el, {
  238. shape: layout
  239. }, seriesModel, newIndex, null);
  240. }
  241. data.setItemGraphicEl(newIndex, el);
  242. el.ignore = isClipped;
  243. group.add(el);
  244. }).remove(function (dataIndex) {
  245. var el = oldData.getItemGraphicEl(dataIndex);
  246. el && removeElementWithFadeOut(el, seriesModel, dataIndex);
  247. }).execute();
  248. var bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group());
  249. bgGroup.removeAll();
  250. for (var i = 0; i < bgEls.length; ++i) {
  251. bgGroup.add(bgEls[i]);
  252. }
  253. group.add(bgGroup);
  254. this._backgroundEls = bgEls;
  255. this._data = data;
  256. };
  257. BarView.prototype._renderLarge = function (seriesModel, ecModel, api) {
  258. this._clear();
  259. createLarge(seriesModel, this.group);
  260. this._updateLargeClip(seriesModel);
  261. };
  262. BarView.prototype._incrementalRenderLarge = function (params, seriesModel) {
  263. this._removeBackground();
  264. createLarge(seriesModel, this.group, true);
  265. };
  266. BarView.prototype._updateLargeClip = function (seriesModel) {
  267. // Use clipPath in large mode.
  268. var clipPath = seriesModel.get('clip', true) ? createClipPath(seriesModel.coordinateSystem, false, seriesModel) : null;
  269. if (clipPath) {
  270. this.group.setClipPath(clipPath);
  271. } else {
  272. this.group.removeClipPath();
  273. }
  274. };
  275. BarView.prototype._enableRealtimeSort = function (realtimeSortCfg, data, api) {
  276. var _this = this; // If no data in the first frame, wait for data to initSort
  277. if (!data.count()) {
  278. return;
  279. }
  280. var baseAxis = realtimeSortCfg.baseAxis;
  281. if (this._isFirstFrame) {
  282. this._dispatchInitSort(data, realtimeSortCfg, api);
  283. this._isFirstFrame = false;
  284. } else {
  285. var orderMapping_1 = function (idx) {
  286. var el = data.getItemGraphicEl(idx);
  287. if (el) {
  288. var shape = el.shape; // If data is NaN, shape.xxx may be NaN, so use || 0 here in case
  289. return (baseAxis.isHorizontal() // The result should be consistent with the initial sort by data value.
  290. // Do not support the case that both positive and negative exist.
  291. ? Math.abs(shape.height) : Math.abs(shape.width)) || 0;
  292. } else {
  293. return 0;
  294. }
  295. };
  296. this._onRendered = function () {
  297. _this._updateSortWithinSameData(data, orderMapping_1, baseAxis, api);
  298. };
  299. api.getZr().on('rendered', this._onRendered);
  300. }
  301. };
  302. BarView.prototype._dataSort = function (data, baseAxis, orderMapping) {
  303. var info = [];
  304. data.each(data.mapDimension(baseAxis.dim), function (ordinalNumber, dataIdx) {
  305. var mappedValue = orderMapping(dataIdx);
  306. mappedValue = mappedValue == null ? NaN : mappedValue;
  307. info.push({
  308. dataIndex: dataIdx,
  309. mappedValue: mappedValue,
  310. ordinalNumber: ordinalNumber
  311. });
  312. });
  313. info.sort(function (a, b) {
  314. // If NaN, it will be treated as min val.
  315. return b.mappedValue - a.mappedValue;
  316. });
  317. return {
  318. ordinalNumbers: map(info, function (item) {
  319. return item.ordinalNumber;
  320. })
  321. };
  322. };
  323. BarView.prototype._isOrderChangedWithinSameData = function (data, orderMapping, baseAxis) {
  324. var scale = baseAxis.scale;
  325. var ordinalDataDim = data.mapDimension(baseAxis.dim);
  326. var lastValue = Number.MAX_VALUE;
  327. for (var tickNum = 0, len = scale.getOrdinalMeta().categories.length; tickNum < len; ++tickNum) {
  328. var rawIdx = data.rawIndexOf(ordinalDataDim, scale.getRawOrdinalNumber(tickNum));
  329. var value = rawIdx < 0 // If some tick have no bar, the tick will be treated as min.
  330. ? Number.MIN_VALUE // PENDING: if dataZoom on baseAxis exits, is it a performance issue?
  331. : orderMapping(data.indexOfRawIndex(rawIdx));
  332. if (value > lastValue) {
  333. return true;
  334. }
  335. lastValue = value;
  336. }
  337. return false;
  338. };
  339. /*
  340. * Consider the case when A and B changed order, whose representing
  341. * bars are both out of sight, we don't wish to trigger reorder action
  342. * as long as the order in the view doesn't change.
  343. */
  344. BarView.prototype._isOrderDifferentInView = function (orderInfo, baseAxis) {
  345. var scale = baseAxis.scale;
  346. var extent = scale.getExtent();
  347. var tickNum = Math.max(0, extent[0]);
  348. var tickMax = Math.min(extent[1], scale.getOrdinalMeta().categories.length - 1);
  349. for (; tickNum <= tickMax; ++tickNum) {
  350. if (orderInfo.ordinalNumbers[tickNum] !== scale.getRawOrdinalNumber(tickNum)) {
  351. return true;
  352. }
  353. }
  354. };
  355. BarView.prototype._updateSortWithinSameData = function (data, orderMapping, baseAxis, api) {
  356. if (!this._isOrderChangedWithinSameData(data, orderMapping, baseAxis)) {
  357. return;
  358. }
  359. var sortInfo = this._dataSort(data, baseAxis, orderMapping);
  360. if (this._isOrderDifferentInView(sortInfo, baseAxis)) {
  361. this._removeOnRenderedListener(api);
  362. api.dispatchAction({
  363. type: 'changeAxisOrder',
  364. componentType: baseAxis.dim + 'Axis',
  365. axisId: baseAxis.index,
  366. sortInfo: sortInfo
  367. });
  368. }
  369. };
  370. BarView.prototype._dispatchInitSort = function (data, realtimeSortCfg, api) {
  371. var baseAxis = realtimeSortCfg.baseAxis;
  372. var sortResult = this._dataSort(data, baseAxis, function (dataIdx) {
  373. return data.get(data.mapDimension(realtimeSortCfg.otherAxis.dim), dataIdx);
  374. });
  375. api.dispatchAction({
  376. type: 'changeAxisOrder',
  377. componentType: baseAxis.dim + 'Axis',
  378. isInitSort: true,
  379. axisId: baseAxis.index,
  380. sortInfo: sortResult
  381. });
  382. };
  383. BarView.prototype.remove = function (ecModel, api) {
  384. this._clear(this._model);
  385. this._removeOnRenderedListener(api);
  386. };
  387. BarView.prototype.dispose = function (ecModel, api) {
  388. this._removeOnRenderedListener(api);
  389. };
  390. BarView.prototype._removeOnRenderedListener = function (api) {
  391. if (this._onRendered) {
  392. api.getZr().off('rendered', this._onRendered);
  393. this._onRendered = null;
  394. }
  395. };
  396. BarView.prototype._clear = function (model) {
  397. var group = this.group;
  398. var data = this._data;
  399. if (model && model.isAnimationEnabled() && data && !this._isLargeDraw) {
  400. this._removeBackground();
  401. this._backgroundEls = [];
  402. data.eachItemGraphicEl(function (el) {
  403. removeElementWithFadeOut(el, model, getECData(el).dataIndex);
  404. });
  405. } else {
  406. group.removeAll();
  407. }
  408. this._data = null;
  409. this._isFirstFrame = true;
  410. };
  411. BarView.prototype._removeBackground = function () {
  412. this.group.remove(this._backgroundGroup);
  413. this._backgroundGroup = null;
  414. };
  415. BarView.type = 'bar';
  416. return BarView;
  417. }(ChartView);
  418. var clip = {
  419. cartesian2d: function (coordSysBoundingRect, layout) {
  420. var signWidth = layout.width < 0 ? -1 : 1;
  421. var signHeight = layout.height < 0 ? -1 : 1; // Needs positive width and height
  422. if (signWidth < 0) {
  423. layout.x += layout.width;
  424. layout.width = -layout.width;
  425. }
  426. if (signHeight < 0) {
  427. layout.y += layout.height;
  428. layout.height = -layout.height;
  429. }
  430. var coordSysX2 = coordSysBoundingRect.x + coordSysBoundingRect.width;
  431. var coordSysY2 = coordSysBoundingRect.y + coordSysBoundingRect.height;
  432. var x = mathMax(layout.x, coordSysBoundingRect.x);
  433. var x2 = mathMin(layout.x + layout.width, coordSysX2);
  434. var y = mathMax(layout.y, coordSysBoundingRect.y);
  435. var y2 = mathMin(layout.y + layout.height, coordSysY2);
  436. var xClipped = x2 < x;
  437. var yClipped = y2 < y; // When xClipped or yClipped, the element will be marked as `ignore`.
  438. // But we should also place the element at the edge of the coord sys bounding rect.
  439. // Beause if data changed and the bar show again, its transition animaiton
  440. // will begin at this place.
  441. layout.x = xClipped && x > coordSysX2 ? x2 : x;
  442. layout.y = yClipped && y > coordSysY2 ? y2 : y;
  443. layout.width = xClipped ? 0 : x2 - x;
  444. layout.height = yClipped ? 0 : y2 - y; // Reverse back
  445. if (signWidth < 0) {
  446. layout.x += layout.width;
  447. layout.width = -layout.width;
  448. }
  449. if (signHeight < 0) {
  450. layout.y += layout.height;
  451. layout.height = -layout.height;
  452. }
  453. return xClipped || yClipped;
  454. },
  455. polar: function (coordSysClipArea, layout) {
  456. var signR = layout.r0 <= layout.r ? 1 : -1; // Make sure r is larger than r0
  457. if (signR < 0) {
  458. var tmp = layout.r;
  459. layout.r = layout.r0;
  460. layout.r0 = tmp;
  461. }
  462. var r = mathMin(layout.r, coordSysClipArea.r);
  463. var r0 = mathMax(layout.r0, coordSysClipArea.r0);
  464. layout.r = r;
  465. layout.r0 = r0;
  466. var clipped = r - r0 < 0; // Reverse back
  467. if (signR < 0) {
  468. var tmp = layout.r;
  469. layout.r = layout.r0;
  470. layout.r0 = tmp;
  471. }
  472. return clipped;
  473. }
  474. };
  475. var elementCreator = {
  476. cartesian2d: function (seriesModel, data, newIndex, layout, isHorizontal, animationModel, axisModel, isUpdate, roundCap) {
  477. var rect = new Rect({
  478. shape: extend({}, layout),
  479. z2: 1
  480. });
  481. rect.__dataIndex = newIndex;
  482. rect.name = 'item';
  483. if (animationModel) {
  484. var rectShape = rect.shape;
  485. var animateProperty = isHorizontal ? 'height' : 'width';
  486. rectShape[animateProperty] = 0;
  487. }
  488. return rect;
  489. },
  490. polar: function (seriesModel, data, newIndex, layout, isRadial, animationModel, axisModel, isUpdate, roundCap) {
  491. var ShapeClass = !isRadial && roundCap ? Sausage : Sector;
  492. var sector = new ShapeClass({
  493. shape: layout,
  494. z2: 1
  495. });
  496. sector.name = 'item';
  497. var positionMap = createPolarPositionMapping(isRadial);
  498. sector.calculateTextPosition = createSectorCalculateTextPosition(positionMap, {
  499. isRoundCap: ShapeClass === Sausage
  500. }); // Animation
  501. if (animationModel) {
  502. var sectorShape = sector.shape;
  503. var animateProperty = isRadial ? 'r' : 'endAngle';
  504. var animateTarget = {};
  505. sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;
  506. animateTarget[animateProperty] = layout[animateProperty];
  507. (isUpdate ? updateProps : initProps)(sector, {
  508. shape: animateTarget // __value: typeof dataValue === 'string' ? parseInt(dataValue, 10) : dataValue
  509. }, animationModel);
  510. }
  511. return sector;
  512. }
  513. };
  514. function shouldRealtimeSort(seriesModel, coordSys) {
  515. var realtimeSortOption = seriesModel.get('realtimeSort', true);
  516. var baseAxis = coordSys.getBaseAxis();
  517. if (process.env.NODE_ENV !== 'production') {
  518. if (realtimeSortOption) {
  519. if (baseAxis.type !== 'category') {
  520. warn('`realtimeSort` will not work because this bar series is not based on a category axis.');
  521. }
  522. if (coordSys.type !== 'cartesian2d') {
  523. warn('`realtimeSort` will not work because this bar series is not on cartesian2d.');
  524. }
  525. }
  526. }
  527. if (realtimeSortOption && baseAxis.type === 'category' && coordSys.type === 'cartesian2d') {
  528. return {
  529. baseAxis: baseAxis,
  530. otherAxis: coordSys.getOtherAxis(baseAxis)
  531. };
  532. }
  533. }
  534. function updateRealtimeAnimation(realtimeSortCfg, seriesAnimationModel, el, layout, newIndex, isHorizontal, isUpdate, isChangeOrder) {
  535. var seriesTarget;
  536. var axisTarget;
  537. if (isHorizontal) {
  538. axisTarget = {
  539. x: layout.x,
  540. width: layout.width
  541. };
  542. seriesTarget = {
  543. y: layout.y,
  544. height: layout.height
  545. };
  546. } else {
  547. axisTarget = {
  548. y: layout.y,
  549. height: layout.height
  550. };
  551. seriesTarget = {
  552. x: layout.x,
  553. width: layout.width
  554. };
  555. }
  556. if (!isChangeOrder) {
  557. // Keep the original growth animation if only axis order changed.
  558. // Not start a new animation.
  559. (isUpdate ? updateProps : initProps)(el, {
  560. shape: seriesTarget
  561. }, seriesAnimationModel, newIndex, null);
  562. }
  563. var axisAnimationModel = seriesAnimationModel ? realtimeSortCfg.baseAxis.model : null;
  564. (isUpdate ? updateProps : initProps)(el, {
  565. shape: axisTarget
  566. }, axisAnimationModel, newIndex);
  567. }
  568. function checkPropertiesNotValid(obj, props) {
  569. for (var i = 0; i < props.length; i++) {
  570. if (!isFinite(obj[props[i]])) {
  571. return true;
  572. }
  573. }
  574. return false;
  575. }
  576. var rectPropties = ['x', 'y', 'width', 'height'];
  577. var polarPropties = ['cx', 'cy', 'r', 'startAngle', 'endAngle'];
  578. var isValidLayout = {
  579. cartesian2d: function (layout) {
  580. return !checkPropertiesNotValid(layout, rectPropties);
  581. },
  582. polar: function (layout) {
  583. return !checkPropertiesNotValid(layout, polarPropties);
  584. }
  585. };
  586. var getLayout = {
  587. // itemModel is only used to get borderWidth, which is not needed
  588. // when calculating bar background layout.
  589. cartesian2d: function (data, dataIndex, itemModel) {
  590. var layout = data.getItemLayout(dataIndex);
  591. var fixedLineWidth = itemModel ? getLineWidth(itemModel, layout) : 0; // fix layout with lineWidth
  592. var signX = layout.width > 0 ? 1 : -1;
  593. var signY = layout.height > 0 ? 1 : -1;
  594. return {
  595. x: layout.x + signX * fixedLineWidth / 2,
  596. y: layout.y + signY * fixedLineWidth / 2,
  597. width: layout.width - signX * fixedLineWidth,
  598. height: layout.height - signY * fixedLineWidth
  599. };
  600. },
  601. polar: function (data, dataIndex, itemModel) {
  602. var layout = data.getItemLayout(dataIndex);
  603. return {
  604. cx: layout.cx,
  605. cy: layout.cy,
  606. r0: layout.r0,
  607. r: layout.r,
  608. startAngle: layout.startAngle,
  609. endAngle: layout.endAngle,
  610. clockwise: layout.clockwise
  611. };
  612. }
  613. };
  614. function isZeroOnPolar(layout) {
  615. return layout.startAngle != null && layout.endAngle != null && layout.startAngle === layout.endAngle;
  616. }
  617. function createPolarPositionMapping(isRadial) {
  618. return function (isRadial) {
  619. var arcOrAngle = isRadial ? 'Arc' : 'Angle';
  620. return function (position) {
  621. switch (position) {
  622. case 'start':
  623. case 'insideStart':
  624. case 'end':
  625. case 'insideEnd':
  626. return position + arcOrAngle;
  627. default:
  628. return position;
  629. }
  630. };
  631. }(isRadial);
  632. }
  633. function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, isPolar) {
  634. var style = data.getItemVisual(dataIndex, 'style');
  635. if (!isPolar) {
  636. el.setShape('r', itemModel.get(['itemStyle', 'borderRadius']) || 0);
  637. }
  638. el.useStyle(style);
  639. var cursorStyle = itemModel.getShallow('cursor');
  640. cursorStyle && el.attr('cursor', cursorStyle);
  641. var labelPositionOutside = isPolar ? isHorizontalOrRadial ? layout.r >= layout.r0 ? 'endArc' : 'startArc' : layout.endAngle >= layout.startAngle ? 'endAngle' : 'startAngle' : isHorizontalOrRadial ? layout.height >= 0 ? 'bottom' : 'top' : layout.width >= 0 ? 'right' : 'left';
  642. var labelStatesModels = getLabelStatesModels(itemModel);
  643. setLabelStyle(el, labelStatesModels, {
  644. labelFetcher: seriesModel,
  645. labelDataIndex: dataIndex,
  646. defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),
  647. inheritColor: style.fill,
  648. defaultOpacity: style.opacity,
  649. defaultOutsidePosition: labelPositionOutside
  650. });
  651. var label = el.getTextContent();
  652. if (isPolar && label) {
  653. var position = itemModel.get(['label', 'position']);
  654. el.textConfig.inside = position === 'middle' ? true : null;
  655. setSectorTextRotation(el, position === 'outside' ? labelPositionOutside : position, createPolarPositionMapping(isHorizontalOrRadial), itemModel.get(['label', 'rotate']));
  656. }
  657. setLabelValueAnimation(label, labelStatesModels, seriesModel.getRawValue(dataIndex), function (value) {
  658. return getDefaultInterpolatedLabel(data, value);
  659. });
  660. var emphasisModel = itemModel.getModel(['emphasis']);
  661. enableHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'));
  662. setStatesStylesFromModel(el, itemModel);
  663. if (isZeroOnPolar(layout)) {
  664. el.style.fill = 'none';
  665. el.style.stroke = 'none';
  666. each(el.states, function (state) {
  667. if (state.style) {
  668. state.style.fill = state.style.stroke = 'none';
  669. }
  670. });
  671. }
  672. } // In case width or height are too small.
  673. function getLineWidth(itemModel, rawLayout) {
  674. // Has no border.
  675. var borderColor = itemModel.get(['itemStyle', 'borderColor']);
  676. if (!borderColor || borderColor === 'none') {
  677. return 0;
  678. }
  679. var lineWidth = itemModel.get(['itemStyle', 'borderWidth']) || 0; // width or height may be NaN for empty data
  680. var width = isNaN(rawLayout.width) ? Number.MAX_VALUE : Math.abs(rawLayout.width);
  681. var height = isNaN(rawLayout.height) ? Number.MAX_VALUE : Math.abs(rawLayout.height);
  682. return Math.min(lineWidth, width, height);
  683. }
  684. var LagePathShape =
  685. /** @class */
  686. function () {
  687. function LagePathShape() {}
  688. return LagePathShape;
  689. }();
  690. var LargePath =
  691. /** @class */
  692. function (_super) {
  693. __extends(LargePath, _super);
  694. function LargePath(opts) {
  695. var _this = _super.call(this, opts) || this;
  696. _this.type = 'largeBar';
  697. return _this;
  698. }
  699. ;
  700. LargePath.prototype.getDefaultShape = function () {
  701. return new LagePathShape();
  702. };
  703. LargePath.prototype.buildPath = function (ctx, shape) {
  704. // Drawing lines is more efficient than drawing
  705. // a whole line or drawing rects.
  706. var points = shape.points;
  707. var startPoint = this.__startPoint;
  708. var baseDimIdx = this.__baseDimIdx;
  709. for (var i = 0; i < points.length; i += 2) {
  710. startPoint[baseDimIdx] = points[i + baseDimIdx];
  711. ctx.moveTo(startPoint[0], startPoint[1]);
  712. ctx.lineTo(points[i], points[i + 1]);
  713. }
  714. };
  715. return LargePath;
  716. }(Path);
  717. function createLarge(seriesModel, group, incremental) {
  718. // TODO support polar
  719. var data = seriesModel.getData();
  720. var startPoint = [];
  721. var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;
  722. startPoint[1 - baseDimIdx] = data.getLayout('valueAxisStart');
  723. var largeDataIndices = data.getLayout('largeDataIndices');
  724. var barWidth = data.getLayout('barWidth');
  725. var backgroundModel = seriesModel.getModel('backgroundStyle');
  726. var drawBackground = seriesModel.get('showBackground', true);
  727. if (drawBackground) {
  728. var points = data.getLayout('largeBackgroundPoints');
  729. var backgroundStartPoint = [];
  730. backgroundStartPoint[1 - baseDimIdx] = data.getLayout('backgroundStart');
  731. var bgEl = new LargePath({
  732. shape: {
  733. points: points
  734. },
  735. incremental: !!incremental,
  736. silent: true,
  737. z2: 0
  738. });
  739. bgEl.__startPoint = backgroundStartPoint;
  740. bgEl.__baseDimIdx = baseDimIdx;
  741. bgEl.__largeDataIndices = largeDataIndices;
  742. bgEl.__barWidth = barWidth;
  743. setLargeBackgroundStyle(bgEl, backgroundModel, data);
  744. group.add(bgEl);
  745. }
  746. var el = new LargePath({
  747. shape: {
  748. points: data.getLayout('largePoints')
  749. },
  750. incremental: !!incremental
  751. });
  752. el.__startPoint = startPoint;
  753. el.__baseDimIdx = baseDimIdx;
  754. el.__largeDataIndices = largeDataIndices;
  755. el.__barWidth = barWidth;
  756. group.add(el);
  757. setLargeStyle(el, seriesModel, data); // Enable tooltip and user mouse/touch event handlers.
  758. getECData(el).seriesIndex = seriesModel.seriesIndex;
  759. if (!seriesModel.get('silent')) {
  760. el.on('mousedown', largePathUpdateDataIndex);
  761. el.on('mousemove', largePathUpdateDataIndex);
  762. }
  763. } // Use throttle to avoid frequently traverse to find dataIndex.
  764. var largePathUpdateDataIndex = throttle(function (event) {
  765. var largePath = this;
  766. var dataIndex = largePathFindDataIndex(largePath, event.offsetX, event.offsetY);
  767. getECData(largePath).dataIndex = dataIndex >= 0 ? dataIndex : null;
  768. }, 30, false);
  769. function largePathFindDataIndex(largePath, x, y) {
  770. var baseDimIdx = largePath.__baseDimIdx;
  771. var valueDimIdx = 1 - baseDimIdx;
  772. var points = largePath.shape.points;
  773. var largeDataIndices = largePath.__largeDataIndices;
  774. var barWidthHalf = Math.abs(largePath.__barWidth / 2);
  775. var startValueVal = largePath.__startPoint[valueDimIdx];
  776. _eventPos[0] = x;
  777. _eventPos[1] = y;
  778. var pointerBaseVal = _eventPos[baseDimIdx];
  779. var pointerValueVal = _eventPos[1 - baseDimIdx];
  780. var baseLowerBound = pointerBaseVal - barWidthHalf;
  781. var baseUpperBound = pointerBaseVal + barWidthHalf;
  782. for (var i = 0, len = points.length / 2; i < len; i++) {
  783. var ii = i * 2;
  784. var barBaseVal = points[ii + baseDimIdx];
  785. var barValueVal = points[ii + valueDimIdx];
  786. if (barBaseVal >= baseLowerBound && barBaseVal <= baseUpperBound && (startValueVal <= barValueVal ? pointerValueVal >= startValueVal && pointerValueVal <= barValueVal : pointerValueVal >= barValueVal && pointerValueVal <= startValueVal)) {
  787. return largeDataIndices[i];
  788. }
  789. }
  790. return -1;
  791. }
  792. function setLargeStyle(el, seriesModel, data) {
  793. var globalStyle = data.getVisual('style');
  794. el.useStyle(extend({}, globalStyle)); // Use stroke instead of fill.
  795. el.style.fill = null;
  796. el.style.stroke = globalStyle.fill;
  797. el.style.lineWidth = data.getLayout('barWidth');
  798. }
  799. function setLargeBackgroundStyle(el, backgroundModel, data) {
  800. var borderColor = backgroundModel.get('borderColor') || backgroundModel.get('color');
  801. var itemStyle = backgroundModel.getItemStyle();
  802. el.useStyle(itemStyle);
  803. el.style.fill = null;
  804. el.style.stroke = borderColor;
  805. el.style.lineWidth = data.getLayout('barWidth');
  806. }
  807. function createBackgroundShape(isHorizontalOrRadial, layout, coord) {
  808. if (isCoordinateSystemType(coord, 'cartesian2d')) {
  809. var rectShape = layout;
  810. var coordLayout = coord.getArea();
  811. return {
  812. x: isHorizontalOrRadial ? rectShape.x : coordLayout.x,
  813. y: isHorizontalOrRadial ? coordLayout.y : rectShape.y,
  814. width: isHorizontalOrRadial ? rectShape.width : coordLayout.width,
  815. height: isHorizontalOrRadial ? coordLayout.height : rectShape.height
  816. };
  817. } else {
  818. var coordLayout = coord.getArea();
  819. var sectorShape = layout;
  820. return {
  821. cx: coordLayout.cx,
  822. cy: coordLayout.cy,
  823. r0: isHorizontalOrRadial ? coordLayout.r0 : sectorShape.r0,
  824. r: isHorizontalOrRadial ? coordLayout.r : sectorShape.r,
  825. startAngle: isHorizontalOrRadial ? sectorShape.startAngle : 0,
  826. endAngle: isHorizontalOrRadial ? sectorShape.endAngle : Math.PI * 2
  827. };
  828. }
  829. }
  830. function createBackgroundEl(coord, isHorizontalOrRadial, layout) {
  831. var ElementClz = coord.type === 'polar' ? Sector : Rect;
  832. return new ElementClz({
  833. shape: createBackgroundShape(isHorizontalOrRadial, layout, coord),
  834. silent: true,
  835. z2: 0
  836. });
  837. }
  838. export default BarView;