Add scatter chart

This commit is contained in:
Jože Fortun
2023-04-18 15:37:41 +02:00
parent 70cd9b8e87
commit df6eaace7f
10 changed files with 90 additions and 33 deletions
@@ -2,17 +2,15 @@
<report-edit
:report.sync="editReport"
:modules="modules"
:dimension-field-kind="['Select']"
:supported-metrics="1"
un-skippable
>
<template #dimension-options="{ index, dimension, field }">
<b-form-group
v-if="showPicker(field)"
:label="$t('edit.dimension.options.label')"
label-class="text-primary"
>
<c-item-picker
v-if="showPicker(field)"
:value="getOptions(dimension)"
:options="field.options.options"
:labels="{
@@ -3,6 +3,27 @@
:report.sync="editReport"
:modules="modules"
>
<template #dimension-options="{ dimension }">
<b-row>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.dimension.rotate.label')"
:description="$t('edit.dimension.rotate.description')"
label-class="text-primary"
>
<b-input
v-model="dimension.rotateLabel"
type="number"
number
/>
</b-form-group>
</b-col>
</b-row>
</template>
<template #y-axis="{ report }">
<div
class="px-3"
@@ -270,6 +291,22 @@
/>
</b-form-group>
</b-col>
<b-col
v-if="metric.type === 'scatter'"
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.metric.symbol.label')"
label-class="text-primary"
>
<b-form-select
v-model="metric.symbol"
:options="scatterSymbolOptions"
/>
</b-form-group>
</b-col>
</b-row>
</template>
@@ -572,6 +609,7 @@ import base from './base'
const ignoredCharts = [
'funnel',
'gauge',
'heatmap',
]
export default {
@@ -637,6 +675,16 @@ export default {
{ value: 'smooth', text: this.$t('edit.metric.lineStyle.smooth') },
{ value: 'step', text: this.$t('edit.metric.lineStyle.step') },
],
scatterSymbolOptions: [
{ value: 'circle', text: this.$t('edit.metric.symbol.circle') },
{ value: 'triangle', text: this.$t('edit.metric.symbol.triangle') },
{ value: 'diamond', text: this.$t('edit.metric.symbol.diamond') },
{ value: 'pin', text: this.$t('edit.metric.symbol.pin') },
{ value: 'arrow', text: this.$t('edit.metric.symbol.arrow') },
{ value: 'rect', text: this.$t('edit.metric.symbol.rect') },
{ value: 'roundRect', text: this.$t('edit.metric.symbol.roundRect') },
],
}
},
@@ -153,18 +153,18 @@
<template v-if="!unSkippable">
<b-row>
<b-col
v-if="!d.skipMissing"
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.dimension.rotate.label')"
:description="$t('edit.dimension.rotate.description')"
:label="$t('edit.dimension.defaultValueLabel')"
:description="$t('edit.dimension.defaultValueFootnote')"
label-class="text-primary"
>
<b-input
v-model="d.rotateLabel"
type="number"
number
<b-form-input
v-model="d.default"
:type="defaultValueInputType(d)"
/>
</b-form-group>
</b-col>
@@ -182,22 +182,10 @@
>
{{ $t('edit.dimension.skipMissingValues') }}
</b-form-checkbox>
</b-form-group>
</b-col>
<b-col
v-if="!d.skipMissing"
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.dimension.defaultValueLabel')"
:description="$t('edit.dimension.defaultValueFootnote')"
label-class="text-primary"
>
<b-form-input
v-model="d.default"
:type="defaultValueInputType(d)"
<slot
name="dimension-options-options"
:dimension="d"
/>
</b-form-group>
</b-col>
@@ -423,7 +411,7 @@ export default {
},
hasAxis () {
return this.metrics.some(({ type }) => ['bar', 'line'].includes(type))
return this.metrics.some(({ type }) => ['bar', 'line', 'scatter'].includes(type))
},
dimensionFields () {
@@ -503,6 +491,8 @@ export default {
if (!this.isTemporalField(f)) {
this.$set(d, 'modifier', this.dimensionModifiers[0].value)
}
this.$set(d.meta, 'fields', [])
},
onMetricFieldChange (field, m) {
@@ -110,7 +110,7 @@ export default {
...module.systemFields(),
].find(({ name }) => name === field)
if (meta.fields) {
if (meta.fields && field.kind === 'Select') {
data.labels = data.labels.map(value => {
const { text } = field.options.options.find(o => o.value === value) || {}
return text || value
@@ -130,8 +130,9 @@ export default {
const { namespaceID } = this.chart || {}
const recordModule = this.getModuleByID(field.options.moduleID)
if (recordModule && data.labels) {
const isValidRecordID = (recordID) => recordID !== dimension.default && recordID !== 'undefined'
await Promise.all(data.labels.map(recordID => {
if (recordID && recordID !== 'undefined') {
if (isValidRecordID(recordID)) {
return this.$ComposeAPI.recordRead({ namespaceID, moduleID: recordModule.moduleID, recordID }).then(record => {
record = new compose.Record(recordModule, record)
@@ -499,7 +499,7 @@ export default {
},
hasAxis () {
return this.reports.some(({ metrics = [] }) => metrics.some(m => ['bar', 'line'].includes(m.type)))
return this.reports.some(({ metrics = [] }) => metrics.some(m => ['bar', 'line', 'scatter'].includes(m.type)))
},
timelineOptions () {
+1
View File
@@ -253,6 +253,7 @@ export class BaseChart {
return {
labels: this.processLabels(labels, dimension),
datasets,
dimension,
}
}
+6 -3
View File
@@ -28,6 +28,7 @@ export default class Chart extends BaseChart {
smooth: m.smooth,
step: m.step ? 'middle' : undefined,
roseType: m.rose ? 'radius' : undefined,
symbol: m.symbol,
stack: m.stack,
tooltip: {
fixed: m.fixTooltips,
@@ -61,7 +62,7 @@ export default class Chart extends BaseChart {
legend: l,
} = reports[0] || {}
const hasAxis = datasets.some(({ type }: any) => ['bar', 'line'].includes(type))
const hasAxis = datasets.some(({ type }: any) => ['bar', 'line', 'scatter'].includes(type))
let horizontal = false
if (hasAxis) {
@@ -127,7 +128,7 @@ export default class Chart extends BaseChart {
}
}
options.series = datasets.map(({ type, label, data, stack, tooltip, fill, smooth, step, roseType }: any, index: number) => {
options.series = datasets.map(({ type, label, data, stack, tooltip, fill, smooth, step, roseType, symbol }: any, index: number) => {
const { fixed, relative } = tooltip
const tooltipFormatter = t?.formatting ? t.formatting : `{a}<br />{b} : {c}${relative ? ' ({d}%)' : ''}`
@@ -202,7 +203,7 @@ export default class Chart extends BaseChart {
bottom: offset?.isDefault ? undefined : offset?.bottom,
left: offset?.isDefault ? undefined : offset?.left,
}
} else if (['bar', 'line'].includes(type)) {
} else if (['bar', 'line', 'scatter'].includes(type)) {
options.tooltip.trigger = 'axis'
const defaultOffset = {
@@ -240,6 +241,7 @@ export default class Chart extends BaseChart {
areaStyle: {
opacity: fill ? 0.7 : 0,
},
symbol,
label: {
show: fixed,
position: 'inside',
@@ -301,6 +303,7 @@ export default class Chart extends BaseChart {
smooth: true,
fill: false,
rose: false,
symbol: 'circle',
})
}
+5 -1
View File
@@ -179,7 +179,11 @@ export default class FunnelChart extends BaseChart {
const report = this.config.reports?.[ri]
const d = report?.dimensions?.[0] as Dimension
for (const { value } of d.meta?.fields || []) {
let { fields = [] } = d.meta || {}
fields = fields.length ? fields : r.labels
for (let label of fields) {
const value = typeof label === 'object' ? label.value : label
values.push({
// Use value for label and resolve it on FE (i18n)
label: value,
+2
View File
@@ -11,6 +11,7 @@ export enum ChartType {
doughnut='doughnut',
funnel = 'funnel',
gauge = 'gauge',
scatter = 'scatter',
}
export interface TemporalDataPoint {
@@ -45,6 +46,7 @@ export interface Metric {
modifier?: string;
fx?: string;
backgroundColor?: string;
symbol?: string;
[_: string]: any;
}
+11 -1
View File
@@ -45,7 +45,7 @@ edit:
unselectAllItems: Unselect all
noItemsFound: No options found
rotate:
label: Rotate label
label: Rotate labels
description: Labels can be rotated from -90 to 90 degrees.
filter:
customize: Customize filter
@@ -97,6 +97,15 @@ edit:
labelColor: Label color
labelLabel: Label
labelPlaceholder: Total
symbol:
label: Symbol
circle: Circle
triangle: Triangle
diamond: Diamond
pin: Pin
arrow: Arrow
rect: Rectangle
roundRect: Rounded Rectangle
legend:
bottom: Bottom
left: Left
@@ -116,6 +125,7 @@ edit:
label: Chart type *
line: Line
pie: Pie
scatter: Scatter
placeholder: Select metric output
relative: Show relative value
relativePrecision: 'Precision:'