@dataloop-ai/components 0.17.94 → 0.17.96
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 +1 -1
- package/src/components/compound/DlCharts/charts/DlScatterChart/DlScatterChart.vue +665 -0
- package/src/components/compound/DlCharts/charts/DlScatterChart/index.ts +2 -0
- package/src/components/compound/DlCharts/charts/index.ts +1 -0
- package/src/components/compound/DlDateTime/DlDatePicker/DlDatePicker.vue +9 -1
- package/src/components/compound/DlSearches/DlSmartSearch/DlSmartSearch.vue +20 -3
- package/src/components/compound/DlSearches/DlSmartSearch/components/DlSmartSearchInput.vue +4 -1
- package/src/components/compound/DlSearches/DlSmartSearch/utils/index.ts +10 -38
- package/src/components/compound/DlSearches/DlSmartSearch/utils/utils.ts +12 -29
- package/src/demos/DlScatterChartDemo.vue +161 -0
- package/src/demos/index.ts +2 -0
- package/src/hooks/use-suggestions.ts +44 -29
package/package.json
CHANGED
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:style="cssVars"
|
|
4
|
+
:class="chartWrapperClasses"
|
|
5
|
+
>
|
|
6
|
+
<DLScatter
|
|
7
|
+
:id="id"
|
|
8
|
+
ref="scatterChart"
|
|
9
|
+
:class="chartClasses"
|
|
10
|
+
:style="(chartStyles, `max-height: ${wrapperHeight}`)"
|
|
11
|
+
:data="chartData"
|
|
12
|
+
:options="chartOptions"
|
|
13
|
+
@mouseout="onChartLeave"
|
|
14
|
+
/>
|
|
15
|
+
<slot
|
|
16
|
+
v-if="displayLabels"
|
|
17
|
+
v-bind="{ ...labelStyles, labels: xLabels, chartWidth }"
|
|
18
|
+
name="axe-x-labels"
|
|
19
|
+
>
|
|
20
|
+
<dl-chart-labels
|
|
21
|
+
:font-size="labelStyles.fontSize"
|
|
22
|
+
:title="labelStyles.title"
|
|
23
|
+
:title-size="labelStyles.titleSize"
|
|
24
|
+
:title-color="labelStyles.titleColor"
|
|
25
|
+
:label-color="labelStyles.labelColor"
|
|
26
|
+
:width="chartWidth"
|
|
27
|
+
:labels="xLabels"
|
|
28
|
+
/>
|
|
29
|
+
</slot>
|
|
30
|
+
<slot
|
|
31
|
+
v-if="displayBrush"
|
|
32
|
+
v-bind="{
|
|
33
|
+
chartWidth,
|
|
34
|
+
modelValue: brush.value,
|
|
35
|
+
handleBrushUpdate,
|
|
36
|
+
brushClasses,
|
|
37
|
+
...brushProperties
|
|
38
|
+
}"
|
|
39
|
+
name="brush"
|
|
40
|
+
>
|
|
41
|
+
<dl-brush
|
|
42
|
+
:model-value="brush.value"
|
|
43
|
+
:width="chartWidth"
|
|
44
|
+
:min="brushProperties.min"
|
|
45
|
+
:max="brushProperties.max"
|
|
46
|
+
:class="brushClasses"
|
|
47
|
+
:thumb-size="brushProperties.thumbSize"
|
|
48
|
+
:track-size="brushProperties.trackSize"
|
|
49
|
+
:step="brushProperties.step"
|
|
50
|
+
:drag-range="brushProperties.dragRange"
|
|
51
|
+
@update:model-value="handleBrushUpdate"
|
|
52
|
+
/>
|
|
53
|
+
</slot>
|
|
54
|
+
<slot
|
|
55
|
+
v-if="displayLegend"
|
|
56
|
+
v-bind="{
|
|
57
|
+
data: legendDatasets,
|
|
58
|
+
chartWidth,
|
|
59
|
+
onHide: hideData,
|
|
60
|
+
onHoverLegend,
|
|
61
|
+
onLeaveLegend,
|
|
62
|
+
...legendProperties
|
|
63
|
+
}"
|
|
64
|
+
name="legend"
|
|
65
|
+
>
|
|
66
|
+
<dl-chart-legend
|
|
67
|
+
:datasets="legendDatasets"
|
|
68
|
+
:width="chartWidth"
|
|
69
|
+
:class="legendClasses"
|
|
70
|
+
:align-items="legendProperties.alignItems"
|
|
71
|
+
@hide="hideData"
|
|
72
|
+
@on-hover="onHoverLegend"
|
|
73
|
+
@on-leave="onLeaveLegend"
|
|
74
|
+
/>
|
|
75
|
+
</slot>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
|
|
79
|
+
<script lang="ts">
|
|
80
|
+
import { Scatter as DLScatter } from '../../types/typedCharts'
|
|
81
|
+
import {
|
|
82
|
+
CommonProps,
|
|
83
|
+
ColumnChartProps,
|
|
84
|
+
defaultLineChartProps
|
|
85
|
+
} from '../../types/props'
|
|
86
|
+
import { defineComponent, reactive, watch, ref, computed } from 'vue-demi'
|
|
87
|
+
import DlBrush from '../../components/DlBrush.vue'
|
|
88
|
+
import DlChartLegend from '../../components/DlChartLegend.vue'
|
|
89
|
+
import DlChartLabels from '../../components/DlChartLabels.vue'
|
|
90
|
+
import { updateKeys } from '../../../../../utils/update-key'
|
|
91
|
+
import { hexToRgbA } from '../../../../../utils'
|
|
92
|
+
import {
|
|
93
|
+
Chart as ChartJS,
|
|
94
|
+
Title,
|
|
95
|
+
Tooltip,
|
|
96
|
+
Legend,
|
|
97
|
+
BarElement,
|
|
98
|
+
CategoryScale,
|
|
99
|
+
LinearScale,
|
|
100
|
+
PointElement,
|
|
101
|
+
LineElement,
|
|
102
|
+
BarControllerDatasetOptions,
|
|
103
|
+
TimeScale
|
|
104
|
+
} from 'chart.js'
|
|
105
|
+
import type {
|
|
106
|
+
Chart,
|
|
107
|
+
ChartMeta,
|
|
108
|
+
ChartDataset,
|
|
109
|
+
ActiveElement,
|
|
110
|
+
ChartData,
|
|
111
|
+
DatasetController,
|
|
112
|
+
ScatterControllerDatasetOptions
|
|
113
|
+
} from 'chart.js'
|
|
114
|
+
import { orderBy, merge, isEqual, unionBy, cloneDeep } from 'lodash'
|
|
115
|
+
import { useThemeVariables } from '../../../../../hooks/use-theme'
|
|
116
|
+
|
|
117
|
+
ChartJS.register(
|
|
118
|
+
Title,
|
|
119
|
+
Tooltip,
|
|
120
|
+
Legend,
|
|
121
|
+
BarElement,
|
|
122
|
+
CategoryScale,
|
|
123
|
+
LinearScale,
|
|
124
|
+
PointElement,
|
|
125
|
+
LineElement,
|
|
126
|
+
TimeScale
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
export default defineComponent({
|
|
130
|
+
name: 'DlScatterChart',
|
|
131
|
+
components: {
|
|
132
|
+
DlBrush,
|
|
133
|
+
DlChartLegend,
|
|
134
|
+
DLScatter,
|
|
135
|
+
DlChartLabels
|
|
136
|
+
},
|
|
137
|
+
props: {
|
|
138
|
+
id: {
|
|
139
|
+
type: String,
|
|
140
|
+
default: null
|
|
141
|
+
},
|
|
142
|
+
...CommonProps,
|
|
143
|
+
...ColumnChartProps
|
|
144
|
+
},
|
|
145
|
+
setup(props, { slots }) {
|
|
146
|
+
const { variables } = useThemeVariables()
|
|
147
|
+
|
|
148
|
+
const chartWidth = ref('100%')
|
|
149
|
+
|
|
150
|
+
const chartHoverDataset: { value: null | ChartMeta } = {
|
|
151
|
+
value: null
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const onResize = (
|
|
155
|
+
chart: Chart,
|
|
156
|
+
size: { height: number; width: number }
|
|
157
|
+
) => {
|
|
158
|
+
if (chart?.scales?.x?.width) {
|
|
159
|
+
chartWidth.value = `${
|
|
160
|
+
parseInt(chart.scales.x.width as unknown as string) -
|
|
161
|
+
parseInt(brushProperties.value.thumbSize) / 4
|
|
162
|
+
}px`
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const chart = computed(() => {
|
|
167
|
+
return scatterChart.value?.chart?.value || {}
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
const replaceColor = (key: keyof typeof variables) =>
|
|
171
|
+
variables[key] || key
|
|
172
|
+
|
|
173
|
+
const scatterChart = ref(null)
|
|
174
|
+
|
|
175
|
+
const brush = reactive({
|
|
176
|
+
value: {
|
|
177
|
+
min: 0,
|
|
178
|
+
max:
|
|
179
|
+
orderBy(props.data.datasets, (o) => o.data.length)[0].data
|
|
180
|
+
.length - 1
|
|
181
|
+
}
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
const getChartBackup = () => {
|
|
185
|
+
if (!chart.value) {
|
|
186
|
+
return {
|
|
187
|
+
data: {},
|
|
188
|
+
options: {}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const datasets: DatasetController<'scatter'> = updateKeys(
|
|
192
|
+
props.data.datasets,
|
|
193
|
+
[
|
|
194
|
+
'backgroundColor',
|
|
195
|
+
'pointBackgroundColor',
|
|
196
|
+
'pointBorderColor',
|
|
197
|
+
'borderColor',
|
|
198
|
+
'hoverBorderColor',
|
|
199
|
+
'hoverBackgroundColor',
|
|
200
|
+
'pointHoverBackgroundColor',
|
|
201
|
+
'pointHoverBorderColor'
|
|
202
|
+
],
|
|
203
|
+
replaceColor
|
|
204
|
+
).map((item: ScatterControllerDatasetOptions) => {
|
|
205
|
+
return {
|
|
206
|
+
...item,
|
|
207
|
+
hoverBackgroundColor:
|
|
208
|
+
item.hoverBackgroundColor ||
|
|
209
|
+
hexToRgbA(item.backgroundColor as string, 0.2),
|
|
210
|
+
hoverBorderColor:
|
|
211
|
+
item.hoverBorderColor ||
|
|
212
|
+
hexToRgbA(item.backgroundColor as string, 0.2)
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
const chartProps = cloneDeep({
|
|
217
|
+
options: props.options,
|
|
218
|
+
data: {
|
|
219
|
+
...props.data,
|
|
220
|
+
datasets
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
return chartProps
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const chartWrapperClasses = computed(() => {
|
|
228
|
+
const classes = 'dl-scatter-chart-wrapper'
|
|
229
|
+
|
|
230
|
+
if (props.rootClass) {
|
|
231
|
+
classes.concat(' ', props.rootClass)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return classes
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
const chartClasses = computed(() => {
|
|
238
|
+
const classes = 'dl-scatter-chart'
|
|
239
|
+
|
|
240
|
+
if (props.chartClass) {
|
|
241
|
+
classes.concat(' ', props.chartClass)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return classes
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
const brushClasses = computed(() => {
|
|
248
|
+
const classes = 'dl-brush'
|
|
249
|
+
|
|
250
|
+
if (props.brushClass) {
|
|
251
|
+
classes.concat(' ', props.brushClass)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return classes
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
const legendClasses = computed(() => {
|
|
258
|
+
const classes = 'dl-legend'
|
|
259
|
+
|
|
260
|
+
if (props.legendClass) {
|
|
261
|
+
classes.concat(' ', props.legendClass)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return classes
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const brushProperties = computed(() => {
|
|
268
|
+
return merge(defaultLineChartProps.brushProps, props.brushProps)
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
const legendProperties = computed(() => {
|
|
272
|
+
return merge(defaultLineChartProps.legendProps, props.legendProps)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
const cssVars = computed(() => {
|
|
276
|
+
return {
|
|
277
|
+
'--dl-brush-thumb-size':
|
|
278
|
+
parseInt(brushProperties.value.thumbSize) / 4 + 'px'
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
const replaceDataColors = (data: ChartData) =>
|
|
283
|
+
updateKeys(
|
|
284
|
+
data,
|
|
285
|
+
[
|
|
286
|
+
'backgroundColor',
|
|
287
|
+
'pointBackgroundColor',
|
|
288
|
+
'pointBorderColor',
|
|
289
|
+
'borderColor',
|
|
290
|
+
'hoverBorderColor',
|
|
291
|
+
'hoverBackgroundColor',
|
|
292
|
+
'pointHoverBackgroundColor',
|
|
293
|
+
'pointHoverBorderColor'
|
|
294
|
+
],
|
|
295
|
+
replaceColor
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
const chartData = ref(replaceDataColors(props.data))
|
|
299
|
+
|
|
300
|
+
const legendDatasets = ref(
|
|
301
|
+
unionBy(
|
|
302
|
+
props.legendProps?.datasets || [],
|
|
303
|
+
props.data?.datasets || [],
|
|
304
|
+
'label'
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
const onChartLeave = () => {
|
|
309
|
+
if (chartHoverDataset.value) {
|
|
310
|
+
const filteredItems = chart.value.data.datasets
|
|
311
|
+
.map((d: ChartDataset, i: number) => ({
|
|
312
|
+
...d,
|
|
313
|
+
index: i
|
|
314
|
+
}))
|
|
315
|
+
.filter(
|
|
316
|
+
(dataset: ChartDataset) =>
|
|
317
|
+
dataset.label !== chartHoverDataset.value.label
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
const backup = getChartBackup()
|
|
321
|
+
|
|
322
|
+
for (const dataset of filteredItems) {
|
|
323
|
+
chart.value.data.datasets[dataset.index].backgroundColor = (
|
|
324
|
+
backup.data as ChartData<'scatter'>
|
|
325
|
+
).datasets[dataset.index].backgroundColor
|
|
326
|
+
chart.value.data.datasets[dataset.index].borderColor = (
|
|
327
|
+
backup.data as ChartData<'scatter'>
|
|
328
|
+
).datasets[dataset.index].borderColor
|
|
329
|
+
}
|
|
330
|
+
chartHoverDataset.value = null
|
|
331
|
+
|
|
332
|
+
chart.value.update()
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
const onHover = (
|
|
337
|
+
event: Event,
|
|
338
|
+
items: ActiveElement[],
|
|
339
|
+
chartJS: Chart
|
|
340
|
+
) => {
|
|
341
|
+
if (event.type !== 'mousemove') {
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
if (
|
|
345
|
+
items.length === 0 ||
|
|
346
|
+
chartJS.getElementsAtEventForMode(
|
|
347
|
+
event,
|
|
348
|
+
'nearest',
|
|
349
|
+
{
|
|
350
|
+
intersect: true
|
|
351
|
+
},
|
|
352
|
+
true
|
|
353
|
+
).length === 0
|
|
354
|
+
) {
|
|
355
|
+
if (chartHoverDataset.value) {
|
|
356
|
+
const filteredItems = chartJS.data.datasets
|
|
357
|
+
.map((d: ChartDataset, i: number) => ({
|
|
358
|
+
...d,
|
|
359
|
+
index: i
|
|
360
|
+
}))
|
|
361
|
+
.filter(
|
|
362
|
+
(dataset: ChartDataset) =>
|
|
363
|
+
dataset.label !== chartHoverDataset.value.label
|
|
364
|
+
)
|
|
365
|
+
const backup = getChartBackup()
|
|
366
|
+
for (const dataset of filteredItems) {
|
|
367
|
+
chartJS.data.datasets[dataset.index].backgroundColor = (
|
|
368
|
+
backup.data as ChartData<'scatter'>
|
|
369
|
+
).datasets[dataset.index].backgroundColor
|
|
370
|
+
|
|
371
|
+
chartJS.data.datasets[dataset.index].borderColor = (
|
|
372
|
+
backup.data as ChartData<'scatter'>
|
|
373
|
+
).datasets[dataset.index].borderColor
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
chartHoverDataset.value = null
|
|
377
|
+
|
|
378
|
+
chartJS.update()
|
|
379
|
+
}
|
|
380
|
+
return
|
|
381
|
+
} else {
|
|
382
|
+
const item = items[0]
|
|
383
|
+
const datasetItem = chartJS.getDatasetMeta(item.datasetIndex)
|
|
384
|
+
if (!chartHoverDataset.value) {
|
|
385
|
+
const filteredDatasets = chartJS.data.datasets
|
|
386
|
+
.map((d: ChartDataset, i: number) => ({
|
|
387
|
+
...d,
|
|
388
|
+
index: i
|
|
389
|
+
}))
|
|
390
|
+
.filter(
|
|
391
|
+
(ds: ChartDataset) => ds.label !== datasetItem.label
|
|
392
|
+
)
|
|
393
|
+
for (const dataset of filteredDatasets) {
|
|
394
|
+
chartJS.data.datasets[dataset.index].backgroundColor =
|
|
395
|
+
hexToRgbA(dataset.backgroundColor as string, 0.2)
|
|
396
|
+
|
|
397
|
+
chart.value.data.datasets[dataset.index].borderColor =
|
|
398
|
+
dataset?.hoverBorderColor ||
|
|
399
|
+
hexToRgbA(dataset.backgroundColor as string, 0.2)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
chartHoverDataset.value = datasetItem
|
|
403
|
+
|
|
404
|
+
chartJS.update()
|
|
405
|
+
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
if (!isEqual(chartHoverDataset.value, datasetItem)) {
|
|
409
|
+
const filteredItems = chartJS.data.datasets
|
|
410
|
+
.map((d: ChartDataset, i: number) => ({
|
|
411
|
+
...d,
|
|
412
|
+
index: i
|
|
413
|
+
}))
|
|
414
|
+
.filter(
|
|
415
|
+
(dataset: ChartDataset) =>
|
|
416
|
+
dataset.label !== chartHoverDataset.value.label
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
const backup = getChartBackup()
|
|
420
|
+
for (const dataset of filteredItems) {
|
|
421
|
+
chartJS.data.datasets[dataset.index].backgroundColor = (
|
|
422
|
+
backup.data as ChartData<'scatter'>
|
|
423
|
+
).datasets[dataset.index].backgroundColor
|
|
424
|
+
|
|
425
|
+
chartJS.data.datasets[dataset.index].borderColor = (
|
|
426
|
+
backup.data as ChartData<'scatter'>
|
|
427
|
+
).datasets[dataset.index].borderColor
|
|
428
|
+
}
|
|
429
|
+
chartHoverDataset.value = datasetItem
|
|
430
|
+
const allFilteredItems = chartJS.data.datasets
|
|
431
|
+
.map((d: ChartDataset, i: number) => ({
|
|
432
|
+
...d,
|
|
433
|
+
index: i
|
|
434
|
+
}))
|
|
435
|
+
.filter(
|
|
436
|
+
(dataset: ChartDataset) =>
|
|
437
|
+
dataset.label !== datasetItem.label
|
|
438
|
+
)
|
|
439
|
+
for (const dataset of allFilteredItems) {
|
|
440
|
+
chartJS.data.datasets[dataset.index].backgroundColor =
|
|
441
|
+
hexToRgbA(dataset.backgroundColor as string, 0.2)
|
|
442
|
+
}
|
|
443
|
+
chartJS.update()
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const chartOptions = reactive(
|
|
449
|
+
updateKeys(
|
|
450
|
+
merge(
|
|
451
|
+
{ onResize, onHover },
|
|
452
|
+
defaultLineChartProps.options,
|
|
453
|
+
props.options
|
|
454
|
+
),
|
|
455
|
+
['color'],
|
|
456
|
+
replaceColor
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
watch(
|
|
461
|
+
() => chart.value?.scales?.x?.width,
|
|
462
|
+
(val: string) => {
|
|
463
|
+
if (val) {
|
|
464
|
+
chartWidth.value = `${
|
|
465
|
+
parseInt(val as unknown as string) -
|
|
466
|
+
parseInt(brushProperties.value.thumbSize) / 4
|
|
467
|
+
}px`
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{ deep: true }
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
const handleBrushUpdate = (value: { min: number; max: number }) => {
|
|
474
|
+
brush.value.min = value.min
|
|
475
|
+
brush.value.max = value.max
|
|
476
|
+
|
|
477
|
+
chart.value.options.scales.x.min = value.min
|
|
478
|
+
chart.value.options.scales.x.max = value.max
|
|
479
|
+
|
|
480
|
+
xLabels.value = chart.value.data.labels.slice(
|
|
481
|
+
value.min,
|
|
482
|
+
value.max + brushProperties.value.step
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
chart.value.update()
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
const xLabels = ref(props.data.labels)
|
|
489
|
+
|
|
490
|
+
const onHoverLegend = (
|
|
491
|
+
item: BarControllerDatasetOptions,
|
|
492
|
+
index: number
|
|
493
|
+
) => {
|
|
494
|
+
const filteredItems = chart.value.data.datasets
|
|
495
|
+
.map((d: ChartDataset, i: number) => ({
|
|
496
|
+
...d,
|
|
497
|
+
index: i
|
|
498
|
+
}))
|
|
499
|
+
.filter(
|
|
500
|
+
(dataset: ChartDataset & { index: number }) =>
|
|
501
|
+
dataset.index! !== index
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
for (const dataset of filteredItems) {
|
|
505
|
+
chart.value.data.datasets[dataset.index].backgroundColor =
|
|
506
|
+
dataset?.hoverBackgroundColor ||
|
|
507
|
+
hexToRgbA(dataset.backgroundColor, 0.2)
|
|
508
|
+
|
|
509
|
+
chart.value.data.datasets[dataset.index].borderColor =
|
|
510
|
+
dataset?.hoverBorderColor ||
|
|
511
|
+
hexToRgbA(dataset.backgroundColor, 0.2)
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
chart.value.update()
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const onLeaveLegend = (
|
|
518
|
+
item: BarControllerDatasetOptions,
|
|
519
|
+
index: number
|
|
520
|
+
) => {
|
|
521
|
+
const filteredItems = chart.value.data.datasets
|
|
522
|
+
.map((d: ChartDataset, i: number) => ({
|
|
523
|
+
...d,
|
|
524
|
+
index: i
|
|
525
|
+
}))
|
|
526
|
+
.filter(
|
|
527
|
+
(dataset: ChartDataset & { index: number }) =>
|
|
528
|
+
dataset.index !== index
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
const backup = getChartBackup()
|
|
532
|
+
|
|
533
|
+
for (const dataset of filteredItems) {
|
|
534
|
+
chart.value.data.datasets[dataset.index].backgroundColor = (
|
|
535
|
+
backup.data as ChartData<'scatter'>
|
|
536
|
+
).datasets[dataset.index].backgroundColor
|
|
537
|
+
|
|
538
|
+
chart.value.data.datasets[dataset.index].borderColor = (
|
|
539
|
+
backup.data as ChartData<'scatter'>
|
|
540
|
+
).datasets[dataset.index].borderColor
|
|
541
|
+
}
|
|
542
|
+
chart.value.update()
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const labelStyles = computed(() => {
|
|
546
|
+
const options = merge(
|
|
547
|
+
{},
|
|
548
|
+
defaultLineChartProps.options,
|
|
549
|
+
props.options
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
return {
|
|
553
|
+
title: options.scales.x.title.text,
|
|
554
|
+
titleSize: `${options.scales.x.title.font.size}px`,
|
|
555
|
+
titleColor: options.scales.x.title.color.replace('--', ''),
|
|
556
|
+
labelColor: options.scales.x.ticks.color.replace('--', ''),
|
|
557
|
+
fontSize: `${options.scales.x.ticks.font.size}px`
|
|
558
|
+
}
|
|
559
|
+
})
|
|
560
|
+
|
|
561
|
+
const hideData = (item: BarControllerDatasetOptions, index: number) => {
|
|
562
|
+
onLeaveLegend(item, index)
|
|
563
|
+
|
|
564
|
+
chart.value.data.datasets[index].hidden = !!item.hidden
|
|
565
|
+
|
|
566
|
+
legendDatasets.value.splice(index, 1, {
|
|
567
|
+
...legendDatasets.value[index],
|
|
568
|
+
hidden: !!item.hidden
|
|
569
|
+
})
|
|
570
|
+
|
|
571
|
+
chart.value.update()
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
watch(variables, () => {
|
|
575
|
+
merge(chart.value.data, getChartBackup().data)
|
|
576
|
+
|
|
577
|
+
merge(
|
|
578
|
+
chart.value.options,
|
|
579
|
+
updateKeys(
|
|
580
|
+
merge(
|
|
581
|
+
{ onResize, onHover },
|
|
582
|
+
defaultLineChartProps.options,
|
|
583
|
+
props.options
|
|
584
|
+
),
|
|
585
|
+
['color'],
|
|
586
|
+
replaceColor
|
|
587
|
+
)
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
chart.value.options.scales.x.min = brush.value.min
|
|
591
|
+
chart.value.options.scales.x.max = brush.value.max
|
|
592
|
+
|
|
593
|
+
chart.value.update()
|
|
594
|
+
})
|
|
595
|
+
|
|
596
|
+
watch(
|
|
597
|
+
[props.data, props.options],
|
|
598
|
+
([newData = {}, newOptions = {}]) => {
|
|
599
|
+
chartData.value = replaceDataColors(newData as ChartData)
|
|
600
|
+
|
|
601
|
+
xLabels.value = (newData as ChartData)?.labels
|
|
602
|
+
|
|
603
|
+
chartOptions.value = updateKeys(
|
|
604
|
+
merge(
|
|
605
|
+
{ onResize, onHover },
|
|
606
|
+
defaultLineChartProps.options,
|
|
607
|
+
newOptions
|
|
608
|
+
),
|
|
609
|
+
['color'],
|
|
610
|
+
replaceColor
|
|
611
|
+
)
|
|
612
|
+
},
|
|
613
|
+
{ deep: true }
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
return {
|
|
617
|
+
variables,
|
|
618
|
+
chartData,
|
|
619
|
+
chartOptions,
|
|
620
|
+
brush,
|
|
621
|
+
xLabels,
|
|
622
|
+
scatterChart,
|
|
623
|
+
handleBrushUpdate,
|
|
624
|
+
chartWrapperClasses,
|
|
625
|
+
chartClasses,
|
|
626
|
+
brushClasses,
|
|
627
|
+
legendClasses,
|
|
628
|
+
brushProperties,
|
|
629
|
+
legendDatasets,
|
|
630
|
+
legendProperties,
|
|
631
|
+
hideData,
|
|
632
|
+
chartWidth,
|
|
633
|
+
onHoverLegend,
|
|
634
|
+
onLeaveLegend,
|
|
635
|
+
onChartLeave,
|
|
636
|
+
chart,
|
|
637
|
+
labelStyles,
|
|
638
|
+
cssVars
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
})
|
|
642
|
+
</script>
|
|
643
|
+
|
|
644
|
+
<style scoped lang="scss">
|
|
645
|
+
.dl-scatter-chart-wrapper {
|
|
646
|
+
display: flex;
|
|
647
|
+
flex-direction: column;
|
|
648
|
+
align-self: stretch;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.dl-brush {
|
|
652
|
+
margin-top: 10px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.dl-legend {
|
|
656
|
+
margin-top: 16px;
|
|
657
|
+
margin-bottom: 16px;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
.dl-brush,
|
|
661
|
+
.dl-legend {
|
|
662
|
+
align-self: flex-end;
|
|
663
|
+
margin-right: var(--dl-brush-thumb-size);
|
|
664
|
+
}
|
|
665
|
+
</style>
|
|
@@ -103,6 +103,10 @@ export default defineComponent({
|
|
|
103
103
|
type: Object as PropType<Partial<DateInterval> | null>,
|
|
104
104
|
default: null
|
|
105
105
|
},
|
|
106
|
+
singleSelection: {
|
|
107
|
+
type: Boolean,
|
|
108
|
+
default: false
|
|
109
|
+
},
|
|
106
110
|
normalizeCalendars: Boolean,
|
|
107
111
|
disabled: Boolean
|
|
108
112
|
},
|
|
@@ -245,7 +249,11 @@ export default defineComponent({
|
|
|
245
249
|
|
|
246
250
|
this.dateInterval = { from: date, to: date }
|
|
247
251
|
|
|
248
|
-
this.
|
|
252
|
+
if (this.singleSelection) {
|
|
253
|
+
this.isSelectionMode = true
|
|
254
|
+
} else {
|
|
255
|
+
this.updateModelValue(this.dateInterval)
|
|
256
|
+
}
|
|
249
257
|
},
|
|
250
258
|
|
|
251
259
|
handleMouseenter(date: Date) {
|
|
@@ -343,7 +343,9 @@ export default defineComponent({
|
|
|
343
343
|
const handleInputModel = (value: string) => {
|
|
344
344
|
inputModel.value = value
|
|
345
345
|
const json = toJSON(removeBrackets(value))
|
|
346
|
-
|
|
346
|
+
if (!isEqual(json, props.modelValue)) {
|
|
347
|
+
emit('update:modelValue', json)
|
|
348
|
+
}
|
|
347
349
|
const stringified = JSON.stringify(json)
|
|
348
350
|
const newQuery = replaceWithAliases(stringified, props.aliases)
|
|
349
351
|
activeQuery.value.query = newQuery
|
|
@@ -356,10 +358,23 @@ export default defineComponent({
|
|
|
356
358
|
|
|
357
359
|
const debouncedInputModel = debounce(handleInputModel, 300)
|
|
358
360
|
|
|
361
|
+
const isValidJSON = (item: string | Object): boolean => {
|
|
362
|
+
let value = typeof item !== 'string' ? JSON.stringify(item) : item
|
|
363
|
+
try {
|
|
364
|
+
value = JSON.parse(value)
|
|
365
|
+
} catch (e) {
|
|
366
|
+
return false
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
return typeof value === 'object' && value !== null
|
|
370
|
+
}
|
|
371
|
+
|
|
359
372
|
const toJSON = (value: string) => {
|
|
360
|
-
|
|
373
|
+
const json = parseSmartQuery(
|
|
361
374
|
replaceWithJsDates(value) ?? inputModel.value
|
|
362
375
|
)
|
|
376
|
+
|
|
377
|
+
return isValidJSON(json) ? json : inputModel.value
|
|
363
378
|
}
|
|
364
379
|
|
|
365
380
|
const setFocused = (value: boolean) => {
|
|
@@ -383,7 +398,9 @@ export default defineComponent({
|
|
|
383
398
|
return
|
|
384
399
|
}
|
|
385
400
|
const stringQuery = stringifySmartQuery(val)
|
|
386
|
-
|
|
401
|
+
if (stringQuery !== inputModel.value.trim()) {
|
|
402
|
+
debouncedInputModel(stringQuery)
|
|
403
|
+
}
|
|
387
404
|
}
|
|
388
405
|
})
|
|
389
406
|
|
|
@@ -117,7 +117,10 @@
|
|
|
117
117
|
:offset="[0, 3]"
|
|
118
118
|
>
|
|
119
119
|
<div class="dl-smart-search-input__date-picker-wrapper">
|
|
120
|
-
<dl-date-picker
|
|
120
|
+
<dl-date-picker
|
|
121
|
+
:single-selection="false"
|
|
122
|
+
@change="handleDateSelectionUpdate"
|
|
123
|
+
/>
|
|
121
124
|
</div>
|
|
122
125
|
</dl-menu>
|
|
123
126
|
</div>
|
|
@@ -2,19 +2,10 @@ export * from './highlightSyntax'
|
|
|
2
2
|
export * from './utils'
|
|
3
3
|
|
|
4
4
|
import { DateInterval } from '../../../DlDateTime/types'
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
)
|
|
10
|
-
const endDatePattern = new RegExp(
|
|
11
|
-
/\(to\s?\d{2}\/\d{2}\/\d{4}\s?\)|\(to\s?dd\/mm\/yyyy\s?\)/,
|
|
12
|
-
'gi'
|
|
13
|
-
)
|
|
14
|
-
const dateIntervalPattern = new RegExp(
|
|
15
|
-
/\((from\s?\(\d{2}\/\d{2}\/\d{4}\)\s?to\s?\(\d{2}\/\d{2}\/\d{4}\))\)|\((from\s?\(dd\/mm\/yyyy\)\s?to\s?\(dd\/mm\/yyyy\))\)/,
|
|
16
|
-
'gi'
|
|
17
|
-
)
|
|
5
|
+
import {
|
|
6
|
+
datePattern,
|
|
7
|
+
datePatternNoBrackets
|
|
8
|
+
} from '../../../../../hooks/use-suggestions'
|
|
18
9
|
|
|
19
10
|
export const isEndOfString = (str: string, pattern: RegExp): boolean => {
|
|
20
11
|
const trimmed = str.trim()
|
|
@@ -23,40 +14,21 @@ export const isEndOfString = (str: string, pattern: RegExp): boolean => {
|
|
|
23
14
|
if (!matches || !matches.length) return false
|
|
24
15
|
|
|
25
16
|
const lastMatch = matches[matches.length - 1]
|
|
17
|
+
|
|
26
18
|
return trimmed.lastIndexOf(lastMatch) + lastMatch.length === trimmed.length
|
|
27
19
|
}
|
|
28
20
|
|
|
29
21
|
export const isEndingWithDateIntervalPattern = (str: string) => {
|
|
30
|
-
return (
|
|
31
|
-
isEndOfString(str, dateIntervalPattern) ||
|
|
32
|
-
isEndOfString(str, startDatePattern) ||
|
|
33
|
-
isEndOfString(str, endDatePattern)
|
|
34
|
-
)
|
|
22
|
+
return isEndOfString(str, datePattern)
|
|
35
23
|
}
|
|
36
24
|
|
|
37
|
-
export const replaceDateInterval = (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
) => {
|
|
41
|
-
const dateFrom = new Date(dateInterval.from)
|
|
42
|
-
const dateTo = new Date(dateInterval.to)
|
|
43
|
-
const values = str.match(/\((.*?)\)/g)
|
|
44
|
-
let newStr = ''
|
|
45
|
-
if (!values) return str
|
|
46
|
-
|
|
47
|
-
if (values.length > 1) {
|
|
48
|
-
newStr = `(From (${formatDate(dateFrom)}) To (${formatDate(dateTo)}))`
|
|
49
|
-
return replaceLastOccurrence(str, newStr, dateIntervalPattern)
|
|
50
|
-
} else if (values[0].includes('From')) {
|
|
51
|
-
newStr = `(From ${formatDate(dateFrom)})`
|
|
52
|
-
return replaceLastOccurrence(str, newStr, startDatePattern)
|
|
53
|
-
} else if (values[0].includes('To')) {
|
|
54
|
-
newStr = `(To ${formatDate(dateTo)})`
|
|
55
|
-
return replaceLastOccurrence(str, newStr, endDatePattern)
|
|
56
|
-
}
|
|
25
|
+
export const replaceDateInterval = (str: string, date: DateInterval) => {
|
|
26
|
+
const newStr = `${formatDate(date.from)}`
|
|
27
|
+
return replaceLastOccurrence(str, newStr, datePatternNoBrackets)
|
|
57
28
|
}
|
|
58
29
|
|
|
59
30
|
const formatDate = (date: Date): string => {
|
|
31
|
+
if (!date) return
|
|
60
32
|
return `${addZero(date.getDate())}/${addZero(
|
|
61
33
|
date.getMonth() + 1
|
|
62
34
|
)}/${date.getFullYear()}`
|
|
@@ -2,9 +2,7 @@ import { ColorSchema, SyntaxColorSchema, Filters } from '../types'
|
|
|
2
2
|
import {
|
|
3
3
|
operators,
|
|
4
4
|
Alias,
|
|
5
|
-
|
|
6
|
-
endDatePattern,
|
|
7
|
-
dateIntervalPattern
|
|
5
|
+
datePattern
|
|
8
6
|
} from '../../../../../hooks/use-suggestions'
|
|
9
7
|
|
|
10
8
|
export function getTabItems(filters: Filters) {
|
|
@@ -25,37 +23,22 @@ export function getTabItems(filters: Filters) {
|
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
export function replaceWithJsDates(str: string) {
|
|
28
|
-
const
|
|
29
|
-
const starts = str.match(startDatePattern)
|
|
30
|
-
const ends = str.match(endDatePattern)
|
|
26
|
+
const dates = str.match(datePattern)
|
|
31
27
|
|
|
32
|
-
|
|
33
|
-
str = str.replaceAll(
|
|
34
|
-
})
|
|
35
|
-
starts?.forEach((start) => {
|
|
36
|
-
str = str.replaceAll(start, formatToDateObj(start))
|
|
37
|
-
})
|
|
38
|
-
ends?.forEach((end) => {
|
|
39
|
-
str = str.replaceAll(end, formatToDateObj(end))
|
|
28
|
+
dates?.forEach((date) => {
|
|
29
|
+
str = str.replaceAll(date, formatToNumericDate(date))
|
|
40
30
|
})
|
|
31
|
+
|
|
41
32
|
return str
|
|
42
33
|
}
|
|
43
34
|
|
|
44
|
-
function
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
parseInt(toMonth),
|
|
52
|
-
parseInt(toDay)
|
|
53
|
-
)
|
|
54
|
-
if (!isValidDate(toDate)) return date.toISOString()
|
|
55
|
-
return JSON.stringify({
|
|
56
|
-
from: date.toISOString(),
|
|
57
|
-
to: toDate.toISOString()
|
|
58
|
-
})
|
|
35
|
+
function formatToNumericDate(str: string) {
|
|
36
|
+
const dateInfo = str.split('/')
|
|
37
|
+
const day = parseInt(dateInfo[0])
|
|
38
|
+
const month = parseInt(dateInfo[1])
|
|
39
|
+
const year = parseInt(dateInfo[2])
|
|
40
|
+
const newDate = new Date(year, month, day)
|
|
41
|
+
return newDate.getTime().toString()
|
|
59
42
|
}
|
|
60
43
|
|
|
61
44
|
function isValidDate(d: Date) {
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
style="
|
|
4
|
+
display: flex;
|
|
5
|
+
width: 1000px;
|
|
6
|
+
flex-wrap: wrap;
|
|
7
|
+
flex-direction: row;
|
|
8
|
+
gap: 0;
|
|
9
|
+
"
|
|
10
|
+
>
|
|
11
|
+
<dl-scatter-chart
|
|
12
|
+
id="example-one"
|
|
13
|
+
:brush-props="brushProps"
|
|
14
|
+
:legend-props="legendProps"
|
|
15
|
+
:data="data"
|
|
16
|
+
:options="options"
|
|
17
|
+
style="width: 100%"
|
|
18
|
+
/>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import { defineComponent } from 'vue-demi'
|
|
24
|
+
import { DlScatterChart } from '../components'
|
|
25
|
+
import { orderBy } from 'lodash'
|
|
26
|
+
|
|
27
|
+
const data = {
|
|
28
|
+
labels: [
|
|
29
|
+
{
|
|
30
|
+
title: '0.1'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
title: '0.2'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: '0.3'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: '0.4'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
title: '0.5'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
title: '0.6'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
title: '0.7'
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
title: '0.8'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
title: '0.9'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
title: '1'
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
datasets: [
|
|
61
|
+
{
|
|
62
|
+
label: 'Scatter Dataset',
|
|
63
|
+
data: [
|
|
64
|
+
{ x: 0.1, y: 0.1 },
|
|
65
|
+
{ x: 0.2, y: 0.1 },
|
|
66
|
+
{ x: 0.3, y: 0.2 },
|
|
67
|
+
{ x: 0.4, y: 0.3 },
|
|
68
|
+
{ x: 0.5, y: 0.35 },
|
|
69
|
+
{ x: 0.6, y: 0.39 },
|
|
70
|
+
{ x: 0.7, y: 0.4 },
|
|
71
|
+
{ x: 0.8, y: 0.8 },
|
|
72
|
+
{ x: 0.9, y: 0.8 }
|
|
73
|
+
],
|
|
74
|
+
backgroundColor: 'rgb(255, 99, 132)',
|
|
75
|
+
borderColor: 'rgba(255, 99, 132, 1)',
|
|
76
|
+
pointRadius: 5,
|
|
77
|
+
showLine: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: 'Dataset 2',
|
|
81
|
+
data: [
|
|
82
|
+
{ x: 0.2, y: 0.1 },
|
|
83
|
+
{ x: 0.2, y: 0.2 },
|
|
84
|
+
{ x: 0.4, y: 0.2 },
|
|
85
|
+
{ x: 0.4, y: 0.3 },
|
|
86
|
+
{ x: 0.6, y: 0.65 },
|
|
87
|
+
{ x: 0.6, y: 0.85 },
|
|
88
|
+
{ x: 0.8, y: 0.6 },
|
|
89
|
+
{ x: 0.8, y: 0.7 },
|
|
90
|
+
{ x: 0.9, y: 0.8 }
|
|
91
|
+
],
|
|
92
|
+
backgroundColor: 'rgba(45, 162, 50, 1)',
|
|
93
|
+
borderColor: 'rgba(45, 162, 50, 1)',
|
|
94
|
+
pointRadius: 5,
|
|
95
|
+
showLine: true
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const brushProps = {
|
|
101
|
+
min: 0,
|
|
102
|
+
max: orderBy(data.datasets, (o) => o.data.length)[0].data.length - 1
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const options = {
|
|
106
|
+
scales: {
|
|
107
|
+
x: {
|
|
108
|
+
type: 'linear',
|
|
109
|
+
position: 'bottom',
|
|
110
|
+
axis: 'Recall',
|
|
111
|
+
scaleLabel: {
|
|
112
|
+
display: true,
|
|
113
|
+
labelString: 'Recall'
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
y: {
|
|
117
|
+
type: 'linear',
|
|
118
|
+
position: 'left',
|
|
119
|
+
axis: 'Precision',
|
|
120
|
+
scaleLabel: {
|
|
121
|
+
display: true,
|
|
122
|
+
labelString: 'Precision'
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const legendProps = {
|
|
129
|
+
alignItems: 'center'
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export default defineComponent({
|
|
133
|
+
name: 'DlScatterChartDemo',
|
|
134
|
+
components: {
|
|
135
|
+
DlScatterChart
|
|
136
|
+
},
|
|
137
|
+
data() {
|
|
138
|
+
return {
|
|
139
|
+
resolution: 'hour',
|
|
140
|
+
options,
|
|
141
|
+
data,
|
|
142
|
+
brushProps,
|
|
143
|
+
legendProps,
|
|
144
|
+
noPointsData: {
|
|
145
|
+
...data,
|
|
146
|
+
datasets: [
|
|
147
|
+
{ ...data.datasets[0], pointRadius: 0, borderWidth: 1 }
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
tensionLineData: {
|
|
151
|
+
...data,
|
|
152
|
+
datasets: [{ ...data.datasets[1], pointRadius: 0 }]
|
|
153
|
+
},
|
|
154
|
+
tensionOptions: { ...options, tension: 0.5 }
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
methods: {}
|
|
158
|
+
})
|
|
159
|
+
</script>
|
|
160
|
+
|
|
161
|
+
<style scoped lang="scss"></style>
|
package/src/demos/index.ts
CHANGED
|
@@ -46,6 +46,7 @@ import DlSwitchDemo from './DlSwitchDemo.vue'
|
|
|
46
46
|
import DlToastDemo from './DlToastDemo.vue'
|
|
47
47
|
import DlChartDoughnutDemo from './DlChartDoughnutDemo.vue'
|
|
48
48
|
import DlLineChartDemo from './DlLineChartDemo.vue'
|
|
49
|
+
import DlScatterChartDemo from './DlScatterChartDemo.vue'
|
|
49
50
|
import DlSpinner from './DlSpinnerDemo.vue'
|
|
50
51
|
import DlConfusionMatrix from './DlConfusionMatrixDemo.vue'
|
|
51
52
|
import DlToggleButtonDemo from './DlToggleButtonDemo.vue'
|
|
@@ -107,6 +108,7 @@ export default {
|
|
|
107
108
|
DlChartDoughnutDemo,
|
|
108
109
|
DlBarChartDemo,
|
|
109
110
|
DlLineChartDemo,
|
|
111
|
+
DlScatterChartDemo,
|
|
110
112
|
DlSpinner,
|
|
111
113
|
DlConfusionMatrix,
|
|
112
114
|
DlToggleButtonDemo,
|
|
@@ -71,24 +71,50 @@ type Expression = {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const space = ' '
|
|
74
|
-
const
|
|
75
|
-
const dateEndSuggestionString = '(To dd/mm/yyyy)'
|
|
76
|
-
const dateIntervalSuggestionString = '(From (dd/mm/yyyy) To (dd/mm/yyyy))'
|
|
74
|
+
const dateSuggestionPattern = '(dd/mm/yyyy)'
|
|
77
75
|
|
|
78
76
|
let localSuggestions: Suggestion[] = []
|
|
79
77
|
|
|
80
|
-
export const
|
|
81
|
-
/(
|
|
82
|
-
'gi'
|
|
83
|
-
)
|
|
84
|
-
export const endDatePattern = new RegExp(
|
|
85
|
-
/(to\s?\d{2}\/\d{2}\/\d{4}\s?|to\s?dd\/mm\/yyyy\s?)/,
|
|
86
|
-
'gi'
|
|
87
|
-
)
|
|
88
|
-
export const dateIntervalPattern = new RegExp(
|
|
89
|
-
/(from\s?\d{2}\/\d{2}\/\d{4}\s?to\s?\d{2}\/\d{2}\/\d{4})|(from\s?dd\/mm\/yyyy\s?to\s?dd\/mm\/yyyy)/,
|
|
78
|
+
export const datePattern = new RegExp(
|
|
79
|
+
/(\(\d{2}\/\d{2}\/\d{4}\)\s?|\s?\(dd\/mm\/yyyy\)\s?)/,
|
|
90
80
|
'gi'
|
|
91
81
|
)
|
|
82
|
+
export const datePatternNoBrackets =
|
|
83
|
+
/(\d{2}\/\d{2}\/\d{4}\s?|\s?dd\/mm\/yyyy\s?)/
|
|
84
|
+
|
|
85
|
+
const mergeWords = (words: string[]) => {
|
|
86
|
+
const result: string[] = []
|
|
87
|
+
let merging = false
|
|
88
|
+
let mergeIndex = -1
|
|
89
|
+
|
|
90
|
+
for (let i = 0; i < words.length; ++i) {
|
|
91
|
+
const currentItem = words[i]
|
|
92
|
+
|
|
93
|
+
if (currentItem === 'IN' || currentItem === 'NOT-IN') {
|
|
94
|
+
merging = true
|
|
95
|
+
mergeIndex = i + 1
|
|
96
|
+
result.push(currentItem)
|
|
97
|
+
continue
|
|
98
|
+
} else if (
|
|
99
|
+
Object.values(Logical).includes(currentItem as any) ||
|
|
100
|
+
Object.values(operators).includes(currentItem as any)
|
|
101
|
+
) {
|
|
102
|
+
merging = false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (merging) {
|
|
106
|
+
if (!result[mergeIndex]) {
|
|
107
|
+
result[mergeIndex] = ''
|
|
108
|
+
}
|
|
109
|
+
result[mergeIndex] += ' ' + currentItem
|
|
110
|
+
continue
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
result.push(currentItem)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return result
|
|
117
|
+
}
|
|
92
118
|
|
|
93
119
|
export const useSuggestions = (
|
|
94
120
|
schema: Schema,
|
|
@@ -123,7 +149,8 @@ export const useSuggestions = (
|
|
|
123
149
|
localSuggestions = sortedSuggestions
|
|
124
150
|
|
|
125
151
|
const words = splitByQuotes(input, space)
|
|
126
|
-
const
|
|
152
|
+
const mergedWords = mergeWords(words)
|
|
153
|
+
const expressions = mapWordsToExpressions(mergedWords)
|
|
127
154
|
|
|
128
155
|
for (const { field, operator, value, keyword } of expressions) {
|
|
129
156
|
let matchedField: Suggestion | null = null
|
|
@@ -191,11 +218,7 @@ export const useSuggestions = (
|
|
|
191
218
|
dataType === 'date' ||
|
|
192
219
|
dataType === 'time'
|
|
193
220
|
) {
|
|
194
|
-
localSuggestions = [
|
|
195
|
-
dateIntervalSuggestionString,
|
|
196
|
-
dateStartSuggestionString,
|
|
197
|
-
dateEndSuggestionString
|
|
198
|
-
]
|
|
221
|
+
localSuggestions = [dateSuggestionPattern]
|
|
199
222
|
|
|
200
223
|
if (!value) continue
|
|
201
224
|
|
|
@@ -356,11 +379,7 @@ const validateBracketValues = (value: string) => {
|
|
|
356
379
|
}
|
|
357
380
|
|
|
358
381
|
const isValidDateIntervalPattern = (str: string) => {
|
|
359
|
-
return (
|
|
360
|
-
!!str.match(dateIntervalPattern) ||
|
|
361
|
-
!!str.match(startDatePattern) ||
|
|
362
|
-
!!str.match(endDatePattern)
|
|
363
|
-
)
|
|
382
|
+
return !!str.match(datePatternNoBrackets)
|
|
364
383
|
}
|
|
365
384
|
|
|
366
385
|
const isValidNumber = (str: string) => {
|
|
@@ -509,11 +528,7 @@ const getValueSuggestions = (dataType: string | string[], operator: string) => {
|
|
|
509
528
|
case 'date':
|
|
510
529
|
case 'time':
|
|
511
530
|
case 'datetime':
|
|
512
|
-
suggestion.push(
|
|
513
|
-
dateIntervalSuggestionString,
|
|
514
|
-
dateStartSuggestionString,
|
|
515
|
-
dateEndSuggestionString
|
|
516
|
-
)
|
|
531
|
+
suggestion.push(dateSuggestionPattern)
|
|
517
532
|
default:
|
|
518
533
|
// do nothing
|
|
519
534
|
break
|