Discover: SidebarFilter Timeframes Apply and create Map done.

This commit is contained in:
chiayin
2023-06-06 14:39:25 +08:00
parent 90a5b7532a
commit 9a403cce71
5 changed files with 147 additions and 47 deletions

View File

@@ -26,7 +26,6 @@
</div> </div>
</template> </template>
</Timeline> </Timeline>
this.postRuleData:{{this.postRuleData}}
</div> </div>
</div> </div>
<!-- Button --> <!-- Button -->

View File

@@ -6,25 +6,27 @@
<span class="material-symbols-outlined mr-2 text-base">info</span> <span class="material-symbols-outlined mr-2 text-base">info</span>
<p>Select or fill in a time range.</p> <p>Select or fill in a time range.</p>
</div> </div>
<div class="chartContainer"> <div class="chartContainer h-3/5 relative">
<canvas id="chartCanvasId"></canvas> <canvas id="chartCanvasId"></canvas>
<div id="chart-mask-left"></div> <div id="chart-mask-left" class="absolute bg-neutral-10/50"></div>
<div id="chart-mask-right"></div> <div id="chart-mask-right" class="absolute bg-neutral-10/50"></div>
</div> </div>
<div class="px-2 py-3">
<div class="px-2">
<!-- <Slider v-model="selectArea" :step="1" :min="1" :max="timeFrameTotal" range class="mx-2"/> -->
<Slider v-model="selectArea" :step="1" :min="0" :max="selectRange" range class="mx-2" @change="changeSelectArea($event)"/> <Slider v-model="selectArea" :step="1" :min="0" :max="selectRange" range class="mx-2" @change="changeSelectArea($event)"/>
<br/>
{{ selectArea }}<br/>
</div> </div>
<div> <!-- Calendar group -->
<div @click.stop.prevent=""> <div class="flex justify-center items-center space-x-2 w-full">
<span class="block">Start date</span> <div>
<Calendar v-model="date" dateFormat="dd/mm/yy" /> <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')"/>
</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')"/>
</div> </div>
<!-- <Calendar v-model="date" @date-select.stop="eee($event)" /> -->
</div> </div>
<!-- End calendar group -->
</section> </section>
</div> </div>
</template> </template>
@@ -33,24 +35,58 @@ import { storeToRefs } from 'pinia';
import AllMapDataStore from '@/stores/allMapData.js'; import AllMapDataStore from '@/stores/allMapData.js';
import { Chart, registerables } from 'chart.js'; import { Chart, registerables } from 'chart.js';
import 'chartjs-adapter-date-fns'; import 'chartjs-adapter-date-fns';
import getMoment from 'moment';
export default{ export default{
setup() { setup() {
const allMapDataStore = AllMapDataStore(); const allMapDataStore = AllMapDataStore();
const { filterTimeframe } = storeToRefs(allMapDataStore); const { filterTimeframe, selectTimeFrame } = storeToRefs(allMapDataStore);
return {allMapDataStore, filterTimeframe} return {allMapDataStore, filterTimeframe, selectTimeFrame }
}, },
data() { data() {
return { return {
selectRange: 300, // 更改 select 的切分數 selectRange: 1000, // 更改 select 的切分數
selectArea: [1,10], selectArea: null,
date: null,
chart: null, chart: null,
canvasId: null, canvasId: null,
startTime: null,
endTime: null,
startMinDate: null,
startMaxDate: null,
endMinDate: null,
endMaxDate: null,
panelProps: {
onClick: (event) => {
event.stopPropagation();
},
},
datetime24h:null,
} }
}, },
computed: { computed: {
// user select time start and end
timeFrameStartEnd: function() {
let start = getMoment(this.startTime).format('YYYY-MM-DDTHH:mm:ss');
let end = getMoment(this.endTime).format('YYYY-MM-DDTHH:mm:ss');
this.selectTimeFrame = [start ,end]; // 傳給後端的資料
return [start ,end];
},
// 找出 slidrData時間格式:毫秒時間戳
sliderData: function() {
let xAxisMin = new Date(this.filterTimeframe.x_axis.min).getTime();
let xAxisMax = new Date(this.filterTimeframe.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;
},
// 加入最大、最小值 // 加入最大、最小值
timeFrameData: function(){ timeFrameData: function(){
let data = this.filterTimeframe.data.map(i=>({x:i.x,y:i.y})) let data = this.filterTimeframe.data.map(i=>({x:i.x,y:i.y}))
@@ -164,7 +200,9 @@ export default{
x: { x: {
type: 'time', type: 'time',
ticks: { ticks: {
color: '#0f172a', autoSkip: false,
maxRotation: 0, // 不旋轉 lable 0~50
color: '#334155',
display: true, display: true,
}, },
grid: { grid: {
@@ -201,30 +239,67 @@ export default{
* @param {array} e [1, 100] * @param {array} e [1, 100]
*/ */
changeSelectArea(e) { changeSelectArea(e) {
this.resizeMask(this.chart) // 日曆改變時,滑塊跟著改變
let sliderData = this.sliderData;
this.startTime = new Date(sliderData[e[0]]);
this.endTime = new Date(sliderData[e[1]]);
// 重新設定 start end 日曆選取範圍
this.endMinDate = new Date(sliderData[e[0]]);
this.startMaxDate = new Date(sliderData[e[1]]);
// 重新算圖
this.resizeMask(this.chart);
// 執行 timeFrameStartEnd 才會改變數據
this.timeFrameStartEnd;
},
/**
* 選取開始或結束時間時,要改變滑塊根圖表
* @param {object} e Tue Jan 25 2022 00:00:00 GMT+0800 (台北標準時間)
* @param {string} direction start or end
*/
sliderTimeRange(e, direction) {
// 找到最鄰近的 index時間格式: 毫秒時間戳
let sliderData = this.sliderData;
const targetTime = [new Date(this.timeFrameStartEnd[0]).getTime(), new Date(this.timeFrameStartEnd[1]).getTime()];
const closestIndexes = targetTime.map(target => {
let closestIndex = 0;
closestIndex = ((target - sliderData[0])/(sliderData[sliderData.length-1]-sliderData[0])) * sliderData.length;
return Math.round(Math.abs(closestIndex));
});
// 改變滑塊
this.selectArea = closestIndexes;
// 重新設定 start end 日曆選取範圍
if(direction === 'start') this.endMinDate = e;
else if(direction === 'end') this.startMaxDate = e;
// 重新算圖
if(!isNaN(closestIndexes[0]) && !isNaN(closestIndexes[1])) this.resizeMask(this.chart);
else return;
}, },
}, },
mounted() { mounted() {
// Chart.js
Chart.register(...registerables); Chart.register(...registerables);
this.createChart(); this.createChart();
this.selectArea = [0, this.selectRange] // Slider
this.selectArea = [0, this.selectRange];
// Calendar
this.startMinDate = new Date(getMoment(this.filterTimeframe.x_axis.min).startOf('day').local().format());
this.startMaxDate = new Date(getMoment(this.filterTimeframe.x_axis.max).startOf('day').local().format());
this.endMinDate = new Date(getMoment(this.filterTimeframe.x_axis.min).startOf('day').local().format());
this.endMaxDate = new Date(getMoment(this.filterTimeframe.x_axis.max).startOf('day').local().format());
// 讓日曆的範圍等於時間軸的範圍
this.startTime = this.startMinDate;
this.endTime = this.startMaxDate;
this.timeFrameStartEnd;
}, },
beforeUnmount() {
this.selectArea = [0, this.selectRange];
this.resizeMask(this.chart);
this.startTime = new Date(getMoment(this.filterTimeframe.x_axis.min).startOf('day').local().format());
this.endTime = new Date(getMoment(this.filterTimeframe.x_axis.max).startOf('day').local().format());
this.timeFrameStartEnd;
}
} }
</script> </script>
<style> <style>
.chart-container {
position: relative;
margin: 2rem 4rem;
padding: 20px 40px;
border: 1px solid black;
width: 60%;
height: 60%;
}
#chartCanvas {
border: 1px solid red !important;
}
#chart-mask-left, #chart-mask-right {
position: absolute;
background-color: rgb(255, 255, 255, 0.5);
}
</style> </style>

View File

@@ -112,6 +112,7 @@ import ActAndSeq from '@/components/Discover/Filter/ActAndSeq.vue';
import Funnel from '@/components/Discover/Filter/Funnel.vue'; import Funnel from '@/components/Discover/Filter/Funnel.vue';
import Trace from '@/components/Discover/Filter/Trace.vue'; import Trace from '@/components/Discover/Filter/Trace.vue';
import Timeframes from '@/components/Discover/Filter/Timeframes.vue'; import Timeframes from '@/components/Discover/Filter/Timeframes.vue';
import getMoment from 'moment';
export default { export default {
props: ['sidebarFilter', 'filterTasks', 'filterStartToEnd', 'filterEndToStart', 'filterTimeframe', 'filterTrace'], props: ['sidebarFilter', 'filterTasks', 'filterStartToEnd', 'filterEndToStart', 'filterTimeframe', 'filterTrace'],
@@ -119,9 +120,9 @@ export default {
const loadingStore = LoadingStore(); const loadingStore = LoadingStore();
const allMapDataStore = AllMapDataStore(); const allMapDataStore = AllMapDataStore();
const { isLoading } = storeToRefs(loadingStore); const { isLoading } = storeToRefs(loadingStore);
const { hasResultRule, temporaryData, postRuleData, ruleData, isRuleData} = storeToRefs(allMapDataStore); const { hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, selectTimeFrame } = storeToRefs(allMapDataStore);
return { isLoading, hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, allMapDataStore } return { isLoading, hasResultRule, temporaryData, postRuleData, ruleData, isRuleData, allMapDataStore, selectTimeFrame }
}, },
data() { data() {
return { return {
@@ -186,7 +187,7 @@ export default {
}, },
filterEndToStartData: function() { filterEndToStartData: function() {
return this.isStartSelected ? this.setStartAndEndData(this.filterStartToEnd, this.rowData, 'sinks') : this.setActData(this.filterEndToStart); return this.isStartSelected ? this.setStartAndEndData(this.filterStartToEnd, this.rowData, 'sinks') : this.setActData(this.filterEndToStart);
} },
}, },
methods: { methods: {
/** /**
@@ -317,6 +318,12 @@ export default {
setRule(e) { setRule(e) {
let label, type; let label, type;
const includeStr = e.is_exclude?" Exclude ":" Include "; const includeStr = e.is_exclude?" Exclude ":" Include ";
let containmentMap = {
'occurred-in' : 'Contained in',
'started-in' : 'Started in',
'completed-in' : 'Ended in',
'occurred-around' : 'Active in'
};
switch(e.type){ switch(e.type){
case "contains-task": case "contains-task":
@@ -347,7 +354,7 @@ export default {
case "started-in": case "started-in":
case "completed-in": case "completed-in":
case "occurred-around": case "occurred-around":
label = `${e.type} from ${moment(e.start).format("YYYY-MM-DD HH:mm:ss")} to ${moment(e.end).format("YYYY-MM-DD HH:mm:ss")} ${includeStr}` label = `${containmentMap[e.type]} from ${getMoment(e.start).format("YYYY-MM-DD HH:mm:ss")} to ${getMoment(e.end).format("YYYY-MM-DD HH:mm:ss")} ${includeStr}`
type = "Timeframe" type = "Timeframe"
break break
case "trace-freq": case "trace-freq":
@@ -358,13 +365,14 @@ export default {
return { return {
type, type,
label, label,
toggle:true, toggle: true,
}; };
}, },
/** /**
* @param {boolean} massage true | false 清空選項 * @param {boolean} massage true | false 清空選項
*/ */
reset(massage) { reset(massage) {
// Sequence
this.selectFilterTask = null; this.selectFilterTask = null;
this.selectFilterStart = null; this.selectFilterStart = null;
this.selectFilterEnd = null; this.selectFilterEnd = null;
@@ -374,9 +382,13 @@ export default {
this.isStartSelected = null; this.isStartSelected = null;
this.isEndSelected = null; this.isEndSelected = null;
this.isActAllTask = true; this.isActAllTask = true;
// Timeframes
this.timeFrameStartEnd = null;
// Trace // Trace
this.$refs.filterTraceView.showTraceId = null; if (this.$refs.filterTraceView) {
this.$refs.filterTraceView.selectArea = [0, this.$refs.filterTraceView.traceTotal]; this.$refs.filterTraceView.showTraceId = null;
this.$refs.filterTraceView.selectArea = [0, this.$refs.filterTraceView.traceTotal];
};
// 成功訊息 // 成功訊息
massage ? this.$toast.success('Reset Success.') : null; massage ? this.$toast.success('Reset Success.') : null;
}, },
@@ -384,7 +396,13 @@ export default {
async submit(){ async submit(){
let data; let data;
let sele = this.selectValue; let sele = this.selectValue;
let isExclude = sele[5] === 'Exclude' ? true : false let isExclude = sele[5] === 'Exclude' ? true : false;
let containmentMap = {
'Contained in': 'occurred-in',
'Started in': 'started-in',
'Ended in': 'completed-in',
'Active in': 'occurred-around'
};
// Filter Type 選 Sequence 的行為 // Filter Type 選 Sequence 的行為
// 若陣列為空,則跳出警告訊息 // 若陣列為空,則跳出警告訊息
@@ -441,6 +459,13 @@ export default {
} }
}; };
} }
} else if(sele[0] === 'Timeframes'){ // Filter Type 選 Timeframes 的行為
data = {
type: containmentMap[sele[6]],
start: this.selectTimeFrame[0],
end: this.selectTimeFrame[1],
is_exclude: isExclude,
}
} else if(sele[0] === 'Trace'){ // Filter Type 選 Trace 的行為 } else if(sele[0] === 'Trace'){ // Filter Type 選 Trace 的行為
data = { data = {
type: 'trace-freq', type: 'trace-freq',
@@ -451,6 +476,7 @@ export default {
} }
// 將資料指向 Vue data 雙向綁定 // 將資料指向 Vue data 雙向綁定
const postData = Array.isArray(data) ? data : [data]; const postData = Array.isArray(data) ? data : [data];
console.log(postData);
// 快速檢查每一 filter 規則是否為空集合 // 快速檢查每一 filter 規則是否為空集合
this.postRuleData = postData; this.postRuleData = postData;

View File

@@ -40,7 +40,6 @@ import PickList from 'primevue/picklist';
import Timeline from 'primevue/timeline'; import Timeline from 'primevue/timeline';
import InputSwitch from 'primevue/inputswitch'; import InputSwitch from 'primevue/inputswitch';
import Chart from 'primevue/chart'; import Chart from 'primevue/chart';
// import 'chartjs-plugin-dragdata';
import Slider from 'primevue/slider'; import Slider from 'primevue/slider';
import Calendar from 'primevue/calendar'; import Calendar from 'primevue/calendar';

View File

@@ -37,6 +37,7 @@ export default defineStore('allMapDataStore', {
isRuleData: [], // toggle button data isRuleData: [], // toggle button data
allFunnelData: [], allFunnelData: [],
isUpdataFilter: false, // 是否成功儲存 Filter 檔 isUpdataFilter: false, // 是否成功儲存 Filter 檔
selectTimeFrame: [], // user select time start and end
}), }),
getters: { getters: {
processMap: state => { processMap: state => {
@@ -304,6 +305,6 @@ export default defineStore('allMapDataStore', {
await delay(500); await delay(500);
$toast.default('Failed to updata an Existing Filter.',{position: 'bottom'}); $toast.default('Failed to updata an Existing Filter.',{position: 'bottom'});
} }
} },
}, },
}) })