From 9927d3409988d52b3f1c8f4f32c0590ed912fb76 Mon Sep 17 00:00:00 2001 From: chiayin Date: Wed, 31 May 2023 17:36:46 +0800 Subject: [PATCH] Discover: SidebarFilter Timeframes div & slider done. --- package-lock.json | 247 ++++++++++++++- package.json | 5 + src/components/Discover/Filter/Timeframes.vue | 296 ++++++++++++++++-- src/components/VueChart.vue | 179 +++++++++++ src/main.js | 1 + src/module/timeframes.js | 121 +++++++ 6 files changed, 824 insertions(+), 25 deletions(-) create mode 100644 src/components/VueChart.vue create mode 100644 src/module/timeframes.js diff --git a/package-lock.json b/package-lock.json index f0e03f5..013fe7f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,13 @@ "autoprefixer": "^10.4.13", "axios": "^1.2.2", "chart.js": "^4.3.0", + "chartjs-adapter-date-fns": "^3.0.0", + "chartjs-plugin-datalabels": "^2.2.0", + "chartjs-plugin-dragdata": "^1.1.3", "cytoscape": "^3.23.0", "cytoscape-dagre": "^2.5.0", "cytoscape-popper": "^2.0.0", + "date-fns": "^2.30.0", "javascript-color-gradient": "^2.4.4", "mitt": "^3.0.0", "moment": "^2.29.4", @@ -25,6 +29,7 @@ "tippy.js": "^6.3.7", "vue": "^3.2.45", "vue-axios": "^3.5.2", + "vue-chartjs": "^5.2.0", "vue-router": "^4.1.6", "vue-sweetalert2": "^5.0.5", "vue-toast-notification": "^3.0.4", @@ -62,6 +67,17 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", + "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -1732,6 +1748,72 @@ "pnpm": ">=7" } }, + "node_modules/chartjs-adapter-date-fns": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", + "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", + "peerDependencies": { + "chart.js": ">=2.8.0", + "date-fns": ">=2.0.0" + } + }, + "node_modules/chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "dependencies": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + } + }, + "node_modules/chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "dependencies": { + "color-name": "^1.0.0" + } + }, + "node_modules/chartjs-color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/chartjs-color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "peerDependencies": { + "chart.js": ">=3.0.0" + } + }, + "node_modules/chartjs-plugin-dragdata": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chartjs-plugin-dragdata/-/chartjs-plugin-dragdata-1.1.3.tgz", + "integrity": "sha512-aRkNiCEoAAWqyPDSNLf+HEfybh87qRdEsp5u596bYmQF0WDWQpUQPI09RtvjPvsZ1xInxpbfWPynWUXy+HHxRA==", + "dependencies": { + "chart.js": "^2.9.3", + "d3-drag": "^1.2.5", + "d3-selection": "^1.4.1" + } + }, + "node_modules/chartjs-plugin-dragdata/node_modules/chart.js": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", + "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", + "dependencies": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + }, "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -1887,8 +1969,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/colorette": { "version": "2.0.19", @@ -2111,6 +2192,25 @@ "cytoscape": "^3.2.0" } }, + "node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + }, + "node_modules/d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "dependencies": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "node_modules/d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + }, "node_modules/dagre": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", @@ -2146,6 +2246,21 @@ "node": ">=12" } }, + "node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/dayjs": { "version": "1.11.7", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", @@ -4948,6 +5063,11 @@ "node": ">=8.10.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -5995,6 +6115,15 @@ "vue": "^3.0.0 || ^2.0.0" } }, + "node_modules/vue-chartjs": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.2.0.tgz", + "integrity": "sha512-d3zpKmGZr2OWHQ1xmxBcAn5ShTG917+/UCLaSpaCDDqT0U7DBsvFzTs69ZnHCgKoXT55GZDW8YEj9Av+dlONLA==", + "peerDependencies": { + "chart.js": "^4.1.1", + "vue": "^3.0.0-0 || ^2.7.0" + } + }, "node_modules/vue-eslint-parser": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz", @@ -6381,6 +6510,14 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz", "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==" }, + "@babel/runtime": { + "version": "7.22.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz", + "integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==", + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -7602,6 +7739,71 @@ "@kurkle/color": "^0.3.0" } }, + "chartjs-adapter-date-fns": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz", + "integrity": "sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==", + "requires": {} + }, + "chartjs-color": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", + "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", + "requires": { + "chartjs-color-string": "^0.6.0", + "color-convert": "^1.9.3" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, + "chartjs-color-string": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", + "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", + "requires": { + "color-name": "^1.0.0" + } + }, + "chartjs-plugin-datalabels": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.2.0.tgz", + "integrity": "sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==", + "requires": {} + }, + "chartjs-plugin-dragdata": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chartjs-plugin-dragdata/-/chartjs-plugin-dragdata-1.1.3.tgz", + "integrity": "sha512-aRkNiCEoAAWqyPDSNLf+HEfybh87qRdEsp5u596bYmQF0WDWQpUQPI09RtvjPvsZ1xInxpbfWPynWUXy+HHxRA==", + "requires": { + "chart.js": "^2.9.3", + "d3-drag": "^1.2.5", + "d3-selection": "^1.4.1" + }, + "dependencies": { + "chart.js": { + "version": "2.9.4", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", + "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", + "requires": { + "chartjs-color": "^2.1.0", + "moment": "^2.10.2" + } + } + } + }, "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -7710,8 +7912,7 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "colorette": { "version": "2.0.19", @@ -7890,6 +8091,25 @@ "@popperjs/core": "^2.0.0" } }, + "d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" + }, + "d3-drag": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", + "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", + "requires": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + }, "dagre": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", @@ -7919,6 +8139,14 @@ "whatwg-url": "^11.0.0" } }, + "date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "requires": { + "@babel/runtime": "^7.21.0" + } + }, "dayjs": { "version": "1.11.7", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", @@ -9965,6 +10193,11 @@ "picomatch": "^2.2.1" } }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -10671,6 +10904,12 @@ "integrity": "sha512-GP+dct7UlAWkl1qoP3ppw0z6jcSua5/IrMpjB5O8bh089iIiJ+hdxPYH2NPEpajlYgkW5EVMP95ttXWdas1O0g==", "requires": {} }, + "vue-chartjs": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/vue-chartjs/-/vue-chartjs-5.2.0.tgz", + "integrity": "sha512-d3zpKmGZr2OWHQ1xmxBcAn5ShTG917+/UCLaSpaCDDqT0U7DBsvFzTs69ZnHCgKoXT55GZDW8YEj9Av+dlONLA==", + "requires": {} + }, "vue-eslint-parser": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.1.0.tgz", diff --git a/package.json b/package.json index fb3fe83..751d12f 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,13 @@ "autoprefixer": "^10.4.13", "axios": "^1.2.2", "chart.js": "^4.3.0", + "chartjs-adapter-date-fns": "^3.0.0", + "chartjs-plugin-datalabels": "^2.2.0", + "chartjs-plugin-dragdata": "^1.1.3", "cytoscape": "^3.23.0", "cytoscape-dagre": "^2.5.0", "cytoscape-popper": "^2.0.0", + "date-fns": "^2.30.0", "javascript-color-gradient": "^2.4.4", "mitt": "^3.0.0", "moment": "^2.29.4", @@ -31,6 +35,7 @@ "tippy.js": "^6.3.7", "vue": "^3.2.45", "vue-axios": "^3.5.2", + "vue-chartjs": "^5.2.0", "vue-router": "^4.1.6", "vue-sweetalert2": "^5.0.5", "vue-toast-notification": "^3.0.4", diff --git a/src/components/Discover/Filter/Timeframes.vue b/src/components/Discover/Filter/Timeframes.vue index 4f22471..de48c76 100644 --- a/src/components/Discover/Filter/Timeframes.vue +++ b/src/components/Discover/Filter/Timeframes.vue @@ -6,9 +6,17 @@ info

