BarView.js 33 KB

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