@record-evolution/widget-linechart 1.6.7 → 1.6.9

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent widget-linechart following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "widget-linechart",
6
- "version": "1.6.7",
6
+ "version": "1.6.9",
7
7
  "type": "module",
8
8
  "main": "dist/widget-linechart.js",
9
9
  "types": "dist/src/widget-linechart.d.ts",
@@ -1,6 +1,4 @@
1
1
  {
2
- "title": "Demo Chart",
3
- "subTitle": "This is a demo chart with multiple data series.",
4
2
  "axis": {
5
3
  "timeseries": true,
6
4
  "xAxisLabel": "Time",
@@ -184,6 +184,7 @@ export class WidgetLinechart extends LitElement {
184
184
  this.chartContainer = this.shadowRoot?.querySelector('.chart-container')
185
185
  this.transformData()
186
186
  this.applyData()
187
+ this.registerTheme(this.theme)
187
188
  // Add ResizeObserver for chart container
188
189
  if (this.chartContainer) {
189
190
  this.resizeObserver = new ResizeObserver(() => {
@@ -196,16 +197,16 @@ export class WidgetLinechart extends LitElement {
196
197
  }
197
198
 
198
199
  registerTheme(theme?: Theme) {
199
- if (!theme || !theme.theme_object || !theme.theme_name) return
200
-
201
- console.log('Registering theme', theme)
202
- echarts.registerTheme(theme.theme_name, theme.theme_object)
203
200
  const cssTextColor = getComputedStyle(this).getPropertyValue('--re-text-color').trim()
204
201
  const cssBgColor = getComputedStyle(this).getPropertyValue('--re-background-color').trim()
205
202
  this.themeBgColor = cssBgColor || this.theme?.theme_object?.backgroundColor
206
203
  this.themeTitleColor = cssTextColor || this.theme?.theme_object?.title?.textStyle?.color
207
204
  this.themeSubtitleColor =
208
205
  cssTextColor || this.theme?.theme_object?.title?.subtextStyle?.color || this.themeTitleColor
206
+
207
+ if (!theme || !theme.theme_object || !theme.theme_name) return
208
+
209
+ echarts.registerTheme(theme.theme_name, theme.theme_object)
209
210
  }
210
211
 
211
212
  transformData() {
@@ -224,7 +225,7 @@ export class WidgetLinechart extends LitElement {
224
225
  ds.data ??= []
225
226
 
226
227
  // pivot data
227
- const distincts = [...new Set(ds.data.map((d) => d.pivot))].sort()
228
+ const distincts = [...new Set(ds.data.map((d) => d.pivot ?? ''))].sort()
228
229
  const derivedBgColors = tinycolor(ds.backgroundColor as ColorInput | undefined)
229
230
  .monochromatic(distincts.length)
230
231
  .map((c: any) => c.toHexString())
@@ -1,486 +0,0 @@
1
- import { html, css, LitElement } from 'lit'
2
- import { repeat } from 'lit/directives/repeat.js'
3
- import { customElement, property, state } from 'lit/decorators.js'
4
- import Chart, { ChartDataset } from 'chart.js/auto'
5
- import tinycolor, { ColorInput } from 'tinycolor2'
6
- // This does not work. See comments at the end of the file.
7
- // import 'chartjs-adapter-dayjs-4/dist/chartjs-adapter-dayjs-4.esm';
8
- // import 'chartjs-adapter-moment';
9
- // import 'chartjs-adapter-date-fns';
10
- import { InputData } from './definition-schema.js'
11
-
12
- type Dataseries = Exclude<InputData['dataseries'], undefined>[number]
13
- type Data = Exclude<Dataseries['data'], undefined>[number]
14
- type ChartCombination = { chartJsInstance?: Chart; dataSets: ChartDataset[] }
15
-
16
- @customElement('widget-linechart-versionplaceholder')
17
- export class WidgetLinechart extends LitElement {
18
- @property({ type: Object })
19
- inputData?: InputData
20
-
21
- @state()
22
- private canvasList: Map<string, ChartCombination> = new Map()
23
-
24
- version: string = 'versionplaceholder'
25
- chartContainer?: HTMLElement | DocumentFragment
26
-
27
- update(changedProperties: Map<string, any>) {
28
- if (changedProperties.has('inputData') && this.chartContainer) {
29
- this.transformInputData()
30
- this.applyInputData()
31
- }
32
- super.update(changedProperties)
33
- }
34
-
35
- protected firstUpdated(): void {
36
- this.chartContainer = this.shadowRoot?.querySelector('.chart-container') as HTMLElement
37
- this.transformInputData()
38
- this.applyInputData()
39
- }
40
-
41
- transformInputData() {
42
- if (!this?.inputData?.dataseries?.length) return
43
-
44
- // reset all existing chart dataseries
45
- this.canvasList.forEach((chartM) => (chartM.dataSets = []))
46
- this.inputData.dataseries.sort((a, b) => (a.advanced?.drawOrder ?? 0) - (b.advanced?.drawOrder ?? 0))
47
- this.inputData.dataseries.forEach((ds) => {
48
- ds.advanced ??= {}
49
- ds.advanced.chartName ??= ''
50
- if (ds.borderDash && typeof ds.borderDash === 'string') {
51
- ds.borderDash = JSON.parse(ds.borderDash)
52
- } else {
53
- ds.borderDash = undefined
54
- }
55
- ds.data ??= []
56
-
57
- // pivot data
58
- const distincts = [...new Set(ds.data.map((d: Data) => d.pivot))].sort()
59
- const derivedBgColors = tinycolor(ds.backgroundColor as ColorInput | undefined)
60
- .monochromatic(distincts.length)
61
- .map((c: any) => c.toHexString())
62
- const derivedBdColors = tinycolor(ds.borderColor as ColorInput | undefined)
63
- .monochromatic(distincts.length)
64
- .map((c: any) => c.toHexString())
65
- //sd
66
- distincts.forEach((piv, i) => {
67
- const prefix = piv ? `${piv} - ` : ''
68
- const pds: any = {
69
- label: prefix + ds.label,
70
- type: ds.type,
71
- showLine: true,
72
- borderColor: ds.advanced?.chartName?.includes('#split#')
73
- ? ds.borderColor
74
- : derivedBdColors[i],
75
- backgroundColor: ds.advanced?.chartName?.includes('#split#')
76
- ? ds.backgroundColor
77
- : derivedBgColors[i],
78
- styling: ds.styling,
79
- pointStyle: ds.styling?.pointStyle,
80
- radius: ds.styling?.radius,
81
- fill: ds.styling?.fill,
82
- borderWidth: ds.styling?.borderWidth,
83
- borderDash: ds.borderDash,
84
- advanced: ds.advanced,
85
- data: distincts.length === 1 ? ds.data : ds.data?.filter((d) => d.pivot === piv)
86
- }
87
- let chartName = ds.advanced?.chartName ?? ''
88
- if (chartName.includes('#split#')) {
89
- chartName = prefix + chartName
90
- }
91
- // If the chartName ends with :pivot: then create a seperate chart for each pivoted dataseries
92
-
93
- if (!this.canvasList.has(chartName)) {
94
- // initialize new charts
95
- this.canvasList.set(chartName, {
96
- chartJsInstance: undefined,
97
- // @ts-ignore
98
- dataSets: [] as Dataseries[]
99
- })
100
- }
101
- this.canvasList.get(chartName)?.dataSets.push(pds)
102
- })
103
- })
104
- // prevent duplicate transformation
105
- // this.inputData.dataseries = []
106
- // console.log('new linechart datasets', this.canvasList)
107
- }
108
-
109
- async applyInputData() {
110
- this.setupCharts()
111
-
112
- this.requestUpdate()
113
- await this.updateComplete
114
- this.canvasList.forEach(({ chartJsInstance, dataSets }) => {
115
- if (chartJsInstance) {
116
- chartJsInstance.data.datasets = dataSets
117
- chartJsInstance.options ??= {}
118
- chartJsInstance.options.scales ??= {}
119
- chartJsInstance.options.scales.x ??= {}
120
- chartJsInstance.options.scales.y ??= {}
121
- chartJsInstance.options.scales.x.type = this.xAxisType()
122
- // @ts-ignore
123
- chartJsInstance.options.scales.x.title.display = !!this.inputData?.axis?.xAxisLabel
124
- // @ts-ignore
125
- chartJsInstance.options.scales.x.title.text = this.inputData?.axis?.xAxisLabel
126
- // @ts-ignore
127
- chartJsInstance.options.scales.y.title.display = !!this.inputData?.axis?.yAxisLabel
128
- // @ts-ignore
129
- chartJsInstance.options.scales.y.title.text = this.inputData?.axis?.yAxisLabel
130
- chartJsInstance?.update('resize')
131
- }
132
- })
133
- }
134
-
135
- xAxisType(): 'linear' | 'logarithmic' | 'category' | 'time' | 'timeseries' | undefined {
136
- if (this.inputData?.axis?.timeseries) return 'time'
137
- const onePoint = this.inputData?.dataseries?.[0]?.data?.[0]
138
- if (!isNaN(Number(onePoint?.x))) return 'linear'
139
- return 'category'
140
- }
141
-
142
- setupCharts() {
143
- this.canvasList.forEach((chartM, chartName) => {
144
- if (!chartM.dataSets.length) {
145
- this.shadowRoot?.querySelector(`div[name="${chartName}"]`)?.remove()
146
- this.canvasList.delete(chartName)
147
- return
148
- }
149
- if (chartM.chartJsInstance) return
150
-
151
- if (!this.chartContainer) throw new Error('chartContainer not found')
152
-
153
- const newContainer = document.createElement('div')
154
- newContainer.setAttribute('name', chartName)
155
- newContainer.setAttribute('class', 'sizer')
156
- const canvas = document.createElement('canvas')
157
- canvas.setAttribute('name', chartName)
158
- newContainer.appendChild(canvas)
159
- this.chartContainer.appendChild(newContainer)
160
-
161
- if (!canvas) throw new Error('canvas not found')
162
- // console.log('chartM', canvas, chartM.chart)
163
- chartM.chartJsInstance = new Chart(canvas, {
164
- type: 'line',
165
- data: {
166
- // @ts-ignore
167
- datasets: chartM.dataSets
168
- },
169
- options: {
170
- responsive: true,
171
- maintainAspectRatio: false,
172
- animations: {
173
- colors: false,
174
- x: false
175
- },
176
- transitions: {
177
- active: {
178
- animation: {
179
- duration: 100
180
- }
181
- }
182
- },
183
- scales: {
184
- x: {
185
- type: this.xAxisType(),
186
- title: {
187
- display: !!this.inputData?.axis?.xAxisLabel,
188
- text: this.inputData?.axis?.xAxisLabel
189
- }
190
- },
191
- y: {
192
- title: {
193
- display: !!this.inputData?.axis?.yAxisLabel,
194
- text: this.inputData?.axis?.yAxisLabel
195
- }
196
- }
197
- }
198
- }
199
- })
200
- })
201
- }
202
-
203
- static styles = css`
204
- :host {
205
- display: block;
206
- color: var(--re-text-color, #000);
207
-
208
- font-family: sans-serif;
209
- padding: 16px;
210
- box-sizing: border-box;
211
- margin: auto;
212
- }
213
-
214
- .paging:not([active]) {
215
- display: none !important;
216
- }
217
-
218
- .columnLayout {
219
- flex-direction: column;
220
- }
221
-
222
- .wrapper {
223
- display: flex;
224
- flex-direction: column;
225
- height: 100%;
226
- width: 100%;
227
- }
228
-
229
- .chart-container {
230
- display: flex;
231
- flex: 1;
232
- overflow: hidden;
233
- position: relative;
234
- }
235
-
236
- .sizer {
237
- flex: 1;
238
- overflow: hidden;
239
- position: relative;
240
- }
241
-
242
- header {
243
- display: flex;
244
- flex-direction: column;
245
- margin: 0 0 16px 0;
246
- }
247
- h3 {
248
- margin: 0;
249
- max-width: 300px;
250
- overflow: hidden;
251
- text-overflow: ellipsis;
252
- white-space: nowrap;
253
- }
254
- p {
255
- margin: 10px 0 0 0;
256
- max-width: 300px;
257
- font-size: 14px;
258
- line-height: 17px;
259
- }
260
-
261
- .no-data {
262
- font-size: 20px;
263
- color: var(--re-text-color, #000);
264
- display: flex;
265
- height: 100%;
266
- width: 100%;
267
- text-align: center;
268
- align-items: center;
269
- justify-content: center;
270
- }
271
- `
272
-
273
- render() {
274
- return html`
275
- <div class="wrapper">
276
- <header>
277
- <h3 class="paging" ?active=${this.inputData?.title}>${this.inputData?.title}</h3>
278
- <p class="paging" ?active=${this.inputData?.subTitle}>${this.inputData?.subTitle}</p>
279
- </header>
280
-
281
- <div class="paging no-data" ?active=${!this.canvasList.size}>No Data</div>
282
- <div
283
- class="chart-container ${this?.inputData?.axis?.columnLayout ? 'columnLayout' : ''}"
284
- ></div>
285
- </div>
286
- `
287
- }
288
- }
289
-
290
- // ############################################### WORKAROUND #######################################################################
291
- //
292
- // For some reason the import of that adapter is messed up. I suspect that rollup does things in the wrong order.
293
- // Because this is an import that has side effects. i.e. it overrides the adapters of the previously imported Chart.js
294
- // So the current solution is to execute the source code here in-line. (moving this to a local file and importing that does not work!)
295
- // This is the source code of https://github.com/chartjs/chartjs-adapter-date-fns/blob/master/src/index.js
296
-
297
- import { _adapters } from 'chart.js'
298
-
299
- import {
300
- parse,
301
- parseISO,
302
- toDate,
303
- isValid,
304
- format,
305
- startOfSecond,
306
- startOfMinute,
307
- startOfHour,
308
- startOfDay,
309
- startOfWeek,
310
- startOfMonth,
311
- startOfQuarter,
312
- startOfYear,
313
- addMilliseconds,
314
- addSeconds,
315
- addMinutes,
316
- addHours,
317
- addDays,
318
- addWeeks,
319
- addMonths,
320
- addQuarters,
321
- addYears,
322
- differenceInMilliseconds,
323
- differenceInSeconds,
324
- differenceInMinutes,
325
- differenceInHours,
326
- differenceInDays,
327
- differenceInWeeks,
328
- differenceInMonths,
329
- differenceInQuarters,
330
- differenceInYears,
331
- endOfSecond,
332
- endOfMinute,
333
- endOfHour,
334
- endOfDay,
335
- endOfWeek,
336
- endOfMonth,
337
- endOfQuarter,
338
- endOfYear
339
- } from 'date-fns'
340
-
341
- const FORMATS = {
342
- datetime: 'MMM d, yyyy, h:mm:ss aaaa',
343
- millisecond: 'h:mm:ss.SSS aaaa',
344
- second: 'h:mm:ss aaaa',
345
- minute: 'h:mm aaaa',
346
- hour: 'ha',
347
- day: 'MMM d',
348
- week: 'PP',
349
- month: 'MMM yyyy',
350
- quarter: 'qqq - yyyy',
351
- year: 'yyyy'
352
- }
353
-
354
- _adapters._date.override({
355
- _id: 'date-fns', // DEBUG
356
- formats: function () {
357
- return FORMATS
358
- },
359
-
360
- parse: function (value, fmt) {
361
- if (value === null || typeof value === 'undefined') {
362
- return null
363
- }
364
- const type = typeof value
365
- if (type === 'number' || value instanceof Date) {
366
- // @ts-ignore
367
- value = toDate(value)
368
- } else if (type === 'string') {
369
- if (typeof fmt === 'string') {
370
- // @ts-ignore
371
- value = parse(value, fmt, new Date(), this.options)
372
- } else {
373
- // @ts-ignore
374
- value = parseISO(value, this.options)
375
- }
376
- }
377
- // @ts-ignore
378
- return isValid(value) ? value.getTime() : null
379
- },
380
-
381
- format: function (time, fmt) {
382
- return format(time, fmt, this.options)
383
- },
384
-
385
- // @ts-ignore
386
- add: function (time, amount, unit) {
387
- switch (unit) {
388
- case 'millisecond':
389
- return addMilliseconds(time, amount)
390
- case 'second':
391
- return addSeconds(time, amount)
392
- case 'minute':
393
- return addMinutes(time, amount)
394
- case 'hour':
395
- return addHours(time, amount)
396
- case 'day':
397
- return addDays(time, amount)
398
- case 'week':
399
- return addWeeks(time, amount)
400
- case 'month':
401
- return addMonths(time, amount)
402
- case 'quarter':
403
- return addQuarters(time, amount)
404
- case 'year':
405
- return addYears(time, amount)
406
- default:
407
- return time
408
- }
409
- },
410
-
411
- diff: function (max, min, unit) {
412
- switch (unit) {
413
- case 'millisecond':
414
- return differenceInMilliseconds(max, min)
415
- case 'second':
416
- return differenceInSeconds(max, min)
417
- case 'minute':
418
- return differenceInMinutes(max, min)
419
- case 'hour':
420
- return differenceInHours(max, min)
421
- case 'day':
422
- return differenceInDays(max, min)
423
- case 'week':
424
- return differenceInWeeks(max, min)
425
- case 'month':
426
- return differenceInMonths(max, min)
427
- case 'quarter':
428
- return differenceInQuarters(max, min)
429
- case 'year':
430
- return differenceInYears(max, min)
431
- default:
432
- return 0
433
- }
434
- },
435
-
436
- // @ts-ignore
437
- startOf: function (time, unit, weekday) {
438
- switch (unit) {
439
- case 'second':
440
- return startOfSecond(time)
441
- case 'minute':
442
- return startOfMinute(time)
443
- case 'hour':
444
- return startOfHour(time)
445
- case 'day':
446
- return startOfDay(time)
447
- case 'week':
448
- return startOfWeek(time)
449
- case 'isoWeek':
450
- // @ts-ignore
451
- return startOfWeek(time, { weekStartsOn: +weekday })
452
- case 'month':
453
- return startOfMonth(time)
454
- case 'quarter':
455
- return startOfQuarter(time)
456
- case 'year':
457
- return startOfYear(time)
458
- default:
459
- return time
460
- }
461
- },
462
-
463
- // @ts-ignore
464
- endOf: function (time, unit) {
465
- switch (unit) {
466
- case 'second':
467
- return endOfSecond(time)
468
- case 'minute':
469
- return endOfMinute(time)
470
- case 'hour':
471
- return endOfHour(time)
472
- case 'day':
473
- return endOfDay(time)
474
- case 'week':
475
- return endOfWeek(time)
476
- case 'month':
477
- return endOfMonth(time)
478
- case 'quarter':
479
- return endOfQuarter(time)
480
- case 'year':
481
- return endOfYear(time)
482
- default:
483
- return time
484
- }
485
- }
486
- })