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

naver / billboard.js / 27122665529

08 Jun 2026 07:32AM UTC coverage: 92.54% (-1.1%) from 93.621%
27122665529

push

github

web-flow
feat(canvas): add canvas rendering mode

Add canvas entry, renderer engine, axis renderer, theme probing, and hit detection.
Support canvas flow, subchart, zoom, selection, grid/regions, export, tooltip, and focus.
Add tests, benchmarks, types, and docs for canvas mode limitations.

10455 of 11840 branches covered (88.3%)

Branch coverage included in aggregate %.

5094 of 5363 new or added lines in 68 files covered. (94.98%)

19 existing lines in 3 files now uncovered.

13349 of 13883 relevant lines covered (96.15%)

26556.19 hits per line

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

79.25
/src/Chart/api/subchart.ts
1
/**
2
 * Copyright (c) 2017 ~ present NAVER Corp.
3
 * billboard.js project is licensed under the MIT license
4
 */
5
import type {TDomain} from "../../ChartInternal/data/IData";
6
import {$COMMON} from "../../config/classes";
7
import {extend, parseDate} from "../../module/util";
8

9
/**
10
 * Select subchart by giving x domain range.
11
 * - **ℹ️ NOTE:**
12
 *  - Due to the limitations of floating point precision, domain value may not be exact returning approximately values.
13
 * @function subchart
14
 * @instance
15
 * @memberof Chart
16
 * @param {Array} domainValue If domain range is given, the subchart will be selected to the given domain. If no argument is given, the current subchart selection domain will be returned.
17
 * @returns {Array} domain value in array
18
 * @example
19
 *  // Specify domain for subchart selection
20
 *  chart.subchart([1, 2]);
21
 *
22
 *  // Get the current subchart selection domain range
23
 *  // Domain value may not be exact returning approximately values.
24
 *  chart.subchart();
25
 */
26
// NOTE: declared function assigning to variable to prevent duplicated method generation in JSDoc.
27
const subchart = function<T = TDomain[]>(domainValue?: T): T | undefined {
243✔
28
        const $$ = this.internal;
75✔
29
        const {axis, brush, config, scale: {x, subX}, state} = $$;
75✔
30
        let domain;
31

32
        if (state.isCanvasMode) {
75✔
33
                if (config.subchart_show) {
45!
34
                        domain = domainValue;
45✔
35

36
                        if (Array.isArray(domain)) {
45✔
37
                                domain = axis.isTimeSeries() ? domain.map(x => parseDate.bind($$)(x)) : domain;
3!
38
                                domain = $$.setCanvasSubchartDomain(domain) || state.domain;
3!
39
                        } else {
40
                                domain = state.domain ?? x.orgDomain();
42✔
41
                        }
42
                }
43

44
                return domain as T;
45✔
45
        }
46

47
        if (config.subchart_show) {
30!
48
                domain = domainValue;
30✔
49

50
                if (Array.isArray(domain)) {
30✔
51
                        if (axis.isTimeSeries()) {
21✔
52
                                domain = domain.map(x => parseDate.bind($$)(x));
6✔
53
                        }
54

55
                        const isWithinRange = $$.withinRange(
21✔
56
                                domain,
57
                                $$.getZoomDomain("subX", true),
58
                                $$.getZoomDomain("subX")
59
                        );
60

61
                        if (isWithinRange) {
21✔
62
                                state.domain = domain;
12✔
63

64
                                brush.move(
12✔
65
                                        brush.getSelection(),
66
                                        domain.map(subX)
67
                                );
68
                        }
69
                } else {
70
                        domain = state.domain ?? x.orgDomain();
9✔
71
                }
72
        }
73

74
        return domain as T;
30✔
75
};
76

