UNPKG

@antv/g2

Version:

the Grammar of Graphics in Javascript

303 lines 12.6 kB
"use strict"; 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FacetRect = exports.createInnerGuide = exports.setChildren = exports.setData = exports.toCell = exports.setStyle = exports.setAnimation = exports.inferColor = void 0; const util_1 = require("@antv/util"); const d3_array_1 = require("d3-array"); const vector_1 = require("../utils/vector"); const container_1 = require("../utils/container"); const array_1 = require("../utils/array"); const utils_1 = require("./utils"); const setScale = (0, utils_1.useDefaultAdaptor)((options) => { const { encode, data, scale, shareSize = false } = options; const { x, y } = encode; const flexDomain = (encode, channel) => { var _a; if (encode === undefined || !shareSize) return {}; const groups = (0, d3_array_1.group)(data, (d) => d[encode]); const domain = ((_a = scale === null || scale === void 0 ? void 0 : scale[channel]) === null || _a === void 0 ? void 0 : _a.domain) || Array.from(groups.keys()); const flex = domain.map((key) => { if (!groups.has(key)) return 1; return groups.get(key).length; }); return { domain, flex }; }; return { scale: { x: Object.assign(Object.assign({ paddingOuter: 0, paddingInner: 0.1, guide: x === undefined ? null : { position: 'top' } }, (x === undefined && { paddingInner: 0 })), flexDomain(x, 'x')), y: Object.assign(Object.assign({ range: [0, 1], paddingOuter: 0, paddingInner: 0.1, guide: y === undefined ? null : { position: 'right' } }, (y === undefined && { paddingInner: 0 })), flexDomain(y, 'y')), }, }; }); /** * BFS view tree and using the last discovered color encode * as the top-level encode for this plot. This is useful when * color encode and color scale is specified in mark node. * It makes sense because the whole facet should shared the same * color encoding, but it also can be override with explicity * encode and scale specification. */ exports.inferColor = (0, utils_1.useDefaultAdaptor)((options) => { const { data, scale } = options; const discovered = [options]; let encodeColor; let scaleColor; let legendColor; while (discovered.length) { const node = discovered.shift(); const { children, encode = {}, scale = {}, legend = {} } = node; const { color: c } = encode; const { color: cs } = scale; const { color: cl } = legend; if (c !== undefined) encodeColor = c; if (cs !== undefined) scaleColor = cs; if (cl !== undefined) legendColor = cl; if (Array.isArray(children)) { discovered.push(...children); } } const domainColor = () => { var _a; const domain = (_a = scale === null || scale === void 0 ? void 0 : scale.color) === null || _a === void 0 ? void 0 : _a.domain; if (domain !== undefined) return [domain]; if (encodeColor === undefined) return [undefined]; const color = typeof encodeColor === 'function' ? encodeColor : (d) => d[encodeColor]; const values = data.map(color); if (values.some((d) => typeof d === 'number')) return [(0, d3_array_1.extent)(values)]; return [Array.from(new Set(values)), 'ordinal']; }; const title = typeof encodeColor === 'string' ? encodeColor : ''; const [domain, type] = domainColor(); return { encode: { color: encodeColor }, scale: { color: (0, util_1.deepMix)({}, scaleColor, { domain, type }) }, legend: { color: (0, util_1.deepMix)({ title }, legendColor) }, }; }); exports.setAnimation = (0, utils_1.useDefaultAdaptor)(() => ({ animate: { enterType: 'fadeIn', }, })); exports.setStyle = (0, utils_1.useOverrideAdaptor)(() => ({ frame: false, encode: { shape: 'hollow', }, style: { lineWidth: 0, }, })); exports.toCell = (0, utils_1.useOverrideAdaptor)(() => ({ type: 'cell', })); /** * Do not set cell data directly, the children will get wrong do if do * so. Use transform to set new data. **/ exports.setData = (0, utils_1.useOverrideAdaptor)((options) => { const { data } = options; const connector = { type: 'custom', callback: () => { const { data, encode } = options; const { x, y } = encode; const X = x ? Array.from(new Set(data.map((d) => d[x]))) : []; const Y = y ? Array.from(new Set(data.map((d) => d[y]))) : []; const cellData = () => { if (X.length && Y.length) { const cellData = []; for (const vx of X) { for (const vy of Y) { cellData.push({ [x]: vx, [y]: vy }); } } return cellData; } if (X.length) return X.map((d) => ({ [x]: d })); if (Y.length) return Y.map((d) => ({ [y]: d })); }; return cellData(); }, }; return { data: { type: 'inline', value: data, transform: [connector] }, }; }); /** * @todo Move some options assignment to runtime. */ exports.setChildren = (0, utils_1.useOverrideAdaptor)((options, subLayout = subLayoutRect, createGuideX = createGuideXRect, createGuideY = createGuideYRect, childOptions = {}) => { const { data: dataValue, encode, children, scale: facetScale, x: originX = 0, y: originY = 0, shareData = false, key: viewKey, } = options; const { value: data } = dataValue; // Only support field encode now. const { x: encodeX, y: encodeY } = encode; const { color: facetScaleColor } = facetScale; const { domain: facetDomainColor } = facetScaleColor; const createChildren = (visualData, scale, layout) => { const { x: scaleX, y: scaleY } = scale; const { paddingLeft, paddingTop, marginLeft, marginTop } = layout; const { domain: domainX } = scaleX.getOptions(); const { domain: domainY } = scaleY.getOptions(); const index = (0, array_1.indexOf)(visualData); const bboxs = visualData.map(subLayout); const values = visualData.map(({ x, y }) => [ scaleX.invert(x), scaleY.invert(y), ]); const filters = values.map(([fx, fy]) => (d) => { const { [encodeX]: x, [encodeY]: y } = d; const inX = encodeX !== undefined ? x === fx : true; const inY = encodeY !== undefined ? y === fy : true; return inX && inY; }); const facetData2d = filters.map((f) => data.filter(f)); const maxDataDomain = shareData ? (0, d3_array_1.max)(facetData2d, (data) => data.length) : undefined; const facets = values.map(([fx, fy]) => ({ columnField: encodeX, columnIndex: domainX.indexOf(fx), columnValue: fx, columnValuesLength: domainX.length, rowField: encodeY, rowIndex: domainY.indexOf(fy), rowValue: fy, rowValuesLength: domainY.length, })); const normalizedChildren = facets.map((facet) => { if (Array.isArray(children)) return children; return [children(facet)].flat(1); }); return index.flatMap((i) => { const [left, top, width, height] = bboxs[i]; const facet = facets[i]; const facetData = facetData2d[i]; const children = normalizedChildren[i]; return children.map((_a) => { var _b, _c; var { scale, key, facet: isFacet = true, axis = {}, legend = {} } = _a, rest = __rest(_a, ["scale", "key", "facet", "axis", "legend"]); const guideY = ((_b = scale === null || scale === void 0 ? void 0 : scale.y) === null || _b === void 0 ? void 0 : _b.guide) || axis.y; const guideX = ((_c = scale === null || scale === void 0 ? void 0 : scale.x) === null || _c === void 0 ? void 0 : _c.guide) || axis.x; const defaultScale = { x: { tickCount: encodeX ? 5 : undefined }, y: { tickCount: encodeY ? 5 : undefined }, }; const newData = isFacet ? facetData : facetData.length === 0 ? [] : data; const newScale = { color: { domain: facetDomainColor }, }; const newAxis = { x: createGuide(guideX, createGuideX)(facet, newData), y: createGuide(guideY, createGuideY)(facet, newData), }; return Object.assign(Object.assign({ key: `${key}-${i}`, data: newData, margin: 0, x: left + paddingLeft + originX + marginLeft, y: top + paddingTop + originY + marginTop, parentKey: viewKey, width, height, paddingLeft: 0, paddingRight: 0, paddingTop: 0, paddingBottom: 0, frame: newData.length ? true : false, dataDomain: maxDataDomain, scale: (0, util_1.deepMix)(defaultScale, scale, newScale), axis: (0, util_1.deepMix)({}, axis, newAxis), // Hide all legends for child mark by default, // they are displayed in the top-level. legend: false }, rest), childOptions); }); }); }; return { children: createChildren, }; }); function subLayoutRect(data) { const { points } = data; return (0, vector_1.calcBBox)(points); } /** * Inner guide not show title, tickLine, label and subTickLine, * if data is empty, do not show guide. */ function createInnerGuide(guide, data) { return data.length ? (0, util_1.deepMix)({ title: false, tick: null, label: null, }, guide) : (0, util_1.deepMix)({ title: false, tick: null, label: null, grid: null, }, guide); } exports.createInnerGuide = createInnerGuide; function createGuideXRect(guide) { return (facet, data) => { const { rowIndex, rowValuesLength, columnIndex, columnValuesLength } = facet; // Only the bottom-most facet show axisX. if (rowIndex !== rowValuesLength - 1) return createInnerGuide(guide, data); // Only the bottom-left facet show title. const title = columnIndex !== columnValuesLength - 1 ? false : undefined; // If data is empty, do not show cell. const grid = data.length ? undefined : null; return (0, util_1.deepMix)({ title, grid }, guide); }; } function createGuideYRect(guide) { return (facet, data) => { const { rowIndex, columnIndex } = facet; // Only the left-most facet show axisY. if (columnIndex !== 0) return createInnerGuide(guide, data); // Only the left-top facet show title. const title = rowIndex !== 0 ? false : undefined; // If data is empty, do not show cell. const grid = data.length ? undefined : null; return (0, util_1.deepMix)({ title, grid }, guide); }; } function createGuide(guide, factory) { if (typeof guide === 'function') return guide; if (guide === null || guide === false) return () => null; return factory(guide); } const FacetRect = () => { return (options) => { const newOptions = container_1.Container.of(options) .call(exports.toCell) .call(exports.inferColor) .call(exports.setAnimation) .call(setScale) .call(exports.setStyle) .call(exports.setData) .call(exports.setChildren) .value(); return [newOptions]; }; }; exports.FacetRect = FacetRect; exports.FacetRect.props = {}; //# sourceMappingURL=facetRect.js.map