MatrixView.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 ComponentView from '../../view/Component.js';
  42. import Model from '../../model/Model.js';
  43. import BoundingRect from 'zrender/lib/core/BoundingRect.js';
  44. import * as vectorUtil from 'zrender/lib/core/vector.js';
  45. import { subPixelOptimize } from 'zrender/lib/graphic/helper/subPixelOptimize.js';
  46. import { Rect, Line, XY, setTooltipConfig, expandOrShrinkRect } from '../../util/graphic.js';
  47. import { clearTmpModel, ListIterator } from '../../util/model.js';
  48. import { getECData } from '../../util/innerStore.js';
  49. import { clone, retrieve2, isFunction, isString } from 'zrender/lib/core/util.js';
  50. import { formatTplSimple } from '../../util/format.js';
  51. import { invert } from 'zrender/lib/core/matrix.js';
  52. import { setLabelStyle } from '../../label/labelStyle.js';
  53. var round = Math.round;
  54. var Z2_BACKGROUND = 0;
  55. var Z2_OUTER_BORDER = 99;
  56. var Z2_BODY_CORNER_CELL_DEFAULT = {
  57. normal: 25,
  58. special: 100
  59. };
  60. var Z2_DIMENSION_CELL_DEFAULT = {
  61. normal: 50,
  62. special: 125
  63. };
  64. var MatrixView = /** @class */function (_super) {
  65. __extends(MatrixView, _super);
  66. function MatrixView() {
  67. var _this = _super !== null && _super.apply(this, arguments) || this;
  68. _this.type = MatrixView.type;
  69. return _this;
  70. }
  71. MatrixView.prototype.render = function (matrixModel, ecModel) {
  72. this.group.removeAll();
  73. var group = this.group;
  74. var coordSys = matrixModel.coordinateSystem;
  75. var rect = coordSys.getRect();
  76. var xDimModel = matrixModel.getDimensionModel('x');
  77. var yDimModel = matrixModel.getDimensionModel('y');
  78. var xDim = xDimModel.dim;
  79. var yDim = yDimModel.dim;
  80. // PENDING:
  81. // reuse the existing text and rect elements for performance?
  82. renderDimensionCells(group, matrixModel, ecModel);
  83. createBodyAndCorner(group, matrixModel, xDim, yDim, ecModel);
  84. var borderZ2Option = matrixModel.getShallow('borderZ2', true);
  85. var outerBorderZ2 = retrieve2(borderZ2Option, Z2_OUTER_BORDER);
  86. var dividerLineZ2 = outerBorderZ2 - 1;
  87. // Outer border and overall background. Use separate elements because of z-order:
  88. // The overall background should appear below any other elements.
  89. // But in most cases, the outer border and the divider line should be above the normal cell borders -
  90. // especially when cell borders have different colors. But users may highlight some specific cells by
  91. // overstirking their border, in which case it should be above the outer border.
  92. var bgStyle = matrixModel.getModel('backgroundStyle').getItemStyle(['borderWidth']);
  93. bgStyle.lineWidth = 0;
  94. var borderStyle = matrixModel.getModel('backgroundStyle').getItemStyle(['color', 'decal', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY']);
  95. borderStyle.fill = 'none';
  96. var bgRect = createMatrixRect(rect.clone(), bgStyle, Z2_BACKGROUND);
  97. var borderRect = createMatrixRect(rect.clone(), borderStyle, outerBorderZ2);
  98. bgRect.silent = true;
  99. borderRect.silent = true;
  100. group.add(bgRect);
  101. group.add(borderRect);
  102. // Header split line.
  103. var xDimCell0 = xDim.getUnitLayoutInfo(0, 0);
  104. var yDimCell0 = yDim.getUnitLayoutInfo(1, 0);
  105. if (xDimCell0 && yDimCell0) {
  106. if (xDim.shouldShow()) {
  107. group.add(createMatrixLine({
  108. x1: rect.x,
  109. y1: yDimCell0.xy,
  110. x2: rect.x + rect.width,
  111. y2: yDimCell0.xy
  112. }, xDimModel.getModel('dividerLineStyle').getLineStyle(), dividerLineZ2));
  113. }
  114. if (yDim.shouldShow()) {
  115. group.add(createMatrixLine({
  116. x1: xDimCell0.xy,
  117. y1: rect.y,
  118. x2: xDimCell0.xy,
  119. y2: rect.y + rect.height
  120. }, yDimModel.getModel('dividerLineStyle').getLineStyle(), dividerLineZ2));
  121. }
  122. }
  123. };
  124. MatrixView.type = 'matrix';
  125. return MatrixView;
  126. }(ComponentView);
  127. function renderDimensionCells(group, matrixModel, ecModel) {
  128. renderOnDimension(0);
  129. renderOnDimension(1);
  130. function renderOnDimension(dimIdx) {
  131. var thisDimModel = matrixModel.getDimensionModel(XY[dimIdx]);
  132. var thisDim = thisDimModel.dim;
  133. if (!thisDim.shouldShow()) {
  134. return;
  135. }
  136. var thisDimBgStyleModel = thisDimModel.getModel('itemStyle');
  137. var thisDimLabelModel = thisDimModel.getModel('label');
  138. var tooltipOption = matrixModel.getShallow('tooltip', true);
  139. var xyLocator = [];
  140. for (var it_1 = thisDim.resetCellIterator(); it_1.next();) {
  141. var dimCell = it_1.item;
  142. var shape = {};
  143. BoundingRect.copy(shape, dimCell.rect);
  144. vectorUtil.set(xyLocator, dimCell.id.x, dimCell.id.y);
  145. createMatrixCell(xyLocator, matrixModel, group, ecModel, dimCell.option, thisDimBgStyleModel, thisDimLabelModel, thisDimModel, shape, dimCell.option.value, Z2_DIMENSION_CELL_DEFAULT, tooltipOption, dimIdx === 0 ? 'x' : 'y');
  146. }
  147. }
  148. }
  149. function createBodyAndCorner(group, matrixModel, xDim, yDim, ecModel) {
  150. createBodyOrCornerCells('body', matrixModel.getBody(), xDim, yDim);
  151. if (xDim.shouldShow() && yDim.shouldShow()) {
  152. createBodyOrCornerCells('corner', matrixModel.getCorner(), yDim, xDim);
  153. }
  154. function createBodyOrCornerCells(bodyCornerOptionRoot, bodyOrCorner, dimForCoordX,
  155. // Can be `matrix.y` (transposed) for corners.
  156. dimForCoordY) {
  157. // Prevent inheriting from ancestor.
  158. var parentCellModel = new Model(matrixModel.getShallow(bodyCornerOptionRoot, true));
  159. var parentItemStyleModel = parentCellModel.getModel('itemStyle');
  160. var parentLabelModel = parentCellModel.getModel('label');
  161. var itx = new ListIterator();
  162. var ity = new ListIterator();
  163. var xyLocator = [];
  164. var tooltipOption = matrixModel.getShallow('tooltip', true);
  165. for (dimForCoordY.resetLayoutIterator(ity, 1); ity.next();) {
  166. for (dimForCoordX.resetLayoutIterator(itx, 0); itx.next();) {
  167. var xLayout = itx.item;
  168. var yLayout = ity.item;
  169. vectorUtil.set(xyLocator, xLayout.id.x, yLayout.id.y);
  170. var bodyCornerCell = bodyOrCorner.getCell(xyLocator);
  171. // If in span of an other body or corner cell, never render it.
  172. if (bodyCornerCell && bodyCornerCell.inSpanOf && bodyCornerCell.inSpanOf !== bodyCornerCell) {
  173. continue;
  174. }
  175. var shape = {};
  176. if (bodyCornerCell && bodyCornerCell.span) {
  177. BoundingRect.copy(shape, bodyCornerCell.spanRect);
  178. } else {
  179. xLayout.dim.getLayout(shape, 0, xyLocator[0]);
  180. yLayout.dim.getLayout(shape, 1, xyLocator[1]);
  181. }
  182. var bodyCornerCellOption = bodyCornerCell ? bodyCornerCell.option : null;
  183. createMatrixCell(xyLocator, matrixModel, group, ecModel, bodyCornerCellOption, parentItemStyleModel, parentLabelModel, parentCellModel, shape, bodyCornerCellOption ? bodyCornerCellOption.value : null, Z2_BODY_CORNER_CELL_DEFAULT, tooltipOption, bodyCornerOptionRoot);
  184. }
  185. }
  186. } // End of createBodyOrCornerCells
  187. }
  188. function createMatrixCell(xyLocator, matrixModel, group, ecModel, cellOption, parentItemStyleModel, parentLabelModel, parentCellModel, shape, textValue, zrCellDefault, tooltipOption, targetType) {
  189. var _a;
  190. // Do not use getModel - a quick performance optimization.
  191. _tmpCellItemStyleModel.option = cellOption ? cellOption.itemStyle : null;
  192. _tmpCellItemStyleModel.parentModel = parentItemStyleModel;
  193. _tmpCellModel.option = cellOption;
  194. _tmpCellModel.parentModel = parentCellModel;
  195. // Use different z2 because special border may be defined in itemStyle.
  196. var z2 = retrieve2(_tmpCellModel.getShallow('z2'), cellOption && cellOption.itemStyle ? zrCellDefault.special : zrCellDefault.normal);
  197. var tooltipOptionShow = tooltipOption && tooltipOption.show;
  198. var cellRect = createMatrixRect(shape, _tmpCellItemStyleModel.getItemStyle(), z2);
  199. group.add(cellRect);
  200. var cursorOption = _tmpCellModel.get('cursor');
  201. if (cursorOption != null) {
  202. cellRect.attr('cursor', cursorOption);
  203. }
  204. var cellText;
  205. if (textValue != null) {
  206. var text = textValue + '';
  207. _tmpCellLabelModel.option = cellOption ? cellOption.label : null;
  208. _tmpCellLabelModel.parentModel = parentLabelModel;
  209. // This is to accept `option.textStyle` as the default.
  210. _tmpCellLabelModel.ecModel = ecModel;
  211. var formatter = _tmpCellLabelModel.getShallow('formatter');
  212. if (formatter) {
  213. var params = {
  214. componentType: 'matrix',
  215. componentIndex: matrixModel.componentIndex,
  216. name: text,
  217. value: textValue,
  218. coord: xyLocator.slice(),
  219. $vars: ['name', 'value', 'coord']
  220. };
  221. if (isString(formatter)) {
  222. text = formatTplSimple(formatter, params);
  223. } else if (isFunction(formatter)) {
  224. var formattedText = formatter(params);
  225. if (formattedText != null) {
  226. text = formattedText + '';
  227. }
  228. }
  229. }
  230. setLabelStyle(cellRect,
  231. // Currently do not support other states (`emphasis`, `select`, `blur`)
  232. {
  233. normal: _tmpCellLabelModel
  234. }, {
  235. defaultText: text,
  236. autoOverflowArea: true,
  237. // By default based on boundingRect. But boundingRect contains borderWidth,
  238. // and borderWidth is half outside the cell. Thus specific `layoutRect` explicitly.
  239. layoutRect: clone(cellRect.shape)
  240. });
  241. cellText = cellRect.getTextContent();
  242. if (cellText) {
  243. cellText.z2 = z2 + 1;
  244. var style = cellText.style;
  245. if (style && style.overflow && style.overflow !== 'none' && style.lineOverflow) {
  246. // `overflow: 'break'/'breakAll'/'truncate'` does not guarantee prevention of overflow
  247. // when space is insufficient. Use a `clipPath` in such case.
  248. var clipShape = {};
  249. BoundingRect.copy(clipShape, shape);
  250. // `lineWidth` is half outside half inside the bounding rect.
  251. expandOrShrinkRect(clipShape, (((_a = cellRect.style) === null || _a === void 0 ? void 0 : _a.lineWidth) || 0) / 2, true, true);
  252. cellRect.updateInnerText();
  253. cellText.getLocalTransform(_tmpInnerTextTrans);
  254. invert(_tmpInnerTextTrans, _tmpInnerTextTrans);
  255. BoundingRect.applyTransform(clipShape, clipShape, _tmpInnerTextTrans);
  256. cellText.setClipPath(new Rect({
  257. shape: clipShape
  258. }));
  259. }
  260. }
  261. setTooltipConfig({
  262. el: cellRect,
  263. componentModel: matrixModel,
  264. itemName: text,
  265. itemTooltipOption: tooltipOption,
  266. formatterParamsExtra: {
  267. xyLocator: xyLocator.slice()
  268. }
  269. });
  270. }
  271. // Set silent
  272. var triggerEvent = matrixModel.get('triggerEvent', true);
  273. if (cellText) {
  274. var labelSilent = _tmpCellLabelModel.get('silent');
  275. // By default, silent: false is needed for triggerEvent or tooltip interaction.
  276. if (labelSilent == null) {
  277. labelSilent = !(triggerEvent || tooltipOptionShow);
  278. }
  279. cellText.silent = labelSilent;
  280. cellText.ignoreHostSilent = true;
  281. }
  282. var rectSilent = _tmpCellModel.get('silent');
  283. if (rectSilent == null) {
  284. rectSilent =
  285. // If no background color in cell, set `rect.silent: false` will cause that only
  286. // the border response to mouse hovering, which is probably weird.
  287. // So we deliberately make rect non-interactive if `silent` is not explicitly specified,
  288. // even if `triggerEvent` is set as `true`.
  289. !cellRect.style || cellRect.style.fill === 'none' || !cellRect.style.fill;
  290. }
  291. cellRect.silent = rectSilent;
  292. // Both `cellRect` (typically non-transparent) and `cellText` may trigger events, depending on both
  293. // `matrix.triggerEvent`, `matrix.xxx.silent` and `matrix.xxx.label.silent` settings.
  294. if (triggerEvent && cellRect) {
  295. var eventData = {
  296. componentType: 'matrix',
  297. componentIndex: matrixModel.componentIndex,
  298. matrixIndex: matrixModel.componentIndex,
  299. targetType: targetType,
  300. name: cellText && cellText.style ? cellText.style.text : undefined,
  301. value: textValue,
  302. coord: xyLocator.slice()
  303. };
  304. getECData(cellRect).eventData = eventData;
  305. }
  306. clearTmpModel(_tmpCellModel);
  307. clearTmpModel(_tmpCellItemStyleModel);
  308. clearTmpModel(_tmpCellLabelModel);
  309. }
  310. var _tmpCellModel = new Model();
  311. var _tmpCellItemStyleModel = new Model();
  312. var _tmpCellLabelModel = new Model();
  313. var _tmpInnerTextTrans = [];
  314. // FIXME: move all of the subpixel process to Matrix.ts resize, otherwise the result of
  315. // `dataToLayout` is not consistent with this rendering, and the caller (like heatmap) can
  316. // not precisely align with the matrix border.
  317. function createMatrixRect(shape, style, z2) {
  318. // Currently `subPixelOptimizeRect` can not be used here because it will break rect alignment.
  319. // Optimize line and rect with the same direction.
  320. var lineWidth = style.lineWidth;
  321. if (lineWidth) {
  322. var x2Original = shape.x + shape.width;
  323. var y2Original = shape.y + shape.height;
  324. shape.x = subPixelOptimize(shape.x, lineWidth, true);
  325. shape.y = subPixelOptimize(shape.y, lineWidth, true);
  326. shape.width = subPixelOptimize(x2Original, lineWidth, true) - shape.x;
  327. shape.height = subPixelOptimize(y2Original, lineWidth, true) - shape.y;
  328. }
  329. return new Rect({
  330. shape: shape,
  331. style: style,
  332. z2: z2
  333. });
  334. }
  335. function createMatrixLine(shape, style, z2) {
  336. var lineWidth = style.lineWidth;
  337. if (lineWidth) {
  338. if (round(shape.x1 * 2) === round(shape.x2 * 2)) {
  339. shape.x1 = shape.x2 = subPixelOptimize(shape.x1, lineWidth, true);
  340. }
  341. if (round(shape.y1 * 2) === round(shape.y2 * 2)) {
  342. shape.y1 = shape.y2 = subPixelOptimize(shape.y1, lineWidth, true);
  343. }
  344. }
  345. return new Line({
  346. shape: shape,
  347. style: style,
  348. silent: true,
  349. z2: z2
  350. });
  351. }
  352. export default MatrixView;