feat: 턴 선택기에서 '드래그' 선택 지원

This commit is contained in:
2021-12-26 23:22:43 +09:00
parent f22a013079
commit 590dfe90c3
2 changed files with 155 additions and 49 deletions
+115 -23
View File
@@ -50,17 +50,29 @@
</div> </div>
<div class="commandTable"> <div class="commandTable">
<template <DragSelect
v-for="(turnObj, turnIdx) in reservedCommandList.slice( :style="rowGridStyle"
0, attribute="turnIdx"
Math.min(maxTurn, viewMaxTurn) @dragStart="isDragToggle = true"
)" @dragDone="
:key="turnIdx" isDragToggle = false;
toggleTurn(...$event);
"
v-slot="{ selected }"
> >
<div class="idx_pad center d-grid" @click="toggleTurn(turnIdx)"> <div
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
0,
viewMaxTurn
)"
:turnIdx="turnIdx"
:key="turnIdx"
class="idx_pad center d-grid"
>
<b-button <b-button
size="sm" size="sm"
:variant=" :variant="
(isDragToggle && selected.has(`${turnIdx}`))?'light':
turnList.has(turnIdx) turnList.has(turnIdx)
? 'info' ? 'info'
: turnList.size == 0 && prevTurnList.has(turnIdx) : turnList.size == 0 && prevTurnList.has(turnIdx)
@@ -70,10 +82,26 @@
>{{ turnIdx + 1 }}</b-button >{{ turnIdx + 1 }}</b-button
> >
</div> </div>
</DragSelect>
<DragSelect
:style="rowGridStyle"
attribute="turnIdx"
@dragStart="isDragSingle = true"
@dragDone="
isDragSingle = false;
selectTurn(...$event);
"
v-slot="{ selected }"
>
<div <div
@click="selectTurn(turnIdx)" v-for="(turnObj, turnIdx) in reservedCommandList.slice(
0,
viewMaxTurn
)"
:key="turnIdx"
height="24" height="24"
class="month_pad center" class="month_pad center"
:turnIdx="turnIdx"
:style="{ :style="{
'white-space': 'nowrap', 'white-space': 'nowrap',
'font-size': `${Math.min( 'font-size': `${Math.min(
@@ -81,18 +109,40 @@
(75 / (`${turnObj.year ?? 1}`.length + 8)) * 1.8 (75 / (`${turnObj.year ?? 1}`.length + 8)) * 1.8
)}px`, )}px`,
overflow: 'hidden', overflow: 'hidden',
color:
isDragSingle && selected.has(`${turnIdx}`) ? 'cyan' : undefined,
}" }"
> >
{{ turnObj.year ? `${turnObj.year}年` : "" }} {{ turnObj.year ? `${turnObj.year}年` : "" }}
{{ turnObj.month ? `${turnObj.month}月` : "" }} {{ turnObj.month ? `${turnObj.month}月` : "" }}
</div> </div>
</DragSelect>
<div :style="rowGridStyle">
<div <div
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
0,
viewMaxTurn
)"
:key="turnIdx"
class="time_pad center" class="time_pad center"
style="background-color: black; white-space: nowrap; overflow: hidden" :style="{
backgroundColor: 'black',
whiteSpace: 'nowrap',
overflow: 'hidden',
}"
> >
{{ turnObj.time }} {{ turnObj.time }}
</div> </div>
<div class="turn_pad center"> </div>
<div :style="rowGridStyle">
<div
v-for="(turnObj, turnIdx) in reservedCommandList.slice(
0,
viewMaxTurn
)"
:key="turnIdx"
class="turn_pad center"
>
<span <span
class="turn_text" class="turn_text"
:style="turnObj.style" :style="turnObj.style"
@@ -101,7 +151,7 @@
v-html="turnObj.brief" v-html="turnObj.brief"
></span> ></span>
</div> </div>
</template> </div>
</div> </div>
<div class="row gx-1"> <div class="row gx-1">
<div class="col d-grid"> <div class="col d-grid">
@@ -200,9 +250,9 @@
<script lang="ts"> <script lang="ts">
import addMilliseconds from "date-fns/esm/addMilliseconds"; import addMilliseconds from "date-fns/esm/addMilliseconds";
import addMinutes from "date-fns/esm/addMinutes"; import addMinutes from "date-fns/esm/addMinutes";
import { range } from "lodash"; import { isString, range } from "lodash";
import { stringifyUrl } from "query-string"; import { stringifyUrl } from "query-string";
import { defineComponent } from "vue"; import { defineComponent, ref, watch } from "vue";
import { formatTime } from "@util/formatTime"; import { formatTime } from "@util/formatTime";
import { joinYearMonth } from "@util/joinYearMonth"; import { joinYearMonth } from "@util/joinYearMonth";
import { mb_strwidth } from "@util/mb_strwidth"; import { mb_strwidth } from "@util/mb_strwidth";
@@ -210,6 +260,8 @@ import { parseTime } from "@util/parseTime";
import { parseYearMonth } from "@util/parseYearMonth"; import { parseYearMonth } from "@util/parseYearMonth";
import { sammoAPI } from "@util/sammoAPI"; import { sammoAPI } from "@util/sammoAPI";
import { convertSearch초성 } from "./util/convertSearch초성"; import { convertSearch초성 } from "./util/convertSearch초성";
import DragSelect from "@/components/DragSelect.vue";
type commandItem = { type commandItem = {
value: string; value: string;
title: string; title: string;
@@ -286,7 +338,9 @@ const searchModeKey = `sammo_searchModeOn`;
export default defineComponent({ export default defineComponent({
name: "PartialReservedCommand", name: "PartialReservedCommand",
components: {
DragSelect,
},
methods: { methods: {
updateNow() { updateNow() {
const serverNow = addMilliseconds(new Date(), this.timeDiff); const serverNow = addMilliseconds(new Date(), this.timeDiff);
@@ -295,16 +349,27 @@ export default defineComponent({
this.updateNow(); this.updateNow();
}, 1000 - serverNow.getMilliseconds()); }, 1000 - serverNow.getMilliseconds());
}, },
toggleTurn(turnIdx: number) { toggleTurn(...turnList: number[] | string[]) {
if (this.turnList.has(turnIdx)) { for (let turnIdx of turnList) {
this.turnList.delete(turnIdx); if (isString(turnIdx)) {
} else { turnIdx = parseInt(turnIdx);
this.turnList.add(turnIdx); }
if (this.turnList.has(turnIdx)) {
this.turnList.delete(turnIdx);
} else {
this.turnList.add(turnIdx);
}
} }
}, },
selectTurn(turnIdx: number) { selectTurn(...turnList: number[] | string[]) {
this.turnList.clear(); this.turnList.clear();
this.turnList.add(turnIdx); for (const turnIdx of turnList) {
if (isString(turnIdx)) {
this.turnList.add(parseInt(turnIdx));
} else {
this.turnList.add(turnIdx);
}
}
}, },
selectAll(e: Event | true) { selectAll(e: Event | true) {
//NOTE: split 구현에 버그가 있어서, 수동으로 구분해야함 //NOTE: split 구현에 버그가 있어서, 수동으로 구분해야함
@@ -519,8 +584,7 @@ export default defineComponent({
return { return {
maxTurn, maxTurn,
flippedMaxTurn: 15,
viewMaxTurn: 15,
maxPushTurn, maxPushTurn,
commandList, commandList,
serverNow: formatTime(serverNowObj, "HH:mm:ss"), serverNow: formatTime(serverNowObj, "HH:mm:ss"),
@@ -533,6 +597,34 @@ export default defineComponent({
searchModeOn, searchModeOn,
}; };
}, },
setup() {
const flippedMaxTurn = 15;
const viewMaxTurn = ref(flippedMaxTurn);
const rowGridStyle = ref({
display: "grid",
gridTemplateRows: `repeat(${viewMaxTurn.value}, 30px)`,
});
watch(viewMaxTurn, (val) => {
rowGridStyle.value.gridTemplateRows = `repeat(${val}, 29.4px)`;
});
function debugSel(val: unknown) {
console.log(val);
}
const isDragSingle = ref(false);
const isDragToggle = ref(false);
return {
isDragSingle,
isDragToggle,
flippedMaxTurn,
viewMaxTurn,
rowGridStyle,
debugSel,
};
},
mounted() { mounted() {
void this.reloadCommandList(); void this.reloadCommandList();
}, },
+40 -26
View File
@@ -14,7 +14,14 @@
<script lang="ts"> <script lang="ts">
/// https://github.com/andi23rosca/drag-select-vue/blob/master/src/DragSelect.vue /// https://github.com/andi23rosca/drag-select-vue/blob/master/src/DragSelect.vue
import { defineComponent, ref, watch, onMounted, onBeforeUnmount, PropType } from "vue"; import {
defineComponent,
ref,
watch,
onMounted,
onBeforeUnmount,
PropType,
} from "vue";
import VueTypes from "vue-types"; import VueTypes from "vue-types";
function getDimensions(p1: coord, p2: coord): rect { function getDimensions(p1: coord, p2: coord): rect {
@@ -47,12 +54,12 @@ export default defineComponent({
required: false, required: false,
}, },
modelValue: { modelValue: {
type: Object as PropType<Set<string>>, type: Object as PropType<Set<string>>,
required: false, required: false,
default: ()=>new Set(), default: () => ref(new Set()),
} },
}, },
emits: ["update:modelValue", "dragDone"], emits: ["update:modelValue", "dragDone", "dragStart"],
setup(props, { emit }) { setup(props, { emit }) {
const intersected = ref<Set<string>>(props.modelValue); const intersected = ref<Set<string>>(props.modelValue);
const container = ref<HTMLElement>(); const container = ref<HTMLElement>();
@@ -60,11 +67,11 @@ export default defineComponent({
watch(intersected, (val) => { watch(intersected, (val) => {
emit("update:modelValue", val); emit("update:modelValue", val);
}); });
watch(props.modelValue, (val)=>{ watch(props.modelValue, (val) => {
if(intersected.value === val){ if (intersected.value === val) {
return; return;
} }
intersected.value = val; intersected.value = val;
}); });
onMounted(() => { onMounted(() => {
@@ -102,22 +109,22 @@ export default defineComponent({
} }
let dismatch = false; let dismatch = false;
for(const oldVal of intersected.value){ for (const oldVal of intersected.value) {
if(!localIntersected.has(oldVal)){ if (!localIntersected.has(oldVal)) {
dismatch = true; dismatch = true;
break; break;
} }
} }
if(!dismatch){ if (!dismatch) {
for(const newVal of localIntersected){ for (const newVal of localIntersected) {
if(!intersected.value.has(newVal)){ if (!intersected.value.has(newVal)) {
dismatch = true; dismatch = true;
break; break;
}
} }
}
} }
if(dismatch){ if (dismatch) {
intersected.value = localIntersected; intersected.value = localIntersected;
} }
} }
function touchStart(e: TouchEvent) { function touchStart(e: TouchEvent) {
@@ -128,8 +135,10 @@ export default defineComponent({
e.preventDefault(); e.preventDefault();
drag(e.touches[0]); drag(e.touches[0]);
} }
let isMine = false;
function startDrag(e: MouseEvent | Touch) { function startDrag(e: MouseEvent | Touch) {
containerRect =uContainer.getBoundingClientRect(); containerRect = uContainer.getBoundingClientRect();
children = uContainer.children; children = uContainer.children;
start = getCoords(e); start = getCoords(e);
end = start; end = start;
@@ -139,6 +148,8 @@ export default defineComponent({
box.style.left = start.x + "px"; box.style.left = start.x + "px";
uContainer.prepend(box); uContainer.prepend(box);
intersection(); intersection();
isMine = true;
emit("dragStart");
} }
function drag(e: MouseEvent | Touch) { function drag(e: MouseEvent | Touch) {
end = getCoords(e); end = getCoords(e);
@@ -161,7 +172,10 @@ export default defineComponent({
document.removeEventListener("mousemove", drag); document.removeEventListener("mousemove", drag);
document.removeEventListener("touchmove", touchMove); document.removeEventListener("touchmove", touchMove);
box.remove(); box.remove();
emit('dragDone', intersected.value); if(isMine){
emit("dragDone", intersected.value);
}
isMine = false;
} }
uContainer.addEventListener("mousedown", startDrag); uContainer.addEventListener("mousedown", startDrag);