Update chart number formatting

This commit is contained in:
Jože Fortun
2024-06-14 13:27:46 +02:00
parent bbb85e9826
commit c73b84369d
19 changed files with 305 additions and 410 deletions
@@ -28,7 +28,7 @@
</b-form-group>
</template>
<template #metric-options="{ metric, presetFormattedOptions }">
<template #metric-options="{ metric }">
<b-row>
<b-col
cols="12"
@@ -68,12 +68,12 @@
md="6"
>
<b-form-group
:label="$t('prefix')"
:label="$t('edit.formatting.prefix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.prefix"
placeholder="USD/mo"
v-model="metric.formatting.prefix"
:placeholder="$t('edit.formatting.prefix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -83,12 +83,12 @@
md="6"
>
<b-form-group
:label="$t('suffix')"
:label="$t('edit.formatting.suffix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.suffix"
placeholder="$"
v-model="metric.formatting.suffix"
:placeholder="$t('edit.formatting.suffix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -96,40 +96,33 @@
<b-col
cols="12"
md="6"
lg="6"
>
<b-form-group
:label="$t('numberFormat')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.numberFormat"
:disabled="report.metricFormatter.presetFormat !== 'noFormat'"
placeholder="0.00"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
lg="6"
>
<b-form-group
:label="$t('edit.additionalConfig.tooltip.formatting.presetFormats.label')"
:label="$t('edit.formatting.presetFormats.label')"
label-class="text-primary"
:description="$t(`edit.formatting.presetFormats.description.${metric.formatting.presetFormat}`)"
style="white-space: pre-line;"
>
<b-form-select
v-model="report.metricFormatter.presetFormat"
:options="presetFormattedOptions.formatOptions"
:disabled="!!report.metricFormatter.numberFormat"
v-model="metric.formatting.presetFormat"
:options="formatOptions"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.formatting.format.label')"
label-class="text-primary"
>
<b-input
v-model="metric.formatting.format"
:disabled="metric.formatting.presetFormat !== 'custom'"
:placeholder="$t('edit.formatting.format.placeholder')"
/>
<slot
v-if="report.metricFormatter.presetFormat === 'accountingNumber'"
name="description"
>
<small class="text-muted">{{ presetFormattedOptions.formattedOptionsDescription }}</small>
</slot>
</b-form-group>
</b-col>
</b-row>
@@ -56,7 +56,7 @@
</b-form-group>
</template>
<template #metric-options="{ metric, presetFormattedOptions }">
<template #metric-options="{ metric }">
<b-row>
<b-col
cols="12"
@@ -133,12 +133,12 @@
md="6"
>
<b-form-group
:label="$t('prefix')"
:label="$t('edit.formatting.prefix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.prefix"
placeholder="USD/mo"
v-model="metric.formatting.prefix"
:placeholder="$t('edit.formatting.prefix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -148,12 +148,12 @@
md="6"
>
<b-form-group
:label="$t('suffix')"
:label="$t('edit.formatting.suffix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.suffix"
placeholder="$"
v-model="metric.formatting.suffix"
:placeholder="$t('edit.formatting.suffix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -163,37 +163,31 @@
md="6"
>
<b-form-group
:label="$t('numberFormat')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.numberFormat"
:disabled="report.metricFormatter.presetFormat !== 'noFormat'"
placeholder="0.00"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
lg="6"
>
<b-form-group
:label="$t('edit.additionalConfig.tooltip.formatting.presetFormats.label')"
:label="$t('edit.formatting.presetFormats.label')"
label-class="text-primary"
:description="$t(`edit.formatting.presetFormats.description.${metric.formatting.presetFormat}`)"
style="white-space: pre-line;"
>
<b-form-select
v-model="report.metricFormatter.presetFormat"
:disabled="!!report.metricFormatter.numberFormat"
:options="presetFormattedOptions.formatOptions"
v-model="metric.formatting.presetFormat"
:options="formatOptions"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.formatting.format.label')"
label-class="text-primary"
>
<b-input
v-model="metric.formatting.format"
:disabled="metric.formatting.presetFormat !== 'custom'"
:placeholder="$t('edit.formatting.format.placeholder')"
/>
<slot
v-if="report.metricFormatter.presetFormat === 'accountingNumber'"
name="description"
>
<small class="text-muted">{{ presetFormattedOptions.formattedOptionsDescription }}</small>
</slot>
</b-form-group>
</b-col>
</b-row>
@@ -210,10 +204,6 @@ import base from './base'
export default {
name: 'GaugeChart',
i18nOptions: {
namespaces: 'chart',
},
components: {
ChartTranslator,
ReportEdit,
@@ -182,12 +182,12 @@
md="6"
>
<b-form-group
:label="$t('prefix')"
:label="$t('edit.formatting.prefix.label')"
label-class="text-primary"
>
<b-input
v-model="report.yAxisFormatter.prefix"
placeholder="USD/mo"
v-model="report.yAxis.formatting.prefix"
:placeholder="$t('edit.formatting.prefix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -197,12 +197,12 @@
md="6"
>
<b-form-group
:label="$t('suffix')"
:label="$t('edit.formatting.suffix.label')"
label-class="text-primary"
>
<b-input
v-model="report.yAxisFormatter.suffix"
placeholder="$"
v-model="report.yAxis.formatting.suffix"
:placeholder="$t('edit.formatting.suffix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -212,12 +212,30 @@
md="6"
>
<b-form-group
:label="$t('numberFormat')"
:label="$t('edit.formatting.presetFormats.label')"
label-class="text-primary"
:description="$t(`edit.formatting.presetFormats.description.${report.yAxis.formatting.presetFormat}`)"
style="white-space: pre-line;"
>
<b-form-select
v-model="report.yAxis.formatting.presetFormat"
:options="formatOptions"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.formatting.format.label')"
label-class="text-primary"
>
<b-input
v-model="report.yAxisFormatter.numberFormat"
placeholder="0.00"
v-model="report.yAxis.formatting.format"
:disabled="report.yAxis.formatting.presetFormat !== 'custom'"
:placeholder="$t('edit.formatting.format.placeholder')"
/>
</b-form-group>
</b-col>
@@ -225,7 +243,7 @@
</div>
</template>
<template #metric-options="{ metric, presetFormattedOptions }">
<template #metric-options="{ metric }">
<b-row>
<b-col
cols="12"
@@ -377,12 +395,12 @@
md="6"
>
<b-form-group
:label="$t('prefix')"
:label="$t('edit.formatting.prefix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.prefix"
placeholder="USD/mo"
v-model="metric.formatting.prefix"
:placeholder="$t('edit.formatting.prefix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -392,12 +410,12 @@
md="6"
>
<b-form-group
:label="$t('suffix')"
:label="$t('edit.formatting.suffix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.suffix"
placeholder="$"
v-model="metric.formatting.suffix"
:placeholder="$t('edit.formatting.suffix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -407,37 +425,31 @@
md="6"
>
<b-form-group
:label="$t('numberFormat')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.numberFormat"
:disabled="report.metricFormatter.presetFormat !== 'noFormat'"
placeholder="0.00"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
lg="6"
>
<b-form-group
:label="$t('edit.additionalConfig.tooltip.formatting.presetFormats.label')"
:label="$t('edit.formatting.presetFormats.label')"
label-class="text-primary"
:description="$t(`edit.formatting.presetFormats.description.${metric.formatting.presetFormat}`)"
style="white-space: pre-line;"
>
<b-form-select
v-model="report.metricFormatter.presetFormat"
:disabled="!!report.metricFormatter.formatting"
:options="presetFormattedOptions.formatOptions"
v-model="metric.formatting.presetFormat"
:options="formatOptions"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.formatting.format.label')"
label-class="text-primary"
>
<b-input
v-model="metric.formatting.format"
:disabled="metric.formatting.presetFormat !== 'custom'"
:placeholder="$t('edit.formatting.format.placeholder')"
/>
<slot
v-if="report.metricFormatter.presetFormat === 'accountingNumber'"
name="description"
>
<small class="text-muted">{{ presetFormattedOptions.formattedOptionsDescription }}</small>
</slot>
</b-form-group>
</b-col>
</b-row>
@@ -460,13 +472,12 @@
lg="6"
>
<b-form-group
:label="$t('edit.additionalConfig.tooltip.formatting.customFormatting')"
:label="$t('edit.additionalConfig.tooltip.formatting.label')"
:description="$t('edit.additionalConfig.tooltip.formatting.description')"
label-class="text-primary"
>
<b-input
v-model="report.tooltip.formatting"
:disabled="report.tooltipFormatter.presetFormat !== 'noFormat'"
:placeholder="$t('edit.additionalConfig.tooltip.formatting.placeholder')"
/>
</b-form-group>
@@ -493,6 +504,7 @@
</div>
<hr>
<div class="px-3 mb-2">
<h5 class="mb-3">
{{ $t('edit.additionalConfig.offset.label') }}
@@ -602,10 +614,6 @@ const ignoredCharts = [
export default {
name: 'GenericChart',
i18nOptions: {
namespaces: 'chart',
},
components: {
ReportEdit,
ChartTranslator,
@@ -3,7 +3,7 @@
:report.sync="editReport"
:modules="modules"
>
<template #metric-options="{ metric, presetFormattedOptions }">
<template #metric-options="{ metric }">
<b-row>
<b-col
cols="12"
@@ -38,12 +38,12 @@
md="6"
>
<b-form-group
:label="$t('prefix')"
:label="$t('edit.formatting.prefix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.prefix"
placeholder="USD/mo"
v-model="metric.formatting.prefix"
:placeholder="$t('edit.formatting.prefix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -53,12 +53,12 @@
md="6"
>
<b-form-group
:label="$t('suffix')"
:label="$t('edit.formatting.suffix.label')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.suffix"
placeholder="$"
v-model="metric.formatting.suffix"
:placeholder="$t('edit.formatting.suffix.placeholder')"
/>
</b-form-group>
</b-col>
@@ -68,37 +68,31 @@
md="6"
>
<b-form-group
:label="$t('numberFormat')"
label-class="text-primary"
>
<b-input
v-model="report.metricFormatter.numberFormat"
:disabled="report.metricFormatter.presetFormat !== 'noFormat'"
placeholder="0.00"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
lg="6"
>
<b-form-group
:label="$t('edit.additionalConfig.tooltip.formatting.presetFormats.label')"
:label="$t('edit.formatting.presetFormats.label')"
label-class="text-primary"
:description="$t(`edit.formatting.presetFormats.description.${metric.formatting.presetFormat}`)"
style="white-space: pre-line;"
>
<b-form-select
v-model="report.metricFormatter.presetFormat"
:disabled="!!report.metricFormatter.numberFormat"
:options="presetFormattedOptions.formatOptions"
v-model="metric.formatting.presetFormat"
:options="formatOptions"
/>
</b-form-group>
</b-col>
<b-col
cols="12"
md="6"
>
<b-form-group
:label="$t('edit.formatting.format.label')"
label-class="text-primary"
>
<b-input
v-model="metric.formatting.format"
:disabled="metric.formatting.presetFormat !== 'custom'"
:placeholder="$t('edit.formatting.format.placeholder')"
/>
<slot
v-if="report.metricFormatter.presetFormat === 'accountingNumber'"
name="description"
>
<small class="text-muted">{{ presetFormattedOptions.formattedOptionsDescription }}</small>
</slot>
</b-form-group>
</b-col>
</b-row>
@@ -169,10 +169,6 @@
name="dimension-options-options"
:dimension="d"
:is-temporal="isTemporalField(d.field)"
:preset-formatted-options="{
formatOptions,
formattedOptionsDescription: $t('edit.additionalConfig.tooltip.formatting.presetFormats.description.accountingNumber')
}"
/>
</b-form-group>
</b-col>
@@ -290,10 +286,6 @@
name="metric-options"
:metric="m"
:report="editReport"
:preset-formatted-options="{
formatOptions,
formattedOptionsDescription: $t('edit.additionalConfig.tooltip.formatting.presetFormats.description.accountingNumber')
}"
/>
</div>
</draggable>
@@ -499,10 +491,6 @@ const aggregateFunctions = [
]
export default {
i18nOptions: {
namespaces: 'chart',
},
name: 'ReportEdit',
components: {
@@ -527,11 +515,6 @@ export default {
{ value: 'horizontal', text: this.$t('edit.additionalConfig.legend.orientation.horizontal') },
{ value: 'vertical', text: this.$t('edit.additionalConfig.legend.orientation.vertical') },
],
formatOptions: [
{ value: 'noFormat', text: this.$t('edit.additionalConfig.tooltip.formatting.presetFormats.options.noFormat') },
{ value: 'accountingNumber', text: this.$t('edit.additionalConfig.tooltip.formatting.presetFormats.options.accountingNumber') },
],
}
},
@@ -660,6 +643,23 @@ export default {
onMetricFieldChange (field, m) {
if (field === 'count') {
this.$set(m, 'aggregate', undefined)
} else if (field) {
// Set field formatting based on number field formatting
const moduleField = this.module.fields.find(f => f.name === field)
if (moduleField) {
const { presetFormat, format, prefix, suffix } = moduleField.options
this.$set(m, 'formatting', {
presetFormat,
format,
prefix,
suffix,
})
}
if (!m.aggregate) {
this.$set(m, 'aggregate', this.metricAggregates[0].value)
}
}
},
@@ -677,7 +677,6 @@ export default {
this.predefinedFilters = []
this.alignments = []
this.orientations = []
this.formatOptions = []
},
},
}
@@ -2,6 +2,10 @@
import { compose, NoID } from '@cortezaproject/corteza-js'
export default {
i18nOptions: {
namespaces: 'chart',
},
props: {
report: {
type: Object,
@@ -58,6 +62,11 @@ export default {
on: this.$t('general:label.yes'),
off: this.$t('general:label.no'),
},
formatOptions: [
{ value: 'custom', text: this.$t('edit.formatting.presetFormats.options.custom') },
{ value: 'accounting', text: this.$t('edit.formatting.presetFormats.options.accounting') },
],
}
},
@@ -184,7 +184,7 @@ export default {
}
}
data.datasets = data.datasets.map((dataset = {}, i) => {
data.datasets = data.datasets.map((dataset = {}) => {
const { label } = dataset
if (label === 'count') {
@@ -82,8 +82,8 @@
<b-form-group
:label="$t('kind.number.presetFormats.label')"
label-class="text-primary"
style="white-space: pre-line;"
:description="formattedOptionsDescription"
style="white-space: pre-line;"
>
<b-form-select
v-model="f.options.presetFormat"
+11 -13
View File
@@ -7,6 +7,7 @@ import {
dimensionFunctions,
makeAlias,
TemporalDataPoint,
defFormatData,
} from './util'
import {
@@ -116,8 +117,10 @@ export class BaseChart {
}
this.config = (conf ? _.merge(this.defConfig(), conf) : false) || this.config || this.defConfig()
this.config.reports?.forEach(report => {
const { dimensions = [], metrics = [] } = report || {}
report.dimensions = dimensions.map(d => {
// Legacy support
if (d.modifier === 'auto') {
@@ -131,7 +134,8 @@ export class BaseChart {
return _.merge(this.defDimension(), d)
})
report.metrics = metrics.map(m => _.merge(this.defMetrics(), m))
report.metrics = metrics.map(m => _.merge(this.defMetric(), m))
})
}
@@ -337,8 +341,10 @@ export class BaseChart {
})
}
defMetrics (): Metric {
return Object.assign({}, {})
defMetric (): Metric {
return Object.assign({}, {
formatting: defFormatData(),
})
}
defReport (): Report {
@@ -346,23 +352,15 @@ export class BaseChart {
moduleID: undefined,
filter: '',
dimensions: [this.defDimension()],
metrics: [this.defMetrics()],
metrics: [this.defMetric()],
yAxis: {
axisType: 'linear',
axisPosition: 'left',
labelPosition: 'end',
rotateLabel: 0,
formatting: defFormatData(),
},
tooltip: {},
tooltipFormatter: {
presetFormat: 'noFormat',
},
metricFormatter: {
presetFormat: 'noFormat',
},
yAxisFormatter: {
presetFormat: 'noFormat',
},
legend: {
isScrollable: true,
orientation: 'horizontal',
+26 -79
View File
@@ -3,9 +3,9 @@ import {
Dimension,
Metric,
TemporalDataPoint,
TooltipParams,
formatChartTooltip,
formatChartValue,
formatChartTooltip,
TooltipParams,
} from './util'
import { getColorschemeColors } from '../../../shared'
@@ -37,6 +37,7 @@ export default class Chart extends BaseChart {
fixed: m.fixTooltips,
relative: m.relativeValue && !['bar', 'line'].includes(m.type as string),
},
formatting: m.formatting,
}
}
@@ -60,13 +61,9 @@ export default class Chart extends BaseChart {
const {
dimensions: [dimension] = [],
yAxis,
yAxisFormatter,
metrics: [metric] = [],
offset,
tooltip: t,
legend: l,
tooltipFormatter,
metricFormatter,
} = reports[0] || {}
const hasAxis = datasets.some(({ type }: any) => ['bar', 'line', 'scatter'].includes(type))
@@ -115,11 +112,7 @@ export default class Chart extends BaseChart {
overflow: 'break',
hideOverlap: true,
rotate: yAxis.rotateLabel,
formatter: (value: string | number, index: string | number): string => {
const { numberFormat = '', prefix = '', suffix = '', presetFormat = '' } = yAxisFormatter || {}
return formatChartValue(value, { numberFormat, prefix, suffix, presetFormat })
},
formatter: (value: string | number): string => formatChartValue(value, yAxis.formatting),
},
axisLine: {
show: false,
@@ -151,21 +144,8 @@ export default class Chart extends BaseChart {
}
}
options.series = datasets.map(({ type, label, data, stack, tooltip, fill, smooth, step, roseType, symbol }: any, index: number) => {
options.series = datasets.map(({ formatting, type, label, data, stack, tooltip, fill, smooth, step, roseType, symbol }: any, index: number) => {
const { fixed, relative } = tooltip
const {
numberFormat: metricNumForm = '',
prefix: metricPref = '',
suffix: metricSuff = '',
presetFormat: metricPresForm = '',
} = metricFormatter || {}
const {
numberFormat: tooltipNumForm = '',
prefix: tooltipPref = '',
suffix: tooltipSuff = '',
presetFormat: tooltipPresForm = '',
} = tooltipFormatter || {}
// We should render the first metric in the dataset as the last
const z = (datasets.length - 1) - index
@@ -212,28 +192,18 @@ export default class Chart extends BaseChart {
trigger: 'item',
appendToBody: true,
formatter: (params: TooltipParams): string => {
const v = formatChartValue(params.value || '', {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
const v = formatChartValue(params.value || '', formatting)
return t?.formatting
? formatChartTooltip(t?.formatting, params)
: `${params.seriesName}<br>${params.marker}${params.name}<span style="float: right; margin-left: 20px">${v}${relative ? ' (' + params.percent + '%)' : ''}</span>`
if (t?.formatting) {
return formatChartTooltip(t?.formatting, params)
}
return `${params.seriesName}<br>${params.marker}${params.name}<span style="float: right; margin-left: 20px">${v}${relative ? ' (' + params.percent + '%)' : ''}</span>`
},
},
label: {
...lbl,
formatter: (params: TooltipParams): string => {
return formatChartValue(params.value || '', {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
},
formatter: (params: TooltipParams): string => formatChartValue(params.value || '', formatting),
},
itemStyle: {
borderRadius: 5,
@@ -302,42 +272,20 @@ export default class Chart extends BaseChart {
// we can either
// add formatting to the value and apply tooltip if trigger: 'item'
// display the same tooltip format name <br/> seriesName value if trigger: 'axis'
// works when trigger is set to axis
valueFormatter: (value: string | number): string => {
const v = formatChartValue(value, {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
return formatChartValue(v, {
numberFormat: tooltipNumForm,
prefix: tooltipPref,
suffix: tooltipSuff,
presetFormat: tooltipPresForm,
})
},
// works when trigger is set to axis
valueFormatter: (value: string | number): string => formatChartValue(value, formatting),
// works when trigger is set to item
formatter: (params: { seriesName?: string; name?: string;value: Array<any>, percent: string | number, marker: string;}): string => {
const { value = [], percent = '' || 0 } = params
const v = formatChartValue(value[1], {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
const { value = [], percent = '' } = params
const formattedValue = formatChartValue(v, {
numberFormat: tooltipNumForm,
prefix: tooltipPref,
suffix: tooltipSuff,
presetFormat: tooltipPresForm,
})
const formattedValue = formatChartValue(value[1], formatting)
return t?.formatting
? formatChartTooltip(t?.formatting, { ...params, value: value[1], percent: params.percent })
: `${params.seriesName}<br>${params.marker}${params.name}<span style="float: right; margin-left: 20px">${formattedValue}${relative ? ' (' + params.percent + '%)' : ''}</span>`
if (t?.formatting) {
return formatChartTooltip(t?.formatting, { ...params, value: value[1], percent })
}
return `${params.seriesName}<br>${params.marker}${params.name}<span style="float: right; margin-left: 20px">${formattedValue}${relative ? ' (' + params.percent + '%)' : ''}</span>`
},
},
label: {
@@ -348,11 +296,10 @@ export default class Chart extends BaseChart {
tooltip: {
trigger: 'axis',
},
formatter: function (params: { seriesName: string, name: string, value: Array<any>, percent: string | number }): string {
const { value = [], percent = '' || 0 } = params
const { numberFormat = '', prefix = '', suffix = '', presetFormat = '' } = metricFormatter || {}
formatter: (params: { seriesName: string, name: string, value: Array<any>, percent: string | number }): string => {
const { value = [], percent = '' } = params
return `${formatChartValue(value[1], { numberFormat, prefix, suffix, presetFormat })}${relative ? ` (${percent}%)` : ''}`
return `${formatChartValue(value[1], formatting)}${relative ? ` (${percent}%)` : ''}`
},
},
data,
@@ -412,8 +359,8 @@ export default class Chart extends BaseChart {
}
}
defMetrics (): Metric {
return Object.assign({}, {
defMetric (): Metric {
return Object.assign(super.defMetric(), {
smooth: true,
fill: false,
rose: false,
+22 -25
View File
@@ -5,6 +5,7 @@ import {
Report,
ChartType,
formatChartValue,
formatChartTooltip,
TooltipParams,
} from './util'
import { getColorschemeColors } from '../../../shared'
@@ -83,6 +84,7 @@ export default class FunnelChart extends BaseChart {
fixed: !!m.fixTooltips,
relative: !!m.relativeValue,
},
formatting: m.formatting,
}
}
@@ -91,15 +93,12 @@ export default class FunnelChart extends BaseChart {
const { saveAsImage } = toolbox || {}
const { labels, datasets = [], tooltip, themeVariables = {} } = data
const { legend: l, metricFormatter } = reports[0] || {}
const colors = getColorschemeColors(colorScheme, data.customColorSchemes)
const { fixed, relative } = tooltip
const {
numberFormat: metricNumForm = '',
prefix: metricPref = '',
suffix: metricSuff = '',
presetFormat: metricPresForm = '',
} = metricFormatter || {}
const { legend: l } = reports[0] || {}
const { formatting } = datasets[0] || {}
const colors = getColorschemeColors(colorScheme, data.customColorSchemes)
return {
animation: !noAnimation,
@@ -120,15 +119,11 @@ export default class FunnelChart extends BaseChart {
tooltip: {
trigger: 'item',
formatter: (params: TooltipParams): string => {
const { seriesName = '', value = '' || 0, percent = '' || 0, marker = '', name = '' } = params
const formattedValue = formatChartValue(value, {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
const { value = '', percent = '' } = params
return `${seriesName}<br>${marker}${name}<span style="float: right; margin-left: 20px">${formattedValue}${tooltip.relative ? ' (' + percent + '%)' : ''}</span>`
const v = formatChartValue(value, formatting)
return `${params.seriesName}<br>${params.marker}${params.name}<span style="float: right; margin-left: 20px">${v}${relative ? ' (' + percent + '%)' : ''}</span>`
},
appendToBody: true,
},
@@ -149,7 +144,7 @@ export default class FunnelChart extends BaseChart {
pageIconColor: themeVariables.black,
pageIconInactiveColor: themeVariables.light,
},
series: datasets.map(({ data, label }: any) => {
series: datasets.map(({ data, label, formatting }: any) => {
return {
name: label,
type: 'funnel',
@@ -159,21 +154,20 @@ export default class FunnelChart extends BaseChart {
left: '5%',
width: '90%',
label: {
show: tooltip.fixed,
show: fixed,
position: 'inside',
align: 'center',
verticalAlign: 'middle',
formatter: (params: TooltipParams): string => {
const { value = '' || 0, percent = '' || 0 } = params
const { numberFormat = '', prefix = '', suffix = '', presetFormat = '' } = metricFormatter || {}
const formattedValue = formatChartValue(value, { numberFormat, prefix, suffix, presetFormat })
const { value = '', percent = '' } = params
const formattedValue = formatChartValue(value, formatting)
return `${params.seriesName}${formattedValue}${tooltip.relative ? ' (' + percent + '%)' : ''}`
return `${formattedValue}${relative ? ' (' + percent + '%)' : ''}`
},
},
emphasis: {
label: {
show: tooltip.fixed,
show: fixed,
fontSize: 14,
},
},
@@ -200,6 +194,7 @@ export default class FunnelChart extends BaseChart {
let tooltip = {}
let label = ''
let formatting = {}
// Above provided data sets might not have their labels/values ordered
// correctly
@@ -214,6 +209,7 @@ export default class FunnelChart extends BaseChart {
tooltip = { ...tooltip, ...r.datasets[0].tooltip }
label = r.datasets[0].label
formatting = r.datasets[0].formatting
// Construct labels & data based on provided reports
const report = this.config.reports?.[ri]
@@ -262,6 +258,7 @@ export default class FunnelChart extends BaseChart {
datasets: [{
label,
data,
formatting,
}],
tooltip,
}
@@ -282,8 +279,8 @@ export default class FunnelChart extends BaseChart {
return cumulative
}
defMetrics (): Metric {
return Object.assign({}, {
defMetric (): Metric {
return Object.assign(super.defMetric(), {
type: ChartType.funnel,
fixTooltips: false,
relativeValue: true,
+7 -13
View File
@@ -71,6 +71,7 @@ export default class GaugeChart extends BaseChart {
tooltip: {
fixed: m.fixTooltips,
},
formatting: m.formatting,
}
}
@@ -86,12 +87,9 @@ export default class GaugeChart extends BaseChart {
tooltip,
startAngle,
endAngle,
formatting,
} = datasets.find(({ value }: any) => value) || datasets[0]
const {
tooltipFormatter,
metricFormatter,
} = reports[0] || {}
const { numberFormat = '', prefix = '', suffix = '', presetFormat = '' } = metricFormatter || {}
const colors = getColorschemeColors(colorScheme, data.customColorSchemes)
const color = steps.map((s: any, i: number) => {
@@ -166,15 +164,11 @@ export default class GaugeChart extends BaseChart {
offsetCenter: [0, '55%'],
valueAnimation: true,
color: themeVariables.black,
formatter: (value: string | number): string => {
const { numberFormat = '', prefix = '', suffix = '', presetFormat = '' } = tooltipFormatter || {}
return formatChartValue(value, { numberFormat, prefix, suffix, presetFormat })
},
formatter: (value: string | number): string => formatChartValue(value, formatting),
},
data: [
{
name: formatChartValue(name, { numberFormat, prefix, suffix, presetFormat }),
name,
value,
},
],
@@ -187,8 +181,8 @@ export default class GaugeChart extends BaseChart {
return 'gauge'
}
defMetrics (): Metric {
return Object.assign({}, {
defMetric (): Metric {
return Object.assign(super.defMetric(), {
type: ChartType.gauge,
fixTooltips: true,
startAngle: 200,
+10 -41
View File
@@ -4,6 +4,7 @@ import {
Metric,
ChartType,
formatChartValue,
TooltipParams,
} from './util'
import { getColorschemeColors } from '../../../shared'
@@ -22,6 +23,7 @@ export default class RadarChart extends BaseChart {
type: m.type,
label: m.label || m.field,
data,
formatting: m.formatting,
}
}
@@ -29,25 +31,12 @@ export default class RadarChart extends BaseChart {
const { reports = [], colorScheme, noAnimation = false, toolbox } = this.config
const { saveAsImage } = toolbox || {}
const { labels, datasets = [], dimension = {}, themeVariables = {} } = data
const {
legend: l,
metricFormatter,
tooltipFormatter,
} = reports[0] || {}
const {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
} = metricFormatter || {}
const {
numberFormat: tooltipNumForm = '',
prefix: tooltipPref = '',
suffix: tooltipSuff = '',
presetFormat: tooltipPresForm = '',
} = tooltipFormatter || {}
const { formatting } = datasets[0] || {}
let min: number = 0
let max: number = Math.max()
@@ -98,21 +87,7 @@ export default class RadarChart extends BaseChart {
show: true,
position: 'top',
appendToBody: true,
valueFormatter: (value: string | number): string => {
const v = formatChartValue(value, {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
return formatChartValue(v, {
numberFormat: tooltipNumForm,
prefix: tooltipPref,
suffix: tooltipSuff,
presetFormat: tooltipPresForm,
})
},
valueFormatter: (value: string | number): string => formatChartValue(value, formatting),
},
radar: {
shape: dimension.shape,
@@ -125,15 +100,9 @@ export default class RadarChart extends BaseChart {
type: 'radar',
label: {
show: dimension.fixTooltips,
formatter: (params: { seriesName: string, name: string, value: string | number }): string => {
const { value = '' || 0 } = params
return formatChartValue(value, {
numberFormat: metricNumForm,
prefix: metricPref,
suffix: metricSuff,
presetFormat: metricPresForm,
})
formatter: (params: { value: string | number }): string => {
const { value = '' } = params
return formatChartValue(value, formatting)
},
},
data: seriesData,
@@ -151,8 +120,8 @@ export default class RadarChart extends BaseChart {
})
}
defMetrics (): Metric {
return Object.assign({}, {
defMetric (): Metric {
return Object.assign(super.defMetric(), {
type: ChartType.radar,
})
}
+20 -13
View File
@@ -1,6 +1,5 @@
import numeral from 'numeral'
import * as fmt from '../../../formatting'
import { formatValueAsAccountingNumber } from '../../utils'
export const rgbaRegex = /^rgba\((\d+),.*?(\d+),.*?(\d+),.*?(\d*\.?\d*)\)$/
@@ -29,7 +28,7 @@ export interface KV {
}
export interface FormatData {
numberFormat?: string,
format?: string,
prefix?: string,
suffix?: string,
presetFormat?: string,
@@ -73,6 +72,7 @@ export interface Metric {
fx?: string;
backgroundColor?: string;
symbol?: string;
formatting: FormatData;
[_: string]: any;
}
@@ -86,6 +86,7 @@ export interface YAxis {
max?: string;
rotateLabel?: number;
horizontal?: boolean;
formatting: FormatData;
}
export interface ChartOffset {
@@ -122,9 +123,6 @@ export interface Report {
tooltip?: Tooltip;
legend?: Legend;
offset?: ChartOffset;
tooltipFormatter?: FormatData;
metricFormatter?: FormatData;
yAxisFormatter?: FormatData;
}
export interface ChartToolbox {
@@ -260,10 +258,10 @@ dimensionFunctions.convert = d => dimensionFunctions.lookup(d).convert(d.field)
export const isRadialChart = ({ type }: KV) => type === 'doughnut' || type === 'pie'
export const hasRelativeDisplay = ({ type }: KV) => isRadialChart({ type })
// Makes a standardize alias from modifier or dimension report option
export const makeAlias = ({ alias, aggregate, modifier, field }: Metric) => alias || `${aggregate || modifier || 'none'}_${field}`.toLocaleLowerCase()
// Makes a standardized alias from modifier or dimension report option
export const makeAlias = ({ alias, aggregate, modifier, field }: Partial<Metric>) => alias || `${aggregate || modifier || 'none'}_${field}`.toLocaleLowerCase()
export function formatChartValue (value: string | number, formatConfig?: FormatData): string {
export function formatChartValue (value: string | number, formatting?: FormatData): string {
let n: number | string = 0 || ''
// if value contains alphabetic chars parseFloat() will return NaN
// and n will equal 0
@@ -282,18 +280,18 @@ export function formatChartValue (value: string | number, formatConfig?: FormatD
n = 0
}
if (formatConfig?.numberFormat) {
result = numeral(n).format(formatConfig.numberFormat)
if (formatting?.format) {
result = numeral(n).format(formatting.format)
} else {
result = fmt.number(n)
}
}
if (formatConfig?.presetFormat === 'accountingNumber') {
result = formatValueAsAccountingNumber(Number(n))
if (formatting?.presetFormat === 'accounting') {
result = fmt.accountingNumber(Number(n))
}
return ` ${formatConfig?.prefix ?? ''} ${result || value} ${formatConfig?.suffix ?? ''}`
return ` ${formatting?.prefix ?? ''} ${result || value} ${formatting?.suffix ?? ''}`
}
export function formatChartTooltip (tooltip: string, params: TooltipParams): string {
@@ -306,6 +304,15 @@ export function formatChartTooltip (tooltip: string, params: TooltipParams): str
.replace('{d}', percent.toString())
}
export function defFormatData (): FormatData {
return Object.assign({}, {
presetFormat: 'custom',
prefix: '',
suffix: '',
format: '',
})
}
const chartUtil = {
dimensionFunctions,
hasRelativeDisplay,
@@ -2,7 +2,6 @@ import numeral from 'numeral'
import { ModuleField, Registry, Options, defaultOptions } from './base'
import { Apply } from '../../../cast'
import * as fmt from '../../../formatting'
import { formatValueAsAccountingNumber } from '../../utils'
const kind = 'Number'
@@ -93,7 +92,7 @@ export class ModuleFieldNumber extends ModuleField {
let out = `${n}`
if (format === 'accounting') {
out = formatAccounting(n)
out = fmt.accountingNumber(n)
} else if (format && format.length > 0) {
out = numeral(n).format(format)
} else {
@@ -104,18 +103,4 @@ export class ModuleFieldNumber extends ModuleField {
}
}
export function formatAccounting (value: number): string {
let result = ''
if (value === 0) {
return '-'
}
if (value < 0) {
result = `(${fmt.number(Math.abs(value))}`
}
return fmt.number(value)
}
Registry.set(kind, ModuleFieldNumber)
-11
View File
@@ -1,11 +0,0 @@
export function formatValueAsAccountingNumber (value: number): string {
let result = ''
if (value < 0) {
result = `(${Math.abs(value)})`
} else if (value === 0) {
result = '-'
}
return result
}
+12
View File
@@ -3,3 +3,15 @@ import { currentLanguage } from './locale'
export function number (input: number, options: Intl.NumberFormatOptions = { maximumFractionDigits: 6 }): string {
return new Intl.NumberFormat(currentLanguage(), options).format(input)
}
export function accountingNumber (value: number): string {
if (value === 0) {
return '-'
}
if (value < 0) {
return `(${number(Math.abs(value))}`
}
return number(value)
}
+21 -14
View File
@@ -64,7 +64,7 @@ edit:
preset: Preset filters
footnote: Simplified SQL condition (WHERE ...) syntax is supported. Variables like {{0}}, {{1}}, {{2}} and {{3}} are evaluated (when available)
placeholder: field1 = 1 AND field2 = 232
noFilter: Select a filter or make a custom one
noFilter: Select a filter
recordsCreatedLastMonth: Records created last month
recordsCreatedLastQuarter: Records created last quarter
recordsCreatedLastYear: Records created last year
@@ -73,6 +73,7 @@ edit:
recordsCreatedThisYear: Records created this year
loadData: Load data
metric:
title: Metrics
add: Add metric
fieldLabel: Field *
fieldPlaceholder: Select metric field
@@ -146,7 +147,6 @@ edit:
relative: Show relative value
relativePrecision: 'Precision:'
cumulative: Cumulative
title: Metrics
module:
label: Module *
placeholder: Pick a module
@@ -202,18 +202,10 @@ edit:
label: Tooltip
labelNextToChart: Show labels next to chart
formatting:
label: Formatting
customFormatting: Custom formatting
label: Custom formatting
description: '{a} - metrics label, {b} - dimension value, {c} - metric value, {d} - metric value percentage'
placeholder: '{a}<br />{b} : {c} ({d}%)'
disclaimer: Adding a value to the formatting field will disable the fields number format, prefix, and suffix and vice versa
presetFormats:
label: Format values using
options:
accounting: Accounting number
noFormat: No format selected
description:
accounting: 'Accounting number displays the data in the same way as the currency format with the two differences: 1) negative numbers are transformed into positive and added in brackets and 2) the value 0 is substituted by a dash'
offset:
label: Offset
default: Default offset
@@ -234,6 +226,24 @@ edit:
x: X-Axis
y: Y-Axis
xy: Both
formatting:
format:
label: Format
placeholder: '0.00'
prefix:
label: Prefix
placeholder: '#'
suffix:
label: Suffix
placeholder: $
presetFormats:
label: Format
options:
custom: Custom
accounting: Accounting number
description:
custom: ''
accounting: Negative numbers are transformed into positive and added in brackets and the value 0 is substituted by a dash
import: 'Import chart(s):'
newLabel: 'Create a new chart:'
name: Chart name *
@@ -249,6 +259,3 @@ notification:
searchPlaceholder: Type here to search all charts in this namespace
title: List of Charts
undefined: undefined
numberFormat: Number format
prefix: Prefix
suffix: Suffix
+10 -13
View File
@@ -38,19 +38,16 @@ type (
}
ChartConfigReport struct {
ReportID uint64 `json:"reportID,string,omitempty"`
Filter string `json:"filter"`
ModuleID uint64 `json:"moduleID,string,omitempty"`
Metrics []map[string]interface{} `json:"metrics,omitempty"`
Dimensions []map[string]interface{} `json:"dimensions,omitempty"`
YAxis map[string]interface{} `json:"yAxis,omitempty"`
Legend map[string]interface{} `json:"legend,omitempty"`
Tooltip map[string]interface{} `json:"tooltip,omitempty"`
TooltipFormatter map[string]interface{} `json:"tooltipFormatter,omitempty"`
MetricFormatter map[string]interface{} `json:"metricFormatter,omitempty"`
YAxisFormatter map[string]interface{} `json:"yAxisFormatter,omitempty"`
Offset map[string]interface{} `json:"offset,omitempty"`
Renderer struct {
ReportID uint64 `json:"reportID,string,omitempty"`
Filter string `json:"filter"`
ModuleID uint64 `json:"moduleID,string,omitempty"`
Metrics []map[string]interface{} `json:"metrics,omitempty"`
Dimensions []map[string]interface{} `json:"dimensions,omitempty"`
YAxis map[string]interface{} `json:"yAxis,omitempty"`
Legend map[string]interface{} `json:"legend,omitempty"`
Tooltip map[string]interface{} `json:"tooltip,omitempty"`
Offset map[string]interface{} `json:"offset,omitempty"`
Renderer struct {
Version string `json:"version,omitempty" `
} `json:"renderer,omitempty"`
}