Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/select interactions #434

Merged
merged 2 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 21 additions & 40 deletions packages/vgrammar-core/src/interactions/element-select.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isNumber, isString } from '@visactor/vutils';
import { isArray } from '@visactor/vutils';
import { InteractionStateEnum } from '../graph/enums';
import type {
ElementSelectOptions,
Expand All @@ -10,7 +10,7 @@ import type {
IView,
InteractionEvent
} from '../types';
import { groupMarksByState } from './utils';
import { groupMarksByState, parseTriggerOffOfSelect } from './utils';
import { BaseInteraction } from './base';

export interface ElementSelect extends IToggleStateMixin, BaseInteraction<ElementSelectOptions> {}
Expand All @@ -23,7 +23,7 @@ export class ElementSelect extends BaseInteraction<ElementSelectOptions> {
state: InteractionStateEnum.selected,
trigger: 'click'
};
protected _resetType?: 'view' | 'self' | 'timeout';
protected _resetType: ('view' | 'self' | 'timeout')[] = [];
protected _marks?: IMark[];
protected _stateMarks: Record<string, IMark[]>;
private _timer?: number;
Expand Down Expand Up @@ -52,35 +52,15 @@ export class ElementSelect extends BaseInteraction<ElementSelectOptions> {
}
];

let eventName = triggerOff;
const { eventNames, resetType } = parseTriggerOffOfSelect(triggerOff);

if (triggerOff === 'empty') {
eventName = trigger as EventType;

this._resetType = 'view';
} else if (triggerOff === 'none') {
eventName = null;
this._resetType = null;
} else if (isString(triggerOff)) {
if ((triggerOff as string).includes('view:')) {
eventName = (triggerOff as string).replace('view:', '') as EventType;

this._resetType = 'view';
} else {
eventName = triggerOff;

this._resetType = 'self';
eventNames.forEach(evt => {
if (evt && (isArray(trigger) ? !trigger.includes(evt) : evt !== trigger)) {
events.push({ type: evt as EventType, handler: this.handleReset });
}
} else if (isNumber(triggerOff)) {
eventName = null;
this._resetType = 'timeout';
} else {
this._resetType = null;
}
});

if (eventName && eventName !== trigger) {
events.push({ type: eventName as EventType, handler: this.handleReset });
}
this._resetType = resetType;

return events;
}
Expand Down Expand Up @@ -108,13 +88,14 @@ export class ElementSelect extends BaseInteraction<ElementSelectOptions> {
const { state, reverseState, isMultiple } = this.options;
if (element && this._marks && this._marks.includes(element.mark)) {
if (element.hasState(state)) {
if (this._resetType === 'self') {
this._statedElements = this.updateStates(
this._statedElements && this._statedElements.filter(el => el !== element),
this._statedElements,
state,
reverseState
);
if (this._resetType.includes('self')) {
const newStatedElements = this._statedElements && this._statedElements.filter(el => el !== element);

if (newStatedElements && newStatedElements.length) {
this._statedElements = this.updateStates(newStatedElements, this._statedElements, state, reverseState);
} else {
this.clearPrevElements();
}
}
} else {
if (this._timer) {
Expand All @@ -130,13 +111,13 @@ export class ElementSelect extends BaseInteraction<ElementSelectOptions> {
);
this.dispatchEvent('start', { elements: this._statedElements, options: this.options });

if (this._resetType === 'timeout') {
if (this._resetType.includes('timeout')) {
this._timer = setTimeout(() => {
this.clearPrevElements();
}, this.options.triggerOff as number) as unknown as number;
}
}
} else if (this._resetType === 'view' && this._statedElements && this._statedElements.length) {
} else if (this._resetType.includes('view') && this._statedElements && this._statedElements.length) {
this.clearPrevElements();
}
}
Expand All @@ -148,9 +129,9 @@ export class ElementSelect extends BaseInteraction<ElementSelectOptions> {

const hasActiveElement = element && this._marks && this._marks.includes(element.mark);

if (this._resetType === 'view' && !hasActiveElement) {
if (this._resetType.includes('view') && !hasActiveElement) {
this.clearPrevElements();
} else if (this._resetType === 'self' && hasActiveElement) {
} else if (this._resetType.includes('self') && hasActiveElement) {
this.clearPrevElements();
}
}
Expand Down
32 changes: 31 additions & 1 deletion packages/vgrammar-core/src/interactions/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { ElementFilterOptions, IElement, IMark, MarkSpec } from '../types';
import { array, isNumber, isString } from '@visactor/vutils';
import type { ElementFilterOptions, ElementSelectTriggerOff, EventType, IElement, IMark, MarkSpec } from '../types';

export const generateFilterValue = (options: ElementFilterOptions) => {
if (options.filterField) {
Expand Down Expand Up @@ -40,3 +41,32 @@ export const groupMarksByState = (marks: IMark[], states: string[]): Record<stri

return res;
};

export const parseTriggerOffOfSelect = (triggerOff: ElementSelectTriggerOff | ElementSelectTriggerOff[]) => {
const triggerOffArray = array(triggerOff);
const resetType: ('view' | 'self' | 'timeout')[] = [];
const eventNames: EventType[] = [];

triggerOffArray.forEach(off => {
if (off === 'empty') {
resetType.push('view');
} else if (isString(off) && off !== 'none') {
if ((off as string).includes('view:')) {
eventNames.push((off as string).replace('view:', '') as EventType);

resetType.push('view');
} else {
eventNames.push(off as EventType);

resetType.push('self');
}
} else if (isNumber(off)) {
resetType.push('timeout');
}
});

return {
eventNames,
resetType
};
};
4 changes: 3 additions & 1 deletion packages/vgrammar-core/src/types/interaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ export interface ElementActiveOptions extends IBaseInteractionOptions {
state?: string;
}

export type ElementSelectTriggerOff = EventType | ViewEventType | 'empty' | 'none' | number;

/**
* the interaction to set the seleted state of specified marks
*/
Expand All @@ -104,7 +106,7 @@ export interface ElementSelectOptions extends IBaseInteractionOptions {
/**
* the reset trigger event name
*/
triggerOff?: EventType | EventType[] | ViewEventType | 'empty' | 'none' | number;
triggerOff?: ElementSelectTriggerOff | ElementSelectTriggerOff[];
/**
* whether or not support multiple selected
*/
Expand Down
1 change: 1 addition & 0 deletions packages/vgrammar-core/src/view/View.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,7 @@ export default class View extends EventEmitter implements IView {
this._unBindResizeEvent();
this.clearProgressive();
Factory.unregisterRuntimeTransforms();
Logger.setInstance(null);

this.animate.stop();

Expand Down
Loading