Line.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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 { isArray, each, retrieve2 } from 'zrender/lib/core/util.js';
  42. import * as vector from 'zrender/lib/core/vector.js';
  43. import * as symbolUtil from '../../util/symbol.js';
  44. import ECLinePath from './LinePath.js';
  45. import * as graphic from '../../util/graphic.js';
  46. import { toggleHoverEmphasis, enterEmphasis, leaveEmphasis, SPECIAL_STATES } from '../../util/states.js';
  47. import { getLabelStatesModels, setLabelStyle } from '../../label/labelStyle.js';
  48. import { round } from '../../util/number.js';
  49. import tokens from '../../visual/tokens.js';
  50. var SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'];
  51. function makeSymbolTypeKey(symbolCategory) {
  52. return '_' + symbolCategory + 'Type';
  53. }
  54. function makeSymbolTypeValue(name, lineData, idx) {
  55. var symbolType = lineData.getItemVisual(idx, name);
  56. if (!symbolType || symbolType === 'none') {
  57. return symbolType;
  58. }
  59. var symbolSize = lineData.getItemVisual(idx, name + 'Size');
  60. var symbolRotate = lineData.getItemVisual(idx, name + 'Rotate');
  61. var symbolOffset = lineData.getItemVisual(idx, name + 'Offset');
  62. var symbolKeepAspect = lineData.getItemVisual(idx, name + 'KeepAspect');
  63. var symbolSizeArr = symbolUtil.normalizeSymbolSize(symbolSize);
  64. var symbolOffsetArr = symbolUtil.normalizeSymbolOffset(symbolOffset || 0, symbolSizeArr);
  65. return symbolType + symbolSizeArr + symbolOffsetArr + (symbolRotate || '') + (symbolKeepAspect || '');
  66. }
  67. /**
  68. * @inner
  69. */
  70. function createSymbol(name, lineData, idx) {
  71. var symbolType = lineData.getItemVisual(idx, name);
  72. if (!symbolType || symbolType === 'none') {
  73. return;
  74. }
  75. var symbolSize = lineData.getItemVisual(idx, name + 'Size');
  76. var symbolRotate = lineData.getItemVisual(idx, name + 'Rotate');
  77. var symbolOffset = lineData.getItemVisual(idx, name + 'Offset');
  78. var symbolKeepAspect = lineData.getItemVisual(idx, name + 'KeepAspect');
  79. var symbolSizeArr = symbolUtil.normalizeSymbolSize(symbolSize);
  80. var symbolOffsetArr = symbolUtil.normalizeSymbolOffset(symbolOffset || 0, symbolSizeArr);
  81. var symbolPath = symbolUtil.createSymbol(symbolType, -symbolSizeArr[0] / 2 + symbolOffsetArr[0], -symbolSizeArr[1] / 2 + symbolOffsetArr[1], symbolSizeArr[0], symbolSizeArr[1], null, symbolKeepAspect);
  82. symbolPath.__specifiedRotation = symbolRotate == null || isNaN(symbolRotate) ? void 0 : +symbolRotate * Math.PI / 180 || 0;
  83. symbolPath.name = name;
  84. return symbolPath;
  85. }
  86. function createLine(points) {
  87. var line = new ECLinePath({
  88. name: 'line',
  89. subPixelOptimize: true
  90. });
  91. setLinePoints(line.shape, points);
  92. return line;
  93. }
  94. function setLinePoints(targetShape, points) {
  95. targetShape.x1 = points[0][0];
  96. targetShape.y1 = points[0][1];
  97. targetShape.x2 = points[1][0];
  98. targetShape.y2 = points[1][1];
  99. targetShape.percent = 1;
  100. var cp1 = points[2];
  101. if (cp1) {
  102. targetShape.cpx1 = cp1[0];
  103. targetShape.cpy1 = cp1[1];
  104. } else {
  105. targetShape.cpx1 = NaN;
  106. targetShape.cpy1 = NaN;
  107. }
  108. }
  109. var Line = /** @class */function (_super) {
  110. __extends(Line, _super);
  111. function Line(lineData, idx, seriesScope) {
  112. var _this = _super.call(this) || this;
  113. _this._createLine(lineData, idx, seriesScope);
  114. return _this;
  115. }
  116. Line.prototype._createLine = function (lineData, idx, seriesScope) {
  117. var seriesModel = lineData.hostModel;
  118. var linePoints = lineData.getItemLayout(idx);
  119. var z2 = lineData.getItemVisual(idx, 'z2');
  120. var line = createLine(linePoints);
  121. line.shape.percent = 0;
  122. graphic.initProps(line, {
  123. z2: retrieve2(z2, 0),
  124. shape: {
  125. percent: 1
  126. }
  127. }, seriesModel, idx);
  128. this.add(line);
  129. each(SYMBOL_CATEGORIES, function (symbolCategory) {
  130. var symbol = createSymbol(symbolCategory, lineData, idx);
  131. // symbols must added after line to make sure
  132. // it will be updated after line#update.
  133. // Or symbol position and rotation update in line#beforeUpdate will be one frame slow
  134. this.add(symbol);
  135. this[makeSymbolTypeKey(symbolCategory)] = makeSymbolTypeValue(symbolCategory, lineData, idx);
  136. }, this);
  137. this._updateCommonStl(lineData, idx, seriesScope);
  138. };
  139. // TODO More strict on the List type in parameters?
  140. Line.prototype.updateData = function (lineData, idx, seriesScope) {
  141. var seriesModel = lineData.hostModel;
  142. var line = this.childOfName('line');
  143. var linePoints = lineData.getItemLayout(idx);
  144. var target = {
  145. shape: {}
  146. };
  147. setLinePoints(target.shape, linePoints);
  148. graphic.updateProps(line, target, seriesModel, idx);
  149. each(SYMBOL_CATEGORIES, function (symbolCategory) {
  150. var symbolType = makeSymbolTypeValue(symbolCategory, lineData, idx);
  151. var key = makeSymbolTypeKey(symbolCategory);
  152. // Symbol changed
  153. if (this[key] !== symbolType) {
  154. this.remove(this.childOfName(symbolCategory));
  155. var symbol = createSymbol(symbolCategory, lineData, idx);
  156. this.add(symbol);
  157. }
  158. this[key] = symbolType;
  159. }, this);
  160. this._updateCommonStl(lineData, idx, seriesScope);
  161. };
  162. ;
  163. Line.prototype.getLinePath = function () {
  164. return this.childAt(0);
  165. };
  166. Line.prototype._updateCommonStl = function (lineData, idx, seriesScope) {
  167. var seriesModel = lineData.hostModel;
  168. var line = this.childOfName('line');
  169. var emphasisLineStyle = seriesScope && seriesScope.emphasisLineStyle;
  170. var blurLineStyle = seriesScope && seriesScope.blurLineStyle;
  171. var selectLineStyle = seriesScope && seriesScope.selectLineStyle;
  172. var labelStatesModels = seriesScope && seriesScope.labelStatesModels;
  173. var emphasisDisabled = seriesScope && seriesScope.emphasisDisabled;
  174. var focus = seriesScope && seriesScope.focus;
  175. var blurScope = seriesScope && seriesScope.blurScope;
  176. // Optimization for large dataset
  177. if (!seriesScope || lineData.hasItemOption) {
  178. var itemModel = lineData.getItemModel(idx);
  179. var emphasisModel = itemModel.getModel('emphasis');
  180. emphasisLineStyle = emphasisModel.getModel('lineStyle').getLineStyle();
  181. blurLineStyle = itemModel.getModel(['blur', 'lineStyle']).getLineStyle();
  182. selectLineStyle = itemModel.getModel(['select', 'lineStyle']).getLineStyle();
  183. emphasisDisabled = emphasisModel.get('disabled');
  184. focus = emphasisModel.get('focus');
  185. blurScope = emphasisModel.get('blurScope');
  186. labelStatesModels = getLabelStatesModels(itemModel);
  187. }
  188. var lineStyle = lineData.getItemVisual(idx, 'style');
  189. var visualColor = lineStyle.stroke;
  190. line.useStyle(lineStyle);
  191. line.style.fill = null;
  192. line.style.strokeNoScale = true;
  193. line.ensureState('emphasis').style = emphasisLineStyle;
  194. line.ensureState('blur').style = blurLineStyle;
  195. line.ensureState('select').style = selectLineStyle;
  196. // Update symbol
  197. each(SYMBOL_CATEGORIES, function (symbolCategory) {
  198. var symbol = this.childOfName(symbolCategory);
  199. if (symbol) {
  200. // Share opacity and color with line.
  201. symbol.setColor(visualColor);
  202. symbol.style.opacity = lineStyle.opacity;
  203. for (var i = 0; i < SPECIAL_STATES.length; i++) {
  204. var stateName = SPECIAL_STATES[i];
  205. var lineState = line.getState(stateName);
  206. if (lineState) {
  207. var lineStateStyle = lineState.style || {};
  208. var state = symbol.ensureState(stateName);
  209. var stateStyle = state.style || (state.style = {});
  210. if (lineStateStyle.stroke != null) {
  211. stateStyle[symbol.__isEmptyBrush ? 'stroke' : 'fill'] = lineStateStyle.stroke;
  212. }
  213. if (lineStateStyle.opacity != null) {
  214. stateStyle.opacity = lineStateStyle.opacity;
  215. }
  216. }
  217. }
  218. symbol.markRedraw();
  219. }
  220. }, this);
  221. var rawVal = seriesModel.getRawValue(idx);
  222. setLabelStyle(this, labelStatesModels, {
  223. labelDataIndex: idx,
  224. labelFetcher: {
  225. getFormattedLabel: function (dataIndex, stateName) {
  226. return seriesModel.getFormattedLabel(dataIndex, stateName, lineData.dataType);
  227. }
  228. },
  229. inheritColor: visualColor || tokens.color.neutral99,
  230. defaultOpacity: lineStyle.opacity,
  231. defaultText: (rawVal == null ? lineData.getName(idx) : isFinite(rawVal) ? round(rawVal) : rawVal) + ''
  232. });
  233. var label = this.getTextContent();
  234. // Always set `textStyle` even if `normalStyle.text` is null, because default
  235. // values have to be set on `normalStyle`.
  236. if (label) {
  237. var labelNormalModel = labelStatesModels.normal;
  238. label.__align = label.style.align;
  239. label.__verticalAlign = label.style.verticalAlign;
  240. // 'start', 'middle', 'end'
  241. label.__position = labelNormalModel.get('position') || 'middle';
  242. var distance = labelNormalModel.get('distance');
  243. if (!isArray(distance)) {
  244. distance = [distance, distance];
  245. }
  246. label.__labelDistance = distance;
  247. }
  248. this.setTextConfig({
  249. position: null,
  250. local: true,
  251. inside: false // Can't be inside for stroke element.
  252. });
  253. toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled);
  254. };
  255. Line.prototype.highlight = function () {
  256. enterEmphasis(this);
  257. };
  258. Line.prototype.downplay = function () {
  259. leaveEmphasis(this);
  260. };
  261. Line.prototype.updateLayout = function (lineData, idx) {
  262. this.setLinePoints(lineData.getItemLayout(idx));
  263. };
  264. Line.prototype.setLinePoints = function (points) {
  265. var linePath = this.childOfName('line');
  266. setLinePoints(linePath.shape, points);
  267. linePath.dirty();
  268. };
  269. Line.prototype.beforeUpdate = function () {
  270. var lineGroup = this;
  271. var symbolFrom = lineGroup.childOfName('fromSymbol');
  272. var symbolTo = lineGroup.childOfName('toSymbol');
  273. var label = lineGroup.getTextContent();
  274. // Quick reject
  275. if (!symbolFrom && !symbolTo && (!label || label.ignore)) {
  276. return;
  277. }
  278. var invScale = 1;
  279. var parentNode = this.parent;
  280. while (parentNode) {
  281. if (parentNode.scaleX) {
  282. invScale /= parentNode.scaleX;
  283. }
  284. parentNode = parentNode.parent;
  285. }
  286. var line = lineGroup.childOfName('line');
  287. // If line not changed
  288. // FIXME Parent scale changed
  289. if (!this.__dirty && !line.__dirty) {
  290. return;
  291. }
  292. var percent = line.shape.percent;
  293. var fromPos = line.pointAt(0);
  294. var toPos = line.pointAt(percent);
  295. var d = vector.sub([], toPos, fromPos);
  296. vector.normalize(d, d);
  297. function setSymbolRotation(symbol, percent) {
  298. // Fix #12388
  299. // when symbol is set to be 'arrow' in markLine,
  300. // symbolRotate value will be ignored, and compulsively use tangent angle.
  301. // rotate by default if symbol rotation is not specified
  302. var specifiedRotation = symbol.__specifiedRotation;
  303. if (specifiedRotation == null) {
  304. var tangent = line.tangentAt(percent);
  305. symbol.attr('rotation', (percent === 1 ? -1 : 1) * Math.PI / 2 - Math.atan2(tangent[1], tangent[0]));
  306. } else {
  307. symbol.attr('rotation', specifiedRotation);
  308. }
  309. }
  310. if (symbolFrom) {
  311. symbolFrom.setPosition(fromPos);
  312. setSymbolRotation(symbolFrom, 0);
  313. symbolFrom.scaleX = symbolFrom.scaleY = invScale * percent;
  314. symbolFrom.markRedraw();
  315. }
  316. if (symbolTo) {
  317. symbolTo.setPosition(toPos);
  318. setSymbolRotation(symbolTo, 1);
  319. symbolTo.scaleX = symbolTo.scaleY = invScale * percent;
  320. symbolTo.markRedraw();
  321. }
  322. if (label && !label.ignore) {
  323. label.x = label.y = 0;
  324. label.originX = label.originY = 0;
  325. var textAlign = void 0;
  326. var textVerticalAlign = void 0;
  327. var distance = label.__labelDistance;
  328. var distanceX = distance[0] * invScale;
  329. var distanceY = distance[1] * invScale;
  330. var halfPercent = percent / 2;
  331. var tangent = line.tangentAt(halfPercent);
  332. var n = [tangent[1], -tangent[0]];
  333. var cp = line.pointAt(halfPercent);
  334. if (n[1] > 0) {
  335. n[0] = -n[0];
  336. n[1] = -n[1];
  337. }
  338. var dir = tangent[0] < 0 ? -1 : 1;
  339. if (label.__position !== 'start' && label.__position !== 'end') {
  340. var rotation = -Math.atan2(tangent[1], tangent[0]);
  341. if (toPos[0] < fromPos[0]) {
  342. rotation = Math.PI + rotation;
  343. }
  344. label.rotation = rotation;
  345. }
  346. var dy = void 0;
  347. switch (label.__position) {
  348. case 'insideStartTop':
  349. case 'insideMiddleTop':
  350. case 'insideEndTop':
  351. case 'middle':
  352. dy = -distanceY;
  353. textVerticalAlign = 'bottom';
  354. break;
  355. case 'insideStartBottom':
  356. case 'insideMiddleBottom':
  357. case 'insideEndBottom':
  358. dy = distanceY;
  359. textVerticalAlign = 'top';
  360. break;
  361. default:
  362. dy = 0;
  363. textVerticalAlign = 'middle';
  364. }
  365. switch (label.__position) {
  366. case 'end':
  367. label.x = d[0] * distanceX + toPos[0];
  368. label.y = d[1] * distanceY + toPos[1];
  369. textAlign = d[0] > 0.8 ? 'left' : d[0] < -0.8 ? 'right' : 'center';
  370. textVerticalAlign = d[1] > 0.8 ? 'top' : d[1] < -0.8 ? 'bottom' : 'middle';
  371. break;
  372. case 'start':
  373. label.x = -d[0] * distanceX + fromPos[0];
  374. label.y = -d[1] * distanceY + fromPos[1];
  375. textAlign = d[0] > 0.8 ? 'right' : d[0] < -0.8 ? 'left' : 'center';
  376. textVerticalAlign = d[1] > 0.8 ? 'bottom' : d[1] < -0.8 ? 'top' : 'middle';
  377. break;
  378. case 'insideStartTop':
  379. case 'insideStart':
  380. case 'insideStartBottom':
  381. label.x = distanceX * dir + fromPos[0];
  382. label.y = fromPos[1] + dy;
  383. textAlign = tangent[0] < 0 ? 'right' : 'left';
  384. label.originX = -distanceX * dir;
  385. label.originY = -dy;
  386. break;
  387. case 'insideMiddleTop':
  388. case 'insideMiddle':
  389. case 'insideMiddleBottom':
  390. case 'middle':
  391. label.x = cp[0];
  392. label.y = cp[1] + dy;
  393. textAlign = 'center';
  394. label.originY = -dy;
  395. break;
  396. case 'insideEndTop':
  397. case 'insideEnd':
  398. case 'insideEndBottom':
  399. label.x = -distanceX * dir + toPos[0];
  400. label.y = toPos[1] + dy;
  401. textAlign = tangent[0] >= 0 ? 'right' : 'left';
  402. label.originX = distanceX * dir;
  403. label.originY = -dy;
  404. break;
  405. }
  406. label.scaleX = label.scaleY = invScale;
  407. label.setStyle({
  408. // Use the user specified text align and baseline first
  409. verticalAlign: label.__verticalAlign || textVerticalAlign,
  410. align: label.__align || textAlign
  411. });
  412. }
  413. };
  414. return Line;
  415. }(graphic.Group);
  416. export default Line;