@antv/g2
Version:
the Grammar of Graphics in Javascript
198 lines • 7.69 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { deepMix } from '@antv/util';
import { group } from '@antv/vendor/d3-array';
import { subObject } from '../utils/helper';
import { createDatumof, createFindElementByEvent, createUseState, createValueof, createXKey, mergeState, offsetTransform, renderBackground, renderLink, selectElementByData, selectG2Elements, selectPlotArea, VALID_FIND_BY_X_MARKS, } from './utils';
/**
* highlight a group of elements.
*/
export function elementHighlight(root, { elements: elementsof, // given the root of chart returns elements to be manipulated
datum, // given each element returns the datum of it
groupKey: eleGroupKey = (d) => d, // group elements by specified key
regionGroupKey = (d) => d, // how to group elements when hover region
link = false, // draw link or not
background = false, // draw background or not
delay = 60, // delay to unhighlighted element
scale, coordinate, emitter, state = {}, region = false, regionEleFilter = (el) => VALID_FIND_BY_X_MARKS.includes(el.markType), // some elements can not be highlighted by region, like shapes in pie.
}) {
var _a, _b;
const allElements = (_a = elementsof(root)) !== null && _a !== void 0 ? _a : [];
const elements = region ? allElements.filter(regionEleFilter) : allElements;
const elementSet = new Set(elements);
const groupKey = region ? regionGroupKey : eleGroupKey;
const keyGroup = group(elements, groupKey);
const findElement = createFindElementByEvent({
elementsof,
root,
coordinate,
scale,
});
const valueof = createValueof(elements, datum);
const [appendLink, removeLink] = renderLink(Object.assign({ elements,
valueof,
link,
coordinate }, subObject(state.active, 'link')));
const [appendBackground, removeBackground, isBackground] = renderBackground(Object.assign({ document: root.ownerDocument, scale,
coordinate,
background,
valueof }, subObject(state.active, 'background')));
const elementStyle = deepMix(state, {
active: Object.assign({}, (((_b = state.active) === null || _b === void 0 ? void 0 : _b.offset) && {
//Apply translate to mock slice out.
transform: (...params) => {
const value = state.active.offset(...params);
const [, i] = params;
return offsetTransform(elements[i], value, coordinate);
},
})),
});
const useState = createUseState(elementStyle, elements);
const { updateState, removeState, hasState } = useState(valueof);
let out; // Timer for delaying unhighlighted.
const pointerover = (event) => {
const { nativeEvent = true } = event;
let element = event.target;
if (region) {
element = findElement(event);
}
if (!elementSet.has(element))
return;
if (out)
clearTimeout(out);
const k = groupKey(element);
const group = keyGroup.get(k);
const groupSet = new Set(group);
for (const e of elements) {
if (groupSet.has(e)) {
if (!hasState(e, 'active'))
updateState(e, 'active');
}
else {
updateState(e, 'inactive');
removeLink(e);
}
if (e !== element)
removeBackground(e);
}
appendBackground(element);
appendLink(group);
// Emit events.
if (!nativeEvent)
return;
emitter.emit('element:highlight', {
nativeEvent,
data: {
data: datum(element),
group: group.map(datum),
},
});
};
const delayUnhighlighted = () => {
if (out)
clearTimeout(out);
out = setTimeout(() => {
unhighlighted();
out = null;
}, delay);
};
const unhighlighted = (nativeEvent = true) => {
for (const e of elements) {
removeState(e, 'active', 'inactive');
removeBackground(e);
removeLink(e);
}
if (nativeEvent) {
emitter.emit('element:unhighlight', { nativeEvent });
}
};
const pointerout = (event) => {
let element = event.target;
if (region) {
element = findElement(event);
}
if (!element) {
if (delay > 0)
delayUnhighlighted();
else
unhighlighted();
return;
}
if (background && !isBackground(element))
return;
if (!background && !elementSet.has(element))
return;
if (delay > 0)
delayUnhighlighted();
else
unhighlighted();
};
const pointerleave = () => {
unhighlighted();
};
root.addEventListener('pointerover', pointerover);
root.addEventListener('pointermove', pointerover);
root.addEventListener('pointerout', pointerout);
root.addEventListener('pointerleave', pointerleave);
const onRest = (e) => {
const { nativeEvent } = e;
if (nativeEvent)
return;
unhighlighted(false);
};
const onHighlight = (e) => {
const { nativeEvent } = e;
if (nativeEvent)
return;
const { data } = e.data;
const element = selectElementByData(elements, data, datum);
if (!element)
return;
pointerover({ target: element, nativeEvent: false });
};
emitter.on('element:highlight', onHighlight);
emitter.on('element:unhighlight', onRest);
return () => {
root.removeEventListener('pointerover', pointerover);
root.removeEventListener('pointermove', pointerover);
root.removeEventListener('pointerout', pointerout);
root.removeEventListener('pointerleave', pointerleave);
emitter.off('element:highlight', onHighlight);
emitter.off('element:unhighlight', onRest);
for (const e of elements) {
removeBackground(e);
removeLink(e);
}
};
}
export function ElementHighlight(_a) {
var { delay, createGroup, createRegionGroup, background = false, link = false } = _a, rest = __rest(_a, ["delay", "createGroup", "createRegionGroup", "background", "link"]);
return (context, _, emitter) => {
const { container, view, options } = context;
const { scale, coordinate } = view;
const plotArea = selectPlotArea(container);
return elementHighlight(plotArea, Object.assign({ elements: selectG2Elements, datum: createDatumof(view), groupKey: createGroup ? createGroup(view) : undefined, regionGroupKey: createRegionGroup
? createRegionGroup(view)
: createXKey(view), coordinate,
scale, state: mergeState(options, [
['active', background ? {} : { lineWidth: '1', stroke: '#000' }],
'inactive',
]), background,
link,
delay,
emitter }, rest));
};
}
ElementHighlight.props = {
reapplyWhenUpdate: true,
};
//# sourceMappingURL=elementHighlight.js.map