Allow actions on chart series (#1417)

Add optional performAction args to accept an arbitrary config and/or context.

Supersedes #1392.
Closes #1391.

Signed-off-by: Yannick Schaus <github@schaus.net>
Also-by: Łukasz Dywicki <luke@code-house.org>
pull/1445/head
Yannick Schaus 2022-07-06 21:12:30 +02:00 committed by GitHub
parent 1094d4b16d
commit 34c59ecc2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 19 deletions

View File

@ -1,6 +1,8 @@
// definitions for the chart widgets // definitions for the chart widgets
// TODO: migrate to WidgetDefinition & use helpers // TODO: migrate to WidgetDefinition & use helpers
import { actionGroup, actionParams } from '../actions'
const positionGroup = { const positionGroup = {
name: 'position', name: 'position',
label: 'Position', label: 'Position',
@ -366,11 +368,12 @@ export default {
label: 'Calendar', label: 'Calendar',
docLink: 'https://echarts.apache.org/en/option.html#calendar', docLink: 'https://echarts.apache.org/en/option.html#calendar',
props: { props: {
parameterGroups: [nameDisplayGroup, componentRelationsGroup], parameterGroups: [nameDisplayGroup, componentRelationsGroup, actionGroup()],
parameters: [ parameters: [
...positionParameters, ...positionParameters,
orientParameter, orientParameter,
gridIndexParameter gridIndexParameter,
...actionParams()
] ]
} }
}, },
@ -379,9 +382,10 @@ export default {
label: 'Data Series', label: 'Data Series',
docLink: 'https://echarts.apache.org/en/option.html#series', docLink: 'https://echarts.apache.org/en/option.html#series',
props: { props: {
parameterGroups: [], parameterGroups: [actionGroup()],
parameters: [ parameters: [
seriesTypeParameter('gauge', 'pie') seriesTypeParameter('gauge', 'pie'),
...actionParams()
] ]
} }
}, },
@ -390,12 +394,13 @@ export default {
label: 'Time Series', label: 'Time Series',
docLink: 'https://echarts.apache.org/en/option.html#series', docLink: 'https://echarts.apache.org/en/option.html#series',
props: { props: {
parameterGroups: [componentRelationsGroup], parameterGroups: [componentRelationsGroup, actionGroup()],
parameters: [ parameters: [
...seriesParameters, ...seriesParameters,
seriesTypeParameter('line', 'bar', 'heatmap', 'scatter'), seriesTypeParameter('line', 'bar', 'heatmap', 'scatter'),
xAxisIndexParameter, xAxisIndexParameter,
yAxisIndexParameter yAxisIndexParameter,
...actionParams()
] ]
} }
}, },
@ -404,7 +409,7 @@ export default {
label: 'Aggregate Series', label: 'Aggregate Series',
docLink: 'https://echarts.apache.org/en/option.html#series', docLink: 'https://echarts.apache.org/en/option.html#series',
props: { props: {
parameterGroups: [componentRelationsGroup], parameterGroups: [componentRelationsGroup, actionGroup()],
parameters: [ parameters: [
...seriesParameters, ...seriesParameters,
seriesTypeParameter('line', 'bar', 'heatmap', 'scatter'), seriesTypeParameter('line', 'bar', 'heatmap', 'scatter'),
@ -432,7 +437,8 @@ export default {
}, },
aggregationFunctionParameter, aggregationFunctionParameter,
xAxisIndexParameter, xAxisIndexParameter,
yAxisIndexParameter yAxisIndexParameter,
...actionParams()
] ]
} }
}, },
@ -441,12 +447,13 @@ export default {
label: 'Calendar Series', label: 'Calendar Series',
docLink: 'https://echarts.apache.org/en/option.html#series', docLink: 'https://echarts.apache.org/en/option.html#series',
props: { props: {
parameterGroups: [componentRelationsGroup], parameterGroups: [componentRelationsGroup, actionGroup()],
parameters: [ parameters: [
...seriesParameters, ...seriesParameters,
seriesTypeParameter('heatmap', 'scatter'), seriesTypeParameter('heatmap', 'scatter'),
aggregationFunctionParameter, aggregationFunctionParameter,
calendarIndexParameter calendarIndexParameter,
...actionParams()
] ]
} }
}, },

View File

