UNPKG

7.48 kBPlain TextView Raw
1/**
2 * Copyright (c) 2017 ~ present NAVER Corp.
3 * billboard.js project is licensed under the MIT license
4 */
5import {transition as d3Transition} from "d3-transition";
6import CLASS from "../../config/classes";
7import {generateWait} from "../../module/generator";
8import {callFn, capitalize, getOption, isTabVisible, notEmpty} from "../../module/util";
9
10export default {
11 redraw(options: any = {}): void {
12 const $$ = this;
13 const {config, state, $el} = $$;
14 const {main} = $el;
15
16 state.redrawing = true;
17
18 const targetsToShow = $$.filterTargetsToShow($$.data.targets);
19 const initializing = options.initializing;
20 const flow = options.flow;
21 const wth = $$.getWithOption(options);
22 const duration = wth.Transition ? config.transition_duration : 0;
23 const durationForExit = wth.TransitionForExit ? duration : 0;
24 const durationForAxis = wth.TransitionForAxis ? duration : 0;
25 const transitions = $$.axis && $$.axis.generateTransitions(durationForAxis);
26
27 $$.updateSizes(initializing);
28
29 // update legend and transform each g
30
31 if (wth.Legend && config.legend_show) {
32 options.withTransition = !!duration;
33 $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
34 } else if (wth.Dimension) {
35 // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
36 // no need to update axis in it because they will be updated in redraw()
37 $$.updateDimension(true);
38 }
39 // update circleY based on updated parameters
40 if (!$$.hasArcType() || state.hasRadar) {
41 $$.updateCircleY && ($$.circleY = $$.updateCircleY());
42 }
43
44 // update axis
45 if (state.hasAxis) {
46 // @TODO: Make 'init' state to be accessible everywhere not passing as argument.
47 $$.axis.redrawAxis(targetsToShow, wth, transitions, flow, initializing);
48
49 // Data empty label positioning and text.
50 config.data_empty_label_text && main.select(`text.${CLASS.text}.${CLASS.empty}`)
51 .attr("x", state.width / 2)
52 .attr("y", state.height / 2)
53 .text(config.data_empty_label_text)
54 .style("display", targetsToShow.length ? "none" : null);
55
56 // grid
57 $$.hasGrid() && $$.updateGrid(duration);
58
59 // rect for regions
60 config.regions.length && $$.updateRegion(duration);
61
62 ["bar", "candlestick", "line", "area"].forEach(v => {
63 const name = capitalize(v);
64
65 if ((/^(line|area)$/.test(v) && $$.hasTypeOf(name)) || $$.hasType(v)) {
66 $$[`update${name}`](durationForExit);
67 }
68 });
69
70
71 // circles for select
72 $el.text && main.selectAll(`.${CLASS.selectedCircles}`)
73 .filter($$.isBarType.bind($$))
74 .selectAll("circle")
75 .remove();
76
77 // event rects will redrawn when flow called
78 if (config.interaction_enabled && !flow && wth.EventRect) {
79 $$.redrawEventRect();
80 $$.bindZoomEvent && $$.bindZoomEvent();
81 }
82 } else {
83 // arc
84 $el.arcs && $$.redrawArc(duration, durationForExit, wth.Transform);
85
86 // radar
87 $el.radar && $$.redrawRadar(durationForExit);
88 }
89
90 // @TODO: Axis & Radar type
91 if (!state.resizing && ($$.hasPointType() || state.hasRadar)) {
92 $$.updateCircle();
93 }
94
95 // text
96 $$.hasDataLabel() && !$$.hasArcType(null, ["radar"]) && $$.updateText(durationForExit);
97
98 // title
99 $$.redrawTitle && $$.redrawTitle();
100
101 initializing && $$.updateTypesElements();
102
103 $$.generateRedrawList(targetsToShow, flow, duration, wth.Subchart);
104 $$.callPluginHook("$redraw", options, duration);
105 },
106
107 /**
108 * Generate redraw list
109 * @param {object} targets targets data to be shown
110 * @param {object} flow flow object
111 * @param {number} duration duration value
112 * @param {boolean} withSubchart whether or not to show subchart
113 * @private
114 */
115 generateRedrawList(targets, flow: any, duration: number, withSubchart: boolean): void {
116 const $$ = this;
117 const {config, state} = $$;
118 const shape = $$.getDrawShape();
119
120 if (state.hasAxis) {
121 // subchart
122 config.subchart_show && $$.redrawSubchart(withSubchart, duration, shape);
123 }
124
125 // generate flow
126 const flowFn = flow && $$.generateFlow({
127 targets,
128 flow,
129 duration: flow.duration,
130 shape,
131 xv: $$.xv.bind($$)
132 });
133 const isTransition = (duration || flowFn) && isTabVisible();
134
135 // redraw list
136 const redrawList = $$.getRedrawList(shape, flow, flowFn, isTransition);
137
138 // callback function after redraw ends
139 const afterRedraw = flow || config.onrendered ? () => {
140 flowFn && flowFn();
141
142 state.redrawing = false;
143 callFn(config.onrendered, $$.api);
144 } : null;
145
146 if (afterRedraw) {
147 // Only use transition when current tab is visible.
148 if (isTransition && redrawList.length) {
149 // Wait for end of transitions for callback
150 const waitForDraw = generateWait();
151
152 // transition should be derived from one transition
153 d3Transition().duration(duration)
154 .each(() => {
155 redrawList
156 .reduce((acc, t1) => acc.concat(t1), [])
157 .forEach(t => waitForDraw.add(t));
158 })
159 .call(waitForDraw, afterRedraw);
160 } else if (!state.transiting) {
161 afterRedraw();
162 }
163 }
164
165 // update fadein condition
166 $$.mapToIds($$.data.targets).forEach(id => {
167 state.withoutFadeIn[id] = true;
168 });
169 },
170
171 getRedrawList(shape, flow, flowFn, isTransition: boolean): Function[] {
172 const $$ = <any> this;
173 const {config, state: {hasAxis, hasRadar}, $el: {grid}} = $$;
174 const {cx, cy, xForText, yForText} = shape.pos;
175 const list: Function[] = [];
176
177 if (hasAxis) {
178 if (config.grid_x_lines.length || config.grid_y_lines.length) {
179 list.push($$.redrawGrid(isTransition));
180 }
181
182 if (config.regions.length) {
183 list.push($$.redrawRegion(isTransition));
184 }
185
186 Object.keys(shape.type).forEach(v => {
187 const name = capitalize(v);
188 const drawFn = shape.type[v];
189
190 if ((/^(area|line)$/.test(v) && $$.hasTypeOf(name)) || $$.hasType(v)) {
191 list.push($$[`redraw${name}`](drawFn, isTransition));
192 }
193 });
194
195 !flow && grid.main && list.push($$.updateGridFocus());
196 }
197
198 if (!$$.hasArcType() || hasRadar) {
199 notEmpty(config.data_labels) && config.data_labels !== false &&
200 list.push($$.redrawText(xForText, yForText, flow, isTransition));
201 }
202
203 if (($$.hasPointType() || hasRadar) && !config.point_focus_only) {
204 $$.redrawCircle && list.push($$.redrawCircle(cx, cy, isTransition, flowFn));
205 }
206
207 return list;
208 },
209
210 updateAndRedraw(options: any = {}): void {
211 const $$ = this;
212 const {config, state} = $$;
213 let transitions;
214
215 // same with redraw
216 options.withTransition = getOption(options, "withTransition", true);
217 options.withTransform = getOption(options, "withTransform", false);
218 options.withLegend = getOption(options, "withLegend", false);
219
220 // NOT same with redraw
221 options.withUpdateXDomain = true;
222 options.withUpdateOrgXDomain = true;
223 options.withTransitionForExit = false;
224 options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition);
225
226 // MEMO: called in updateLegend in redraw if withLegend
227 if (!(options.withLegend && config.legend_show)) {
228 if (state.hasAxis) {
229 transitions = $$.axis.generateTransitions(
230 options.withTransitionForAxis ? config.transition_duration : 0
231 );
232 }
233
234 // Update scales
235 $$.updateScales();
236 $$.updateSvgSize();
237
238 // Update g positions
239 $$.transformAll(options.withTransitionForTransform, transitions);
240 }
241
242 // Draw with new sizes & scales
243 $$.redraw(options, transitions);
244 },
245
246 redrawWithoutRescale() {
247 this.redraw({
248 withY: false,
249 withSubchart: false,
250 withEventRect: false,
251 withTransitionForAxis: false
252 });
253 }
254};