• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

naver / billboard.js / 16137267914

08 Jul 2025 07:51AM UTC coverage: 86.941% (-7.2%) from 94.118%
16137267914

push

github

web-flow
chore(deps-dev): update dependency (#4014)

update dependencies to the latest versions

5668 of 7016 branches covered (80.79%)

Branch coverage included in aggregate %.

7487 of 8115 relevant lines covered (92.26%)

11761.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.85
/src/ChartInternal/ChartInternal.ts
1
/**
2
 * Copyright (c) 2017 ~ present NAVER Corp.
3
 * billboard.js project is licensed under the MIT license
4
 * @ignore
5
 */
6
import {select as d3Select} from "d3-selection";
7
import {
8
        timeFormat as d3TimeFormat,
9
        timeParse as d3TimeParse,
10
        utcFormat as d3UtcFormat,
11
        utcParse as d3UtcParse
12
} from "d3-time-format";
13
import type {d3Selection, d3Transition} from "../../types/types";
14
import {$CIRCLE, $COMMON, $TEXT} from "../config/classes";
15
import Options from "../config/Options/Options";
16
import Store from "../config/Store/Store";
17
import {document, window} from "../module/browser";
18
import Cache from "../module/Cache";
19
import {checkModuleImport} from "../module/error";
20
import {generateResize} from "../module/generator";
21
import {
22
        callFn,
23
        capitalize,
24
        convertInputType,
25
        extend,
26
        getOption,
27
        getRandom,
28
        hasStyle,
29
        isFunction,
30
        isObject,
31
        isString,
32
        notEmpty,
33
        sortValue
34
} from "../module/util";
35

36
// data
37
import dataConvert from "./data/convert";
38
import data from "./data/data";
39
import dataLoad from "./data/load";
40

41
// interactions
42
import interaction from "./interactions/interaction";
43

44
// internals
45
import category from "./internals/category"; // used to retrieve radar Axis name
46
import classModule from "./internals/class";
47
import color from "./internals/color";
48
import domain from "./internals/domain";
49
import format from "./internals/format";
50
import legend from "./internals/legend";
51
import redraw from "./internals/redraw";
52
import scale from "./internals/scale";
53
import size from "./internals/size";
54
import style from "./internals/style";
55
import text from "./internals/text";
56
import title from "./internals/title";
57
import tooltip from "./internals/tooltip";
58
import transform from "./internals/transform";
59
import typeInternals from "./internals/type";
60
import shape from "./shape/shape";
61

62
/**
63
 * Internal chart class.
64
 * - Note: Instantiated internally, not exposed for public.
65
 * @class ChartInternal
66
 * @ignore
67
 * @private
68
 */
69
export default class ChartInternal {
70
        public api; // API interface
71
        public config; // config object
72
        public cache; // cache instance
73
        public $el; // elements
74
        public state; // state variables
75
        public charts; // all Chart instances array within page (equivalent of 'bb.instances')
76

77
        // data object
78
        public data = {
2,904✔
79
                xs: {},
80
                targets: []
81
        };
82

83
        // Axis
84
        public axis; // Axis
85

86
        // scales
87
        public scale = {
2,904✔
88
                x: null,
89
                y: null,
90
                y2: null,
91
                subX: null,
92
                subY: null,
93
                subY2: null,
94
                zoom: null
95
        };
96

97
        // original values
98
        public org = {
2,904✔
99
                xScale: null,
100
                xDomain: null
101
        };
102

103
        // formatter function
104
        public color;
105
        public patterns;
106
        public levelColor;
107
        public point;
108
        public brush;
109

110
        // format function
111
        public format = {
2,904✔
112
                extraLineClasses: null,
113
                xAxisTick: null,
114
                dataTime: null, // dataTimeFormat
115
                defaultAxisTime: null, // defaultAxisTimeFormat
116
                axisTime: null // axisTimeFormat
117
        };
118

119
        constructor(api) {
120
                const $$ = this;
2,904✔
121

122
                $$.api = api; // Chart class instance alias
2,904✔
123
                $$.config = new Options();
2,904✔
124
                $$.cache = new Cache();
2,904✔
125

126
                const store = new Store();
2,904✔
127

128
                $$.$el = store.getStore("element");
2,904✔
129
                $$.state = store.getStore("state");
2,904✔
130

131
                $$.$T = $$.$T.bind($$);
2,904✔
132
        }
133

134
        /**
135
         * Get the selection based on transition config
136
         * @param {SVGElement|d3Selection} selection Target selection
137
         * @param {boolean} force Force transition
138
         * @param {string} name Transition name
139
         * @returns {d3Selection}
140
         * @private
141
         */
142
        $T(selection: SVGElement | d3Selection | d3Transition, force?: boolean,
143
                name?: string): d3Selection {
144
                const {config, state} = this;
138,243✔
145
                const duration = config.transition_duration;
138,243✔
146
                const subchart = config.subchart_show;
138,243✔
147
                let t = selection;
138,243✔
148

149
                if (t) {
138,243✔
150
                        // in case of non d3 selection, wrap with d3 selection
151
                        if ("tagName" in t) {
132,714✔
152
                                t = d3Select(t);
1,725✔
153
                        }
154

155
                        // do not transit on:
156
                        // - wheel zoom (state.zooming = true)
157
                        // - when has no subchart
158
                        // - initialization
159
                        // - resizing
160
                        const transit = ((force !== false && duration) || force) &&
132,714✔
161
                                (!state.zooming || state.dragging) &&
162
                                !state.resizing &&
163
                                state.rendered &&
164
                                !subchart;
165

166
                        // @ts-ignore
167
                        t = (transit ? t.transition(name).duration(duration) : t) as d3Selection;
132,714✔
168
                }
169

170
                return t;
138,243✔
171
        }
172

173
        beforeInit(): void {
174
                const $$ = this;
2,904✔
175

176
                $$.callPluginHook("$beforeInit");
2,904✔
177

178
                // can do something
179
                callFn($$.config.onbeforeinit, $$.api);
2,898✔
180
        }
181

182
        afterInit(): void {
183
                const $$ = this;
2,826✔
184

185
                $$.callPluginHook("$afterInit");
2,826✔
186

187
                // can do something
188
                callFn($$.config.onafterinit, $$.api);
2,826✔
189
        }
190

191
        init(): void {
192
                const $$ = <any>this;
2,898✔
193
                const {config, state, $el} = $$;
2,898✔
194
                const {boost_useCssRule, bindto} = config;
2,898✔
195

196
                checkModuleImport($$);
2,898✔
197

198
                const hasArcType = $$.hasArcType();
2,835✔
199
                state.hasRadar = !state.hasAxis && $$.hasType("radar");
2,835✔
200
                state.hasFunnel = !state.hasAxis && $$.hasType("funnel");
2,835✔
201
                state.hasTreemap = !state.hasAxis && $$.hasType("treemap");
2,835✔
202
                state.hasAxis = !hasArcType && !state.hasFunnel && !state.hasTreemap;
2,835✔
203

204
                // datetime to be used for uniqueness
205
                state.datetimeId = `bb-${+new Date() * (getRandom() as number)}`;
2,835✔
206

207
                if (boost_useCssRule) {
2,835✔
208
                        // append style element
209
                        const styleEl = document.createElement("style");
12✔
210

211
                        // styleEl.id = styleId;
212
                        styleEl.type = "text/css";
12✔
213
                        document.head.appendChild(styleEl);
12✔
214

215
                        state.style = {
12✔
216
                                rootSelctor: `.${state.datetimeId}`,
217
                                sheet: styleEl.sheet
218
                        };
219

220
                        // used on .destroy()
221
                        $el.style = styleEl;
12✔
222
                }
223

224
                const bindConfig = {
2,835✔
225
                        element: bindto,
226
                        classname: "bb"
227
                };
228

229
                if (isObject(bindto)) {
2,835✔
230
                        bindConfig.element = bindto.element || "#chart";
3!
231
                        bindConfig.classname = bindto.classname || bindConfig.classname;
3!
232
                }
233

234
                // select bind element
235
                $el.chart = isFunction(bindConfig.element.node) ?
2,835!
236
                        bindto.element :
237
                        d3Select(bindConfig.element || []);
2,835!
238

239
                if ($el.chart.empty()) {
2,835✔
240
                        $el.chart = d3Select(document.body.appendChild(document.createElement("div")));
99✔
241
                }
242

243
                $el.chart.html("")
2,835✔
244
                        .classed(bindConfig.classname, true)
245
                        .classed(state.datetimeId, boost_useCssRule)
246
                        .style("position", "relative");
247

248
                $$.initParams();
2,835✔
249
                $$.initToRender();
2,835✔
250
        }
251

252
        /**
253
         * Initialize the rendering process
254
         * @param {boolean} forced Force to render process
255
         * @private
256
         */
257
        initToRender(forced?: boolean): void {
258
                const $$ = <any>this;
2,847✔
259
                const {config, state, $el: {chart}} = $$;
2,847✔
260
                const isHidden = () => hasStyle(chart, {display: "none", visibility: "hidden"});
2,847✔
261

262
                const isLazy = config.render.lazy === false ? false : config.render.lazy || isHidden();
2,847✔
263
                const MutationObserver = window.MutationObserver;
2,847✔
264

265
                if (isLazy && MutationObserver && config.render.observe !== false && !forced) {
2,847✔
266
                        new MutationObserver((mutation, observer) => {
9✔
267
                                if (!isHidden()) {
9!
268
                                        observer.disconnect();
9✔
269
                                        !state.rendered && $$.initToRender(true);
9✔
270
                                }
271
                        }).observe(chart.node(), {
272
                                attributes: true,
273
                                attributeFilter: ["class", "style"]
274
                        });
275
                }
276

277
                if (!isLazy || forced) {
2,847✔
278
                        $$.convertData(config, res => {
2,835✔
279
                                $$.initWithData(res);
2,826✔
280
                                $$.afterInit();
2,826✔
281
                        });
282
                }
283
        }
284

285
        initParams(): void {
286
                const $$ = <any>this;
2,835✔
287
                const {config, format, state} = $$;
2,835✔
288

289
                // color settings
290
                $$.color = $$.generateColor();
2,835✔
291
                $$.levelColor = $$.generateLevelColor();
2,835✔
292

293
                // when 'padding=false' is set, disable axes and subchart. Because they are useless.
294
                if (config.padding === false) {
2,835✔
295
                        config.axis_x_show = false;
6✔
296
                        config.axis_y_show = false;
6✔
297
                        config.axis_y2_show = false;
6✔
298
                        config.subchart_show = false;
6✔
299
                }
300

301
                if ($$.hasPointType() || $$.hasLegendDefsPoint?.()) {
2,835✔
302
                        $$.point = $$.generatePoint();
753✔
303
                }
304

305
                if (state.hasAxis) {
2,835✔
306
                        $$.initClip();
2,073✔
307

308
                        format.extraLineClasses = $$.generateExtraLineClass();
2,073✔
309
                        format.dataTime = config.data_xLocaltime ? d3TimeParse : d3UtcParse;
2,073!
310
                        format.axisTime = config.axis_x_localtime ? d3TimeFormat : d3UtcFormat;
2,073!
311

312
                        const isDragZoom = config.zoom_enabled && config.zoom_type === "drag";
2,073✔
313

314
                        format.defaultAxisTime = d => {
2,073✔
315
                                const {x, zoom} = $$.scale;
1,275✔
316
                                const isZoomed = isDragZoom ?
1,275✔
317
                                        zoom :
318
                                        zoom && x.orgDomain().toString() !== zoom.domain().toString();
1,401✔
319

320
                                const specifier: string = (d.getMilliseconds() && ".%L") ||
1,275!
321
                                        (d.getSeconds() && ".:%S") ||
322
                                        (d.getMinutes() && "%I:%M") ||
323
                                        (d.getHours() && "%I %p") ||
324
                                        (d.getDate() !== 1 && "%b %d") ||
325
                                        (isZoomed && d.getDate() === 1 && "%b'%y") ||
326
                                        (d.getMonth() && "%-m/%-d") || "%Y";
327

328
                                return format.axisTime(specifier)(d);
1,275✔
329
                        };
330
                }
331

332
                const {legend_position, legend_inset_anchor, axis_rotated} = config;
2,835✔
333

334
                state.isLegendRight = legend_position === "right";
2,835✔
335
                state.isLegendInset = legend_position === "inset";
2,835✔
336
                state.isLegendTop = legend_inset_anchor === "top-left" ||
2,835✔
337
                        legend_inset_anchor === "top-right";
338
                state.isLegendLeft = legend_inset_anchor === "top-left" ||
2,835✔
339
                        legend_inset_anchor === "bottom-left";
340

341
                state.rotatedPadding.top = $$.getResettedPadding(state.rotatedPadding.top);
2,835✔
342
                state.rotatedPadding.right = axis_rotated && !config.axis_x_show ? 0 : 30;
2,835!
343

344
                state.inputType = convertInputType(
2,835✔
345
                        config.interaction_inputType_mouse,
346
                        config.interaction_inputType_touch
347
                );
348
        }
349

350
        initWithData(data): void {
351
                const $$ = <any>this;
2,826✔
352
                const {config, scale, state, $el, org} = $$;
2,826✔
353
                const {hasAxis, hasFunnel, hasTreemap} = state;
2,826✔
354
                const hasInteraction = config.interaction_enabled;
2,826✔
355
                const hasPolar = $$.hasType("polar");
2,826✔
356
                const labelsBGColor = config.data_labels_backgroundColors;
2,826✔
357

358
                // for arc type, set axes to not be shown
359
                // $$.hasArcType() && ["x", "y", "y2"].forEach(id => (config[`axis_${id}_show`] = false));
360

361
                if (hasAxis) {
2,826✔
362
                        $$.axis = $$.getAxisInstance();
2,064✔
363
                        config.zoom_enabled && $$.initZoom();
2,064✔
364
                }
365

366
                // Init data as targets
367
                $$.data.xs = {};
2,826✔
368
                $$.data.targets = $$.convertDataToTargets(data);
2,826✔
369

370
                if (config.data_filter) {
2,826!
371
                        $$.data.targets = $$.data.targets.filter(config.data_filter.bind($$.api));
×
372
                }
373

374
                // Set targets to hide if needed
375
                if (config.data_hide) {
2,826✔
376
                        $$.addHiddenTargetIds(
6✔
377
                                config.data_hide === true ? $$.mapToIds($$.data.targets) : config.data_hide
6!
378
                        );
379
                }
380

381
                if (config.legend_hide) {
2,826✔
382
                        $$.addHiddenLegendIds(
9✔
383
                                config.legend_hide === true ? $$.mapToIds($$.data.targets) : config.legend_hide
9✔
384
                        );
385
                }
386

387
                // Init sizes and scales
388
                $$.updateSizes();
2,826✔
389
                $$.updateScales(true);
2,826✔
390

391
                // retrieve scale after the 'updateScales()' is called
392
                if (hasAxis) {
2,826✔
393
                        const {x, y, y2, subX, subY, subY2} = scale;
2,064✔
394

395
                        // Set domains for each scale
396
                        if (x) {
2,064!
397
                                x.domain(sortValue($$.getXDomain($$.data.targets), !config.axis_x_inverted));
2,064✔
398
                                subX.domain(x.domain());
2,064✔
399

400
                                // Save original x domain for zoom update
401
                                org.xDomain = x.domain();
2,064✔
402
                        }
403

404
                        if (y) {
2,064!
405
                                y.domain($$.getYDomain($$.data.targets, "y"));
2,064✔
406
                                subY.domain(y.domain());
2,064✔
407
                        }
408

409
                        if (y2) {
2,064✔
410
                                y2.domain($$.getYDomain($$.data.targets, "y2"));
243✔
411
                                subY2 && subY2.domain(y2.domain());
243✔
412
                        }
413
                }
414

415
                // -- Basic Elements --
416
                $el.svg = $el.chart.append("svg")
2,826✔
417
                        .style("overflow", "hidden")
418
                        .style("display", "block");
419

420
                if (hasInteraction && state.inputType) {
2,826✔
421
                        const isTouch = state.inputType === "touch";
2,823✔
422
                        const {onclick, onover, onout} = config;
2,823✔
423

424
                        $el.svg
2,823✔
425
                                .on("click", onclick?.bind($$.api) || null)
5,643✔
426
                                .on(isTouch ? "touchstart" : "mouseenter", onover?.bind($$.api) || null)
8,466✔
427
                                .on(isTouch ? "touchend" : "mouseleave", onout?.bind($$.api) || null);
8,466✔
428
                }
429

430
                config.svg_classname && $el.svg.attr("class", config.svg_classname);
2,826✔
431

432
                // Define defs
433
                const hasColorPatterns = isFunction(config.color_tiles) && $$.patterns;
2,826✔
434

435
                if (
2,826✔
436
                        hasAxis || hasColorPatterns || hasPolar || hasTreemap ||
6,336✔
437
                        labelsBGColor || $$.hasLegendDefsPoint?.()
438
                ) {
439
                        $el.defs = $el.svg.append("defs");
2,190✔
440

441
                        if (hasAxis) {
2,190✔
442
                                ["id", "idXAxis", "idYAxis", "idGrid"].forEach(v => {
2,064✔
443
                                        $$.appendClip($el.defs, state.clip[v]);
8,256✔
444
                                });
445
                        }
446

447
                        // Append data background color filter definition
448
                        $$.generateTextBGColorFilter(labelsBGColor);
2,190✔
449

450
                        // set color patterns
451
                        if (hasColorPatterns) {
2,190✔
452
                                $$.patterns.forEach(p => $el.defs.append(() => p.node));
153✔
453
                        }
454
                }
455

456
                $$.updateSvgSize();
2,826✔
457

458
                // Bind resize event
459
                $$.bindResize();
2,826✔
460

461
                // Define regions
462
                const main = $el.svg.append("g")
2,826✔
463
                        .classed($COMMON.main, true)
464
                        .attr("transform", hasFunnel || hasTreemap ? null : $$.getTranslate("main"));
8,424✔
465

466
                $el.main = main;
2,826✔
467

468
                // initialize subchart when subchart show option is set
469
                config.subchart_show && $$.initSubchart();
2,826✔
470

471
                config.tooltip_show && $$.initTooltip();
2,826✔
472

473
                config.title_text && $$.initTitle();
2,826✔
474
                !hasTreemap && config.legend_show && $$.initLegend();
2,826✔
475

476
                // -- Main Region --
477

478
                // text when empty
479
                if (config.data_empty_label_text) {
2,826!
480
                        main.append("text")
×
481
                                .attr("class", `${$TEXT.text} ${$COMMON.empty}`)
482
                                .attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers.
483
                                .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE.
484
                }
485

486
                if (hasAxis) {
2,826✔
487
                        // Regions
488
                        config.regions.length && $$.initRegion();
2,064✔
489

490
                        // Add Axis here, when clipPath is 'false'
491
                        !config.clipPath && $$.axis.init();
2,064✔
492
                }
493

494
                // Define g for chart area
495
                main.append("g")
2,826✔
496
                        .classed($COMMON.chart, true)
497
                        .attr("clip-path", hasAxis ? state.clip.path : null);
2,826✔
498

499
                $$.callPluginHook("$init");
2,826✔
500

501
                $$.initChartElements();
2,826✔
502

503
                if (hasAxis) {
2,826✔
504
                        // Cover whole with rects for events
505
                        hasInteraction && $$.initEventRect?.();
2,064✔
506

507
                        // Grids
508
                        $$.initGrid();
2,064✔
509

510
                        // Add Axis here, when clipPath is 'true'
511
                        config.clipPath && $$.axis?.init();
2,064✔
512
                }
513

514
                // Set targets
515
                $$.updateTargets($$.data.targets);
2,826✔
516

517
                // Draw with targets
518
                $$.updateDimension();
2,826✔
519

520
                // oninit callback
521
                callFn(config.oninit, $$.api);
2,826✔
522

523
                // Set background
524
                $$.setBackground();
2,826✔
525

526
                $$.redraw({
2,826✔
527
                        withTransition: false,
528
                        withTransform: true,
529
                        withUpdateXDomain: true,
530
                        withUpdateOrgXDomain: true,
531
                        withTransitionForAxis: false,
532
                        initializing: true
533
                });
534

535
                // data.onmin/max callback
536
                if (config.data_onmin || config.data_onmax) {
2,826!
537
                        const minMax = $$.getMinMaxData();
×
538

539
                        callFn(config.data_onmin, $$.api, minMax.min);
×
540
                        callFn(config.data_onmax, $$.api, minMax.max);
×
541
                }
542

543
                config.tooltip_show && $$.initShowTooltip();
2,826✔
544
                state.rendered = true;
2,826✔
545
        }
546

547
        /**
548
         * Initialize chart elements
549
         * @private
550
         */
551
        initChartElements(): void {
552
                const $$ = <any>this;
2,826✔
553
                const {hasAxis, hasRadar, hasTreemap} = $$.state;
2,826✔
554
                const types: string[] = [];
2,826✔
555

556
                if (hasAxis) {
2,826✔
557
                        const shapes = ["bar", "bubble", "candlestick", "line"];
2,064✔
558

559
                        if ($$.config.bar_front) {
2,064!
560
                                shapes.push(shapes.shift() as string);
×
561
                        }
562

563
                        for (const shape of shapes) {
2,064✔
564
                                const name = capitalize(shape);
8,256✔
565
                                if ((shape === "line" && $$.hasTypeOf(name)) || $$.hasType(shape)) {
8,256✔
566
                                        types.push(name);
2,067✔
567
                                }
568
                        }
569
                } else if (hasTreemap) {
762✔
570
                        types.push("Treemap");
51✔
571
                } else if ($$.hasType("funnel")) {
711✔
572
                        types.push("Funnel");
54✔
573
                } else {
574
                        const hasPolar = $$.hasType("polar");
657✔
575
                        const hasGauge = $$.hasType("gauge");
657✔
576

577
                        if (!hasRadar) {
657✔
578
                                types.push("Arc", "Pie");
567✔
579
                        }
580

581
                        if (hasGauge) {
657✔
582
                                types.push("Gauge");
234✔
583
                        } else if (hasRadar) {
423✔
584
                                types.push("Radar");
90✔
585
                        } else if (hasPolar) {
333✔
586
                                types.push("Polar");
66✔
587
                        }
588
                }
589

590
                for (const type of types) {
2,826✔
591
                        $$[`init${type}`]();
3,696✔
592
                }
593

594
                if (notEmpty($$.config.data_labels) && !$$.hasArcType(null, ["radar"])) {
2,826✔
595
                        $$.initText();
165✔
596
                }
597
        }
598

599
        /**
600
         * Set chart elements
601
         * @private
602
         */
603
        setChartElements(): void {
604
                const $$ = this;
3,060✔
605
                const {
606
                        $el: {
607
                                chart,
608
                                svg,
609
                                defs,
610
                                main,
611
                                tooltip,
612
                                legend,
613
                                title,
614
                                grid,
615
                                needle,
616
                                arcs: arc,
617
                                circle: circles,
618
                                bar: bars,
619
                                candlestick,
620
                                line: lines,
621
                                area: areas,
622
                                text: texts
623
                        }
624
                } = $$;
3,060✔
625

626
                // public
627
                $$.api.$ = {
3,060✔
628
                        chart,
629
                        svg,
630
                        defs,
631
                        main,
632
                        tooltip,
633
                        legend,
634
                        title,
635
                        grid,
636
                        arc,
637
                        circles,
638
                        bar: {bars},
639
                        candlestick,
640
                        line: {lines, areas},
641
                        needle,
642
                        text: {texts}
643
                };
644
        }
645

646
        /**
647
         * Set background element/image
648
         * @private
649
         */
650
        setBackground(): void {
651
                const $$ = this;
2,826✔
652
                const {config: {background: bg}, state, $el: {svg}} = $$;
2,826✔
653

654
                if (notEmpty(bg)) {
2,826✔
655
                        const element = svg.select("g")
15✔
656
                                .insert(bg.imgUrl ? "image" : "rect", ":first-child");
15✔
657

658
                        if (bg.imgUrl) {
15✔
659
                                element.attr("href", bg.imgUrl);
6✔
660
                        } else if (bg.color) {
9!
661
                                element
9✔
662
                                        .style("fill", bg.color)
663
                                        .attr("clip-path", state.clip.path);
664
                        }
665

666
                        element
15✔
667
                                .attr("class", bg.class || null)
18✔
668
                                .attr("width", "100%")
669
                                .attr("height", "100%");
670
                }
671
        }
672

673
        /**
674
         * Update targeted element with given data
675
         * @param {object} targets Data object formatted as 'target'
676
         * @private
677
         */
678
        updateTargets(targets): void {
679
                const $$ = <any>this;
3,036✔
680
                const {hasAxis, hasFunnel, hasRadar, hasTreemap} = $$.state;
3,036✔
681
                const helper = type =>
3,036✔
682
                        $$[`updateTargetsFor${type}`](
2,982✔
683
                                targets.filter($$[`is${type}Type`].bind($$))
684
                        );
685

686
                // Text
687
                $$.updateTargetsForText(targets);
3,036✔
688

689
                if (hasAxis) {
3,036✔
690
                        const shapes = ["bar", "candlestick", "line"];
2,247✔
691
                        for (const shape of shapes) {
2,247✔
692
                                const name = capitalize(shape);
6,741✔
693
                                if ((shape === "line" && $$.hasTypeOf(name)) || $$.hasType(shape)) {
6,741✔
694
                                        helper(name);
2,193✔
695
                                }
696
                        }
697

698
                        // Sub Chart
699
                        $$.updateTargetsForSubchart?.(targets);
2,247✔
700

701
                        // Arc, Polar, Radar
702
                } else if ($$.hasArcType(targets)) {
789✔
703
                        let type = "Arc";
672✔
704

705
                        if (hasRadar) {
672✔
706
                                type = "Radar";
93✔
707
                        } else if ($$.hasType("polar")) {
579✔
708
                                type = "Polar";
66✔
709
                        }
710

711
                        helper(type);
672✔
712
                } else if (hasFunnel) {
117✔
713
                        helper("Funnel");
60✔
714
                } else if (hasTreemap) {
57!
715
                        helper("Treemap");
57✔
716
                }
717

718
                // Point types
719
                const hasPointType = $$.hasType("bubble") || $$.hasType("scatter");
3,036✔
720

721
                if (hasPointType) {
3,036✔
722
                        $$.updateTargetForCircle?.();
141✔
723
                }
724

725
                // Fade-in each chart
726
                $$.filterTargetsToShowAtInit(hasPointType);
3,036✔
727
        }
728

729
        /**
730
         * Display targeted elements at initialization
731
         * @param {boolean} hasPointType whether has point type(bubble, scatter) or not
732
         * @private
733
         */
734
        filterTargetsToShowAtInit(hasPointType: boolean = false): void {
×
735
                const $$ = <any>this;
3,036✔
736
                const {$el: {svg}, $T} = $$;
3,036✔
737
                let selector = `.${$COMMON.target}`;
3,036✔
738

739
                if (hasPointType) {
3,036✔
740
                        selector += `, .${$CIRCLE.chartCircles} > .${$CIRCLE.circles}`;
141✔
741
                }
742

743
                $T(svg.selectAll(selector)
3,036✔
744
                        .filter(d => $$.isTargetToShow(d.id))).style("opacity", null);
7,389✔
745
        }
746

747
        getWithOption(options) {
748
                const withOptions = {
4,044✔
749
                        Dimension: true,
750
                        EventRect: true,
751
                        Legend: false,
752
                        Subchart: true,
753
                        Transform: false,
754
                        Transition: true,
755
                        TrimXDomain: true,
756
                        UpdateXAxis: "UpdateXDomain",
757
                        UpdateXDomain: false,
758
                        UpdateOrgXDomain: false,
759
                        TransitionForExit: "Transition",
760
                        TransitionForAxis: "Transition",
761
                        Y: true
762
                };
763

764
                for (const [key, defVal] of Object.entries(withOptions)) {
4,044✔
765
                        const value = isString(defVal) ? withOptions[defVal] : defVal;
52,572✔
766
                        withOptions[key] = getOption(options, `with${key}`, value);
52,572✔
767
                }
768

769
                return withOptions;
4,044✔
770
        }
771

772
        initialOpacity(d): null | "0" {
773
                const $$ = <any>this;
11,796✔
774
                const {withoutFadeIn} = $$.state;
11,796✔
775

776
                return $$.getBaseValue(d) !== null && withoutFadeIn[d.id] ? null : "0";
11,796✔
777
        }
778

779
        bindResize(): void {
780
                const $$ = <any>this;
2,826✔
781
                const {$el, config, state} = $$;
2,826✔
782
                const resizeFunction = generateResize(config.resize_timer);
2,826✔
783
                const {resize_auto} = config;
2,826✔
784
                const list: (() => void)[] = [];
2,826✔
785

786
                list.push(() => callFn(config.onresize, $$.api));
2,826✔
787

788
                if (/^(true|parent)$/.test(resize_auto)) {
2,826✔
789
                        list.push(() => {
2,778✔
790
                                state.resizing = true;
69✔
791

792
                                // https://github.com/naver/billboard.js/issues/2650
793
                                if (config.legend_show) {
69!
794
                                        $$.updateSizes();
69✔
795
                                        $$.updateLegend();
69✔
796
                                }
797

798
                                $$.api.flush(false);
69✔
799
                        });
800
                }
801

802
                list.push(() => {
2,826✔
803
                        callFn(config.onresized, $$.api);
72✔
804
                        state.resizing = false;
72✔
805
                });
806

807
                // add resize functions
808
                list.forEach(v => resizeFunction.add(v));
8,430✔
809
                $$.resizeFunction = resizeFunction;
2,826✔
810

811
                // attach resize event
812
                if (resize_auto === "parent") {
2,826✔
813
                        ($$.resizeFunction.resizeObserver = new ResizeObserver($$.resizeFunction.bind($$)))
3✔
814
                                .observe($el.chart.node().parentNode);
815
                } else {
816
                        window.addEventListener("resize", $$.resizeFunction);
2,823✔
817
                }
818
        }
819

820
        /**
821
         * Call plugin hook
822
         * @param {string} phase The lifecycle phase
823
         * @param {Array} args Arguments
824
         * @private
825
         */
826
        callPluginHook(phase, ...args): void {
827
                this.config.plugins.forEach(v => {
12,897✔
828
                        if (phase === "$beforeInit") {
678✔
829
                                v.$$ = this;
171✔
830
                                this.api.plugins.push(v);
171✔
831
                        }
832

833
                        v[phase](...args);
678✔
834
                });
835
        }
836
}
837

838
extend(ChartInternal.prototype, [
228✔
839
        // common
840
        dataConvert,
841
        data,
842
        dataLoad,
843
        category,
844
        classModule,
845
        color,
846
        domain,
847
        interaction,
848
        format,
849
        legend,
850
        redraw,
851
        scale,
852
        shape,
853
        size,
854
        style,
855
        text,
856
        title,
857
        tooltip,
858
        transform,
859
        typeInternals
860
]);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc