This repository has been archived by the owner on Jul 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 85
/
barchart.ts
119 lines (105 loc) · 3.65 KB
/
barchart.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @license
* Copyright 2018 Google LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/
import {View} from 'vega';
import embed, {Mode, Result as EmbedRes, VisualizationSpec} from 'vega-embed';
import {Drawable, VisOptions} from '../types';
import {getDrawArea, nextFrame, shallowEquals} from './render_utils';
/**
* Renders a barchart.
*
* @param data Data in the following format, (an array of objects)
* [ {index: number, value: number} ... ]
* @param container An HTMLElement or Surface in which to draw the bar chart.
* Note that the chart expects to have complete control over
* the contents of the container and can clear its contents
* at will.
* @param opts optional parameters
* @param opts.width width of chart in px
* @param opts.height height of chart in px
* @param opts.xLabel label for x-axis, set to null to hide the
* @param opts.yLabel label for y-axis, set to null to hide the
*
* @returns Promise - indicates completion of rendering
*/
export async function renderBarchart(
data: Array<{index: number; value: number;}>, container: Drawable,
opts: VisOptions = {}): Promise<void> {
const drawArea = getDrawArea(container);
const values = data;
const options = Object.assign({}, defaultOpts, opts);
// If we have rendered this chart before with the same options we can do a
// data only update, else we do a regular re-render.
if (instances.has(drawArea)) {
const instanceInfo = instances.get(drawArea)!;
if (shallowEquals(options, instanceInfo.lastOptions)) {
await nextFrame();
const view = instanceInfo.view;
const changes = view.changeset().remove(() => true).insert(values);
await view.change('values', changes).runAsync();
return;
}
}
const {xLabel, yLabel, xType, yType} = options;
let xAxis: {}|null = null;
if (xLabel != null) {
xAxis = {title: xLabel};
}
let yAxis: {}|null = null;
if (yLabel != null) {
yAxis = {title: yLabel};
}
const embedOpts = {
actions: false,
mode: 'vega-lite' as Mode,
};
const spec: VisualizationSpec = {
'width': options.width || drawArea.clientWidth,
'height': options.height || drawArea.clientHeight,
'padding': 5,
'autosize': {
'type': 'fit',
'contains': 'padding',
'resize': true,
},
'data': {'values': values, 'name': 'values'},
'mark': 'bar',
'encoding': {
'x': {'field': 'index', 'type': xType, 'axis': xAxis},
'y': {'field': 'value', 'type': yType, 'axis': yAxis}
}
};
await nextFrame();
const embedRes = await embed(drawArea, spec, embedOpts);
instances.set(drawArea, {
view: embedRes.view,
lastOptions: options,
});
}
const defaultOpts = {
xLabel: '',
yLabel: '',
xType: 'ordinal',
yType: 'quantitative',
};
// We keep a map of containers to chart instances in order to reuse the instance
// where possible.
const instances: Map<HTMLElement, InstanceInfo> =
new Map<HTMLElement, InstanceInfo>();
interface InstanceInfo {
view: View;
lastOptions: VisOptions;
}