| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import { group } from 'd3-array';
- import { subObject } from '../utils/helper';
- import { mergeState, selectG2Elements, useState, createValueof, createDatumof, } from './utils';
- import { markerOf, labelOf, itemsOf, legendsOf, dataOf } from './legendFilter';
- export function LegendHighlight() {
- return (context, _, emitter) => {
- const { container, view, options } = context;
- const legends = legendsOf(container);
- const elements = selectG2Elements(container);
- const channelOf = (legend) => {
- return dataOf(legend).scales[0].name;
- };
- const scaleOf = (channel) => {
- const { scale: { [channel]: scale }, } = view;
- return scale;
- };
- const markState = mergeState(options, ['active', 'inactive']);
- const valueof = createValueof(elements, createDatumof(view));
- const destroys = [];
- // Bind events for each legend.
- for (const legend of legends) {
- const datumOf = (item) => {
- const { data } = legend.attributes;
- const { __data__: datum } = item;
- const { index } = datum;
- return data[index].label;
- };
- const channel = channelOf(legend);
- const items = itemsOf(legend);
- const scale = scaleOf(channel);
- const elementGroup = group(elements, (d) => scale.invert(d.__data__[channel]));
- const { state: legendState = {} } = legend.attributes;
- const { inactive = {} } = legendState;
- const { setState, removeState } = useState(markState, valueof);
- // Handle styles of inner item.
- const markerStyle = { inactive: subObject(inactive, 'marker') };
- const labelStyle = { inactive: subObject(inactive, 'label') };
- const { setState: setM, removeState: removeM } = useState(markerStyle);
- const { setState: setL, removeState: removeL } = useState(labelStyle);
- const updateLegendState = (highlight) => {
- for (const item of items) {
- const marker = markerOf(item);
- const label = labelOf(item);
- if (item === highlight || highlight === null) {
- removeM(marker, 'inactive');
- removeL(label, 'inactive');
- }
- else {
- setM(marker, 'inactive');
- setL(label, 'inactive');
- }
- }
- };
- const highlightItem = (event, item) => {
- // Update UI.
- const value = datumOf(item);
- const elementSet = new Set(elementGroup.get(value));
- for (const e of elements) {
- if (elementSet.has(e))
- setState(e, 'active');
- else
- setState(e, 'inactive');
- }
- updateLegendState(item);
- // Emit events.
- const { nativeEvent = true } = event;
- if (!nativeEvent)
- return;
- emitter.emit('legend:highlight', Object.assign(Object.assign({}, event), { nativeEvent, data: { channel, value } }));
- };
- const itemPointerover = new Map();
- // Add listener for the legend items.
- for (const item of items) {
- const pointerover = (event) => {
- highlightItem(event, item);
- };
- item.addEventListener('pointerover', pointerover);
- itemPointerover.set(item, pointerover);
- }
- // Add listener for the legend group.
- const pointerleave = (event) => {
- for (const e of elements)
- removeState(e, 'inactive', 'active');
- updateLegendState(null);
- // Emit events.
- const { nativeEvent = true } = event;
- if (!nativeEvent)
- return;
- emitter.emit('legend:unhighlight', { nativeEvent });
- };
- const onHighlight = (event) => {
- const { nativeEvent, data } = event;
- if (nativeEvent)
- return;
- const { channel: specifiedChannel, value } = data;
- if (specifiedChannel !== channel)
- return;
- const item = items.find((d) => datumOf(d) === value);
- if (!item)
- return;
- highlightItem({ nativeEvent: false }, item);
- };
- const onUnHighlight = (event) => {
- const { nativeEvent } = event;
- if (nativeEvent)
- return;
- pointerleave({ nativeEvent: false });
- };
- legend.addEventListener('pointerleave', pointerleave);
- emitter.on('legend:highlight', onHighlight);
- emitter.on('legend:unhighlight', onUnHighlight);
- const destroy = () => {
- legend.removeEventListener(pointerleave);
- emitter.off('legend:highlight', onHighlight);
- emitter.off('legend:unhighlight', onUnHighlight);
- for (const [item, pointerover] of itemPointerover) {
- item.removeEventListener(pointerover);
- }
- };
- destroys.push(destroy);
- }
- return () => destroys.forEach((d) => d());
- };
- }
- //# sourceMappingURL=legendHighlight.js.map
|