UNPKG

billboard.js

Version:

Re-usable easy interface JavaScript chart library, based on D3 v4+

164 lines (163 loc) • 5.45 kB
/*! * Copyright (c) 2017 ~ present NAVER Corp. * billboard.js project is licensed under the MIT license * * billboard.js, JavaScript chart library * https://naver.github.io/billboard.js/ * * @version 4.1.1 */ import { diffDomain } from "../../module/util/type-checks.js"; import classes_default from "../../config/classes.js"; import { generateWait } from "../../module/generator.js"; //#region src/ChartInternal/interactions/flow.ts /** * Copyright (c) 2017 ~ present NAVER Corp. * billboard.js project is licensed under the MIT license */ var flow_default = { /** * Generate flow * @param {object} args option object * @returns {function} * @private */ generateFlow(args) { const $$ = this; const { data, state, $el } = $$; return function() { const flowLength = args.flow.length; state.flowing = true; data.targets.forEach((d) => { d.values.splice(0, flowLength); }); state.dataGeneration++; if ($$.updateXGrid) $$.updateXGrid(true); const elements = {}; [ "axis.x", "grid.x", "gridLines.x", "region.list", "text", "bar", "line", "area", "circle" ].forEach((v) => { const name = v.split("."); let node = $el[name[0]]; if (node && name.length > 1) node = node[name[1]]; if (node?.size()) elements[v] = node; }); $$.hideGridFocus?.(); $$.setFlowList(elements, args); }; }, /** * Set flow list * @param {object} elements Target elements * @param {object} args option object * @private */ setFlowList(elements, args) { const $$ = this; const { flow, targets } = args; const { duration = args.duration, index: flowIndex, length: flowLength, orgDataCount } = flow; const transform = $$.getFlowTransform(targets, orgDataCount, flowIndex, flowLength); const wait = generateWait(); let n; wait.add(Object.keys(elements).map((v) => { n = elements[v].transition().ease((t) => +t).duration(duration); if (v === "axis.x") n = n.call((g) => { $$.axis.x.setTransition(g).create(g); }); else if (v === "region.list") n = n.filter($$.isRegionOnX).attr("transform", transform); else n = n.attr("transform", transform); return n; })); n.call(wait, () => { $$.cleanUpFlow(elements, args); }); }, /** * Clean up flow * @param {object} elements Target elements * @param {object} args option object * @private */ cleanUpFlow(elements, args) { const $$ = this; const { config, state, $el: { svg } } = $$; const isRotated = config.axis_rotated; const { flow, shape, xv } = args; const { cx, cy, xForText, yForText } = shape.pos; const { done = () => {}, length: flowLength } = flow; if (flowLength) { [ "circle", "text", "shape", "eventRect" ].forEach((v) => { const target = []; for (let i = 0; i < flowLength; i++) target.push(`.${classes_default[v]}-${i}`); svg.selectAll(`.${classes_default[`${v}s`]}`).selectAll(target).remove(); }); svg.select(`.${classes_default.xgrid}`).remove(); } Object.keys(elements).forEach((v) => { const n = elements[v]; if (v !== "axis.x") n.attr("transform", null); if (v === "grid.x") n.attr(state.xgridAttr); else if (v === "gridLines.x") { n.attr("x1", isRotated ? 0 : xv).attr("x2", isRotated ? state.width : xv); n.select("text").attr("x", isRotated ? state.width : 0).attr("y", xv); } else if (/^(area|bar|line)$/.test(v)) n.attr("d", shape.type[v]); else if (v === "text") n.attr("x", xForText).attr("y", yForText).style("fill-opacity", $$.opacityForText.bind($$)); else if (v === "circle") { if ($$.isCirclePoint()) n.attr("cx", cx).attr("cy", cy); else { const xFunc = (d) => cx(d) - config.point_r; const yFunc = (d) => cy(d) - config.point_r; n.attr("x", xFunc).attr("y", yFunc); } } else if (v === "region.list") n.select("rect").filter($$.isRegionOnX).attr("x", $$.regionX.bind($$)).attr("width", $$.regionWidth.bind($$)); }); config.interaction_enabled && $$.redrawEventRect(); done.call($$.api); state.flowing = false; }, /** * Get flow transform value * @param {object} targets target * @param {number} orgDataCount original data count * @param {number} flowIndex flow index * @param {number} flowLength flow length * @returns {string} * @private */ getFlowTransform(targets, orgDataCount, flowIndex, flowLength) { const $$ = this; const { data, scale: { x } } = $$; const dataValues = data.targets[0].values; let flowStart = $$.getValueOnIndex(dataValues, flowIndex); let flowEnd = $$.getValueOnIndex(dataValues, flowIndex + flowLength); let translateX; const orgDomain = x.domain(); const domain = $$.updateXDomain(targets, true, true); if (!orgDataCount) { if (dataValues.length !== 1) translateX = x(orgDomain[0]) - x(domain[0]); else if ($$.axis.isTimeSeries()) { flowStart = $$.getValueOnIndex(dataValues, 0); flowEnd = $$.getValueOnIndex(dataValues, dataValues.length - 1); translateX = x(flowStart.x) - x(flowEnd.x); } else translateX = diffDomain(domain) / 2; } else if (orgDataCount === 1 || flowStart?.x === flowEnd?.x) translateX = x(orgDomain[0]) - x(domain[0]); else translateX = $$.axis.isTimeSeries() ? x(orgDomain[0]) - x(domain[0]) : x(flowStart?.x || 0) - x(flowEnd.x); const scaleX = diffDomain(orgDomain) / diffDomain(domain); return `translate(${translateX},0) scale(${scaleX},1)`; } }; //#endregion export { flow_default as default };