Upgrade ECharts to v5, add support for ECharts gauge & chart widget (#814)

Add a oh-chart widget to add charts to layout pages; change oh-chart-page to use it.
Add a oh-data-series component with the ability to add gauges representing a single value.
Upgrade ECharts to v5.0.1.

Also-by: Yannick Schaus <github@schaus.net>
Signed-off-by: Boris Krivonog <boris.krivonog@inova.si>
pull/853/head
Boris Krivonog 2021-01-27 01:25:49 +01:00 committed by GitHub
parent ece12a1ed5
commit 379cbbe0c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 342 additions and 166 deletions

View File

@ -12,13 +12,12 @@
"cronstrue": "^1.100.0",
"dayjs": "^1.9.6",
"dom7": "^2.1.5",
"echarts": "^4.9.0",
"echarts": "^5.0.1",
"event-source-polyfill": "^1.0.22",
"expression-eval": "^2.1.0",
"framework7": "^5.7.12",
"framework7-icons": "^3.0.1",
"framework7-vue": "^5.7.12",
"global-prefix": "^3.0.0",
"later-again": "^0.1.1",
"leaflet": "^1.7.1",
"leaflet-providers": "^1.11.0",
@ -26,7 +25,6 @@
"nearley": "^2.19.6",
"pkce-challenge": "^2.1.0",
"qrcode": "^1.0.0",
"resolve-dir": "^1.0.1",
"sprintf-js": "^1.1.2",
"template7": "^1.4.2",
"tern": "^0.23.0",
@ -74,6 +72,7 @@
"eslint-loader": "^2.2.1",
"eslint-plugin-vue": "^5.2.3",
"file-loader": "^3.0.1",
"global-prefix": "^3.0.0",
"html-webpack-plugin": "^3.2.0",
"jest": "^24.9.0",
"jest-serializer-vue": "^2.0.2",
@ -85,6 +84,7 @@
"ora": "^3.4.0",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"resolve-dir": "^1.0.1",
"rimraf": "^2.7.1",
"standard": "^12.0.1",
"strip-ansi": "=3.0.1",
@ -7620,13 +7620,19 @@
}
},
"node_modules/echarts": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz",
"integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.0.1.tgz",
"integrity": "sha512-JYn22Dolt2esY2jEzUsw1OxbobuW67oGjIoTjZO3rW89SWkfJ4kbrmC2OW9JjsBrD1rdkmaWBuZZ2HgmThyxJw==",
"dependencies": {
"zrender": "4.3.2"
"tslib": "2.0.3",
"zrender": "5.0.3"
}
},
"node_modules/echarts/node_modules/tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
},
"node_modules/editorconfig": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
@ -8565,6 +8571,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
"integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
"dev": true,
"dependencies": {
"homedir-polyfill": "^1.0.1"
},
@ -10283,6 +10290,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
"integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
"dev": true,
"dependencies": {
"ini": "^1.3.5",
"kind-of": "^6.0.2",
@ -10599,6 +10607,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
"integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
"dev": true,
"dependencies": {
"parse-passwd": "^1.0.0"
},
@ -11023,6 +11032,7 @@
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"engines": {
"node": "*"
}
@ -11561,6 +11571,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -11594,7 +11605,8 @@
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"node_modules/isobject": {
"version": "3.0.1",
@ -12587,6 +12599,7 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -14681,6 +14694,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -17257,6 +17271,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
"integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
"dev": true,
"dependencies": {
"expand-tilde": "2.0.2",
"global-modules": "1.0.0"
@ -17269,6 +17284,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
"integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
"dev": true,
"dependencies": {
"global-prefix": "1.0.2",
"is-windows": "1.0.2",
@ -21494,6 +21510,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"dependencies": {
"isexe": "2.0.0"
},
@ -21890,9 +21907,17 @@
}
},
"node_modules/zrender": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz",
"integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g=="
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.0.3.tgz",
"integrity": "sha512-TVcN2IMdo7je3GEq/E4CER4AGBe/n50/izILdupppyHf/hVHuiXCRliqdu8+32Z1OmGg6RfKt5qQlkX+bOtU0g==",
"dependencies": {
"tslib": "2.0.3"
}
},
"node_modules/zrender/node_modules/tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
}
},
"dependencies": {
@ -28839,11 +28864,19 @@
}
},
"echarts": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-4.9.0.tgz",
"integrity": "sha512-+ugizgtJ+KmsJyyDPxaw2Br5FqzuBnyOWwcxPKO6y0gc5caYcfnEUIlNStx02necw8jmKmTafmpHhGo4XDtEIA==",
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/echarts/-/echarts-5.0.1.tgz",
"integrity": "sha512-JYn22Dolt2esY2jEzUsw1OxbobuW67oGjIoTjZO3rW89SWkfJ4kbrmC2OW9JjsBrD1rdkmaWBuZZ2HgmThyxJw==",
"requires": {
"zrender": "4.3.2"
"tslib": "2.0.3",
"zrender": "5.0.3"
},
"dependencies": {
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
}
}
},
"editorconfig": {
@ -29622,6 +29655,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
"integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
"dev": true,
"requires": {
"homedir-polyfill": "^1.0.1"
}
@ -31060,6 +31094,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
"integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
"dev": true,
"requires": {
"ini": "^1.3.5",
"kind-of": "^6.0.2",
@ -31312,6 +31347,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
"integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
"dev": true,
"requires": {
"parse-passwd": "^1.0.0"
}
@ -31677,7 +31713,8 @@
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true
},
"inquirer": {
"version": "6.5.2",
@ -32098,7 +32135,8 @@
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
"dev": true
},
"is-wsl": {
"version": "1.1.0",
@ -32123,7 +32161,8 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"isobject": {
"version": "3.0.1",
@ -32941,7 +32980,8 @@
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true
},
"kleur": {
"version": "3.0.3",
@ -34671,7 +34711,8 @@
"parse-passwd": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="
"integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
"dev": true
},
"parse5": {
"version": "4.0.0",
@ -36763,6 +36804,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
"integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
"dev": true,
"requires": {
"expand-tilde": "2.0.2",
"global-modules": "1.0.0"
@ -36772,6 +36814,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
"integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
"dev": true,
"requires": {
"global-prefix": "1.0.2",
"is-windows": "1.0.2",
@ -40365,6 +40408,7 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true,
"requires": {
"isexe": "2.0.0"
}
@ -40725,9 +40769,19 @@
}
},
"zrender": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.2.tgz",
"integrity": "sha512-bIusJLS8c4DkIcdiK+s13HiQ/zjQQVgpNohtd8d94Y2DnJqgM1yjh/jpDb8DoL6hd7r8Awagw8e3qK/oLaWr3g=="
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-5.0.3.tgz",
"integrity": "sha512-TVcN2IMdo7je3GEq/E4CER4AGBe/n50/izILdupppyHf/hVHuiXCRliqdu8+32Z1OmGg6RfKt5qQlkX+bOtU0g==",
"requires": {
"tslib": "2.0.3"
},
"dependencies": {
"tslib": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
}
}
}
}
}