77
extend(subchart, {
243✔
78
        /**
79
         * Show subchart
80
         * - **NOTE:** for ESM imports, needs to import 'subchart' exports and instantiate it by calling `subchart()`.
81
         * @function subchart․show
82
         * @instance
83
         * @memberof Chart
84
         * @example
85
         * // for ESM imports, needs to import 'subchart' and must be instantiated first to enable subchart's API.
86
         * import {subchart} from "billboard.js";
87
         *
88
         * const chart = bb.generate({
89
         *   ...
90
         *   subchart: {
91
         *      // need to be instantiated by calling 'subchart()'
92
         *      enabled: subchart()
93
         *
94
         *      // in case don't want subchart to be shown at initialization, instantiate with '!subchart()'
95
         *      enabled: !subchart()
96
         *   }
97
         * });
98
         *
99
         * chart.subchart.show();
100
         */
101
        show(): void {
102
                const $$ = this.internal;
15✔
103
                const {$el: {subchart}, config} = $$;
15✔
104
                const show = config.subchart_show;
15✔
105

106
                if (!show) {
15!
107
                        if ($$.state.isCanvasMode) {
15!
NEW
108
                                $$.unbindZoomEvent?.();
×
NEW
109
                                config.subchart_show = true;
×
NEW
110
                                this.resize();
×
NEW
111
                                return;
×
112
                        }
113

114
                        // unbind zoom event bound to chart rect area
115
                        $$.unbindZoomEvent();
15✔
116

117
                        config.subchart_show = !show;
15✔
118
                        !subchart.main && $$.initSubchart();
15✔
119

120
                        let $target = subchart.main.selectAll(`.${$COMMON.target}`);
15✔
121

122
                        // need to cover when new data has been loaded
123
                        if ($$.data.targets.length !== $target.size()) {
15✔
124
                                $$.updateSizes();
9✔
125
                                $$.updateTargetsForSubchart($$.data.targets);
9✔
126

127
                                $target = subchart.main?.selectAll(`.${$COMMON.target}`);
9✔
128
                        }
129

130
                        $target?.style("opacity", null);
15✔
131
                        subchart.main?.style("display", null);
15✔
132

133
                        this.resize();
15✔
134
                }
135
        },
136

137
        /**
138
         * Hide generated subchart
139
         * - **NOTE:** for ESM imports, needs to import 'subchart' exports and instantiate it by calling `subchart()`.
140
         * @function subchart․hide
141
         * @instance
142
         * @memberof Chart
143
         * @example
144
         *  chart.subchart.hide();
145
         */
146
        hide(): void {
147
                const $$ = this.internal;
12✔
148
                const {$el: {subchart: {main}}, config} = $$;
12✔
149

150
                if ($$.state.isCanvasMode) {
12!
NEW
151
                        if (config.subchart_show) {
×
NEW
152
                                config.subchart_show = false;
×
NEW
153
                                this.resize();
×
NEW
154
                                $$.bindZoomEvent?.();
×
155
                        }
156

NEW
157
                        return;
×
158
                }
159

160
                if (config.subchart_show && main?.style("display") !== "none") {
12!
161
                        config.subchart_show = false;
12✔
162
                        main.style("display", "none");
12✔
163

164
                        this.resize();
12✔
165
                }
166
        },
167

168
        /**
169
         * Toggle the visibility of subchart
170
         * - **NOTE:** for ESM imports, needs to import 'subchart' exports and instantiate it by calling `subchart()`.
171
         * @function subchart․toggle
172
         * @instance
173
         * @memberof Chart
174
         * @example
175
         * // When subchart is hidden, will be shown
176
         * // When subchart is shown, will be hidden
177
         * chart.subchart.toggle();
178
         */
179
        toggle(): void {
180
                const $$ = this.internal;
9✔
181
                const {config} = $$;
9✔
182

183
                this.subchart[config.subchart_show ? "hide" : "show"]();
9✔
184
        },
185

186
        /**
187
         * Reset subchart selection
188
         * @function subchart․reset
189
         * @instance
190
         * @memberof Chart
191
         * @example
192
         * // Reset subchart selection
193
         * chart.subchart.reset();
194
         */
195
        reset(): void {
196
                const $$ = this.internal;
6✔
197
                const {brush} = $$;
6✔
198

199
                if ($$.state.isCanvasMode) {
6!
NEW
200
                        $$.clearCanvasSubchartDomain?.(true, false);
×
NEW
201
                        return;
×
202
                }
203

204
                brush.clear(brush.getSelection());
6✔
205
        }
206
});
207

208
export default {
209
        subchart
210
};
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