billboard.js
Version:
Re-usable easy interface JavaScript chart library, based on D3 v4+
211 lines (210 loc) • 8.96 kB
JavaScript
/*!
* 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 { notEmpty } from "../../module/util/type-checks.js";
import { callFn, capitalize, getOption } from "../../module/util/object.js";
import { isTabVisible } from "../../module/util/dom.js";
import { $COMMON, $SELECT, $TEXT } from "../../config/classes.js";
import { KEY } from "../../module/Cache.js";
import { generateWait } from "../../module/generator.js";
import { transition } from "d3-transition";
//#region src/ChartInternal/internals/redraw.ts
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
var redraw_default = {
redraw(options = {}) {
const $$ = this;
const { config, state, $el } = $$;
const { main, treemap } = $el;
state.redrawing = true;
state.redrawGeneration++;
if (state.dirty.data || state.dirty.visibility || options.initializing) state.dataGeneration++;
if (options.initializing || state.dirty.size || state.dirty.data || !state.rendered) $$.cache.remove([KEY.svgLeft]);
const targetsToShow = $$.filterTargetsToShow($$.data.targets);
state._targetsToShow = targetsToShow;
const dirtySnapshot = {
data: state.dirty.data,
visibility: state.dirty.visibility,
size: state.dirty.size
};
state.dirty.data = false;
state.dirty.visibility = false;
state.dirty.size = false;
const { flow, initializing } = options;
const wth = $$.getWithOption(options);
const duration = wth.Transition ? config.transition_duration : 0;
const durationForExit = wth.TransitionForExit ? duration : 0;
const transitions = $$.axis?.generateTransitions(wth.TransitionForAxis ? duration : 0);
const needShapeUpdate = dirtySnapshot.data || dirtySnapshot.visibility || initializing;
if (state.isCanvasMode) {
$$.setContainerSize();
$$.updateHtmlLegend?.();
}
$$.updateSizes(initializing);
if (state.isCanvasMode) {
const zoomScale = $$.scale.zoom;
const zoomDomain = zoomScale?.domain();
zoomScale && ($$.scale.zoom = null);
$$.updateScales(initializing, wth.UpdateXDomain);
if (zoomScale) {
zoomScale.range($$.scale.x.range());
zoomDomain && zoomScale.domain(zoomDomain);
$$.scale.zoom = $$.getCustomizedXScale(zoomScale);
$$.axis.x.scale($$.scale.zoom);
$$.scale.x.domain(config.zoom_rescale ? zoomDomain : $$.org.xDomain);
$$.scale.subX.domain($$.org.xDomain);
}
state.hasAxis && $$.axis.syncAxisDomains(targetsToShow, wth, flow);
state.hasAxis && $$.applyCanvasSubchartDomain?.();
const shape = needShapeUpdate ? $$.getDrawShape() : state._cachedDrawShape || $$.getDrawShape();
if (needShapeUpdate) state._cachedDrawShape = shape;
if (config.legend_show && $el.legend && !(config.legend_contents_bindto && config.legend_contents_template)) $$.positionHtmlLegend?.();
$$.resizeCanvas?.();
state.canvasFocusKey = null;
$$.renderCanvasFrame(shape, null, true);
initializing && $$.updateTypesElements();
$$.callPluginHook("$redraw", options, 0);
state.redrawing = false;
state._targetsToShow = null;
state._cachedDrawShape = null;
$$.mapToIds($$.data.targets).forEach((id) => {
state.withoutFadeIn[id] = true;
});
callFn(config.onrendered, $$.api);
return;
}
if (wth.Legend && config.legend_show) {
options.withTransition = !!duration;
!treemap && $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
} else if (wth.Dimension) $$.updateDimension(true);
config.data_empty_label_text && main.select(`text.${$TEXT.text}.${$COMMON.empty}`).attr("x", state.width / 2).attr("y", state.height / 2).text(config.data_empty_label_text).style("display", targetsToShow.length ? "none" : null);
$$.redrawTitle?.();
if (state.hasAxis) {
$$.axis.redrawAxis(targetsToShow, wth, transitions, flow, initializing);
$$.hasGrid?.() && $$.updateGrid();
config.regions.length && $$.updateRegion?.();
[
"bar",
"candlestick",
"line",
"area"
].forEach((v) => {
const name = capitalize(v);
if (/^(line|area)$/.test(v) && $$.hasTypeOf(name) || $$.hasType(v)) {
if (needShapeUpdate) $$[`update${name}`](wth.TransitionForExit);
}
});
$el.text && main.selectAll(`.${$SELECT.selectedCircles}`).filter($$.isBarType.bind($$)).selectAll("circle").remove();
if (config.interaction_enabled && !flow && wth.EventRect) {
$$.redrawEventRect();
$$.bindZoomEvent?.();
}
} else {
$el.arcs && $$.redrawArc(duration, durationForExit, wth.Transform);
$el.radar && $$.redrawRadar();
$el.polar && $$.redrawPolar();
$el.funnel && $$.redrawFunnel();
treemap && $$.updateTreemap(durationForExit);
}
if (!state.resizing && !treemap && ($$.hasPointType() || state.hasRadar)) {
if (needShapeUpdate) $$.updateCircle();
} else if ($$.hasLegendDefsPoint?.()) $$.data.targets.forEach($$.point("create", this));
if ($$.hasDataLabel() && !$$.hasArcType(null, ["radar"])) {
if (needShapeUpdate) $$.updateText();
}
initializing && $$.updateTypesElements();
$$.generateRedrawList(targetsToShow, flow, duration, wth.Subchart, needShapeUpdate);
$$.updateTooltipOnRedraw();
$$.callPluginHook("$redraw", options, duration);
},
/**
* Generate redraw list
* @param {object} targets targets data to be shown
* @param {object} flow flow object
* @param {number} duration duration value
* @param {boolean} withSubchart whether or not to show subchart
* @param {boolean} needShapeRegen whether to regenerate draw shape
* @private
*/
generateRedrawList(targets, flow, duration, withSubchart, needShapeRegen = true) {
const $$ = this;
const { config, state } = $$;
const shape = needShapeRegen ? $$.getDrawShape() : state._cachedDrawShape || $$.getDrawShape();
if (needShapeRegen) state._cachedDrawShape = shape;
if (state.hasAxis) config.subchart_show && $$.redrawSubchart(withSubchart, duration, shape);
const flowFn = flow && $$.generateFlow({
targets,
flow,
duration: flow.duration,
shape,
xv: $$.xv.bind($$)
});
const withTransition = (duration || flowFn) && isTabVisible();
const redrawList = $$.getRedrawList(shape, flow, flowFn, withTransition);
const afterRedraw = () => {
flowFn && flowFn();
state.redrawing = false;
state._targetsToShow = null;
state._cachedDrawShape = null;
callFn(config.onrendered, $$.api);
};
if (withTransition && redrawList.length) {
const waitForDraw = generateWait();
transition().duration(duration).each(() => {
redrawList.flatMap((t1) => t1).forEach((t) => waitForDraw.add(t));
}).call(waitForDraw, afterRedraw);
} else if (!state.transiting) afterRedraw();
$$.mapToIds($$.data.targets).forEach((id) => {
state.withoutFadeIn[id] = true;
});
},
getRedrawList(shape, flow, flowFn, withTransition) {
const $$ = this;
const { config, state: { hasAxis, hasRadar, hasTreemap }, $el: { grid } } = $$;
const { cx, cy, xForText, yForText } = shape.pos;
const list = [];
if (hasAxis) {
if ($$.redrawGrid && (config.grid_x_lines.length || config.grid_y_lines.length)) list.push($$.redrawGrid(withTransition));
if ($$.redrawRegion && config.regions.length) list.push($$.redrawRegion(withTransition));
for (const v in shape.type) {
const name = capitalize(v);
const drawFn = shape.type[v];
if (/^(area|line)$/.test(v) && $$.hasTypeOf(name) || $$.hasType(v)) list.push($$[`redraw${name}`](drawFn, withTransition));
}
!flow && grid.main && $$.updateGridFocus && list.push($$.updateGridFocus());
}
if (!$$.hasArcType() || hasRadar) notEmpty(config.data_labels) && config.data_labels !== false && list.push($$.redrawText(xForText, yForText, flow, withTransition));
if (($$.hasPointType() || hasRadar) && !$$.isPointFocusOnly()) $$.redrawCircle && list.push($$.redrawCircle(cx, cy, withTransition, flowFn));
if (hasTreemap) list.push($$.redrawTreemap(withTransition));
return list;
},
updateAndRedraw(options = {}) {
const $$ = this;
const { config, state } = $$;
let transitions;
options.withTransition = getOption(options, "withTransition", true);
options.withTransform = getOption(options, "withTransform", false);
options.withLegend = getOption(options, "withLegend", false);
options.withUpdateXDomain = true;
options.withUpdateOrgXDomain = true;
options.withTransitionForExit = false;
options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition);
if (!(options.withLegend && config.legend_show)) {
if (state.hasAxis) transitions = $$.axis.generateTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
$$.updateScales();
$$.updateSvgSize();
$$.transformAll(options.withTransitionForTransform, transitions);
}
$$.redraw(options);
}
};
//#endregion
export { redraw_default as default };