diff --git a/src/component/matrix/MatrixView.ts b/src/component/matrix/MatrixView.ts index 022ba938cd..7a2f344de4 100644 --- a/src/component/matrix/MatrixView.ts +++ b/src/component/matrix/MatrixView.ts @@ -31,6 +31,7 @@ import { LineShape } from 'zrender/src/graphic/shape/Line'; import { subPixelOptimize } from 'zrender/src/graphic/helper/subPixelOptimize'; import { Group, Text, Rect, Line, XY, setTooltipConfig, expandOrShrinkRect } from '../../util/graphic'; import { clearTmpModel, ListIterator } from '../../util/model'; +import { getECData } from '../../util/innerStore'; import { clone, retrieve2, isFunction, isString } from 'zrender/src/core/util'; import { formatTplSimple } from '../../util/format'; import { invert } from 'zrender/src/core/matrix'; @@ -175,7 +176,8 @@ function renderDimensionCells(group: Group, matrixModel: MatrixModel, ecModel: G shape, dimCell.option.value, Z2_DIMENSION_CELL_DEFAULT, - tooltipOption + tooltipOption, + dimIdx === 0 ? 'x' : 'y' ); } } @@ -246,13 +248,16 @@ function createBodyAndCorner( shape, bodyCornerCellOption ? bodyCornerCellOption.value : null, Z2_BODY_CORNER_CELL_DEFAULT, - tooltipOption + tooltipOption, + bodyCornerOptionRoot ); } } } // End of createBodyOrCornerCells } +type MatrixTargetType = 'x' | 'y' | 'body' | 'corner'; + function createMatrixCell( xyLocator: MatrixXYLocator[], matrixModel: MatrixModel, @@ -266,6 +271,7 @@ function createMatrixCell( textValue: unknown, zrCellDefault: Z2CellDefault, tooltipOption: MatrixOption['tooltip'], + targetType: MatrixTargetType ): void { // Do not use getModel for handy performance optimization. _tmpCellItemStyleModel.option = cellOption ? cellOption.itemStyle : null; @@ -361,12 +367,12 @@ function createMatrixCell( } // Set silent + const triggerEvent = matrixModel.get('triggerEvent'); if (cellText) { let labelSilent = _tmpCellLabelModel.get('silent'); - // auto, tooltip of text cells need silient: false, but non-text cells - // do not need a special cursor in most cases. + // By default, silent: false is needed for triggerEvent or tooltip interaction. if (labelSilent == null) { - labelSilent = !tooltipOptionShow; + labelSilent = !(triggerEvent || tooltipOptionShow); } cellText.silent = labelSilent; cellText.ignoreHostSilent = true; @@ -381,6 +387,18 @@ function createMatrixCell( } cellRect.silent = rectSilent; + if (triggerEvent && cellText) { + const eventData = { + componentType: 'matrix' as const, + componentIndex: matrixModel.componentIndex, + matrixIndex: matrixModel.componentIndex, + targetType: targetType, + name: textValue != null ? textValue + '' : null, + coord: xyLocator.slice() + }; + getECData(cellText).eventData = eventData; + } + clearTmpModel(_tmpCellModel); clearTmpModel(_tmpCellItemStyleModel); clearTmpModel(_tmpCellLabelModel); diff --git a/src/coord/matrix/MatrixModel.ts b/src/coord/matrix/MatrixModel.ts index b6b0e53291..6c5234759e 100644 --- a/src/coord/matrix/MatrixModel.ts +++ b/src/coord/matrix/MatrixModel.ts @@ -44,6 +44,7 @@ export interface MatrixOption extends ComponentOption, BoxLayoutOptionMixin { // Used on the outer border and the divider line. borderZ2?: number; tooltip?: CommonTooltipOption; + triggerEvent?: boolean; // PENDING: do we need to support other states, i.e., `emphasis`, `blur`, `select`? } @@ -292,6 +293,7 @@ const defaultMatrixOption: MatrixOption = { borderColor: tokens.color.axisLine, borderWidth: 1, }, + triggerEvent: false, }; diff --git a/test/matrix.html b/test/matrix.html index 7fffee5e03..6f2aeba718 100644 --- a/test/matrix.html +++ b/test/matrix.html @@ -47,6 +47,7 @@
+
@@ -708,6 +709,71 @@ + + + + + diff --git a/test/ut/spec/component/matrix/event.test.ts b/test/ut/spec/component/matrix/event.test.ts new file mode 100644 index 0000000000..5a337c3dcd --- /dev/null +++ b/test/ut/spec/component/matrix/event.test.ts @@ -0,0 +1,136 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import { createChart } from '../../../core/utHelper'; +import { EChartsType } from '../../../../../src/echarts'; +import { getECData } from '../../../../../src/util/innerStore'; + +describe('matrix_event', function () { + + let chart: EChartsType; + beforeEach(function () { + chart = createChart(); + }); + + afterEach(function () { + chart.dispose(); + }); + + it('should trigger click event on matrix cell when triggerEvent is true', function () { + const option = { + matrix: { + triggerEvent: true, + x: { + data: ['A', 'B'] + }, + y: { + data: ['Y'] + }, + body: { + data: [ + { coord: [0, 0], value: 'Cell A' } + ] + } + } + }; + + chart.setOption(option); + + let clickedParams: any = null; + + chart.on('click', function (params) { + clickedParams = params; + }); + + // Find the matrix cell text element + // Note: Text elements are stored as textContent of their parent Rect, not directly in displayList + const zr = chart.getZr(); + const displayList = zr.storage.getDisplayList(); + + let targetEl; + for (let i = 0; i < displayList.length; i++) { + const el = displayList[i]; + // Check if this element has a text content with eventData + const textContent = el.getTextContent && el.getTextContent(); + if (textContent) { + const textEcData = getECData(textContent); + if (textEcData && textEcData.eventData && textEcData.eventData.name === 'Cell A') { + // Found the text element with the specific name + targetEl = textContent; + break; + } + } + } + + expect(targetEl).toBeDefined(); + + // Trigger click + zr.trigger('click', { + target: targetEl, + offsetX: 10, // Dummy + offsetY: 10 // Dummy + }); + + expect(clickedParams).not.toBeNull(); + expect(clickedParams.componentType).toEqual('matrix'); + expect(clickedParams.matrixIndex).toEqual(0); + expect(clickedParams.targetType).toEqual('body'); + expect(clickedParams.name).toEqual('Cell A'); + expect(clickedParams.coord).toEqual([0, 0]); + }); + + it('should not attach eventData when triggerEvent is false (default)', function () { + const option = { + matrix: { + x: { + data: ['A'] + }, + y: { + data: ['Y'] + }, + body: { + data: [ + { coord: [0, 0], value: 'Cell A' } + ] + } + } + }; + + chart.setOption(option); + + const zr = chart.getZr(); + const displayList = zr.storage.getDisplayList(); + + let hasEventData = false; + for (let i = 0; i < displayList.length; i++) { + const el = displayList[i]; + // Check text content for eventData + const textContent = el.getTextContent && el.getTextContent(); + if (textContent) { + const textEcData = getECData(textContent); + if (textEcData && textEcData.eventData && textEcData.eventData.componentType === 'matrix') { + hasEventData = true; + break; + } + } + } + + expect(hasEventData).toEqual(false); + }); +});