@circutor/charts 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundler/itic-chart.js +1 -1
- package/dist/charts/charts.esm.js +1 -1
- package/dist/charts/p-70293967.entry.js +25 -0
- package/dist/cjs/charts.cjs.js +1 -1
- package/dist/cjs/itic-chart.cjs.entry.js +452 -100
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/itic-chart/index.js +59 -58
- package/dist/collection/components/itic-chart/itic-chart.i18n.js +26 -0
- package/dist/collection/components/itic-chart/itic-chart.options.js +100 -42
- package/dist/collection/components/itic-chart/itic-chart.phases.js +55 -0
- package/dist/collection/playground/itic-chart.scenarios.js +129 -0
- package/dist/collection/playground/playground.js +170 -0
- package/dist/components/itic-chart.js +2 -2
- package/dist/esm/charts.js +1 -1
- package/dist/esm/itic-chart.entry.js +452 -100
- package/dist/esm/loader.js +1 -1
- package/dist/types/components/itic-chart/index.d.ts +19 -15
- package/dist/types/components/itic-chart/itic-chart.i18n.d.ts +13 -0
- package/dist/types/components/itic-chart/itic-chart.options.d.ts +32 -17
- package/dist/types/components/itic-chart/itic-chart.phases.d.ts +17 -0
- package/dist/types/components.d.ts +19 -29
- package/dist/types/index.d.ts +1 -1
- package/package.json +2 -5
- package/readme.md +138 -73
- package/dist/charts/p-943aa343.entry.js +0 -25
package/dist/cjs/loader.cjs.js
CHANGED
|
@@ -6,7 +6,7 @@ var appGlobals = require('./app-globals-V2Kpy_OQ.js');
|
|
|
6
6
|
const defineCustomElements = async (win, options) => {
|
|
7
7
|
if (typeof window === 'undefined') return undefined;
|
|
8
8
|
await appGlobals.globalScripts();
|
|
9
|
-
return index.bootstrapLazy([["itic-chart.cjs",[[1,"itic-chart",{"groups":[1],"
|
|
9
|
+
return index.bootstrapLazy([["itic-chart.cjs",[[1,"itic-chart",{"groups":[1],"locale":[1],"timeZone":[1,"time-zone"]},null,{"groups":[{"onGroupsChange":0}],"locale":[{"onLocaleChange":0}],"timeZone":[{"onTimeZoneChange":0}]}]]]], options);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
exports.setNonce = index.setNonce;
|
|
@@ -3,22 +3,28 @@ import * as echarts from "echarts/core";
|
|
|
3
3
|
import { LineChart, ScatterChart } from "echarts/charts";
|
|
4
4
|
import { GridComponent, LegendComponent, TooltipComponent } from "echarts/components";
|
|
5
5
|
import { CanvasRenderer } from "echarts/renderers";
|
|
6
|
-
import {
|
|
6
|
+
import { getMessages, normalizeLocale } from "./itic-chart.i18n";
|
|
7
|
+
import { buildChartOptions, findClickedPoint, isValidTimeZone, parseGroups, } from "./itic-chart.options";
|
|
7
8
|
// Register only what this chart uses, so bundles don't ship all of ECharts
|
|
8
9
|
echarts.use([LineChart, ScatterChart, GridComponent, LegendComponent, TooltipComponent, CanvasRenderer]);
|
|
9
10
|
export class IticChart {
|
|
10
11
|
constructor() {
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
+
* Language of the texts, dates and numbers: `ca`, `de`, `en`, `es`, `fr` or `pt`. Only the language
|
|
14
|
+
* is used (`es-ES` → `es`); any other value falls back to `en`.
|
|
13
15
|
*/
|
|
14
|
-
this.
|
|
15
|
-
/**
|
|
16
|
-
* Name of the voltage (Y) axis.
|
|
17
|
-
*/
|
|
18
|
-
this.yAxisName = DEFAULT_SETTINGS.yAxisName;
|
|
16
|
+
this.locale = 'en';
|
|
19
17
|
this.parsedGroups = [];
|
|
20
18
|
}
|
|
21
|
-
|
|
19
|
+
onGroupsChange() {
|
|
20
|
+
this.updateChart();
|
|
21
|
+
}
|
|
22
|
+
onLocaleChange() {
|
|
23
|
+
this.updateAriaLabel();
|
|
24
|
+
this.updateChart();
|
|
25
|
+
}
|
|
26
|
+
onTimeZoneChange() {
|
|
27
|
+
this.validateTimeZone();
|
|
22
28
|
this.updateChart();
|
|
23
29
|
}
|
|
24
30
|
connectedCallback() {
|
|
@@ -26,9 +32,13 @@ export class IticChart {
|
|
|
26
32
|
if (!this.el.hasAttribute('role')) {
|
|
27
33
|
this.el.setAttribute('role', 'img');
|
|
28
34
|
}
|
|
35
|
+
this.updateAriaLabel();
|
|
29
36
|
// componentDidLoad only fires once, so re-create the chart when the element is re-attached
|
|
30
37
|
this.initChart();
|
|
31
38
|
}
|
|
39
|
+
componentWillLoad() {
|
|
40
|
+
this.validateTimeZone();
|
|
41
|
+
}
|
|
32
42
|
componentDidLoad() {
|
|
33
43
|
this.initChart();
|
|
34
44
|
}
|
|
@@ -39,6 +49,27 @@ export class IticChart {
|
|
|
39
49
|
(_b = this.chart) === null || _b === void 0 ? void 0 : _b.dispose();
|
|
40
50
|
this.chart = undefined;
|
|
41
51
|
}
|
|
52
|
+
updateAriaLabel() {
|
|
53
|
+
const current = this.el.getAttribute('aria-label');
|
|
54
|
+
if (current !== null && current !== this.defaultAriaLabel) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.defaultAriaLabel = getMessages(normalizeLocale(this.locale)).ariaLabel;
|
|
58
|
+
this.el.setAttribute('aria-label', this.defaultAriaLabel);
|
|
59
|
+
}
|
|
60
|
+
// Validated when it changes, not on every redraw, so an invalid value is only reported once
|
|
61
|
+
validateTimeZone() {
|
|
62
|
+
this.validTimeZone = undefined;
|
|
63
|
+
if (!this.timeZone) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (isValidTimeZone(this.timeZone)) {
|
|
67
|
+
this.validTimeZone = this.timeZone;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.error(`[itic-chart] Invalid "timeZone" prop: "${this.timeZone}". Using the browser's time zone.`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
42
73
|
initChart() {
|
|
43
74
|
if (!this.container || this.chart) {
|
|
44
75
|
return;
|
|
@@ -57,7 +88,6 @@ export class IticChart {
|
|
|
57
88
|
this.updateChart();
|
|
58
89
|
}
|
|
59
90
|
updateChart() {
|
|
60
|
-
var _a;
|
|
61
91
|
if (!this.chart) {
|
|
62
92
|
return;
|
|
63
93
|
}
|
|
@@ -69,14 +99,13 @@ export class IticChart {
|
|
|
69
99
|
console.error('[itic-chart] Invalid "groups" prop:', error);
|
|
70
100
|
}
|
|
71
101
|
const options = buildChartOptions(this.parsedGroups, {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
tooltipFormatter: (_a = this.tooltipFormatter) !== null && _a !== void 0 ? _a : DEFAULT_SETTINGS.tooltipFormatter,
|
|
102
|
+
locale: normalizeLocale(this.locale),
|
|
103
|
+
timeZone: this.validTimeZone,
|
|
75
104
|
});
|
|
76
105
|
this.chart.setOption(options, { notMerge: true });
|
|
77
106
|
}
|
|
78
107
|
render() {
|
|
79
|
-
return h("div", { key: '
|
|
108
|
+
return h("div", { key: 'e202bbf61ad19502fd76a42f37a8ea69f2d8c58b', class: "chart", ref: el => (this.container = el) });
|
|
80
109
|
}
|
|
81
110
|
static get is() { return "itic-chart"; }
|
|
82
111
|
static get encapsulation() { return "shadow"; }
|
|
@@ -97,7 +126,7 @@ export class IticChart {
|
|
|
97
126
|
"mutable": false,
|
|
98
127
|
"complexType": {
|
|
99
128
|
"original": "ITICChartMarks[] | string",
|
|
100
|
-
"resolved": "ITICChartMarks[] | string",
|
|
129
|
+
"resolved": "ITICChartMarks[] | string | undefined",
|
|
101
130
|
"references": {
|
|
102
131
|
"ITICChartMarks": {
|
|
103
132
|
"location": "import",
|
|
@@ -108,17 +137,17 @@ export class IticChart {
|
|
|
108
137
|
}
|
|
109
138
|
},
|
|
110
139
|
"required": false,
|
|
111
|
-
"optional":
|
|
140
|
+
"optional": true,
|
|
112
141
|
"docs": {
|
|
113
142
|
"tags": [],
|
|
114
|
-
"text": "Point groups, as an array or a JSON string.
|
|
143
|
+
"text": "Point groups, as an array or a JSON string. Each group's `phase` code sets its name, color and order.\nExtra fields in groups and points are kept and passed back in `pointClick`."
|
|
115
144
|
},
|
|
116
145
|
"getter": false,
|
|
117
146
|
"setter": false,
|
|
118
147
|
"reflect": false,
|
|
119
148
|
"attribute": "groups"
|
|
120
149
|
},
|
|
121
|
-
"
|
|
150
|
+
"locale": {
|
|
122
151
|
"type": "string",
|
|
123
152
|
"mutable": false,
|
|
124
153
|
"complexType": {
|
|
@@ -130,57 +159,32 @@ export class IticChart {
|
|
|
130
159
|
"optional": false,
|
|
131
160
|
"docs": {
|
|
132
161
|
"tags": [],
|
|
133
|
-
"text": "
|
|
162
|
+
"text": "Language of the texts, dates and numbers: `ca`, `de`, `en`, `es`, `fr` or `pt`. Only the language\nis used (`es-ES` \u2192 `es`); any other value falls back to `en`."
|
|
134
163
|
},
|
|
135
164
|
"getter": false,
|
|
136
165
|
"setter": false,
|
|
137
166
|
"reflect": false,
|
|
138
|
-
"attribute": "
|
|
139
|
-
"defaultValue": "'
|
|
167
|
+
"attribute": "locale",
|
|
168
|
+
"defaultValue": "'en'"
|
|
140
169
|
},
|
|
141
|
-
"
|
|
170
|
+
"timeZone": {
|
|
142
171
|
"type": "string",
|
|
143
172
|
"mutable": false,
|
|
144
173
|
"complexType": {
|
|
145
174
|
"original": "string",
|
|
146
|
-
"resolved": "string",
|
|
175
|
+
"resolved": "string | undefined",
|
|
147
176
|
"references": {}
|
|
148
177
|
},
|
|
149
178
|
"required": false,
|
|
150
|
-
"optional":
|
|
179
|
+
"optional": true,
|
|
151
180
|
"docs": {
|
|
152
181
|
"tags": [],
|
|
153
|
-
"text": "
|
|
182
|
+
"text": "IANA time zone of the dates in the tooltip (e.g. `Europe/Madrid`). Defaults to the browser's,\nwhich is also used, with a console error, when the value isn't valid."
|
|
154
183
|
},
|
|
155
184
|
"getter": false,
|
|
156
185
|
"setter": false,
|
|
157
186
|
"reflect": false,
|
|
158
|
-
"attribute": "
|
|
159
|
-
"defaultValue": "'Voltage (% of nominal voltage)'"
|
|
160
|
-
},
|
|
161
|
-
"tooltipFormatter": {
|
|
162
|
-
"type": "unknown",
|
|
163
|
-
"mutable": false,
|
|
164
|
-
"complexType": {
|
|
165
|
-
"original": "ITICTooltipFormatter",
|
|
166
|
-
"resolved": "(point: ITICPoint, group: ITICChartMarks) => string",
|
|
167
|
-
"references": {
|
|
168
|
-
"ITICTooltipFormatter": {
|
|
169
|
-
"location": "import",
|
|
170
|
-
"path": "./itic-chart.options",
|
|
171
|
-
"id": "src/components/itic-chart/itic-chart.options.ts::ITICTooltipFormatter",
|
|
172
|
-
"referenceLocation": "ITICTooltipFormatter"
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
"required": false,
|
|
177
|
-
"optional": true,
|
|
178
|
-
"docs": {
|
|
179
|
-
"tags": [],
|
|
180
|
-
"text": "Returns the HTML of a point's tooltip. JS/React property only (not an HTML attribute).\nThe HTML is inserted as is: escaping the values is up to the formatter.\nDefaults to an English tooltip with phase, duration, voltage and timestamp."
|
|
181
|
-
},
|
|
182
|
-
"getter": false,
|
|
183
|
-
"setter": false
|
|
187
|
+
"attribute": "time-zone"
|
|
184
188
|
}
|
|
185
189
|
};
|
|
186
190
|
}
|
|
@@ -213,16 +217,13 @@ export class IticChart {
|
|
|
213
217
|
static get watchers() {
|
|
214
218
|
return [{
|
|
215
219
|
"propName": "groups",
|
|
216
|
-
"methodName": "
|
|
217
|
-
}, {
|
|
218
|
-
"propName": "xAxisName",
|
|
219
|
-
"methodName": "onOptionsChange"
|
|
220
|
+
"methodName": "onGroupsChange"
|
|
220
221
|
}, {
|
|
221
|
-
"propName": "
|
|
222
|
-
"methodName": "
|
|
222
|
+
"propName": "locale",
|
|
223
|
+
"methodName": "onLocaleChange"
|
|
223
224
|
}, {
|
|
224
|
-
"propName": "
|
|
225
|
-
"methodName": "
|
|
225
|
+
"propName": "timeZone",
|
|
226
|
+
"methodName": "onTimeZoneChange"
|
|
226
227
|
}];
|
|
227
228
|
}
|
|
228
229
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import ca from "./i18n/ca.json";
|
|
2
|
+
import de from "./i18n/de.json";
|
|
3
|
+
import en from "./i18n/en.json";
|
|
4
|
+
import es from "./i18n/es.json";
|
|
5
|
+
import fr from "./i18n/fr.json";
|
|
6
|
+
import pt from "./i18n/pt.json";
|
|
7
|
+
export const LOCALES = ['ca', 'de', 'en', 'es', 'fr', 'pt'];
|
|
8
|
+
export const DEFAULT_LOCALE = 'en';
|
|
9
|
+
const MESSAGES = { ca, de, en, es, fr, pt };
|
|
10
|
+
/** Keeps the language of a locale (`es-ES` → `es`), falling back to `en` when it isn't translated. */
|
|
11
|
+
export function normalizeLocale(locale) {
|
|
12
|
+
const language = String(locale !== null && locale !== void 0 ? locale : '')
|
|
13
|
+
.split(/[-_]/)[0]
|
|
14
|
+
.toLowerCase();
|
|
15
|
+
return LOCALES.includes(language) ? language : DEFAULT_LOCALE;
|
|
16
|
+
}
|
|
17
|
+
export const getMessages = (locale) => MESSAGES[locale];
|
|
18
|
+
const hasOwn = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
19
|
+
/** Translated event type, or the code as is when it isn't in the catalog. */
|
|
20
|
+
export function translateEventType(messages, code) {
|
|
21
|
+
return hasOwn(messages.eventTypes, code) ? messages.eventTypes[code] : code;
|
|
22
|
+
}
|
|
23
|
+
/** Translated name of a phase code that has one (`ALL`, `NONE`), or `undefined`. */
|
|
24
|
+
export function translatePhase(messages, code) {
|
|
25
|
+
return hasOwn(messages.phases, code) ? messages.phases[code] : undefined;
|
|
26
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DEFAULT_LOCALE, getMessages, translateEventType } from "./itic-chart.i18n";
|
|
2
|
+
import { getPhase, sortGroups } from "./itic-chart.phases";
|
|
3
|
+
export const DEFAULT_SETTINGS = { locale: DEFAULT_LOCALE };
|
|
2
4
|
/**
|
|
3
5
|
* Normalizes the `groups` prop, which arrives as an array from JS/React
|
|
4
6
|
* or as a JSON string when set as an HTML attribute.
|
|
@@ -13,6 +15,16 @@ export function parseGroups(groups) {
|
|
|
13
15
|
}
|
|
14
16
|
return parsed;
|
|
15
17
|
}
|
|
18
|
+
export function isValidTimeZone(timeZone) {
|
|
19
|
+
try {
|
|
20
|
+
// The result must be used: Rollup and terser drop an unused `new Intl.DateTimeFormat()` as side-effect free,
|
|
21
|
+
// which turned this check into `return true` in the built packages
|
|
22
|
+
return Boolean(new Intl.DateTimeFormat('en', { timeZone }).resolvedOptions().timeZone);
|
|
23
|
+
}
|
|
24
|
+
catch (_a) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
16
28
|
export function escapeHtml(value) {
|
|
17
29
|
return value
|
|
18
30
|
.replace(/&/g, '&')
|
|
@@ -21,57 +33,95 @@ export function escapeHtml(value) {
|
|
|
21
33
|
.replace(/"/g, '"')
|
|
22
34
|
.replace(/'/g, ''');
|
|
23
35
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
const isBlank = (value) => value == null || value === '';
|
|
37
|
+
/**
|
|
38
|
+
* Returns the tooltip HTML of a point: one row per field, in the chart's language. Rows without a value
|
|
39
|
+
* are left out, and every value is escaped, since it comes from the consumer's data.
|
|
40
|
+
*/
|
|
41
|
+
export function createTooltipFormatter({ locale, timeZone }) {
|
|
42
|
+
const messages = getMessages(locale);
|
|
43
|
+
const dateFormat = new Intl.DateTimeFormat(locale, {
|
|
44
|
+
day: '2-digit',
|
|
45
|
+
month: 'short',
|
|
46
|
+
hour: '2-digit',
|
|
47
|
+
minute: '2-digit',
|
|
48
|
+
second: '2-digit',
|
|
49
|
+
// Short events are milliseconds apart
|
|
50
|
+
fractionalSecondDigits: 3,
|
|
51
|
+
hourCycle: 'h23',
|
|
52
|
+
timeZone,
|
|
53
|
+
});
|
|
54
|
+
const durationFormat = new Intl.NumberFormat(locale, { style: 'unit', unit: 'millisecond', maximumFractionDigits: 3 });
|
|
55
|
+
const voltageFormat = new Intl.NumberFormat(locale, { style: 'percent', maximumFractionDigits: 1 });
|
|
56
|
+
// `volt` isn't a unit supported by Intl
|
|
57
|
+
const voltsFormat = new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
58
|
+
const formatDate = (ts) => {
|
|
59
|
+
const date = new Date(ts);
|
|
60
|
+
return Number.isNaN(date.getTime()) ? String(ts !== null && ts !== void 0 ? ts : '') : dateFormat.format(date);
|
|
31
61
|
};
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
const formatVolts = (value) => (Number(value) ? `${voltsFormat.format(Number(value))} V` : undefined);
|
|
63
|
+
return (point, group) => {
|
|
64
|
+
const rows = [
|
|
65
|
+
['asset', isBlank(group.assetName) ? undefined : String(group.assetName)],
|
|
66
|
+
['date', formatDate(point.ts)],
|
|
67
|
+
['eventType', isBlank(point.eventType) ? undefined : translateEventType(messages, String(point.eventType))],
|
|
68
|
+
['duration', durationFormat.format(Number(point.duration))],
|
|
69
|
+
// The value is already in %
|
|
70
|
+
['voltage', voltageFormat.format(Number(point.voltage) / 100)],
|
|
71
|
+
['status', isBlank(point.status) ? undefined : String(point.status)],
|
|
72
|
+
['phase', getPhase(group.phase, messages).name || '-'],
|
|
73
|
+
['min', formatVolts(point.min)],
|
|
74
|
+
['max', formatVolts(point.max)],
|
|
75
|
+
];
|
|
76
|
+
return rows
|
|
77
|
+
.filter((row) => row[1] !== undefined)
|
|
78
|
+
.map(([key, value]) => ` <strong>${messages.tooltip[key]}</strong>: ${escapeHtml(value)}`)
|
|
79
|
+
.join('<br/>');
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Formats the axis labels in the chart's language; ECharts always uses English separators. */
|
|
83
|
+
export function createAxisLabelFormatter(locale) {
|
|
84
|
+
const numberFormat = new Intl.NumberFormat(locale);
|
|
85
|
+
return value => numberFormat.format(value);
|
|
86
|
+
}
|
|
41
87
|
export const isClickable = (point) => point.clickable !== false;
|
|
42
88
|
export function buildChartOptions(groups, settings = DEFAULT_SETTINGS) {
|
|
43
|
-
|
|
89
|
+
const messages = getMessages(settings.locale);
|
|
90
|
+
const formatTooltip = createTooltipFormatter(settings);
|
|
91
|
+
const axisLabel = { formatter: createAxisLabelFormatter(settings.locale) };
|
|
92
|
+
return Object.assign(Object.assign({}, BASE_OPTIONS), { xAxis: Object.assign(Object.assign({}, BASE_OPTIONS.xAxis), { name: messages.xAxisName, axisLabel }), yAxis: Object.assign(Object.assign({}, BASE_OPTIONS.yAxis), { name: messages.yAxisName, axisLabel }), series: [
|
|
44
93
|
...CURVE_SERIES,
|
|
45
|
-
...groups.map((group) =>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
94
|
+
...sortGroups(groups).map((group) => {
|
|
95
|
+
const { name, color } = getPhase(group.phase, messages);
|
|
96
|
+
return {
|
|
97
|
+
type: 'scatter',
|
|
98
|
+
name,
|
|
99
|
+
// ECharts 6 reads `cursor` per data item, although its types only declare it per series
|
|
100
|
+
data: group.points.map(point => ({
|
|
101
|
+
value: [point.duration, point.voltage],
|
|
102
|
+
cursor: isClickable(point) ? 'pointer' : 'default',
|
|
103
|
+
})),
|
|
104
|
+
symbolSize: 12,
|
|
105
|
+
z: 4,
|
|
106
|
+
// Phases without a color take the next one of the ECharts palette
|
|
107
|
+
itemStyle: color ? { color, opacity: 1 } : { opacity: 1 },
|
|
108
|
+
tooltip: {
|
|
109
|
+
formatter: params => formatTooltip(group.points[params.dataIndex], group),
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}),
|
|
63
113
|
] });
|
|
64
114
|
}
|
|
65
115
|
/**
|
|
66
|
-
* Maps an ECharts click back to the original point and group
|
|
67
|
-
* scatter series after the ITIC curve series,
|
|
116
|
+
* Maps an ECharts click back to the original point and group. `buildChartOptions` draws the groups as
|
|
117
|
+
* scatter series after the ITIC curve series, sorted with `sortGroups`.
|
|
68
118
|
* Returns `undefined` for clicks outside the points and on points that aren't clickable.
|
|
69
119
|
*/
|
|
70
120
|
export function findClickedPoint(groups, { componentType, seriesIndex, dataIndex }) {
|
|
71
121
|
if (componentType !== 'series' || seriesIndex == null || dataIndex == null) {
|
|
72
122
|
return undefined;
|
|
73
123
|
}
|
|
74
|
-
const group = groups[seriesIndex - CURVE_SERIES.length];
|
|
124
|
+
const group = sortGroups(groups)[seriesIndex - CURVE_SERIES.length];
|
|
75
125
|
const point = group === null || group === void 0 ? void 0 : group.points[dataIndex];
|
|
76
126
|
if (!point || !isClickable(point)) {
|
|
77
127
|
return undefined;
|
|
@@ -96,10 +146,11 @@ const ITIC_CURVE_NODAMAGE_REGION = [
|
|
|
96
146
|
[10000, 90],
|
|
97
147
|
[100000, 90],
|
|
98
148
|
];
|
|
149
|
+
// Fixed ranges, as in Scout: ECharts clips points outside them (duration < 1 ms or voltage > 200%)
|
|
99
150
|
const BASE_OPTIONS = {
|
|
100
151
|
animation: false,
|
|
101
152
|
grid: {
|
|
102
|
-
right: '
|
|
153
|
+
right: '20px',
|
|
103
154
|
left: '60px',
|
|
104
155
|
},
|
|
105
156
|
// ECharts 6 moved the default legend to the bottom; keep it on top as in previous versions
|
|
@@ -111,7 +162,7 @@ const BASE_OPTIONS = {
|
|
|
111
162
|
},
|
|
112
163
|
xAxis: {
|
|
113
164
|
type: 'log',
|
|
114
|
-
min:
|
|
165
|
+
min: 1,
|
|
115
166
|
max: 100000,
|
|
116
167
|
nameGap: 30,
|
|
117
168
|
nameLocation: 'middle',
|
|
@@ -123,7 +174,7 @@ const BASE_OPTIONS = {
|
|
|
123
174
|
yAxis: {
|
|
124
175
|
type: 'value',
|
|
125
176
|
min: 0,
|
|
126
|
-
max:
|
|
177
|
+
max: 200,
|
|
127
178
|
nameTextStyle: {
|
|
128
179
|
fontSize: 16,
|
|
129
180
|
fontWeight: 'bold',
|
|
@@ -133,6 +184,7 @@ const BASE_OPTIONS = {
|
|
|
133
184
|
nameLocation: 'middle',
|
|
134
185
|
},
|
|
135
186
|
};
|
|
187
|
+
// `silent`: the curve doesn't react to the mouse (no tooltip, cursor or click)
|
|
136
188
|
const CURVE_SERIES = [
|
|
137
189
|
{
|
|
138
190
|
type: 'line',
|
|
@@ -144,6 +196,7 @@ const CURVE_SERIES = [
|
|
|
144
196
|
lineStyle: {
|
|
145
197
|
color: '#000',
|
|
146
198
|
},
|
|
199
|
+
silent: true,
|
|
147
200
|
showSymbol: false,
|
|
148
201
|
emphasis: {
|
|
149
202
|
disabled: true,
|
|
@@ -156,6 +209,7 @@ const CURVE_SERIES = [
|
|
|
156
209
|
origin: 'start',
|
|
157
210
|
color: '#FFF5DF',
|
|
158
211
|
},
|
|
212
|
+
silent: true,
|
|
159
213
|
showSymbol: false,
|
|
160
214
|
lineStyle: {
|
|
161
215
|
color: '#000',
|
|
@@ -171,6 +225,7 @@ const CURVE_SERIES = [
|
|
|
171
225
|
origin: 100,
|
|
172
226
|
color: '#DDFAF1',
|
|
173
227
|
},
|
|
228
|
+
silent: true,
|
|
174
229
|
showSymbol: false,
|
|
175
230
|
lineStyle: {
|
|
176
231
|
color: '#000',
|
|
@@ -186,6 +241,7 @@ const CURVE_SERIES = [
|
|
|
186
241
|
origin: 100,
|
|
187
242
|
color: '#DDFAF1',
|
|
188
243
|
},
|
|
244
|
+
silent: true,
|
|
189
245
|
showSymbol: false,
|
|
190
246
|
lineStyle: {
|
|
191
247
|
color: '#000',
|
|
@@ -204,6 +260,7 @@ const CURVE_SERIES = [
|
|
|
204
260
|
origin: 100,
|
|
205
261
|
color: '#DDFAF1',
|
|
206
262
|
},
|
|
263
|
+
silent: true,
|
|
207
264
|
showSymbol: false,
|
|
208
265
|
lineStyle: {
|
|
209
266
|
color: 'transparent',
|
|
@@ -222,6 +279,7 @@ const CURVE_SERIES = [
|
|
|
222
279
|
origin: 100,
|
|
223
280
|
color: '#DDFAF1',
|
|
224
281
|
},
|
|
282
|
+
silent: true,
|
|
225
283
|
showSymbol: false,
|
|
226
284
|
lineStyle: {
|
|
227
285
|
color: 'transparent',
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { translatePhase } from "./itic-chart.i18n";
|
|
2
|
+
const L1 = '#a67c52';
|
|
3
|
+
const L2 = '#20262C';
|
|
4
|
+
const L3 = '#B9BDC0';
|
|
5
|
+
const THREE_PHASE = '#00B388';
|
|
6
|
+
// Same catalog as Scout. Names that change with the language (`ALL`, `NONE`) are in the i18n JSON files.
|
|
7
|
+
const PHASES = {
|
|
8
|
+
AN: { name: 'L1', color: L1 },
|
|
9
|
+
BN: { name: 'L2', color: L2 },
|
|
10
|
+
CN: { name: 'L3', color: L3 },
|
|
11
|
+
AB: { name: 'L1', color: L1 },
|
|
12
|
+
BC: { name: 'L2', color: L2 },
|
|
13
|
+
CA: { name: 'L3', color: L3 },
|
|
14
|
+
'AN,BN,CN': { name: 'L1,L2,L3', color: THREE_PHASE },
|
|
15
|
+
'AB,BC,CA': { name: 'L1,L2,L3', color: THREE_PHASE },
|
|
16
|
+
ALL: { name: '', color: '#4C5CC5' },
|
|
17
|
+
A: { name: 'L1' },
|
|
18
|
+
B: { name: 'L2' },
|
|
19
|
+
C: { name: 'L3' },
|
|
20
|
+
'AN,BN': { name: 'L1,L2' },
|
|
21
|
+
'AN,CN': { name: 'L1,L3' },
|
|
22
|
+
'BN,CN': { name: 'L2,L3' },
|
|
23
|
+
'AB,BC': { name: 'L1,L2' },
|
|
24
|
+
'AB,CA': { name: 'L1,L3' },
|
|
25
|
+
'BC,CA': { name: 'L2,L3' },
|
|
26
|
+
NONE: { name: '' },
|
|
27
|
+
};
|
|
28
|
+
const phaseCode = (phase) => (phase == null ? '' : String(phase));
|
|
29
|
+
// Unknown codes keep the code as name and have no color
|
|
30
|
+
const catalogPhase = (code) => Object.prototype.hasOwnProperty.call(PHASES, code) ? PHASES[code] : { name: code };
|
|
31
|
+
/** Name, in the given language, and color of a phase code. */
|
|
32
|
+
export function getPhase(phase, messages) {
|
|
33
|
+
var _a;
|
|
34
|
+
const code = phaseCode(phase);
|
|
35
|
+
const known = catalogPhase(code);
|
|
36
|
+
return Object.assign(Object.assign({}, known), { name: (_a = translatePhase(messages, code)) !== null && _a !== void 0 ? _a : known.name });
|
|
37
|
+
}
|
|
38
|
+
// `NONE` (no name) goes after the named phases and `ALL` always last. Only these two names are translated,
|
|
39
|
+
// so ranking them by code keeps the order the same in every language.
|
|
40
|
+
const rank = (code) => (code === 'ALL' ? 2 : code === 'NONE' ? 1 : 0);
|
|
41
|
+
/**
|
|
42
|
+
* Sorts groups by phase name, then by code (e.g. `AN` and `AB` are both "L1"), with `NONE` and `ALL` last.
|
|
43
|
+
* Compares characters, not with a locale's rules, so the legend is the same in every language.
|
|
44
|
+
* Returns a new array with the same group objects; groups with the same code keep their order.
|
|
45
|
+
*/
|
|
46
|
+
export function sortGroups(groups) {
|
|
47
|
+
const keyed = groups.map(group => {
|
|
48
|
+
const code = phaseCode(group.phase);
|
|
49
|
+
return { group, code, rank: rank(code), name: catalogPhase(code).name };
|
|
50
|
+
});
|
|
51
|
+
return keyed
|
|
52
|
+
.sort((a, b) => a.rank - b.rank || compare(a.name, b.name) || compare(a.code, b.code))
|
|
53
|
+
.map(({ group }) => group);
|
|
54
|
+
}
|
|
55
|
+
const compare = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|