Map Attributes: value type Slider done.
This commit is contained in:
@@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<section class="h-full">
|
||||
<p class="h2 ml-1 mb-2">Activity Select</p>
|
||||
<!-- selectedAttName: {{ selectedAttName }} <br>
|
||||
selectedAttRange: {{ selectedAttRange }} <br>
|
||||
attRangeData: {{ attRangeData }} -->
|
||||
<!-- selectedAttName: {{ selectedAttName }} <br> -->
|
||||
<!-- selectedAttRange: {{ selectedAttRange }} <br> -->
|
||||
<!-- attRangeData: {{ attRangeData }} <br> -->
|
||||
<!-- filterAttrs: {{ filterAttrs }} <br> -->
|
||||
|
||||
<div class="flex flex-row justify-between items-start gap-4 w-full h-[calc(100%_-_48px)]">
|
||||
<!-- Attribute Name -->
|
||||
<div class="basis-1/3 bg-neutral-10 border border-neutral-300 rounded-xl px-4 pb-4 w-full h-full relative text-sm">
|
||||
<p class="h2 border-b border-500 my-2">Attribute Name ({{ attTotal }})</p>
|
||||
<p class="h2 my-2">Attribute Name ({{ attTotal }})</p>
|
||||
<div class="overflow-y-auto overflow-x-auto scrollbar -mx-2 h-[calc(100%_-_56px)]">
|
||||
<DataTable v-model:selection="selectedAttName" :value="filterAttrs" dataKey="key" breakpoint="0" :tableClass="tableClass">
|
||||
<DataTable v-model:selection="selectedAttName" :value="filterAttrs" dataKey="key" breakpoint="0" :tableClass="tableClass" @row-select="onRowSelect">
|
||||
<Column selectionMode="single" :headerClass="headerModeClass" :bodyClass="bodyModeClass"></Column>
|
||||
<Column field="key" header="Activity" :headerClass="headerClass" :bodyClass="bodyClass" sortable></Column>
|
||||
<Column field="key" header="Attribute" :headerClass="headerClass" :bodyClass="bodyClass" sortable></Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,7 +27,7 @@
|
||||
<div v-if="selectedAttName?.type === 'boolean'">
|
||||
<DataTable v-model:selection="selectedAttRange" :value="attRangeData" dataKey="id" breakpoint="0" :tableClass="tableClass" @row-select="onRowSelect">
|
||||
<Column selectionMode="single" :headerClass="headerModeClass" :bodyClass="bodyModeClass"></Column>
|
||||
<Column field="label" header="Activity" :headerClass="headerClass" :bodyClass="bodyClass"></Column>
|
||||
<Column field="label" header="Value" :headerClass="headerClass" :bodyClass="bodyClass"></Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
<!-- type: string -->
|
||||
@@ -34,7 +35,7 @@
|
||||
<DataTable v-model:selection="selectedAttRange" :value="attRangeData" dataKey="id" breakpoint="0" tableClass="w-full !border-separate !border-spacing-x-2 !table-auto text-sm" @row-select="onRowSelect">
|
||||
<ColumnGroup type="header">
|
||||
<Row>
|
||||
<Column selectionMode="multiple" :headerClass="headerModeClass"></Column>
|
||||
<Column selectionMode="multiple" :headerClass="headerModeClass" ></Column>
|
||||
<Column field="value" header="Value" :headerClass="headerClass" sortable />
|
||||
<Column field="freq" header="Occurrences" :headerClass="headerClass" sortable :colspan="3" />
|
||||
</Row>
|
||||
@@ -52,8 +53,29 @@
|
||||
<Column field="occ_ratio" header="Occurrence Ratio" bodyClass="!text-right !py-2 !border-0"></Column>
|
||||
</DataTable>
|
||||
</div>
|
||||
<!-- type: value -->
|
||||
<div v-else>
|
||||
other
|
||||
<div class="h-3/5 relative">
|
||||
<!-- <canvas id="chartCanvasId"></canvas> -->
|
||||
<Chart type="line" :data="chartData" :options="chartOptions" class="h-30rem" id="chartCanvasId"/>
|
||||
<div id="chart-mask-left" class="absolute bg-neutral-10/50"></div>
|
||||
<div id="chart-mask-right" class="absolute bg-neutral-10/50"></div>
|
||||
</div>
|
||||
<div class="px-2 py-3">
|
||||
<Slider v-model="selectArea" :step="1" :min="0" :max="selectRange" range class="mx-2" @change="changeSelectArea($event)"/>
|
||||
</div>
|
||||
<!-- Calendar group -->
|
||||
<!-- <div class="flex justify-center items-center space-x-2 w-full">
|
||||
<div>
|
||||
<span class="block mb-2">Start time</span>
|
||||
<Calendar v-model="startTime" dateFormat="yy/mm/dd" :panelProps="panelProps" :minDate="startMinDate" :maxDate="startMaxDate" showTime showIcon hourFormat="24" @date-select="sliderTimeRange($event, 'start')" id="startCalendar"/>
|
||||
</div>
|
||||
<span class="block mt-4">~</span>
|
||||
<div>
|
||||
<span class="block mb-2">End time</span>
|
||||
<Calendar v-model="endTime" dateFormat="yy/mm/dd" :panelProps="panelProps" :minDate="endMinDate" :maxDate="endMaxDate" showTime showIcon hourFormat="24" @date-select="sliderTimeRange($event, 'end')" id="endCalendar"/>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,6 +85,10 @@
|
||||
<script>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import AllMapDataStore from '@/stores/allMapData.js';
|
||||
import { Chart, registerables } from 'chart.js';
|
||||
import 'chartjs-adapter-date-fns';
|
||||
import { setLineChartData, setBarChartData, timeRange, yTimeRange, getXIndex, formatTime } from '@/module/setChartData.js';
|
||||
import getMoment from 'moment';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
@@ -75,13 +101,24 @@ export default {
|
||||
return {
|
||||
selectedAttName: null,
|
||||
selectedAttRange: null,
|
||||
valueTypes: ['int', 'float', 'date'],
|
||||
classTypes: ['boolean', 'string'],
|
||||
chartData: null,
|
||||
chartOptions: null,
|
||||
chartComplete: null, // 已出圖的 chart.js 資料
|
||||
selectArea: null,
|
||||
selectRange: 1000, // 更改 select 的切分數
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
startMinDate: null,
|
||||
startMaxDate: null,
|
||||
endMinDate: null,
|
||||
endMaxDate: null,
|
||||
tableClass: 'w-full h-full !border-separate !border-spacing-x-2 !table-auto text-sm',
|
||||
headerModeClass: 'w-8 !p-2 !bg-neutral-10 !border-neutral-500 sticky top-0 left-0 z-10 bg-neutral-10',
|
||||
headerClass: '!bg-neutral-10 !border-neutral-500 !py-2 sticky top-0 left-0 z-10 bg-neutral-10',
|
||||
bodyModeClass: '!p-2 !border-0',
|
||||
bodyClass: 'break-words !py-2 !border-0',
|
||||
valueTypes: ['int', 'float', 'date'],
|
||||
classTypes: ['boolean', 'string'],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -139,19 +176,34 @@ export default {
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
// if(valueTypes.includes(type)){
|
||||
// data = {
|
||||
|
||||
// }
|
||||
// }else if(classTypes.includes(type)){
|
||||
|
||||
// }
|
||||
},
|
||||
// 取出選取的 Attribute radio 數值型的資料
|
||||
valueData: function() {
|
||||
// filter 回傳陣列,find 回傳遞一個找到的元素,因此使用 find 方法。
|
||||
if(this.valueTypes.includes(this.selectedAttName?.type)){
|
||||
const valueData = this.filterAttrs.find(item => item.type === this.selectedAttName?.type && item.key === this.selectedAttName?.key);
|
||||
return valueData
|
||||
}
|
||||
},
|
||||
// 找出 slidrData,時間格式:毫秒時間戳
|
||||
sliderData: function() {
|
||||
let xAxisMin = new Date(this.valueData.chart.x_axis.min).getTime();
|
||||
let xAxisMax = new Date(this.valueData.chart.x_axis.max).getTime();
|
||||
let range = xAxisMax - xAxisMin;
|
||||
let step = range / this.selectRange;
|
||||
let sliderData = []
|
||||
|
||||
for (let i = 0; i <= this.selectRange; i++) {
|
||||
sliderData.push(xAxisMin + (step * i));
|
||||
}
|
||||
|
||||
return sliderData;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onRowSelect(e) {
|
||||
// this.$emit('on-row-select', e)
|
||||
if(this.valueData) this.createChart();
|
||||
// this.$emit('on-row-select', e.data)
|
||||
},
|
||||
/**
|
||||
* set progress bar width
|
||||
@@ -170,6 +222,149 @@ export default {
|
||||
if((val * 100).toFixed(1) >= 100) return `100%`;
|
||||
else return `${(val * 100).toFixed(1)}%`;
|
||||
},
|
||||
/**
|
||||
* 調整遮罩大小
|
||||
* @param {object} chart 取得 chart.js 資料
|
||||
*/
|
||||
resizeMask(chart) {
|
||||
let from = (this.selectArea[0] * 0.01) / (this.selectRange * 0.01);
|
||||
let to = (this.selectArea[1] * 0.01) / (this.selectRange * 0.01);
|
||||
this.resizeLeftMask(chart, from);
|
||||
this.resizeRightMask(chart, to);
|
||||
},
|
||||
/**
|
||||
* 調整左邊遮罩大小
|
||||
* @param {object} chart 取得 chart.js 資料
|
||||
* @param {number} chart 取得 chart.js 資料
|
||||
*/
|
||||
resizeLeftMask(chart, from) {
|
||||
const canvas = document.querySelector('#chartCanvasId canvas');
|
||||
const mask = document.getElementById("chart-mask-left");
|
||||
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`;
|
||||
},
|
||||
/**
|
||||
* 調整又邊遮罩大小
|
||||
* @param {object} chart 取得 chart.js 資料
|
||||
*/
|
||||
resizeRightMask(chart, to) {
|
||||
const canvas = document.querySelector('#chartCanvasId canvas');
|
||||
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`;
|
||||
},
|
||||
/**
|
||||
* create chart
|
||||
* @param {object} valueData 選取的 Attribute,包含後端原始數據的 type、key
|
||||
*/
|
||||
createChart() {
|
||||
const valueData = this.valueData;
|
||||
const max = valueData.chart.y_axis.max * 1.1;
|
||||
const data = setLineChartData(valueData.chart.data, valueData.chart.x_axis.max, valueData.chart.x_axis.min);
|
||||
|
||||
this.chartData = {
|
||||
datasets: [
|
||||
{
|
||||
label: 'Case',
|
||||
data: data,
|
||||
fill: 'start',
|
||||
showLine: false,
|
||||
tension: 0.4,
|
||||
backgroundColor: 'rgba(0,153,255)',
|
||||
pointRadius: 0,
|
||||
x: 'x',
|
||||
y: 'y',
|
||||
}
|
||||
]
|
||||
};
|
||||
this.chartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 16,
|
||||
left: 8,
|
||||
right: 8,
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: false, // 圖例
|
||||
filler: {
|
||||
propagate: false
|
||||
},
|
||||
title: false
|
||||
},
|
||||
// animations: false, // 取消動畫
|
||||
animation: {
|
||||
onComplete: e => {
|
||||
this.chartComplete = e.chart;
|
||||
this.resizeMask(e.chart);
|
||||
}
|
||||
},
|
||||
interaction: {
|
||||
intersect: true,
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
type: 'time',
|
||||
ticks: {
|
||||
autoSkip: false,
|
||||
maxRotation: 0, // 不旋轉 lable 0~50
|
||||
color: '#334155',
|
||||
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, // 隱藏左側多出來的線
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
},
|
||||
/**
|
||||
* 滑塊改變的時候
|
||||
* @param {array} e [1, 100]
|
||||
*/
|
||||
changeSelectArea(e) {
|
||||
// 日曆改變時,滑塊跟著改變
|
||||
let sliderData = this.sliderData;
|
||||
let start = sliderData[e[0].toFixed()];
|
||||
let end = sliderData[e[1].toFixed()]; // 取得 index,須為整數。
|
||||
|
||||
this.startTime = new Date(start);
|
||||
this.endTime = new Date(end);
|
||||
// 重新設定 start end 日曆選取範圍
|
||||
this.endMinDate = new Date(start);
|
||||
this.startMaxDate = new Date(end);
|
||||
// 重新算圖
|
||||
this.resizeMask(this.chartComplete);
|
||||
// 執行 timeFrameStartEnd 才會改變數據
|
||||
// this.timeFrameStartEnd;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// this.setChartData();
|
||||
this.selectArea = [0, this.selectRange]; // 初始化滑塊
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -315,5 +315,3 @@ export default{
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
|
||||
@@ -5,6 +5,7 @@ import getMoment from 'moment';
|
||||
* @param {array} baseData 後端給的 10 個時間點
|
||||
* @param {number} xMax 2022-05-23T18:00:00
|
||||
* @param {number} xMin 2022-05-23T08:00:00
|
||||
* @param {number} isPercent 是否以百分比顯示
|
||||
* @param {number} yMax case
|
||||
* @param {number} yMin case
|
||||
* @returns {array} 可直接套入 chart.js 的 data
|
||||
|
||||
Reference in New Issue
Block a user