Select or fill in a time range.

- + +
+ + +
+
+
+
- + +
{{ selectArea }}
total: {{ timeFrameData.length }}
@@ -20,7 +28,6 @@
- @@ -28,7 +35,10 @@ import { storeToRefs } from 'pinia'; import AllMapDataStore from '@/stores/allMapData.js'; import getMoment from 'moment'; -import Chart from 'chart.js/auto' +import { timeRange, yTimeRange } from '@/module/timeframes.js'; +import { Chart, registerables } from 'chart.js'; +import 'chartjs-adapter-date-fns'; +import "chart.js/auto"; export default{ setup() { @@ -42,13 +52,15 @@ export default{ // timeFrameData: [], chartOptions: null, selectArea: [1, 10], - date: null + date: null, + chart: null, + canvasId: null, } }, computed: { // Set Slider Time Range,滑塊範圍: 最小值 + data(10 個) + 最大值 timeFrameData: function(){ - let data = [...this.filterTimeframe.data]; + let data = this.filterTimeframe.data.map(i=>({x:i.x,y:i.y})) // y 軸斜率計算請參考 ./public/timeFrameSlope 的圖 // x 值為 0 ~ 11, // 將三的座標(ax, ay), (bx, by), (cx, cy)命名為 (a, b), (c, d), (e, f) @@ -85,7 +97,12 @@ export default{ y: mf, }) + let xVal = timeRange(data[0].x, data[data.length-1].x, 100); + let yVal = yTimeRange(data, 100); // y 還沒做切分份數 + let timeData = xVal.map((x, index) => ({ x, y: yVal[index] })); + return data; + // return timeData; }, timeFrameTotal: function() { return this.timeFrameData.length; @@ -94,9 +111,12 @@ export default{ // !!畫面顯示的時間,資料轉換,在這邊最後一個步驟做就好!! let labels = this.timeFrameData.map(time => getMoment(time.x).format("YYYY-MM-DD")); let chartData = this.timeFrameData.map(item => { - return item.y - // x: getMoment(item.x).format("YYYY-MM-DD"), - }) + // return item.y + return { + x: getMoment(item.x).format("YYYY-MM-DD"), + y: item.y, + } + }) const start = this.selectArea[0]-1; const end = this.selectArea[1]-1; @@ -105,11 +125,12 @@ export default{ return { // 要呈現的資料 - labels, + // labels:'Data', datasets: [ { label: 'Case', // 資料的標題標籤 - data: chartData, + // data: chartData, + data: this.timeFrameData, fill: true, showLine: false, tension: 0.4, @@ -118,24 +139,111 @@ export default{ spanGaps: true, segment: { backgroundColor: ctx => inside(ctx, 'rgb(0,153,255)') || outside(ctx, 'rgb(203, 213, 225)'), + // backgroundColor: ctx => inside(ctx, 'rgb(245,40,145)') || outside(ctx, 'rgb(250, 196, 224)'), }, + x: 'x', + y: 'y', }, ] }; + }, + options: function() { + const max = this.filterTimeframe.y_axis.max * 1.1; + return { + onResize: (chart, size) => { + this.resizeMask(chart, 0.38, 0.72); + }, + responsive: true, + maintainAspectRatio: false, + layout: { + padding: { + top: 16, + left: 8, + right: 8, + } + }, + plugins: { + legend: false, // 圖例 + filler: { + propagate: false + }, + }, + animations: false, // 取消動畫 + interaction: { + intersect: false, + }, + scales: { + x: { + type: 'time', + ticks: { + color: '#0f172a', + display: true, + }, + grid: { + display: false, // 隱藏 x 軸網格 + }, + }, + y: { + beginAtZero: true, // scale 包含 0 + max: max, + ticks: { // 設定間隔數值 + display: false, // 隱藏數值,只顯示格線 + stepSize: max / 4, + }, + grid: { + color: 'rgba(100,116,139)', + z: 1, + }, + border: { + display: false, // 隱藏左側多出來的線 + } + }, + }, + } + }, + config: function() { + const data = { + datasets: [ + { + label: 'Case', + data: this.timeFrameData, + fill: 'start', + showLine: false, + tension: 0.4, + backgroundColor: 'rgba(0,153,255)', + pointRadius: 0, + x: 'x', + y: 'y', + } + ] + }; + return { + type: 'line', + data: data, + options: this.options, + }; } }, methods: { - eee(e){ - console.log(e); - }, /** * Set bar chart Options */ setChartOptions() { - // 找出 y 軸最大值,乘以 1.1 讓圖的上方多一點空間 - const max = this.filterTimeframe.y_axis.max * 1.1; + // 給取並取得 chart canvas 的 ID + // this.$nextTick(() => { + // const canvasId = this.$refs.TimeChart.$el; + // const chartCanvasId = canvasId.querySelector('canvas'); + // chartCanvasId.setAttribute('id', 'chartCanvas'); + // }); + // console.log(chartCanvasId); + // 找出 y 軸最大值,乘以 1.1 讓圖的上方多一點空間 + const max = this.filterTimeframe.y_axis.max * 1.1; - return { // 自訂屬性設定 + const config = { // 自訂屬性設定 + // onResize: (chart, size) => { + // this.resizeMask(chart, 0.38, 0.72); + // }, + // responsive: true, maintainAspectRatio: false, aspectRatio: 0.6, layout: { @@ -148,14 +256,19 @@ export default{ plugins: { legend: false, // 圖例 filler: { - propagate: false - } + propagate: false + }, }, animations: false, // 取消動畫 scales: { x: { + type: 'time', + time: { + tooltipFormat: 'DD T', + }, ticks: { color: '#0f172a', + display: true, }, grid: { display: false, // 隱藏 x 軸網格 @@ -178,13 +291,154 @@ export default{ }, }, }; + // const myChart = new Chart(chartCanvasId, config); + // this.resizeMask(myChart, 0.38, 0.72); + // myChart.destroy() + + return config + }, + resizeMask(chart, from, to) { + console.log('resizeMask'); + if (chart.chartArea === undefined) return; + this.resizeLeftMask(chart, from); + this.resizeRightMask(chart, to); + }, + resizeLeftMask(chart, from) { + console.log('resizeLeftMask'); + const canvas = document.getElementById("chartCanvasId"); + const mask = document.getElementById("chart-mask-left"); + console.log(canvas); + mask.style.left = `${canvas.offsetLeft + chart.chartArea.left}px`; + mask.style.width = `${chart.chartArea.width * from}px`; + mask.style.top = `${canvas.offsetTop + chart.chartArea.top}px`; + mask.style.height = `${chart.chartArea.height}px`; + }, + resizeRightMask(chart, to) { + console.log('resizeRightMask'); + const canvas = document.getElementById("chartCanvasId"); + const mask = document.getElementById("chart-mask-right"); + mask.style.left = `${canvas.offsetLeft + chart.chartArea.left + chart.chartArea.width * to}px`; + mask.style.width = `${chart.chartArea.width * (1 - to)}px`; + mask.style.top = `${canvas.offsetTop + chart.chartArea.top}px`; + mask.style.height = `${chart.chartArea.height}px`; + }, + createChart(start, end) { + const max = this.filterTimeframe.y_axis.max * 1.1; + + const data = { + datasets: [ + { + label: 'Case', + data: this.timeFrameData, + fill: 'start', + showLine: false, + tension: 0.4, + backgroundColor: 'rgba(0,153,255)', + pointRadius: 0, + x: 'x', + y: 'y', + } + ] + }; + const options = { + onResize: (chart, size) => { + this.resizeMask(chart, start, end); + }, + responsive: true, + maintainAspectRatio: false, + layout: { + padding: { + top: 16, + left: 8, + right: 8, + } + }, + plugins: { + legend: false, // 圖例 + filler: { + propagate: false + }, + }, + animations: false, // 取消動畫 + interaction: { + intersect: false, + }, + scales: { + x: { + type: 'time', + ticks: { + color: '#0f172a', + display: true, + }, + grid: { + display: false, // 隱藏 x 軸網格 + }, + }, + y: { + beginAtZero: true, // scale 包含 0 + max: max, + ticks: { // 設定間隔數值 + display: false, // 隱藏數值,只顯示格線 + stepSize: max / 4, + }, + grid: { + color: 'rgba(100,116,139)', + z: 1, + }, + border: { + display: false, // 隱藏左側多出來的線 + } + }, + }, + }; + const config = { + type: 'line', + data: data, + options: options, + }; + this.canvasId = document.getElementById("chartCanvasId"); + this.chart = new Chart(this.canvasId, config); + this.resizeMask(this.chart, start, end); + }, + /** + * 滑塊改變的時候 + * @param {array} e [1, 100] + */ + changeSelectArea(e) { + // const canvas = document.getElementById("chartCanvasId"); + // window.chartCanvasId.destroy(); + // const chart = new Chart(canvas, this.config); + // const chart = new Chart(this.canvasId, this.config); + + // this.resizeMask(this.chart, e[0]/10, e[1]/10); + this.chart.destroy() + this.createChart(e[0]*0.01, e[1]*0.01) }, }, mounted() { - this.chartOptions = this.setChartOptions(); - this.selectArea = [1, this.timeFrameTotal]; + Chart.register(...registerables); + this.createChart(0.38, 0.72); + // this.chartOptions = this.setChartOptions(); + // this.selectArea = [1, this.timeFrameTotal]; + this.selectArea = [38, 72] + }, } diff --git a/src/components/VueChart.vue b/src/components/VueChart.vue new file mode 100644 index 0000000..0397799 --- /dev/null +++ b/src/components/VueChart.vue @@ -0,0 +1,179 @@ + + + + + + + + + + + + +​ +
+ +
+
+
+​ + + + + \ No newline at end of file diff --git a/src/main.js b/src/main.js index bc19a15..6549274 100644 --- a/src/main.js +++ b/src/main.js @@ -40,6 +40,7 @@ import PickList from 'primevue/picklist'; import Timeline from 'primevue/timeline'; import InputSwitch from 'primevue/inputswitch'; import Chart from 'primevue/chart'; +// import 'chartjs-plugin-dragdata'; import Slider from 'primevue/slider'; import Calendar from 'primevue/calendar'; diff --git a/src/module/timeframes.js b/src/module/timeframes.js new file mode 100644 index 0000000..8b4075b --- /dev/null +++ b/src/module/timeframes.js @@ -0,0 +1,121 @@ +/** + * 將一段時間均分成多段的時間點 + * @param {string} startTime 開始時間(ex:2017-10-05) + * @param {string} endTime 結束時間(ex:2017-10-06) + * @param {number} amount 切分成多少段 + * @returns {array} 均分成多段的時間 array + */ +export function timeRange(minTime, maxTime, amount) { + // x 軸(時間軸)的範圍是最大-最小,從最小值按照 index 累加間距到最大值 + const startTime = Date.parse(minTime)/1000; // 計算開始時間的時間戳記(單位:秒) + const endTime = Date.parse(maxTime)/1000; // 計算結束時間的時間戳記(單位:秒) + const timeRange = []; // return數據初始化 + const timeGap = (endTime - startTime) / (amount - 1); // 切割後的時間間格 + + for (let i = 0; i < amount; i++) { + timeRange.push(startTime + timeGap * i); + } + + return timeRange; + // min: this.timeFrameData[0].x + // max: this.timeFrameData[this.timeFrameData.length-1].x +} +/** + * 將 y 軸的值分割成跟 x 時間軸一樣的等份,使用統計學 R 語言算出貝茲曲線攻勢 + * @param {array} data 切分成多少段 + * @param {number} yAmount 切分成多少段 + * @returns {array} 均分成多段的時間 array + */ +export function yTimeRange(data, yAmount) { + const yRange = []; + + // 貝茲曲線公式 + const threebsr = function (t, a1, a2, a3, a4) { + return ( + (1 - t) * (1 - t) * (1 - t) * a1 + + 3 * t * (1 - t)* (1 - t) * a2 + + 3 * t * t * (1 - t) * a3 + + t * t * t * a4 + ) + } + + // console.log(data); + // y min 切 5 份 + for (let i = 0; i <= 1; i += 0.25) { + yRange.push(threebsr(i, data[0].y, data[0].y, data[1].y, data[1].y)); + } + // console.log(yRange); + + // y middle 每段切 6 份,從 0.1 開始 + for (let j = 1; j < data.length - 2; j++) { + for (let i = 0.1; i <= 1; i += 0.1) { + yRange.push(threebsr(i, data[j].y, data[j].y, data[j+1].y, data[j+1].y)); + } + // console.log(yRange); + } + + // y max + for (let i = 0.2; i <= 1; i += 0.2) { + yRange.push(threebsr(i, data[data.length - 2].y, data[data.length - 2].y, data[data.length - 1].y, data[data.length - 1].y)); + } + // console.log(yRange); + + return yRange; + + // y min + // const yMinPercent = 0.05; + // const yMinGap = (data[1].y-data[0].y) / (yAmount * yMinPercent - 1) ; + // for (let i = 0; i < yAmount * yMinPercent; i++) { + // // yRange.push(data[0].y + yMaxGap * i); + // } + + // // y middle + // const yMiddlePercent = 0.11; + // for (let j = 1; j < data.length - 2; j++) { + // const yMiddleGap = (data[j + 1].y - data[j].y) / (yAmount * yMiddlePercent - 1); + // for (let i = 1; i < yAmount * yMiddlePercent; i++) { + // yRange.push(data[j].y + yMiddleGap * i); + // } + // } + + // // y max + // const yMaxPercent = 0.06; + // const yMaxGap = (data[data.length - 1].y - data[data.length - 2].y) / (yAmount * yMaxPercent - 1); + // for (let i = 1; i < yAmount * yMaxPercent; i++) { + // yRange.push(data[data.length - 2].y + yMaxGap * i); + // } + + // return yRange; + // // data: this.timeFrameData + + // 貝茲曲線公式 + // let threebsr = function (t, a1, a2, a3, a4) { + // return ( + // (1 - t) * (1 - t) * (1 - t) * a1 + + // 3 * t * (1 - t)* (1 - t) * a2 + + // 3 * t * t * (1 - t) * a3 + + // t * t * t * a4 + // ) + // }; + + // y min + // let y = [ + // threebsr(0, 448, 448, 429, 429), + // threebsr(0.1, 448, 448, 429, 429), + // threebsr(0.2, 448, 448, 429, 429), + // threebsr(0.3, 448, 448, 429, 429), + // threebsr(0.4, 448, 448, 429, 429), + // threebsr(0.5, 448, 448, 429, 429), + // threebsr(0.6, 448, 448, 429, 429), + // threebsr(0.7, 448, 448, 429, 429), + // threebsr(0.8, 448, 448, 429, 429), + // threebsr(0.9, 448, 448, 429, 429), + // threebsr(1, 448, 448, 429, 429), + // ] + // let y = [] + // for (let i = 0; i <= 1; i += 0.25) { + // y.push(threebsr(i, 448, 448, 429, 429)); + // } + // console.log(y); + +}