Skip to content

Commit

Permalink
Merge pull request #20129 from apache/fix/legend-action-isolation
Browse files Browse the repository at this point in the history
fix(legend): fix legend action is not isolated from other legend components
  • Loading branch information
linghaoSu committed Jul 16, 2024
2 parents 4d3cb2c + 13fe1d9 commit 89cfb36
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 38 deletions.
3 changes: 2 additions & 1 deletion src/component/legend/LegendView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ class LegendView extends ComponentView {
},
onclick() {
api.dispatchAction({
type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect'
type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect',
legendId: legendModel.id
});
}
});
Expand Down
96 changes: 59 additions & 37 deletions src/component/legend/legendAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,59 +17,81 @@
* 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' | 'allSelect' | 'inverseSelect';

function legendSelectActionHandler(methodName, payload, ecModel) {
const selectedMap = {};
const isToggleSelect = methodName === 'toggleSelected';
let isSelected;
// Update all legend components
ecModel.eachComponent('legend', function (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') {
function legendSelectActionHandler(methodName: LegendSelectMethodNames, payload: Payload, ecModel: GlobalModel) {
const isAllSelect = methodName === 'allSelect' || methodName === 'inverseSelect';
const selectedMap: Record<string, boolean> = {};

const actionLegendIndices: number[] = [];
ecModel.eachComponent({ mainType: 'legend', query: payload }, function (legendModel: LegendModel) {
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 (selectedMap.hasOwnProperty(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<string, boolean> = {};

// 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: allSelectedMap,
// return legendIndex array to tell the developers which legends are allSelect / inverseSelect
legendIndex: actionLegendIndices
}
: {
name: payload.name,
selected: selectedMap
selected: allSelectedMap
};
}

export function installLegendAction(registers) {
function makeSelectedMap(legendModel: LegendModel, out?: Record<string, boolean>) {
const selectedMap: Record<string, boolean> = 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
* @type {Object}
Expand Down Expand Up @@ -113,4 +135,4 @@ export function installLegendAction(registers) {
'legendUnSelect', 'legendunselected',
curry(legendSelectActionHandler, 'unSelect')
);
}
}
136 changes: 136 additions & 0 deletions test/legend-action.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/runTest/actions/__meta__.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/runTest/actions/legend-action.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 89cfb36

Please sign in to comment.