@ -5,6 +5,7 @@
v-if="ready" v-if="ready"
:options="options" :options="options"
class="oh-chart" class="oh-chart"
@click="handleClick"
:class="{ 'with-tabbar': context.tab, 'with-toolbar': context.analyzer }" :class="{ 'with-tabbar': context.tab, 'with-toolbar': context.analyzer }"
:theme="$f7.data.themeOptions.dark === 'dark' ? 'dark' : undefined" autoresize /> :theme="$f7.data.themeOptions.dark === 'dark' ? 'dark' : undefined" autoresize />
<f7-menu class="padding float-right" v-if="periodVisible"> <f7-menu class="padding float-right" v-if="periodVisible">
@ -35,6 +36,7 @@
<script> <script>
import mixin from '../widget-mixin' import mixin from '../widget-mixin'
import chart from '../chart/chart-mixin' import chart from '../chart/chart-mixin'
import { actionsMixin } from '../widget-actions'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import LocalizedFormat from 'dayjs/plugin/localizedFormat' import LocalizedFormat from 'dayjs/plugin/localizedFormat'
@ -62,7 +64,7 @@ import 'echarts/lib/component/calendar'
import ECharts from 'vue-echarts/components/ECharts' import ECharts from 'vue-echarts/components/ECharts'
export default { export default {
mixins: [mixin, chart], mixins: [mixin, chart, actionsMixin],
components: { components: {
'chart': ECharts 'chart': ECharts
}, },
@ -113,6 +115,14 @@ export default {
if (this.calendarPicker) this.calendarPicker.destroy() if (this.calendarPicker) this.calendarPicker.destroy()
}, },
methods: { methods: {
handleClick (evt) {
if (evt.seriesIndex !== undefined) {
if (this.context.component.slots && this.context.component.slots.series && Array.isArray(this.context.component.slots.series) && this.context.component.slots.series.length) {
let series = this.context.component.slots.series[evt.seriesIndex]
this.performAction(evt.event, null, series.config, null)
}
}
},
pickFixedStartDate (evt) { pickFixedStartDate (evt) {
const self = this const self = this
const value = this.startTime.toDate() const value = this.startTime.toDate()

View File

@ -28,14 +28,34 @@ export const actionsMixin = {
})).open() })).open()
} }
}, },
performAction (evt, prefix) { /**
if (!this.context || !this.config) return * Performs an action determined by config parameters.
const actionPropsParameterGroup = this.config[((prefix) ? prefix + '_' : '') + 'actionPropsParameterGroup'] *
const actionConfig = (actionPropsParameterGroup) ? this.evaluateExpression('$props', this.context.props) : this.config * If no prefix is specified, will use the parameter "action" and other parameters beginning with "action"
* If a prefix is specified, the parameters considered will be "prefix_action*"
*
* Instead of "[prefix_]action" and others, "[prefix_]actionPropsParameterGroup" can be provided.
* The value must match the name of a parameter group with the context set to "actions".
* The actual prefix of the parameters will then match the name of the group with the term "action" removed.
* For example, for a "dblclickAction" parameter group, the action parameters will be "dblclick_action*".
* This allows custom widget designers to offer actions parameters to configure their widget.
*
* @param {Event} evt the event (e.g. "click") at the origin of the action
* @param {String} prefix the prefix for the parameter group and associated parameters (see below)
* @param {Object} config the config object containing the parameters to use, will use `this.config` if unset
* @param {Object} context the context to use, will use `this.context` if unset
* @returns {Boolean?} true if the action was performed, otherwise undefined
*/
performAction (evt, prefix, config, context) {
if (!context) context = this.context
if (!config) config = this.config
if (!config || !context) return
const actionPropsParameterGroup = config[((prefix) ? prefix + '_' : '') + 'actionPropsParameterGroup']
const actionConfig = (actionPropsParameterGroup) ? this.evaluateExpression('$props', context.props) : config
prefix = (actionPropsParameterGroup) ? actionPropsParameterGroup.replace(/action/gi, '') : prefix prefix = (actionPropsParameterGroup) ? actionPropsParameterGroup.replace(/action/gi, '') : prefix
prefix = (prefix) ? prefix += '_' : '' prefix = (prefix) ? prefix += '_' : ''
const action = actionConfig[prefix + 'action'] const action = actionConfig[prefix + 'action']
if (this.context.editmode) { if (context.editmode) {
this.showActionFeedback(prefix, actionConfig, `Action '${action}' not performed while in edit mode`) this.showActionFeedback(prefix, actionConfig, `Action '${action}' not performed while in edit mode`)
return return
} }
@ -65,8 +85,8 @@ export const actionsMixin = {
const actionToggleItem = actionConfig[prefix + 'actionItem'] const actionToggleItem = actionConfig[prefix + 'actionItem']
const actionToggleCommand = actionConfig[prefix + 'actionCommand'] const actionToggleCommand = actionConfig[prefix + 'actionCommand']
const actionToggleCommandAlt = actionConfig[prefix + 'actionCommandAlt'] const actionToggleCommandAlt = actionConfig[prefix + 'actionCommandAlt']
const state = this.context.store[actionToggleItem].state const state = context.store[actionToggleItem].state
let cmd = this.context.store[actionToggleItem].state === actionToggleCommand ? actionToggleCommandAlt : actionToggleCommand let cmd = context.store[actionToggleItem].state === actionToggleCommand ? actionToggleCommandAlt : actionToggleCommand
// special behavior for Color, Dimmer // special behavior for Color, Dimmer
if (actionToggleCommand === 'OFF' && state.split(',').length === 3 && parseInt(state.split(',')[2]) === 0) cmd = actionToggleCommandAlt if (actionToggleCommand === 'OFF' && state.split(',').length === 3 && parseInt(state.split(',')[2]) === 0) cmd = actionToggleCommandAlt
if (actionToggleCommand === 'ON' && state.split(',').length === 3 && parseInt(state.split(',')[2]) > 0) cmd = actionToggleCommandAlt if (actionToggleCommand === 'ON' && state.split(',').length === 3 && parseInt(state.split(',')[2]) > 0) cmd = actionToggleCommandAlt
@ -227,7 +247,7 @@ export const actionsMixin = {
case 'variable': case 'variable':
const actionVariable = actionConfig[prefix + 'actionVariable'] const actionVariable = actionConfig[prefix + 'actionVariable']
const actionVariableValue = actionConfig[prefix + 'actionVariableValue'] const actionVariableValue = actionConfig[prefix + 'actionVariableValue']
this.$set(this.context.vars, actionVariable, actionVariableValue) this.$set(context.vars, actionVariable, actionVariableValue)
break break
default: default:
console.log('Invalid action: ' + action) console.log('Invalid action: ' + action)