Discover: SidebarFilter Timeframes Apply and create Map done.
This commit is contained in:
@@ -26,7 +26,6 @@
|
||||
</div>
|
||||
</template>
|
||||
</Timeline>
|
||||
this.postRuleData:{{this.postRuleData}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- Button -->
|
||||
|
||||
@@ -6,25 +6,27 @@
|
||||
<span class="material-symbols-outlined mr-2 text-base">info</span>
|
||||
<p>Select or fill in a time range.</p>
|
||||
</div>
|
||||
<div class="chartContainer">
|
||||
<div class="chartContainer h-3/5 relative">
|
||||
<canvas id="chartCanvasId"></canvas>
|
||||
<div id="chart-mask-left"></div>
|
||||
<div id="chart-mask-right"></div>
|
||||
<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">
|
||||
<!-- <Slider v-model="selectArea" :step="1" :min="1" :max="timeFrameTotal" range class="mx-2"/> -->
|
||||
<div class="px-2 py-3">
|
||||
<Slider v-model="selectArea" :step="1" :min="0" :max="selectRange" range class="mx-2" @change="changeSelectArea($event)"/>
|
||||
<br/>
|
||||
{{ selectArea }}<br/>
|
||||
</div>
|
||||
<div>
|
||||
<div @click.stop.prevent="">
|
||||
<span class="block">Start date</span>
|
||||
<Calendar v-model="date" dateFormat="dd/mm/yy" />
|
||||
<!-- 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')"/>
|
||||
</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>
|
||||
<!-- <Calendar v-model="date" @date-select.stop="eee($event)" /> -->
|
||||
</div>
|
||||
<!-- End calendar group -->
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
@@ -33,24 +35,58 @@ import { storeToRefs } from 'pinia';
|
||||
import AllMapDataStore from '@/stores/allMapData.js';
|
||||
import { Chart, registerables } from 'chart.js';
|
||||
import 'chartjs-adapter-date-fns';
|
||||
import getMoment from 'moment';
|
||||
|
||||
export default{
|
||||
setup() {
|
||||
const allMapDataStore = AllMapDataStore();
|
||||
const { filterTimeframe } = storeToRefs(allMapDataStore);
|
||||
const { filterTimeframe, selectTimeFrame } = storeToRefs(allMapDataStore);
|
||||
|
||||
return {allMapDataStore, filterTimeframe}
|
||||
return {allMapDataStore, filterTimeframe, selectTimeFrame }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectRange: 300, // 更改 select 的切分數
|
||||
selectArea: [1,10],
|
||||
date: null,
|
||||
selectRange: 1000, // 更改 select 的切分數
|
||||
selectArea: null,
|
||||
chart: null,
|
||||
canvasId: null,
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
startMinDate: null,
|
||||
startMaxDate: null,
|
||||
endMinDate: null,
|
||||
endMaxDate: null,
|
||||
panelProps: {
|
||||
onClick: (event) => {
|
||||
event.stopPropagation();
|
||||
},
|
||||
},
|
||||
datetime24h:null,
|
||||
}
|
||||
},
|
||||
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(){
|
||||
let data = this.filterTimeframe.data.map(i=>({x:i.x,y:i.y}))
|
||||
@@ -164,7 +200,9 @@ export default{
|
||||
x: {
|
||||
type: 'time',
|
||||
ticks: {
|
||||
color: '#0f172a',
|
||||
autoSkip: false,
|
||||
maxRotation: 0, // 不旋轉 lable 0~50
|
||||
color: '#334155',
|
||||
display: true,
|
||||
},
|
||||
grid: {
|
||||
@@ -201,30 +239,67 @@ export default{
|
||||
* @param {array} e [1, 100]
|
||||
*/
|
||||
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() {
|
||||
// Chart.js
|
||||
Chart.register(...registerables);
|
||||
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>
|
||||
<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>
|
||||
|
||||
@@ -112,6 +112,7 @@ import ActAndSeq from '@/components/Discover/Filter/ActAndSeq.vue';
|
||||
import Funnel from '@/components/Discover/Filter/Funnel.vue';
|
||||
import Trace from '@/components/Discover/Filter/Trace.vue';
|
||||
import Timeframes from '@/components/Discover/Filter/Timeframes.vue';
|
||||
import getMoment from 'moment';
|
||||
|
||||
export default {
|
||||
props: ['sidebarFilter', 'filterTasks', 'filterStartToEnd', 'filterEndToStart', 'filterTimeframe', 'filterTrace'],
|
||||
@@ -119,9 +120,9 @@ export default {
|
||||
const loadingStore = LoadingStore();
|
||||
const allMapDataStore = AllMapDataStore();
|
||||
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() {
|
||||
return {
|
||||
@@ -186,7 +187,7 @@ export default {
|
||||
},
|
||||
filterEndToStartData: function() {
|
||||
return this.isStartSelected ? this.setStartAndEndData(this.filterStartToEnd, this.rowData, 'sinks') : this.setActData(this.filterEndToStart);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
@@ -317,6 +318,12 @@ export default {
|
||||
setRule(e) {
|
||||
let label, type;
|
||||
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){
|
||||
case "contains-task":
|
||||
@@ -347,7 +354,7 @@ export default {
|
||||
case "started-in":
|
||||
case "completed-in":
|
||||
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"
|
||||
break
|
||||
case "trace-freq":
|
||||
@@ -358,13 +365,14 @@ export default {
|
||||
return {
|
||||
type,
|
||||
label,
|
||||
toggle:true,
|
||||
toggle: true,
|
||||
};
|
||||
},
|
||||
/**
|
||||
* @param {boolean} massage true | false 清空選項
|
||||
*/
|
||||
reset(massage) {
|
||||
// Sequence
|
||||
this.selectFilterTask = null;
|
||||
this.selectFilterStart = null;
|
||||
this.selectFilterEnd = null;
|
||||
@@ -374,9 +382,13 @@ export default {
|
||||
this.isStartSelected = null;
|
||||
this.isEndSelected = null;
|
||||
this.isActAllTask = true;
|
||||
// Timeframes
|
||||
this.timeFrameStartEnd = null;
|
||||
// Trace
|
||||
this.$refs.filterTraceView.showTraceId = null;
|
||||
this.$refs.filterTraceView.selectArea = [0, this.$refs.filterTraceView.traceTotal];
|
||||
if (this.$refs.filterTraceView) {
|
||||
this.$refs.filterTraceView.showTraceId = null;
|
||||
this.$refs.filterTraceView.selectArea = [0, this.$refs.filterTraceView.traceTotal];
|
||||
};
|
||||
// 成功訊息
|
||||
massage ? this.$toast.success('Reset Success.') : null;
|
||||
},
|
||||
@@ -384,7 +396,13 @@ export default {
|
||||
async submit(){
|
||||
let data;
|
||||
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 的行為
|
||||
// 若陣列為空,則跳出警告訊息
|
||||
@@ -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 的行為
|
||||
data = {
|
||||
type: 'trace-freq',
|
||||
@@ -451,6 +476,7 @@ export default {
|
||||
}
|
||||
// 將資料指向 Vue data 雙向綁定
|
||||
const postData = Array.isArray(data) ? data : [data];
|
||||
console.log(postData);
|
||||
|
||||
// 快速檢查每一 filter 規則是否為空集合
|
||||
this.postRuleData = postData;
|
||||
|
||||
@@ -40,7 +40,6 @@ 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';
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ export default defineStore('allMapDataStore', {
|
||||
isRuleData: [], // toggle button data
|
||||
allFunnelData: [],
|
||||
isUpdataFilter: false, // 是否成功儲存 Filter 檔
|
||||
selectTimeFrame: [], // user select time start and end
|
||||
}),
|
||||
getters: {
|
||||
processMap: state => {
|
||||
@@ -304,6 +305,6 @@ export default defineStore('allMapDataStore', {
|
||||
await delay(500);
|
||||
$toast.default('Failed to updata an Existing Filter.',{position: 'bottom'});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user