View File

@ -60,7 +60,7 @@
"cronstrue": "^1.100.0",
"dayjs": "^1.9.6",
"dom7": "^2.1.5",
"echarts": "^4.9.0",
"echarts": "^5.0.1",
"event-source-polyfill": "^1.0.22",
"expression-eval": "^2.1.0",
"framework7": "^5.7.12",

View File

@ -375,6 +375,17 @@ export default {
}
},
'oh-data-series': {
label: 'Data Series',
docLink: 'https://echarts.apache.org/en/option.html#series',
props: {
parameterGroups: [],
parameters: [
seriesTypeParameter('gauge')
]
}
},
'oh-time-series': {
label: 'Time Series',
docLink: 'https://echarts.apache.org/en/option.html#series',

View File

@ -1,33 +1,7 @@
// definitions for the chart page & widgets
import { WidgetDefinition, po } from '../helpers'
import { WidgetDefinition } from '../helpers'
import ChartParameters from '../system/chart'
export const OhChartPageDefinition = () => new WidgetDefinition('oh-chart-page', 'Chart Page', 'Visualize historical series')
.params([
po('chartType', 'Chart Type', 'Define a fixed period for the chart, aligned at the beginning of the period, e.g. January 1st at midnight for a year chart. If not set (or set to dynamic), the length of the period will be configurable but certain combinations like aggregated series might not work', [
{ value: '', label: 'Dynamic period' },
{ value: 'day', label: 'Day' },
{ value: 'isoWeek', label: 'Week (starting on Monday)' },
{ value: 'week', label: 'Week (starting on Sunday)' },
{ value: 'month', label: 'Month' },
{ value: 'year', label: 'Year' }
]).r(),
po('period', 'Initial Period', 'The initial period for the chart', [
{ value: 'h', label: 'h' },
{ value: '2h', label: '2h' },
{ value: '4h', label: '4h' },
{ value: '12h', label: '12h' },
{ value: 'D', label: 'D' },
{ value: '2D', label: '2D' },
{ value: '3D', label: '3D' },
{ value: 'W', label: 'W' },
{ value: '2W', label: '2W' },
{ value: 'M', label: 'M' },
{ value: '2M', label: '2M' },
{ value: '4M', label: '4M' },
{ value: '6M', label: '6M' },
{ value: 'Y', label: 'Y' }
]).v((value, configuration, configDescription, parameters) => {
return !configuration.chartType
})
])
.params(ChartParameters())

View File

@ -0,0 +1,30 @@
import { po } from '../helpers'
export default () => [
po('chartType', 'Chart Type', 'Define a fixed period for the chart, aligned at the beginning of the period, e.g. January 1st at midnight for a year chart. If not set (or set to dynamic), the length of the period will be configurable but certain combinations like aggregated series might not work', [
{ value: '', label: 'Dynamic period' },
{ value: 'day', label: 'Day' },
{ value: 'isoWeek', label: 'Week (starting on Monday)' },
{ value: 'week', label: 'Week (starting on Sunday)' },
{ value: 'month', label: 'Month' },
{ value: 'year', label: 'Year' }
]).r(),
po('period', 'Initial Period', 'The initial period for the chart', [
{ value: 'h', label: 'h' },
{ value: '2h', label: '2h' },
{ value: '4h', label: '4h' },
{ value: '12h', label: '12h' },
{ value: 'D', label: 'D' },
{ value: '2D', label: '2D' },
{ value: '3D', label: '3D' },
{ value: 'W', label: 'W' },
{ value: '2W', label: '2W' },
{ value: 'M', label: 'M' },
{ value: '2M', label: '2M' },
{ value: '4M', label: '4M' },
{ value: '6M', label: '6M' },
{ value: 'Y', label: 'Y' }
]).v((value, configuration, configDescription, parameters) => {
return !configuration.chartType
})
]

View File

@ -9,6 +9,10 @@ export const OhButtonDefinition = () => new WidgetDefinition('oh-button', 'Butto
.paramGroup(actionGroup(), actionParams())
.params([...ButtonParameters(), VariableParameter, ClearVariableParameter])
import ChartParameters from './chart'
export const OhChartDefinition = () => new WidgetDefinition('oh-chart', 'Chart', 'Visualize series of data')
.params(ChartParameters())
import ColorpickerParameters from './colorpicker'
export const OhColorpickerDefinition = () => new WidgetDefinition('oh-colorpicker', 'Colorpicker', 'Control to pick a color')
.params(ColorpickerParameters())

View File

@ -23,7 +23,7 @@ function getWidgetDefinitions (cm) {
switch (componentType) {
case 'chart':
return [
OhChartPageDefinition,
OhChartPageDefinition(),
...Object.keys(ChartWidgetsDefinitions).map((name) => {
return Object.assign({}, ChartWidgetsDefinitions[name], { name })
})
@ -39,7 +39,10 @@ function getWidgetDefinitions (cm) {
return [
...(componentType === 'home') ? [OhLocationCardParameters(), OhEquipmentCardParameters(), OhPropertyCardParameters()] : [],
...ohComponents.map((c) => c.widget()).sort((c1, c2) => c1.name.localeCompare(c2.name)),
...f7Components.sort((c1, c2) => c1.name.localeCompare(c2.name))
...f7Components.sort((c1, c2) => c1.name.localeCompare(c2.name)),
...Object.keys(ChartWidgetsDefinitions).map((name) => {
return Object.assign({}, ChartWidgetsDefinitions[name], { name })
})
]
}
}

View File

@ -42,6 +42,7 @@ export default {
confine: true,
position: [10, 10]
},
backgroundColor: (this.$f7.data.themeOptions.dark === 'dark') ? '#121212' : undefined,
series: this.series
}
}
@ -93,7 +94,7 @@ export default {
}
}
return this.$oh.api.get('/rest/things').then((data) => {
let zWaveNodes = data.filter((t) => t.properties && t.properties.zwave_nodeid)
let zWaveNodes = data.filter((t) => t.properties && t.properties.zwave_nodeid && t.properties.zwave_neighbours)
zWaveNodes.forEach((t) => {
let nodeid = t.properties.zwave_nodeid

View File

@ -9,6 +9,7 @@ import OhCalendarAxis from './axis/oh-calendar-axis'
import OhCategoryAxis from './axis/oh-category-axis'
// Series components
import OhDataSeries from './series/oh-data-series'
import OhTimeSeries from './series/oh-time-series'
import OhAggregateSeries from './series/oh-aggregate-series'
import OhCalendarSeries from './series/oh-calendar-series'
@ -29,6 +30,7 @@ const axisComponents = {
}
const seriesComponents = {
'oh-data-series': OhDataSeries,
'oh-time-series': OhTimeSeries,
'oh-aggregate-series': OhAggregateSeries,
'oh-calendar-series': OhCalendarSeries
@ -36,8 +38,9 @@ const seriesComponents = {
export default {
data () {
const chartType = this.context.component.config.chartType
const period = this.context.component.config.period || 'D'
const config = this.context.component.config || {}
const chartType = config.chartType
const period = config.period || 'D'
let endTime = (chartType) ? this.addOrSubtractPeriod(dayjs().startOf(chartType), 1) : dayjs()
return {
items: {},
@ -51,7 +54,11 @@ export default {
return this.addOrSubtractPeriod(this.endTime, -1)
},
options () {
if (!this.config) return {}
const chartConfig = this.config.options || {}
if (!chartConfig.backgroundColor && this.$f7.data.themeOptions.dark === 'dark') {
chartConfig.backgroundColor = '#121212'
}
return {
...chartConfig,
grid: this.grid,
@ -121,7 +128,13 @@ export default {
},
methods: {
getSeriesPromises (component) {
const getter = (data) => seriesComponents[component.component].get(component, data.map((d) => d[1]), this.startTime, this.endTime, this)
const neededItems = seriesComponents[component.component].neededItems(component).filter(i => !!i)
if (neededItems.length === 0) {
return Promise.resolve(getter([]))
}
const itemPromises = neededItems.map((neededItem) => {
if (this.items[neededItem]) return Promise.resolve(this.items[neededItem])
return this.$oh.api.get(`/rest/items/${neededItem}`).then((item) => {
@ -147,9 +160,7 @@ export default {
return Promise.all([itemPromises[neededItem], this.$oh.api.get(url, query)])
})
return Promise.all(combinedPromises).then((data) => {
return seriesComponents[component.component].get(component, data.map((d) => d[1]), this.startTime, this.endTime, this)
})
return Promise.all(combinedPromises).then(getter)
},
setPeriod (period) {
this.period = period
@ -167,6 +178,7 @@ export default {
this.endTime = this.addOrSubtractPeriod(this.endTime, 1)
},
addOrSubtractPeriod (day, direction) {
if (!this.context.component.config) return
const fn = (direction < 0) ? day.subtract : day.add
const chartType = this.context.component.config.chartType
for (let i = 0; i < Math.abs(direction); i++) {

View File

@ -1,31 +1,13 @@
<template>
<div>
<chart
ref="chart"
v-if="ready"
:options="options"
class="oh-chart-page-chart"
:class="{ 'with-tabbar': context.tab, 'with-toolbar': context.analyzer }"
:theme="$f7.data.themeOptions.dark === 'dark' ? 'dark' : undefined" autoresize></chart>
<f7-menu class="padding float-right">
<f7-menu-item @click="earlierPeriod()" icon-f7="chevron_left" />
<f7-menu-item v-if="context.component.config.chartType" :text="fixedPeriodLabel" type="text" @click="pickFixedStartDate">
<input ref="calendarInput" type="text" style="width: 40px; height: 0; visibility: hidden">
</f7-menu-item>
<f7-menu-item v-else dropdown :text="period">
<f7-menu-dropdown right>
<f7-menu-dropdown-item v-for="p in ['h', '2h', '4h', '12h', 'D', '2D', '3D', 'W', '2W', 'M', '2M', '4M', '6M', 'Y']"
:key="p" @click="setPeriod(p)" href="#" :text="p"></f7-menu-dropdown-item>
</f7-menu-dropdown>
</f7-menu-item>
<f7-menu-item @click="laterPeriod()" icon-f7="chevron_right" />
</f7-menu>
</div>
<oh-chart
class="oh-chart-page-chart"
:class="{ 'with-tabbar': context.tab, 'with-toolbar': context.analyzer }"
:context="this.context" />
</template>
<style lang="stylus">
.oh-chart-page-chart
position absolute
position absolute !important
background-color white
overflow-x hidden
top calc(var(--f7-safe-area-top) + var(--f7-navbar-height))
@ -35,97 +17,20 @@
height calc(100% - var(--f7-safe-area-top) - var(--f7-safe-area-bottom) - var(--f7-navbar-height) - var(--f7-tabbar-labels-height)) !important
&.with-toolbar
height calc(100% - var(--f7-safe-area-top) - var(--f7-safe-area-bottom) - var(--f7-navbar-height) - var(--f7-toolbar-height)) !important
&.with-sheet
&.sheet-opened
height calc(100% - var(--f7-safe-area-top) - var(--f7-safe-area-bottom) - var(--f7-navbar-height) - var(--f7-sheet-height)) !important
.echarts
width calc(100% - 20px)
height 100%
</style>
<script>
import mixin from '../widget-mixin'
import chart from './chart-mixin'
import dayjs from 'dayjs'
import LocalizedFormat from 'dayjs/plugin/localizedFormat'
dayjs.extend(LocalizedFormat)
// import echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/heatmap'
import 'echarts/lib/chart/scatter'
import 'echarts/lib/component/title'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/legendScroll'
import 'echarts/lib/component/toolbox'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/dataZoom'
import 'echarts/lib/component/markLine'
import 'echarts/lib/component/markPoint'
import 'echarts/lib/component/markArea'
import 'echarts/lib/component/visualMap'
import 'echarts/lib/component/calendar'
import ECharts from 'vue-echarts/components/ECharts'
import OhChart from '../system/oh-chart.vue'
import { OhChartPageDefinition } from '@/assets/definitions/widgets/chart/page'
export default {
mixins: [mixin, chart],
mixins: [mixin],
components: {
'chart': ECharts
OhChart
},
widget: OhChartPageDefinition,
computed: {
fixedPeriodLabel () {
const startTime = this.startTime
if (!this.startTime) return ''
switch (this.context.component.config.chartType) {
case 'hour':
return startTime.format('lll')
case 'day':
return startTime.format('ll')
case 'week':
case 'isoWeek':
return startTime.format('ll')
case 'month':
return startTime.format('MMM YYYY')
case 'year':
return startTime.format('YYYY')
default:
return startTime.format('ll')
}
}
},
data () {
return {
ready: false,
calendarPicker: null
}
},
mounted () {
this.ready = true
},
beforeDestroy () {
if (this.calendarPicker) this.calendarPicker.destroy()
},
methods: {
pickFixedStartDate (evt) {
const self = this
const value = this.startTime.toDate()
this.calendarPicker = this.$f7.calendar.create({
inputEl: this.$refs.calendarInput,
value: [value],
on: {
change (calendar, value) {
if (value.length < 1) return
if (dayjs(value[0]).isSame(self.startTime)) return
self.setDate(value[0])
}
}
})
this.calendarPicker.open()
}
}
widget: OhChartPageDefinition
}
</script>

View File

@ -0,0 +1,32 @@
import Framework7 from 'framework7'
export default {
neededItems () {
return []
},
get (component, points, startTime, endTime, chart) {
if (!component.config || typeof component.config !== 'object') return {}
if (!component.dataSeriesId) {
component.dataSeriesId = Framework7.utils.id()
}
let series = chart.evaluateExpression(component.dataSeriesId, component.config)
if (series.data && Array.isArray(series.data)) {
series.data = series.data.map((v, index) => {
const item = chart.evaluateExpression(component.dataSeriesId + 'data.' + index, v)
return Number.isNaN(item.value) ? {} : item
})
}
if (series.axisLine && series.axisLine.lineStyle && series.axisLine.lineStyle.color && Array.isArray(series.axisLine.lineStyle.color)) {
series.axisLine.lineStyle.color = series.axisLine.lineStyle.color.map((v, index) => {
if (!Array.isArray(v)) return v
return v.map((s, subindex) => chart.evaluateExpression(component.dataSeriesId + 'axisLine.lineStyle.color.' + index + '.' + subindex, s))
})
}
return series
}
}

View File

@ -19,3 +19,4 @@ export { default as OhSwiperSlide } from './oh-swiper-slide.vue'
export { default as OhTrend } from './oh-trend.vue'
export { default as OhWebframe } from './oh-webframe.vue'
export { default as OhRepeater } from './oh-repeater.vue'
export { default as OhChart } from './oh-chart.vue'

View File

@ -0,0 +1,133 @@
<template>
<div class="oh-chart-container" v-bind:style="{ height: activeHeight }">
<chart
ref="chart"
v-if="ready"
:options="options"
class="oh-chart"
:class="{ 'with-tabbar': context.tab, 'with-toolbar': context.analyzer }"
:theme="$f7.data.themeOptions.dark === 'dark' ? 'dark' : undefined" autoresize></chart>
<f7-menu class="padding float-right" v-if="periodVisible">
<f7-menu-item @click="earlierPeriod()" icon-f7="chevron_left" />
<f7-menu-item v-if="context.component.config.chartType" :text="fixedPeriodLabel" type="text" @click="pickFixedStartDate">
<input ref="calendarInput" type="text" style="width: 40px; height: 0; visibility: hidden">
</f7-menu-item>
<f7-menu-item v-else dropdown :text="period">
<f7-menu-dropdown right>
<f7-menu-dropdown-item v-for="p in ['h', '2h', '4h', '12h', 'D', '2D', '3D', 'W', '2W', 'M', '2M', '4M', '6M', 'Y']"
:key="p" @click="setPeriod(p)" href="#" :text="p"></f7-menu-dropdown-item>
</f7-menu-dropdown>
</f7-menu-item>
<f7-menu-item @click="laterPeriod()" icon-f7="chevron_right" />
</f7-menu>
</div>
</template>
<style lang="stylus">
.oh-chart-container
position relative
.oh-chart
position absolute
width 100%
height 100%
</style>
<script>
import mixin from '../widget-mixin'
import chart from '../chart/chart-mixin'
import dayjs from 'dayjs'
import LocalizedFormat from 'dayjs/plugin/localizedFormat'
dayjs.extend(LocalizedFormat)
// import echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/line'
import 'echarts/lib/chart/bar'
import 'echarts/lib/chart/gauge'
import 'echarts/lib/chart/heatmap'
import 'echarts/lib/chart/scatter'
import 'echarts/lib/component/title'
import 'echarts/lib/component/legend'
import 'echarts/lib/component/legendScroll'
import 'echarts/lib/component/toolbox'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/dataZoom'
import 'echarts/lib/component/markLine'
import 'echarts/lib/component/markPoint'
import 'echarts/lib/component/markArea'
import 'echarts/lib/component/visualMap'
import 'echarts/lib/component/calendar'
import ECharts from 'vue-echarts/components/ECharts'
export default {
mixins: [mixin, chart],
components: {
'chart': ECharts
},
computed: {
activeHeight () {
const config = this.config || {}
return config.height || '300px'
},
periodVisible () {
if (!this.config || this.config.periodVisible === undefined) {
if (this.context.component.slots && this.context.component.slots.series && Array.isArray(this.context.component.slots.series) && this.context.component.slots.series.length) {
return this.context.component.slots.series[0].component !== 'oh-data-series'
}
return true
}
return this.config.periodVisible
},
fixedPeriodLabel () {
const startTime = this.startTime
if (!this.startTime) return ''
switch (this.context.component.config.chartType) {
case 'hour':
return startTime.format('lll')
case 'day':
return startTime.format('ll')
case 'week':
case 'isoWeek':
return startTime.format('ll')
case 'month':
return startTime.format('MMM YYYY')
case 'year':
return startTime.format('YYYY')
default:
return startTime.format('ll')
}
}
},
data () {
return {
ready: false,
calendarPicker: null
}
},
mounted () {
this.ready = true
},
beforeDestroy () {
if (this.calendarPicker) this.calendarPicker.destroy()
},
methods: {
pickFixedStartDate (evt) {
const self = this
const value = this.startTime.toDate()
this.calendarPicker = this.$f7.calendar.create({
inputEl: this.$refs.calendarInput,
value: [value],
on: {
change (calendar, value) {
if (value.length < 1) return
if (dayjs(value[0]).isSame(self.startTime)) return
self.setDate(value[0])
}
}
})
this.calendarPicker.open()
}
}
}
</script>

View File

@ -0,0 +1,16 @@
<template>
<oh-chart-component :context="this.context" />
</template>
<script>
import mixin from '../widget-mixin'
import { OhChartDefinition } from '@/assets/definitions/widgets/system'
export default {
mixins: [mixin],
components: {
'oh-chart-component': () => import(/* webpackChunkName: "oh-chart-component" */ './oh-chart-component.vue')
},
widget: OhChartDefinition
}
</script>