UNPKG

@antv/g2

Version:

the Grammar of Graphics in Javascript

179 lines 8.67 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.SliderFilter = exports.SLIDER_CLASS_NAME = void 0; const util_1 = require("@antv/util"); const g_1 = require("@antv/g"); const coordinate_1 = require("../utils/coordinate"); const scale_1 = require("../utils/scale"); exports.SLIDER_CLASS_NAME = 'slider'; function filterDataByDomain(options, scaleOptions, prefix, hasState = false, channel0 = 'x', channel1 = 'y') { const { marks } = options; const newMarks = marks.map((mark) => { var _a, _b; return (0, util_1.deepMix)({ // Hide label to keep smooth transition. axis: { x: { transform: [{ type: 'hide' }] }, y: { transform: [{ type: 'hide' }] }, }, }, mark, { scale: scaleOptions, // Don't rerender sliders. [prefix]: Object.assign(Object.assign({}, (((_a = mark[prefix]) === null || _a === void 0 ? void 0 : _a[channel0]) && { [channel0]: Object.assign({ preserve: true }, (hasState && { ratio: null })), })), (((_b = mark[prefix]) === null || _b === void 0 ? void 0 : _b[channel1]) && { [channel1]: { preserve: true }, })), animate: false, }); }); // Rerender and update view. return Object.assign(Object.assign({}, options), { marks: newMarks, clip: true, animate: false }); } function abstractValue(values, scale, reverse) { const [x, x1] = values; const v = reverse ? (d) => 1 - d : (d) => d; const d0 = (0, scale_1.invert)(scale, v(x), true); const d1 = (0, scale_1.invert)(scale, v(x1), false); return (0, scale_1.domainOf)(scale, [d0, d1]); } function extentOf(domain) { return [domain[0], domain[domain.length - 1]]; } /** * @todo Support click to reset after fix click and dragend conflict. */ function SliderFilter({ initDomain = {}, className = exports.SLIDER_CLASS_NAME, prefix = 'slider', setValue = (component, values) => component.setValues(values), hasState = false, wait = 50, leading = true, trailing = false, getInitValues = (slider) => { var _a; const values = (_a = slider === null || slider === void 0 ? void 0 : slider.attributes) === null || _a === void 0 ? void 0 : _a.values; if (values[0] !== 0 || values[1] !== 1) return values; }, }) { return (context, _, emitter) => { const { container, view, update, setState } = context; const sliders = container.getElementsByClassName(className); if (!sliders.length) return () => { }; let filtering = false; const { scale, coordinate, layout } = view; const { paddingLeft, paddingTop, paddingBottom, paddingRight } = layout; const { x: scaleX, y: scaleY } = scale; const transposed = (0, coordinate_1.isTranspose)(coordinate); const channelOf = (orientation) => { const channel0 = orientation === 'vertical' ? 'y' : 'x'; const channel1 = orientation === 'vertical' ? 'x' : 'y'; if (transposed) return [channel1, channel0]; return [channel0, channel1]; }; const sliderHandler = new Map(); const emitHandlers = new Set(); // Store current domain of x and y scale. const channelDomain = { x: initDomain.x || scaleX.getOptions().domain, y: initDomain.y || scaleY.getOptions().domain, }; for (const slider of sliders) { const { orientation } = slider.attributes; const [channel0, channel1] = channelOf(orientation); const eventName = `${prefix}${(0, util_1.upperFirst)(channel0)}:filter`; const isX = channel0 === 'x'; const { ratio: ratioX } = scaleX.getOptions(); const { ratio: ratioY } = scaleY.getOptions(); const domainsOf = (event) => { // From abstract values. if (event.data) { const { selection } = event.data; const [X = extentOf(channelDomain.x), Y = extentOf(channelDomain.y)] = selection; return isX ? [(0, scale_1.domainOf)(scaleX, X, ratioX), (0, scale_1.domainOf)(scaleY, Y, ratioY)] : [(0, scale_1.domainOf)(scaleY, Y, ratioY), (0, scale_1.domainOf)(scaleX, X, ratioX)]; } // From visual values. const { value: values } = event.detail; const scale0 = scale[channel0]; const domain0 = abstractValue(values, scale0, transposed && orientation === 'horizontal'); const domain1 = channelDomain[channel1]; return [domain0, domain1]; }; const onValueChange = (0, util_1.throttle)((event) => __awaiter(this, void 0, void 0, function* () { const { initValue = false } = event; if (filtering && !initValue) return; filtering = true; const { nativeEvent = true } = event; // Get and update domain. const [domain0, domain1] = domainsOf(event); channelDomain[channel0] = domain0; channelDomain[channel1] = domain1; if (nativeEvent) { // Emit events. const X = isX ? domain0 : domain1; const Y = isX ? domain1 : domain0; emitter.emit(eventName, Object.assign(Object.assign({}, event), { nativeEvent, data: { selection: [extentOf(X), extentOf(Y)] } })); } setState(slider, (options) => (Object.assign(Object.assign({}, filterDataByDomain(options, // Set nice to false to avoid modify domain. // Only update domain of current slider / scrollbar. { [channel0]: { domain: domain0, nice: false } }, prefix, hasState, channel0, channel1)), { paddingLeft, paddingTop, paddingBottom, paddingRight }))); yield update(); filtering = false; }), wait, { leading, trailing }); const emitHandler = (event) => { const { nativeEvent } = event; if (nativeEvent) return; const { data } = event; const { selection } = data; const [X, Y] = selection; // Update data. slider.dispatchEvent(new g_1.CustomEvent('valuechange', { data, nativeEvent: false, })); // Update slider. const V = isX ? (0, scale_1.abstractOf)(X, scaleX) : (0, scale_1.abstractOf)(Y, scaleY); setValue(slider, V); }; emitter.on(eventName, emitHandler); slider.addEventListener('valuechange', onValueChange); sliderHandler.set(slider, onValueChange); emitHandlers.add([eventName, emitHandler]); const values = getInitValues(slider); if (values) { // Init values. slider.dispatchEvent(new g_1.CustomEvent('valuechange', { detail: { value: values, }, nativeEvent: false, initValue: true, })); } } // Update to async state such as scale. update(); return () => { for (const [slider, handler] of sliderHandler) { slider.removeEventListener('valuechange', handler); } for (const [name, handler] of emitHandlers) { emitter.off(name, handler); } }; }; } exports.SliderFilter = SliderFilter; //# sourceMappingURL=sliderFilter.js.map