From 769bfef7160c770c1e8b218bda5a37fc6ab34834 Mon Sep 17 00:00:00 2001 From: zhangyu Date: Tue, 25 Jun 2024 17:01:24 +0800 Subject: [PATCH 01/22] fix(pie): Missing pie chart label display. close #20070 --- src/chart/pie/labelLayout.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chart/pie/labelLayout.ts b/src/chart/pie/labelLayout.ts index 934b49cadc..4736a4b937 100644 --- a/src/chart/pie/labelLayout.ts +++ b/src/chart/pie/labelLayout.ts @@ -89,7 +89,7 @@ function adjustSingleSide( const rA = r + item.len; const rA2 = rA * rA; // Use ellipse implicit function to calculate x - const dx = Math.sqrt((1 - Math.abs(dy * dy / rB2)) * rA2); + const dx = Math.sqrt(Math.abs((1 - Math.abs(dy * dy / rB2)) * rA2)); const newX = cx + (dx + item.len2) * dir; const deltaX = newX - item.label.x; const newTargetWidth = item.targetTextWidth - deltaX * dir; From e6dab043c24dba2e7c7eaba2d5529a3ea861c4da Mon Sep 17 00:00:00 2001 From: plainheart Date: Tue, 2 Jul 2024 12:12:25 +0800 Subject: [PATCH 02/22] fix(candlestick): add back missing support for non-normal states since v5.0.0 --- src/chart/candlestick/CandlestickView.ts | 23 +++++++--- src/chart/candlestick/candlestickVisual.ts | 31 +++++++------ test/candlestick-case.html | 51 +++++++++++++++++++++- test/runTest/actions/__meta__.json | 2 +- test/runTest/actions/candlestick-case.json | 2 +- 5 files changed, 84 insertions(+), 25 deletions(-) diff --git a/src/chart/candlestick/CandlestickView.ts b/src/chart/candlestick/CandlestickView.ts index 3d05e81c70..728291424c 100644 --- a/src/chart/candlestick/CandlestickView.ts +++ b/src/chart/candlestick/CandlestickView.ts @@ -20,7 +20,7 @@ import * as zrUtil from 'zrender/src/core/util'; import ChartView from '../../view/Chart'; import * as graphic from '../../util/graphic'; -import { setStatesStylesFromModel } from '../../util/states'; +import { setStatesStylesFromModel, toggleHoverEmphasis } from '../../util/states'; import Path, { PathProps } from 'zrender/src/graphic/Path'; import {createClipPath} from '../helper/createClipPathFromCoordSys'; import CandlestickSeriesModel, { CandlestickDataItemOption } from './CandlestickSeries'; @@ -33,6 +33,7 @@ import { CoordinateSystemClipArea } from '../../coord/CoordinateSystem'; import Model from '../../model/Model'; import { saveOldStyle } from '../../animation/basicTransition'; import Element from 'zrender/src/Element'; +import { getBorderColor, getColor } from './candlestickVisual'; const SKIP_PROPS = ['color', 'borderColor'] as const; @@ -294,6 +295,19 @@ function setBoxCommon(el: NormalBoxPath, data: SeriesData, dataIndex: number, is el.__simpleBox = isSimpleBox; setStatesStylesFromModel(el, itemModel); + + const sign = data.getItemLayout(dataIndex).sign; + zrUtil.each(el.states, (state, stateName) => { + const stateModel = itemModel.getModel(stateName as any); + const color = getColor(sign, stateModel); + const borderColor = getBorderColor(sign, stateModel) || color; + const stateStyle = state.style || (state.style = {}); + color && (stateStyle.fill = color); + borderColor && (stateStyle.stroke = borderColor); + }); + + const emphasisModel = itemModel.getModel('emphasis'); + toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled')); } function transInit(points: number[][], itemLayout: CandlestickItemLayout) { @@ -391,12 +405,9 @@ function createLarge( function setLargeStyle(sign: number, el: LargeBoxPath, seriesModel: CandlestickSeriesModel, data: SeriesData) { // TODO put in visual? - let borderColor = seriesModel.get(['itemStyle', sign > 0 ? 'borderColor' : 'borderColor0']) + const borderColor = getBorderColor(sign, seriesModel) // Use color for border color by default. - || seriesModel.get(['itemStyle', sign > 0 ? 'color' : 'color0']); - if (sign === 0) { - borderColor = seriesModel.get(['itemStyle', 'borderColorDoji']); - } + || getColor(sign, seriesModel); // Color must be excluded. // Because symbol provide setColor individually to set fill and stroke diff --git a/src/chart/candlestick/candlestickVisual.ts b/src/chart/candlestick/candlestickVisual.ts index 8882d63333..a665ea3b69 100644 --- a/src/chart/candlestick/candlestickVisual.ts +++ b/src/chart/candlestick/candlestickVisual.ts @@ -29,6 +29,21 @@ const dojiBorderColorQuery = ['itemStyle', 'borderColorDoji'] as const; const positiveColorQuery = ['itemStyle', 'color'] as const; const negativeColorQuery = ['itemStyle', 'color0'] as const; +export function getColor(sign: number, model: Model>) { + return model.get( + sign > 0 ? positiveColorQuery : negativeColorQuery + ); +} + +export function getBorderColor(sign: number, model: Model>) { + return model.get( + sign === 0 ? dojiBorderColorQuery + : sign > 0 + ? positiveBorderColorQuery + : negativeBorderColorQuery + ); +} + const candlestickVisual: StageHandler = { seriesType: 'candlestick', @@ -39,22 +54,6 @@ const candlestickVisual: StageHandler = { performRawSeries: true, reset: function (seriesModel: CandlestickSeriesModel, ecModel) { - - function getColor(sign: number, model: Model>) { - return model.get( - sign > 0 ? positiveColorQuery : negativeColorQuery - ); - } - - function getBorderColor(sign: number, model: Model>) { - return model.get( - sign === 0 ? dojiBorderColorQuery - : sign > 0 - ? positiveBorderColorQuery - : negativeBorderColorQuery - ); - } - // Only visible series has each data be visual encoded if (ecModel.isSeriesFiltered(seriesModel)) { return; diff --git a/test/candlestick-case.html b/test/candlestick-case.html index 2e5a33f747..6a408a644a 100644 --- a/test/candlestick-case.html +++ b/test/candlestick-case.html @@ -38,7 +38,7 @@
- +
@@ -363,6 +363,55 @@ }); + diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 26eac6dd21..998f79077a 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -45,7 +45,7 @@ "calendar-heatmap": 1, "calendar-month": 1, "candlestick": 2, - "candlestick-case": 1, + "candlestick-case": 2, "candlestick-empty": 1, "candlestick-large": 4, "candlestick-large2": 1, diff --git a/test/runTest/actions/candlestick-case.json b/test/runTest/actions/candlestick-case.json index bc02692b43..0b07b405ea 100644 --- a/test/runTest/actions/candlestick-case.json +++ b/test/runTest/actions/candlestick-case.json @@ -1 +1 @@ -[{"name":"Action 1","ops":[{"type":"mousedown","time":300,"x":50,"y":77},{"type":"mouseup","time":423,"x":50,"y":77},{"time":424,"delay":400,"type":"screenshot-auto"}],"scrollY":0,"scrollX":0,"timestamp":1626405373145}] \ No newline at end of file +[{"name":"Action 1","ops":[{"type":"mousedown","time":300,"x":50,"y":77},{"type":"mouseup","time":423,"x":50,"y":77},{"time":424,"delay":400,"type":"screenshot-auto"}],"scrollY":0,"scrollX":0,"timestamp":1626405373145},{"name":"Action 2","ops":[{"type":"mousemove","time":303,"x":145,"y":215},{"type":"mousemove","time":505,"x":169,"y":336},{"type":"mousemove","time":722,"x":170,"y":369},{"type":"screenshot","time":1492},{"type":"mousemove","time":1769,"x":199,"y":364},{"type":"mousemove","time":1969,"x":287,"y":329},{"type":"mousemove","time":2172,"x":315,"y":329},{"type":"screenshot","time":2995},{"type":"mousemove","time":3319,"x":318,"y":329},{"type":"mousemove","time":3523,"x":446,"y":340},{"type":"mousemove","time":3742,"x":462,"y":343},{"type":"screenshot","time":4427},{"type":"mousemove","time":4885,"x":462,"y":344},{"type":"mousemove","time":5085,"x":639,"y":376},{"type":"mousemove","time":5290,"x":638,"y":381},{"type":"screenshot","time":6027}],"scrollY":357,"scrollX":0,"timestamp":1719893340178}] \ No newline at end of file From e4061f69e6eb38cccf0ca5d1c99fb48414e871df Mon Sep 17 00:00:00 2001 From: plainheart Date: Tue, 2 Jul 2024 12:57:03 +0800 Subject: [PATCH 03/22] fix(candlestick): disable emphasis state by default for forward compatibility --- src/chart/candlestick/CandlestickSeries.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chart/candlestick/CandlestickSeries.ts b/src/chart/candlestick/CandlestickSeries.ts index 019e1c55f4..141fbf5723 100644 --- a/src/chart/candlestick/CandlestickSeries.ts +++ b/src/chart/candlestick/CandlestickSeries.ts @@ -124,7 +124,8 @@ class CandlestickSeriesModel extends SeriesModel { }, emphasis: { - scale: true, + // disable emphasis state by default for forward compatibility + disabled: true, itemStyle: { borderWidth: 2 } From a4d803f6c0bffc9d6b3abd385111682d7b5d7de5 Mon Sep 17 00:00:00 2001 From: hxada Date: Thu, 4 Jul 2024 14:13:58 +0800 Subject: [PATCH 04/22] feature(axis): add feature to remove SplitLine on specified tick --- src/component/axis/CartesianAxisView.ts | 11 +++- src/coord/Axis.ts | 4 +- src/coord/axisCommonTypes.ts | 6 +- src/coord/axisDefault.ts | 2 + test/axis-splitLine.html | 83 +++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 test/axis-splitLine.html diff --git a/src/component/axis/CartesianAxisView.ts b/src/component/axis/CartesianAxisView.ts index 3cc48e3041..abc3e8cff7 100644 --- a/src/component/axis/CartesianAxisView.ts +++ b/src/component/axis/CartesianAxisView.ts @@ -123,6 +123,8 @@ const axisElementBuilders: Record boolean) + interval?: 'auto' | number | ((index:number, value: string) => boolean), + // true | false + showMinLine?: boolean, + // true | false + showMaxLine?: boolean, // colors will display in turn lineStyle?: LineStyleOption } diff --git a/src/coord/axisDefault.ts b/src/coord/axisDefault.ts index 4d2c6674b3..ae589f365a 100644 --- a/src/coord/axisDefault.ts +++ b/src/coord/axisDefault.ts @@ -93,6 +93,8 @@ const defaultOption: AxisBaseOption = { }, splitLine: { show: true, + showMinLine: true, + showMaxLine: true, lineStyle: { color: ['#E0E6F1'], width: 1, diff --git a/test/axis-splitLine.html b/test/axis-splitLine.html new file mode 100644 index 0000000000..2dfd1a320d --- /dev/null +++ b/test/axis-splitLine.html @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + +
+ + + + + + From 35fa0cb7051da0a10bbc5deb5b91d67f1e253782 Mon Sep 17 00:00:00 2001 From: plainheart Date: Mon, 8 Jul 2024 10:54:45 +0800 Subject: [PATCH 05/22] chore: enable prompt to use typescript from workspace --- .vscode/settings.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index c7c1623bc4..68348ac459 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "typescript.tsdk": "./node_modules/typescript/lib" -} \ No newline at end of file + "typescript.tsdk": "./node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true +} From 1166f2d2634d1e672ba6a067ce2698011563d58c Mon Sep 17 00:00:00 2001 From: plainheart Date: Mon, 8 Jul 2024 18:40:53 +0800 Subject: [PATCH 06/22] fix(legend): fix legend action is not isolated from other legend components (resolves #20128) --- src/component/legend/LegendView.ts | 3 ++- src/component/legend/legendAction.ts | 26 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/component/legend/LegendView.ts b/src/component/legend/LegendView.ts index 35b0779f2b..9016468240 100644 --- a/src/component/legend/LegendView.ts +++ b/src/component/legend/LegendView.ts @@ -329,7 +329,8 @@ class LegendView extends ComponentView { }, onclick() { api.dispatchAction({ - type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect' + type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect', + legendId: legendModel.id }); } }); diff --git a/src/component/legend/legendAction.ts b/src/component/legend/legendAction.ts index 04ed3723a8..2edc27dfc2 100644 --- a/src/component/legend/legendAction.ts +++ b/src/component/legend/legendAction.ts @@ -17,16 +17,22 @@ * under the License. */ -// @ts-nocheck +import {curry, each, hasOwn} from 'zrender/src/core/util'; +import { EChartsExtensionInstallRegisters } from '../../extension'; +import { Payload } from '../../util/types'; +import type GlobalModel from '../../model/Global'; +import type LegendModel from './LegendModel'; -import {curry, each} from 'zrender/src/core/util'; +type LegendSelectMethodNames = + 'select' | 'unSelect' | + 'toggleSelected' | 'toggleSelected' | + 'allSelect' | 'inverseSelect'; -function legendSelectActionHandler(methodName, payload, ecModel) { - const selectedMap = {}; +function legendSelectActionHandler(methodName: LegendSelectMethodNames, payload: Payload, ecModel: GlobalModel) { + const selectedMap: Record = {}; const isToggleSelect = methodName === 'toggleSelected'; - let isSelected; - // Update all legend components - ecModel.eachComponent('legend', function (legendModel) { + let isSelected: boolean; + ecModel.eachComponent({ mainType: 'legend', query: payload }, function (legendModel: LegendModel) { if (isToggleSelect && isSelected != null) { // Force other legend has same selected status // Or the first is toggled to true and other are toggled to false @@ -49,7 +55,7 @@ function legendSelectActionHandler(methodName, payload, ecModel) { return; } const isItemSelected = legendModel.isSelected(name); - if (selectedMap.hasOwnProperty(name)) { + if (hasOwn(selectedMap, name)) { // Unselected if any legend is unselected selectedMap[name] = selectedMap[name] && isItemSelected; } @@ -69,7 +75,7 @@ function legendSelectActionHandler(methodName, payload, ecModel) { }; } -export function installLegendAction(registers) { +export function installLegendAction(registers: EChartsExtensionInstallRegisters) { /** * @event legendToggleSelect * @type {Object} @@ -113,4 +119,4 @@ export function installLegendAction(registers) { 'legendUnSelect', 'legendunselected', curry(legendSelectActionHandler, 'unSelect') ); -} \ No newline at end of file +} From 7564282bacd79954e3c84b438d7d503aaa42e740 Mon Sep 17 00:00:00 2001 From: plainheart Date: Tue, 9 Jul 2024 10:01:03 +0800 Subject: [PATCH 07/22] test(legend): add a test case for legend action --- test/legend-action.html | 106 ++++++++++++++++++++++++ test/runTest/actions/__meta__.json | 1 + test/runTest/actions/legend-action.json | 1 + 3 files changed, 108 insertions(+) create mode 100644 test/legend-action.html create mode 100644 test/runTest/actions/legend-action.json diff --git a/test/legend-action.html b/test/legend-action.html new file mode 100644 index 0000000000..07f3688843 --- /dev/null +++ b/test/legend-action.html @@ -0,0 +1,106 @@ + + + + + + + + + + + + +
+ + + + diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index 26eac6dd21..54a683e54f 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -122,6 +122,7 @@ "label-position": 1, "largeLine-tooltip": 1, "legend": 11, + "legend-action": 1, "legend-visualMapColor": 2, "line": 1, "line-animation": 1, diff --git a/test/runTest/actions/legend-action.json b/test/runTest/actions/legend-action.json new file mode 100644 index 0000000000..31ec2f6443 --- /dev/null +++ b/test/runTest/actions/legend-action.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":223,"x":351,"y":33},{"type":"mousemove","time":427,"x":312,"y":71},{"type":"mousemove","time":661,"x":309,"y":75},{"type":"mousedown","time":679,"x":308,"y":75},{"type":"mouseup","time":789,"x":308,"y":75},{"time":790,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":876,"x":308,"y":75},{"type":"mousemove","time":1156,"x":300,"y":68},{"type":"mousemove","time":1360,"x":279,"y":57},{"type":"mousemove","time":1573,"x":255,"y":71},{"type":"mousedown","time":1734,"x":253,"y":74},{"type":"mousemove","time":1775,"x":253,"y":74},{"type":"mouseup","time":1869,"x":253,"y":74},{"time":1870,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2189,"x":253,"y":71},{"type":"mousemove","time":2389,"x":310,"y":49},{"type":"mousemove","time":2589,"x":492,"y":43},{"type":"mousemove","time":2789,"x":722,"y":33},{"type":"mousemove","time":2989,"x":712,"y":64},{"type":"mousemove","time":3195,"x":678,"y":81},{"type":"mousemove","time":3273,"x":680,"y":81},{"type":"mousemove","time":3476,"x":696,"y":76},{"type":"mousedown","time":3479,"x":696,"y":76},{"type":"mouseup","time":3581,"x":696,"y":76},{"time":3582,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3706,"x":692,"y":76},{"type":"mousemove","time":3909,"x":648,"y":75},{"type":"mousedown","time":4135,"x":648,"y":75},{"type":"mouseup","time":4309,"x":648,"y":75},{"time":4310,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4339,"x":647,"y":75},{"type":"mousemove","time":4789,"x":647,"y":74},{"type":"mousemove","time":4993,"x":652,"y":71},{"type":"mousemove","time":5226,"x":653,"y":54},{"type":"mousemove","time":5523,"x":649,"y":51},{"type":"mousemove","time":5723,"x":406,"y":53},{"type":"mousemove","time":5931,"x":329,"y":74},{"type":"mousemove","time":6139,"x":299,"y":66},{"type":"mousemove","time":6339,"x":270,"y":73},{"type":"mousedown","time":6470,"x":265,"y":75},{"type":"mousemove","time":6544,"x":265,"y":75},{"type":"mouseup","time":6597,"x":265,"y":75},{"time":6598,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":6889,"x":269,"y":75},{"type":"mousemove","time":7089,"x":289,"y":68},{"type":"mousedown","time":7270,"x":292,"y":68},{"type":"mousemove","time":7295,"x":292,"y":68},{"type":"mouseup","time":7430,"x":292,"y":68},{"time":7431,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7790,"x":292,"y":66},{"type":"mousemove","time":7993,"x":295,"y":66},{"type":"mousemove","time":8573,"x":297,"y":67},{"type":"mousemove","time":8776,"x":312,"y":80},{"type":"mousemove","time":8989,"x":304,"y":83},{"type":"mousemove","time":9193,"x":251,"y":73},{"type":"mousedown","time":9303,"x":251,"y":73},{"type":"mouseup","time":9413,"x":251,"y":73},{"time":9414,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9756,"x":251,"y":72},{"type":"mousemove","time":9956,"x":265,"y":68},{"type":"mousemove","time":10160,"x":379,"y":39}],"scrollY":0,"scrollX":0,"timestamp":1720490304919}] \ No newline at end of file From 403dce221e5b368e44b402a4491bab137e414d35 Mon Sep 17 00:00:00 2001 From: zhangyu Date: Tue, 9 Jul 2024 17:39:45 +0800 Subject: [PATCH 08/22] fix(pie): fix some labels may not show #20074 --- src/chart/pie/labelLayout.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chart/pie/labelLayout.ts b/src/chart/pie/labelLayout.ts index 4736a4b937..5052ca236b 100644 --- a/src/chart/pie/labelLayout.ts +++ b/src/chart/pie/labelLayout.ts @@ -89,7 +89,7 @@ function adjustSingleSide( const rA = r + item.len; const rA2 = rA * rA; // Use ellipse implicit function to calculate x - const dx = Math.sqrt(Math.abs((1 - Math.abs(dy * dy / rB2)) * rA2)); + const dx = Math.sqrt(Math.abs((1 - dy * dy / rB2) * rA2)); const newX = cx + (dx + item.len2) * dir; const deltaX = newX - item.label.x; const newTargetWidth = item.targetTextWidth - deltaX * dir; From cc26ef3788861723e9b295172694bd69d9856f27 Mon Sep 17 00:00:00 2001 From: plainheart Date: Thu, 11 Jul 2024 13:34:12 +0800 Subject: [PATCH 09/22] fix(legend): fix legend item is selected but corresponding series may not show after dispatching `legendAllSelect` action. --- src/component/legend/legendAction.ts | 77 +++++++++++++++---------- test/legend-action.html | 38 ++++++++++-- test/runTest/actions/legend-action.json | 2 +- 3 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/component/legend/legendAction.ts b/src/component/legend/legendAction.ts index 2edc27dfc2..92e3d14d0e 100644 --- a/src/component/legend/legendAction.ts +++ b/src/component/legend/legendAction.ts @@ -17,7 +17,7 @@ * under the License. */ -import {curry, each, hasOwn} from 'zrender/src/core/util'; +import {curry, each, hasOwn, indexOf, map} from 'zrender/src/core/util'; import { EChartsExtensionInstallRegisters } from '../../extension'; import { Payload } from '../../util/types'; import type GlobalModel from '../../model/Global'; @@ -29,45 +29,44 @@ type LegendSelectMethodNames = 'allSelect' | 'inverseSelect'; function legendSelectActionHandler(methodName: LegendSelectMethodNames, payload: Payload, ecModel: GlobalModel) { + const isAllSelect = methodName === 'allSelect' || methodName === 'inverseSelect'; const selectedMap: Record = {}; - const isToggleSelect = methodName === 'toggleSelected'; - let isSelected: boolean; + + const actionLegendIndices: number[] = []; ecModel.eachComponent({ mainType: 'legend', query: payload }, function (legendModel: LegendModel) { - if (isToggleSelect && isSelected != null) { - // Force other legend has same selected status - // Or the first is toggled to true and other are toggled to false - // In the case one legend has some item unSelected in option. And if other legend - // doesn't has the item, they will assume it is selected. - legendModel[isSelected ? 'select' : 'unSelect'](payload.name); - } - else if (methodName === 'allSelect' || methodName === 'inverseSelect') { + if (isAllSelect) { legendModel[methodName](); } else { legendModel[methodName](payload.name); - isSelected = legendModel.isSelected(payload.name); } - const legendData = legendModel.getData(); - each(legendData, function (model) { - const name = model.get('name'); - // Wrap element - if (name === '\n' || name === '') { - return; - } - const isItemSelected = legendModel.isSelected(name); - if (hasOwn(selectedMap, name)) { - // Unselected if any legend is unselected - selectedMap[name] = selectedMap[name] && isItemSelected; - } - else { - selectedMap[name] = isItemSelected; - } + + makeSelectedMap(legendModel, selectedMap); + + actionLegendIndices.push(legendModel.componentIndex); + }); + + const allSelectedMap: Record = {}; + + // make selectedMap from all legend components + ecModel.eachComponent('legend', function (legendModel: LegendModel) { + each(selectedMap, function (isSelected, name) { + // Force other legend has same selected status + // Or the first is toggled to true and other are toggled to false + // In the case one legend has some item unSelected in option. And if other legend + // doesn't has the item, they will assume it is selected. + legendModel[isSelected ? 'select' : 'unSelect'](name); }); + + makeSelectedMap(legendModel, allSelectedMap); }); + // Return the event explicitly - return (methodName === 'allSelect' || methodName === 'inverseSelect') + return isAllSelect ? { - selected: selectedMap + selected: selectedMap, + // return legendIndex array to tell the developers which legends are allSelect / inverseSelect + legendIndex: actionLegendIndices } : { name: payload.name, @@ -75,6 +74,26 @@ function legendSelectActionHandler(methodName: LegendSelectMethodNames, payload: }; } +function makeSelectedMap(legendModel: LegendModel, out?: Record) { + const selectedMap: Record = out || {}; + each(legendModel.getData(), function (model) { + const name = model.get('name'); + // Wrap element + if (name === '\n' || name === '') { + return; + } + const isItemSelected = legendModel.isSelected(name); + if (hasOwn(selectedMap, name)) { + // Unselected if any legend is unselected + selectedMap[name] = selectedMap[name] && isItemSelected; + } + else { + selectedMap[name] = isItemSelected; + } + }); + return selectedMap; +} + export function installLegendAction(registers: EChartsExtensionInstallRegisters) { /** * @event legendToggleSelect diff --git a/test/legend-action.html b/test/legend-action.html index 07f3688843..90dda2e3f2 100644 --- a/test/legend-action.html +++ b/test/legend-action.html @@ -46,6 +46,7 @@ legend: [ { id: 1, + name: 'legend1', data: ['Steppe', 'Forest'], left: '10%', selector: [ @@ -59,7 +60,8 @@ }, { id: 2, - data: ['Desert', 'Wetland'], + name: 'legend2', + data: ['Desert', 'Wetland', 'Steppe' /* test for the same item in other legend */], right: '10%', selector: [ { @@ -94,12 +96,40 @@ } ] }; - var chart = testHelper.create(echarts, 'main0', { + var chart = window.myChart0 = testHelper.create(echarts, 'main0', { title: [ - 'Legend action should be isolated from other legend components' + 'Legend action should be isolated from other legend components\n(except for the items with the same name)' ], - option: option + option: option, + buttons: [ + { + text: 'Dispatch `legendAllSelect` for both legend components', + onclick() { + chart.dispatchAction({ + type: 'legendAllSelect', + legendName: ['legend1', 'legend2'], + // legendId: ['0', '1'], + // legendIndex: [0, 1] + }) + } + }, + { + text: 'Dispatch `legendInverseSelect` for both legend components', + onclick() { + chart.dispatchAction({ + type: 'legendInverseSelect', + // legendName: ['legend1', 'legend2'], + legendId: ['1', '2'], + // legendIndex: [0, 1] + }) + } + } + ] }); + var logFn = e => console.log(JSON.stringify(e, null, 2)); + chart.on('legendselectall', logFn); + chart.on('legendinverseselect', logFn); + chart.on('legendselectchanged', logFn); }); diff --git a/test/runTest/actions/legend-action.json b/test/runTest/actions/legend-action.json index 31ec2f6443..bd0b61577f 100644 --- a/test/runTest/actions/legend-action.json +++ b/test/runTest/actions/legend-action.json @@ -1 +1 @@ -[{"name":"Action 1","ops":[{"type":"mousemove","time":223,"x":351,"y":33},{"type":"mousemove","time":427,"x":312,"y":71},{"type":"mousemove","time":661,"x":309,"y":75},{"type":"mousedown","time":679,"x":308,"y":75},{"type":"mouseup","time":789,"x":308,"y":75},{"time":790,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":876,"x":308,"y":75},{"type":"mousemove","time":1156,"x":300,"y":68},{"type":"mousemove","time":1360,"x":279,"y":57},{"type":"mousemove","time":1573,"x":255,"y":71},{"type":"mousedown","time":1734,"x":253,"y":74},{"type":"mousemove","time":1775,"x":253,"y":74},{"type":"mouseup","time":1869,"x":253,"y":74},{"time":1870,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2189,"x":253,"y":71},{"type":"mousemove","time":2389,"x":310,"y":49},{"type":"mousemove","time":2589,"x":492,"y":43},{"type":"mousemove","time":2789,"x":722,"y":33},{"type":"mousemove","time":2989,"x":712,"y":64},{"type":"mousemove","time":3195,"x":678,"y":81},{"type":"mousemove","time":3273,"x":680,"y":81},{"type":"mousemove","time":3476,"x":696,"y":76},{"type":"mousedown","time":3479,"x":696,"y":76},{"type":"mouseup","time":3581,"x":696,"y":76},{"time":3582,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3706,"x":692,"y":76},{"type":"mousemove","time":3909,"x":648,"y":75},{"type":"mousedown","time":4135,"x":648,"y":75},{"type":"mouseup","time":4309,"x":648,"y":75},{"time":4310,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4339,"x":647,"y":75},{"type":"mousemove","time":4789,"x":647,"y":74},{"type":"mousemove","time":4993,"x":652,"y":71},{"type":"mousemove","time":5226,"x":653,"y":54},{"type":"mousemove","time":5523,"x":649,"y":51},{"type":"mousemove","time":5723,"x":406,"y":53},{"type":"mousemove","time":5931,"x":329,"y":74},{"type":"mousemove","time":6139,"x":299,"y":66},{"type":"mousemove","time":6339,"x":270,"y":73},{"type":"mousedown","time":6470,"x":265,"y":75},{"type":"mousemove","time":6544,"x":265,"y":75},{"type":"mouseup","time":6597,"x":265,"y":75},{"time":6598,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":6889,"x":269,"y":75},{"type":"mousemove","time":7089,"x":289,"y":68},{"type":"mousedown","time":7270,"x":292,"y":68},{"type":"mousemove","time":7295,"x":292,"y":68},{"type":"mouseup","time":7430,"x":292,"y":68},{"time":7431,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7790,"x":292,"y":66},{"type":"mousemove","time":7993,"x":295,"y":66},{"type":"mousemove","time":8573,"x":297,"y":67},{"type":"mousemove","time":8776,"x":312,"y":80},{"type":"mousemove","time":8989,"x":304,"y":83},{"type":"mousemove","time":9193,"x":251,"y":73},{"type":"mousedown","time":9303,"x":251,"y":73},{"type":"mouseup","time":9413,"x":251,"y":73},{"time":9414,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9756,"x":251,"y":72},{"type":"mousemove","time":9956,"x":265,"y":68},{"type":"mousemove","time":10160,"x":379,"y":39}],"scrollY":0,"scrollX":0,"timestamp":1720490304919}] \ No newline at end of file +[{"name":"Action 1","ops":[{"type":"mousemove","time":301,"x":470,"y":19},{"type":"mousemove","time":500,"x":289,"y":47},{"type":"mousemove","time":700,"x":197,"y":115},{"type":"mousemove","time":903,"x":188,"y":132},{"type":"mousedown","time":1024,"x":188,"y":132},{"type":"mouseup","time":1169,"x":188,"y":132},{"time":1170,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":1483,"x":201,"y":132},{"type":"mousemove","time":1689,"x":273,"y":120},{"type":"mousemove","time":1900,"x":325,"y":117},{"type":"mousemove","time":2103,"x":242,"y":126},{"type":"mousemove","time":2266,"x":242,"y":127},{"type":"mousedown","time":2408,"x":257,"y":133},{"type":"mousemove","time":2469,"x":257,"y":133},{"type":"mouseup","time":2552,"x":257,"y":133},{"time":2553,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":2899,"x":261,"y":133},{"type":"mousemove","time":3099,"x":268,"y":132},{"type":"mousemove","time":3299,"x":297,"y":129},{"type":"mousedown","time":3472,"x":299,"y":129},{"type":"mousemove","time":3503,"x":299,"y":129},{"type":"mouseup","time":3646,"x":299,"y":129},{"time":3647,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4016,"x":304,"y":129},{"type":"mousemove","time":4216,"x":474,"y":132},{"type":"mousemove","time":4421,"x":548,"y":141},{"type":"mousemove","time":4669,"x":525,"y":131},{"type":"mousedown","time":4681,"x":525,"y":131},{"type":"mouseup","time":4816,"x":525,"y":131},{"time":4817,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4999,"x":526,"y":130},{"type":"mousemove","time":5199,"x":622,"y":130},{"type":"mousemove","time":5399,"x":646,"y":131},{"type":"mousedown","time":5521,"x":651,"y":132},{"type":"mousemove","time":5604,"x":651,"y":133},{"type":"mouseup","time":5655,"x":651,"y":133},{"time":5656,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":5886,"x":651,"y":133},{"type":"mousemove","time":6050,"x":651,"y":134},{"type":"mousemove","time":6333,"x":661,"y":135},{"type":"mousemove","time":6533,"x":689,"y":134},{"type":"mousedown","time":6648,"x":690,"y":134},{"type":"mousemove","time":6736,"x":690,"y":134},{"type":"mouseup","time":6759,"x":690,"y":134},{"time":6760,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":6983,"x":688,"y":134},{"type":"mousemove","time":7187,"x":659,"y":133},{"type":"mousedown","time":7304,"x":659,"y":133},{"type":"mouseup","time":7438,"x":659,"y":133},{"time":7439,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":7699,"x":651,"y":133},{"type":"mousemove","time":7899,"x":583,"y":135},{"type":"mousemove","time":8105,"x":521,"y":135},{"type":"mousedown","time":8203,"x":521,"y":135},{"type":"mouseup","time":8310,"x":521,"y":135},{"time":8311,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":8432,"x":542,"y":135},{"type":"mousemove","time":8636,"x":640,"y":135},{"type":"mousemove","time":8870,"x":656,"y":134},{"type":"mousedown","time":8896,"x":656,"y":134},{"type":"mouseup","time":9038,"x":656,"y":134},{"time":9039,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":9184,"x":654,"y":130},{"type":"mousemove","time":9387,"x":613,"y":109},{"type":"mousemove","time":9599,"x":582,"y":96},{"type":"mousemove","time":9803,"x":577,"y":94},{"type":"mousedown","time":9927,"x":577,"y":94},{"type":"mouseup","time":10136,"x":577,"y":94},{"time":10137,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":10401,"x":574,"y":93},{"type":"mousemove","time":10603,"x":407,"y":94},{"type":"mousemove","time":10820,"x":304,"y":94},{"type":"mousemove","time":11116,"x":301,"y":94},{"type":"mousedown","time":11319,"x":296,"y":97},{"type":"mousemove","time":11323,"x":296,"y":97},{"type":"mouseup","time":11430,"x":296,"y":97},{"time":11431,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":11616,"x":296,"y":98},{"type":"mousemove","time":11817,"x":246,"y":118},{"type":"mousemove","time":12021,"x":218,"y":135},{"type":"mousedown","time":12137,"x":218,"y":135},{"type":"mouseup","time":12230,"x":218,"y":135},{"time":12231,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12382,"x":293,"y":133},{"type":"mousemove","time":12583,"x":397,"y":129},{"type":"mousemove","time":12786,"x":441,"y":129},{"type":"mousedown","time":12804,"x":441,"y":129},{"type":"mouseup","time":12886,"x":441,"y":129},{"time":12887,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":12950,"x":419,"y":128},{"type":"mousemove","time":13154,"x":244,"y":79},{"type":"mousemove","time":13366,"x":244,"y":91},{"type":"mousedown","time":13431,"x":245,"y":92},{"type":"mousemove","time":13569,"x":245,"y":92},{"type":"mouseup","time":13574,"x":245,"y":92},{"time":13575,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":13749,"x":256,"y":94},{"type":"mousemove","time":13949,"x":451,"y":91},{"type":"mousemove","time":14153,"x":473,"y":88},{"type":"mousedown","time":14353,"x":473,"y":87},{"type":"mousemove","time":14371,"x":473,"y":87},{"type":"mouseup","time":14520,"x":473,"y":87},{"time":14521,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":15049,"x":474,"y":87},{"type":"mousemove","time":15252,"x":516,"y":83},{"type":"mousemove","time":15487,"x":519,"y":92},{"type":"mousemove","time":15736,"x":514,"y":97},{"type":"mousedown","time":15920,"x":514,"y":97},{"type":"mouseup","time":16054,"x":514,"y":97},{"time":16055,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":16666,"x":531,"y":94},{"type":"mousemove","time":16870,"x":612,"y":81}],"scrollY":0,"scrollX":0,"timestamp":1720675612620}] \ No newline at end of file From c7f672f8e9df5818d186c4c58b946ad13e88e69d Mon Sep 17 00:00:00 2001 From: plainheart Date: Thu, 11 Jul 2024 13:39:06 +0800 Subject: [PATCH 10/22] fix(legend): remove unused import --- src/component/legend/legendAction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/component/legend/legendAction.ts b/src/component/legend/legendAction.ts index 92e3d14d0e..6576af60e7 100644 --- a/src/component/legend/legendAction.ts +++ b/src/component/legend/legendAction.ts @@ -17,7 +17,7 @@ * under the License. */ -import {curry, each, hasOwn, indexOf, map} from 'zrender/src/core/util'; +import {curry, each, hasOwn} from 'zrender/src/core/util'; import { EChartsExtensionInstallRegisters } from '../../extension'; import { Payload } from '../../util/types'; import type GlobalModel from '../../model/Global'; From 33249dcdc33ff2de39026e9d117a644bb22e31a8 Mon Sep 17 00:00:00 2001 From: Zhongxiang Wang Date: Thu, 11 Jul 2024 16:31:53 +0800 Subject: [PATCH 11/22] chore(workflow): fix pr-preview workflow --- .github/workflows/pr-preview.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml index 70804d19d7..5ff31130f9 100644 --- a/.github/workflows/pr-preview.yml +++ b/.github/workflows/pr-preview.yml @@ -46,10 +46,12 @@ jobs: workflow: ${{ github.event.workflow.id }} run_id: ${{ github.event.workflow_run.id }} name: pr_preview + path: pr-dist if_no_artifact_found: fail - name: Output PR metadata id: pr-metadata + working-directory: pr-dist run: | echo "NUMBER=$(cat pr_number)" >> $GITHUB_OUTPUT echo "COMMIT_SHA=$(cat pr_commit_sha)" >> $GITHUB_OUTPUT @@ -59,6 +61,7 @@ jobs: env: PR_NUMBER: ${{ steps.pr-metadata.outputs.NUMBER }} SURGE_TOKEN: ${{ secrets.SURGE_TOKEN }} + working-directory: pr-dist run: | export SURGE_DOMAIN=https://echarts-pr-$PR_NUMBER.surge.sh npx surge --project ./package --domain $SURGE_DOMAIN --token $SURGE_TOKEN From 6ce6ba312d85537f036e23fc43279313c2855eae Mon Sep 17 00:00:00 2001 From: plainheart Date: Thu, 11 Jul 2024 17:14:12 +0800 Subject: [PATCH 12/22] fix(legend): remove duplicated type of legend select method name --- src/component/legend/legendAction.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/component/legend/legendAction.ts b/src/component/legend/legendAction.ts index 6576af60e7..9a05c367e2 100644 --- a/src/component/legend/legendAction.ts +++ b/src/component/legend/legendAction.ts @@ -23,10 +23,7 @@ import { Payload } from '../../util/types'; import type GlobalModel from '../../model/Global'; import type LegendModel from './LegendModel'; -type LegendSelectMethodNames = - 'select' | 'unSelect' | - 'toggleSelected' | 'toggleSelected' | - 'allSelect' | 'inverseSelect'; +type LegendSelectMethodNames = 'select' | 'unSelect' | 'toggleSelected' | 'allSelect' | 'inverseSelect'; function legendSelectActionHandler(methodName: LegendSelectMethodNames, payload: Payload, ecModel: GlobalModel) { const isAllSelect = methodName === 'allSelect' || methodName === 'inverseSelect'; From 13fe1d903715f1edf1ec13a2f556ec44028d8794 Mon Sep 17 00:00:00 2001 From: Zhongxiang Wang Date: Thu, 11 Jul 2024 22:57:22 +0800 Subject: [PATCH 13/22] fix(legend): return allSelectedMap rather than selectedMap --- src/component/legend/legendAction.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/component/legend/legendAction.ts b/src/component/legend/legendAction.ts index 9a05c367e2..d0771e79aa 100644 --- a/src/component/legend/legendAction.ts +++ b/src/component/legend/legendAction.ts @@ -61,13 +61,13 @@ function legendSelectActionHandler(methodName: LegendSelectMethodNames, payload: // Return the event explicitly return isAllSelect ? { - selected: selectedMap, + selected: allSelectedMap, // return legendIndex array to tell the developers which legends are allSelect / inverseSelect legendIndex: actionLegendIndices } : { name: payload.name, - selected: selectedMap + selected: allSelectedMap }; } From 86db174f89e2719b7ee3b1d35c4ae26906faa7bc Mon Sep 17 00:00:00 2001 From: plainheart Date: Mon, 15 Jul 2024 17:11:09 +0800 Subject: [PATCH 14/22] perf(line): prebind context of `_changePolyState` function to current instance rather than create an new function to reduce runtime memory cost (fix #20151) --- src/chart/line/LineView.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chart/line/LineView.ts b/src/chart/line/LineView.ts index 9672eb720b..be4ff3571e 100644 --- a/src/chart/line/LineView.ts +++ b/src/chart/line/LineView.ts @@ -624,6 +624,8 @@ class LineView extends ChartView { this._symbolDraw = symbolDraw; this._lineGroup = lineGroup; + + this._changePolyState = zrUtil.bind(this._changePolyState, this); } render(seriesModel: LineSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) { @@ -885,9 +887,7 @@ class LineView extends ChartView { toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled); } - const changePolyState = (toState: DisplayState) => { - this._changePolyState(toState); - }; + const changePolyState = this._changePolyState; data.eachItemGraphicEl(function (el) { // Switch polyline / polygon state if element changed its state. From 89a15af59084e1ada5bb984154674e2d6704d6ec Mon Sep 17 00:00:00 2001 From: Zhongxiang Wang Date: Mon, 15 Jul 2024 20:28:40 +0800 Subject: [PATCH 15/22] fix(candelstick): still enable emphasis state by default --- src/chart/candlestick/CandlestickSeries.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/chart/candlestick/CandlestickSeries.ts b/src/chart/candlestick/CandlestickSeries.ts index 141fbf5723..f152fce2cf 100644 --- a/src/chart/candlestick/CandlestickSeries.ts +++ b/src/chart/candlestick/CandlestickSeries.ts @@ -124,8 +124,6 @@ class CandlestickSeriesModel extends SeriesModel { }, emphasis: { - // disable emphasis state by default for forward compatibility - disabled: true, itemStyle: { borderWidth: 2 } From 72e3f8016bad75fc742f5095d9cc18157149cc7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 02:39:06 +0000 Subject: [PATCH 16/22] chore(deps-dev): bump socket.io-parser in /test/runTest Bumps [socket.io-parser](https://github.com/Automattic/socket.io-parser) from 3.3.3 to 3.3.4. - [Release notes](https://github.com/Automattic/socket.io-parser/releases) - [Changelog](https://github.com/socketio/socket.io-parser/blob/3.3.4/CHANGELOG.md) - [Commits](https://github.com/Automattic/socket.io-parser/compare/3.3.3...3.3.4) --- updated-dependencies: - dependency-name: socket.io-parser dependency-type: indirect ... Signed-off-by: dependabot[bot] --- test/runTest/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/runTest/package-lock.json b/test/runTest/package-lock.json index cd221ad51a..2cce4e0929 100644 --- a/test/runTest/package-lock.json +++ b/test/runTest/package-lock.json @@ -2416,9 +2416,9 @@ "dev": true }, "node_modules/socket.io-client/node_modules/socket.io-parser": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz", - "integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.4.tgz", + "integrity": "sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==", "dev": true, "dependencies": { "component-emitter": "~1.3.0", @@ -4724,9 +4724,9 @@ "dev": true }, "socket.io-parser": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz", - "integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.4.tgz", + "integrity": "sha512-z/pFQB3x+EZldRRzORYW1vwVO8m/3ILkswtnpoeU6Ve3cbMWkmHEWDAVJn4QJtchiiFTo5j7UG2QvwxvaA9vow==", "dev": true, "requires": { "component-emitter": "~1.3.0", From 5fb9e9d5ec4785a8da196b4e5208a7161251aa17 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Wed, 24 Jul 2024 14:50:46 +0800 Subject: [PATCH 17/22] fix(axis): ticks overflowing grid area with dataZoom #20185 --- src/coord/axisTickLabelBuilder.ts | 9 +- test/axis-customTicks.html | 186 ++++++++++++++++++++++++++++++ 2 files changed, 193 insertions(+), 2 deletions(-) diff --git a/src/coord/axisTickLabelBuilder.ts b/src/coord/axisTickLabelBuilder.ts index e7f7bbb088..329ad6447b 100644 --- a/src/coord/axisTickLabelBuilder.ts +++ b/src/coord/axisTickLabelBuilder.ts @@ -84,8 +84,11 @@ export function createAxisLabels(axis: Axis): { const custom = axis.getLabelModel().get('customValues'); if (custom) { const labelFormatter = makeLabelFormatter(axis); + const extent = axis.scale.getExtent(); + const tickNumbers = tickValuesToNumbers(axis, custom); + const ticks = zrUtil.filter(tickNumbers, val => val >= extent[0] && val <= extent[1]); return { - labels: tickValuesToNumbers(axis, custom).map(numval => { + labels: zrUtil.map(ticks, numval => { const tick = {value: numval}; return { formattedLabel: labelFormatter(tick), @@ -115,8 +118,10 @@ export function createAxisTicks(axis: Axis, tickModel: AxisBaseModel): { } { const custom = axis.getTickModel().get('customValues'); if (custom) { + const extent = axis.scale.getExtent(); + const tickNumbers = tickValuesToNumbers(axis, custom); return { - ticks: tickValuesToNumbers(axis, custom) + ticks: zrUtil.filter(tickNumbers, val => val >= extent[0] && val <= extent[1]) }; } // Only ordinal scale support tick interval diff --git a/test/axis-customTicks.html b/test/axis-customTicks.html index 24f9c7dc97..7f79f099d8 100644 --- a/test/axis-customTicks.html +++ b/test/axis-customTicks.html @@ -38,6 +38,8 @@
+
+
+ + + + + From ce500cf22a8413452e3d9da1dbe4df499bbf5dc2 Mon Sep 17 00:00:00 2001 From: huanxi Date: Mon, 29 Jul 2024 12:39:41 +0800 Subject: [PATCH 18/22] feature(treemap): add custom cursor properties for treemap (#20113) --- src/chart/treemap/TreemapSeries.ts | 4 +- src/chart/treemap/TreemapView.ts | 3 + test/treemap-cursor.html | 193 +++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 test/treemap-cursor.html diff --git a/src/chart/treemap/TreemapSeries.ts b/src/chart/treemap/TreemapSeries.ts index 571475e714..a38446ed85 100644 --- a/src/chart/treemap/TreemapSeries.ts +++ b/src/chart/treemap/TreemapSeries.ts @@ -144,7 +144,9 @@ export interface TreemapSeriesNodeItemOption extends TreemapSeriesVisualOption, color?: ColorString[] | 'none' - decal?: DecalObject[] | 'none' + decal?: DecalObject[] | 'none', + + cursor?: string } export interface TreemapSeriesOption diff --git a/src/chart/treemap/TreemapView.ts b/src/chart/treemap/TreemapView.ts index bc59c28544..a0b892e1ee 100644 --- a/src/chart/treemap/TreemapView.ts +++ b/src/chart/treemap/TreemapView.ts @@ -877,6 +877,9 @@ function renderNode( // Only for enabling highlight/downplay. data.setItemGraphicEl(thisNode.dataIndex, group); + const cursorStyle = nodeModel.getShallow('cursor'); + cursorStyle && content.attr('cursor', cursorStyle); + enableHoverFocus(group, focusOrIndices, blurScope); } diff --git a/test/treemap-cursor.html b/test/treemap-cursor.html new file mode 100644 index 0000000000..2a415d4ccb --- /dev/null +++ b/test/treemap-cursor.html @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + +
+
+ + + + From aeb078eb769064e8645477f69b860207bfb8a75d Mon Sep 17 00:00:00 2001 From: semla Date: Thu, 1 Aug 2024 12:33:12 +0200 Subject: [PATCH 19/22] feat(aria): allows excluding data in aria-label --- src/util/types.ts | 3 +- src/visual/aria.ts | 4 +- .../spec/series/aria-columns-exclude.test.ts | 97 +++++++++++++++++++ 3 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 test/ut/spec/series/aria-columns-exclude.test.ts diff --git a/src/util/types.ts b/src/util/types.ts index 653b687d91..c29d158747 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -1733,7 +1733,8 @@ export interface AriaLabelOption { separator?: { middle?: string; end?: string; - } + }, + excludeDataId?: number[] } } diff --git a/src/visual/aria.ts b/src/visual/aria.ts index a184776274..d44aa6e4bb 100644 --- a/src/visual/aria.ts +++ b/src/visual/aria.ts @@ -218,11 +218,13 @@ export default function ariaVisual(ecModel: GlobalModel, api: ExtensionAPI) { const middleSeparator = labelModel.get(['data', 'separator', 'middle']); const endSeparator = labelModel.get(['data', 'separator', 'end']); + const excludeDataId = labelModel.get(['data', 'excludeDataId']); const dataLabels = []; for (let i = 0; i < data.count(); i++) { if (i < maxDataCnt) { const name = data.getName(i); - const value = data.getValues(i); + const value = !excludeDataId ? data.getValues(i) + : zrUtil.filter(data.getValues(i), (v, j) => zrUtil.indexOf(excludeDataId, j) === -1); const dataLabel = labelModel.get(['data', name ? 'withName' : 'withoutName']); dataLabels.push( replace(dataLabel, { diff --git a/test/ut/spec/series/aria-columns-exclude.test.ts b/test/ut/spec/series/aria-columns-exclude.test.ts new file mode 100644 index 0000000000..2c91bb5771 --- /dev/null +++ b/test/ut/spec/series/aria-columns-exclude.test.ts @@ -0,0 +1,97 @@ +/* + * 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 { EChartsType } from '@/src/echarts'; +import { createChart, getECModel } from '../../core/utHelper'; + +describe('aria, omit data', function () { + let chart: EChartsType; + const option = { + 'aria': { + 'enabled': true, + 'data': { + 'excludeDataId': [0, 1, 2] + }, + }, + 'dataset': [ + { + 'dimensions': [ + 'lng', + 'lat', + 'name', + 'value', + 'capacity', + ], + 'source': [ + [ + 1.58285827, + 42.099784969, + 'Llosa del Cavall (Navès)', + 17.945, + 80, + ], + [ + 0.960270444, + 41.134931354, + 'Riudecanyes', + 0.401, + 5.32, + ], + ] + + } + ], + 'series': [ + { + 'coordinateSystem': 'geo', + 'encode': { + 'itemName': 'name' + }, + 'type': 'scatter', + } + ], + }; + beforeEach(function () { + chart = createChart(); + }); + + afterEach(function () { + chart.dispose(); + }); + + it('specified columns should be omitted from Aria (geolocation and name)', () => { + chart.setOption(option); + const el = chart.getDom(); + const ariaValue = el.getAttribute('aria-label'); + expect(ariaValue).toContain('Llosa del Cavall (Navès) is 17.945, 80'); + expect(ariaValue).toContain('Riudecanyes is 0.401, 5.32'); + expect(ariaValue).not.toContain(1.58285827); + expect(ariaValue).not.toContain(42.099784969); + expect(ariaValue).not.toContain(0.960270444); + expect(ariaValue).not.toContain(41.134931354); + }); + + it('should not modify the data of the chart', async () => { + chart.setOption(option); + const listData = getECModel(chart).getSeries()[0].getData(); + expect(listData.getValues(0)).toEqual([1.58285827, 42.099784969, 'Llosa del Cavall (Navès)', 17.945, 80]); + expect(listData.getValues(1)).toEqual([0.960270444, 41.134931354, 'Riudecanyes', 0.401, 5.32]); + }); + +}); From b1a237448b11bcb326c3a61339c369c9ccded5ed Mon Sep 17 00:00:00 2001 From: semla Date: Fri, 2 Aug 2024 09:08:53 +0200 Subject: [PATCH 20/22] refactor(aria): rename property to exclude --- src/util/types.ts | 2 +- src/visual/aria.ts | 7 ++++--- test/ut/spec/series/aria-columns-exclude.test.ts | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/util/types.ts b/src/util/types.ts index c29d158747..1d085c198f 100644 --- a/src/util/types.ts +++ b/src/util/types.ts @@ -1734,7 +1734,7 @@ export interface AriaLabelOption { middle?: string; end?: string; }, - excludeDataId?: number[] + excludeDimensionId?: number[] } } diff --git a/src/visual/aria.ts b/src/visual/aria.ts index d44aa6e4bb..33187c4f9d 100644 --- a/src/visual/aria.ts +++ b/src/visual/aria.ts @@ -218,13 +218,14 @@ export default function ariaVisual(ecModel: GlobalModel, api: ExtensionAPI) { const middleSeparator = labelModel.get(['data', 'separator', 'middle']); const endSeparator = labelModel.get(['data', 'separator', 'end']); - const excludeDataId = labelModel.get(['data', 'excludeDataId']); + const excludeDimensionId = labelModel.get(['data', 'excludeDimensionId']); const dataLabels = []; for (let i = 0; i < data.count(); i++) { if (i < maxDataCnt) { const name = data.getName(i); - const value = !excludeDataId ? data.getValues(i) - : zrUtil.filter(data.getValues(i), (v, j) => zrUtil.indexOf(excludeDataId, j) === -1); + const value = !excludeDimensionId ? data.getValues(i) + : zrUtil.filter(data.getValues(i), (v, j) => + zrUtil.indexOf(excludeDimensionId, j) === -1); const dataLabel = labelModel.get(['data', name ? 'withName' : 'withoutName']); dataLabels.push( replace(dataLabel, { diff --git a/test/ut/spec/series/aria-columns-exclude.test.ts b/test/ut/spec/series/aria-columns-exclude.test.ts index 2c91bb5771..08df08f50d 100644 --- a/test/ut/spec/series/aria-columns-exclude.test.ts +++ b/test/ut/spec/series/aria-columns-exclude.test.ts @@ -26,7 +26,7 @@ describe('aria, omit data', function () { 'aria': { 'enabled': true, 'data': { - 'excludeDataId': [0, 1, 2] + 'excludeDimensionId': [0, 1, 2] }, }, 'dataset': [ From 7c7a3ed89a88b0dbdba71dc4e779f5e832a42f15 Mon Sep 17 00:00:00 2001 From: Najam Shehzad Date: Tue, 6 Aug 2024 16:31:12 +0200 Subject: [PATCH 21/22] feat(i18n): add Swedish(SV) translation (#20227) --- src/i18n/langSV.ts | 144 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/i18n/langSV.ts diff --git a/src/i18n/langSV.ts b/src/i18n/langSV.ts new file mode 100644 index 0000000000..83f3874ca9 --- /dev/null +++ b/src/i18n/langSV.ts @@ -0,0 +1,144 @@ +/* + * 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. + */ + +/** + * Language: Swedish. + */ + +export default { + time: { + month: [ + 'januari', 'februari', 'mars', 'april', 'maj', 'juni', + 'juli', 'augusti', 'september', 'oktober', 'november', 'december', + ], + monthAbbr: [ + 'jan', 'feb', 'mar', 'apr', 'maj', 'jun', + 'jul', 'aug', 'sep', 'okt', 'nov', 'dec', + ], + dayOfWeek: [ + 'söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag', + ], + dayOfWeekAbbr: [ + 'sön', 'mån', 'tis', 'ons', 'tor', 'fre', 'lör', + ], + }, + legend: { + selector: { + all: 'Alla', + inverse: 'Omvänd', + }, + }, + toolbox: { + brush: { + title: { + rect: 'Rektangelurval', + polygon: 'Lassomarkering', + lineX: 'Vågrätt urval', + lineY: 'Lodrätt urval', + keep: 'Behåll urval', + clear: 'Rensa urval', + }, + }, + dataView: { + title: 'Datavy', + lang: ['Datavy', 'Stäng', 'Uppdatera'], + }, + dataZoom: { + title: { + zoom: 'Zooma', + back: 'Återställ zoom', + }, + }, + magicType: { + title: { + line: 'Byt till linjediagram', + bar: 'Byt till stapeldiagram', + stack: 'Stapla', + tiled: 'Sida vid sida', + }, + }, + restore: { + title: 'Återställ', + }, + saveAsImage: { + title: 'Spara som bild', + lang: ['Högerklicka för att spara bild'], + }, + }, + series: { + typeNames: { + pie: 'Cirkeldiagram', + bar: 'Stapeldiagram', + line: 'Linjediagram', + scatter: 'Punktdiagram', + effectScatter: 'Punktdiagram med rippeleffekt', + radar: 'Radardiagram', + tree: 'Träd', + treemap: 'Trädkarta', + boxplot: 'Lådagram', + candlestick: 'Candlestick', + k: 'K-linjediagram', + heatmap: 'Värmekarta', + map: 'Karta', + parallel: 'Parallella koordinater', + lines: 'Linjediagram', + graph: 'Relationsgraf', + sankey: 'Sankeydiagram', + funnel: 'Trattdiagram', + gauge: 'Mätare', + pictorialBar: 'Bildstapel', + themeRiver: 'Tematisk flod', + sunburst: 'Solburstdiagram', + custom: 'Anpassat', + chart: 'Diagram', + }, + }, + aria: { + general: { + withTitle: 'Detta är ett diagram om "{title}"', + withoutTitle: 'Detta är ett diagram', + }, + series: { + single: { + prefix: '', + withName: ' med typnamn {name}.', + withoutName: ' med typ {seriesType}.', + }, + multiple: { + prefix: '. Det består av {seriesCount} serier.', + withName: ' Serien {seriesId} är en {seriesType} som representerar {seriesName}.', + withoutName: ' Serien {seriesId} är en {seriesType}.', + separator: { + middle: '', + end: '', + }, + }, + }, + data: { + allData: 'Data är som följer: ', + partialData: 'De första {displayCnt} objekten är: ', + withName: 'datavärdet för {name} är {value}', + withoutName: '{value}', + separator: { + middle: ', ', + end: '. ', + }, + }, + }, + }; \ No newline at end of file From 3bd3c7cf00a6caa8975aa48db87473c2e2949a09 Mon Sep 17 00:00:00 2001 From: Ovilia Date: Mon, 12 Aug 2024 15:12:08 +0800 Subject: [PATCH 22/22] fix(time): bar bandWidth with inversed time axis #20068 --- src/coord/axisHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coord/axisHelper.ts b/src/coord/axisHelper.ts index 53485fb31e..76d42a8d16 100644 --- a/src/coord/axisHelper.ts +++ b/src/coord/axisHelper.ts @@ -115,7 +115,7 @@ function adjustScaleForOverflow( // Get Axis Length const axisExtent = model.axis.getExtent(); - const axisLength = axisExtent[1] - axisExtent[0]; + const axisLength = Math.abs(axisExtent[1] - axisExtent[0]); // Get bars on current base axis and calculate min and max overflow const barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);