mirror of
https://github.com/yeicor-3d/yet-another-cad-viewer.git
synced 2025-12-19 22:24:17 +01:00
add selection keyboard shortcuts
This commit is contained in:
@@ -21,7 +21,7 @@ export type MObject3D = Object3D & {
|
|||||||
|
|
||||||
let props = defineProps<{ viewer: typeof ModelViewerWrapperT | null }>();
|
let props = defineProps<{ viewer: typeof ModelViewerWrapperT | null }>();
|
||||||
let emit = defineEmits<{ findModel: [string] }>();
|
let emit = defineEmits<{ findModel: [string] }>();
|
||||||
let {disableTap, setDisableTap} = inject('disableTap');
|
let {setDisableTap} = inject<{setDisableTap: (boolean) => void}>('disableTap');
|
||||||
let selectionEnabled = ref(false);
|
let selectionEnabled = ref(false);
|
||||||
let selected = defineModel<Array<Intersection<MObject3D>>>({default: []});
|
let selected = defineModel<Array<Intersection<MObject3D>>>({default: []});
|
||||||
let highlightNextSelection = ref([false, false]); // Second is whether selection was enabled before
|
let highlightNextSelection = ref([false, false]); // Second is whether selection was enabled before
|
||||||
@@ -29,7 +29,7 @@ let showBoundingBox = ref<Boolean>(false); // Enabled automatically on start
|
|||||||
let showDistances = ref<Boolean>(true);
|
let showDistances = ref<Boolean>(true);
|
||||||
|
|
||||||
let mouseDownAt: [number, number] | null = null;
|
let mouseDownAt: [number, number] | null = null;
|
||||||
let selectFilter = ref('Any');
|
let selectFilter = ref('Any (S)');
|
||||||
const raycaster = new Raycaster();
|
const raycaster = new Raycaster();
|
||||||
|
|
||||||
|
|
||||||
@@ -54,16 +54,16 @@ let selectionListener = (event: MouseEvent) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set raycaster parameters
|
// Set raycaster parameters
|
||||||
if (selectFilter.value === 'Any') {
|
if (selectFilter.value === 'Any (S)') {
|
||||||
raycaster.params.Line.threshold = 0.2;
|
raycaster.params.Line.threshold = 0.2;
|
||||||
raycaster.params.Points.threshold = 0.8;
|
raycaster.params.Points.threshold = 0.8;
|
||||||
} else if (selectFilter.value === 'Edges') {
|
} else if (selectFilter.value === '(E)dges') {
|
||||||
raycaster.params.Line.threshold = 0.8;
|
raycaster.params.Line.threshold = 0.8;
|
||||||
raycaster.params.Points.threshold = 0.0;
|
raycaster.params.Points.threshold = 0.0;
|
||||||
} else if (selectFilter.value === 'Vertices') {
|
} else if (selectFilter.value === '(V)ertices') {
|
||||||
raycaster.params.Line.threshold = 0.0;
|
raycaster.params.Line.threshold = 0.0;
|
||||||
raycaster.params.Points.threshold = 0.8;
|
raycaster.params.Points.threshold = 0.8;
|
||||||
} else if (selectFilter.value === 'Faces') {
|
} else if (selectFilter.value === '(F)aces') {
|
||||||
raycaster.params.Line.threshold = 0.0;
|
raycaster.params.Line.threshold = 0.0;
|
||||||
raycaster.params.Points.threshold = 0.0;
|
raycaster.params.Points.threshold = 0.0;
|
||||||
}
|
}
|
||||||
@@ -89,10 +89,10 @@ let selectionListener = (event: MouseEvent) => {
|
|||||||
const hits = raycaster.intersectObject(scene, true);
|
const hits = raycaster.intersectObject(scene, true);
|
||||||
let hit = hits.find((hit) => {
|
let hit = hits.find((hit) => {
|
||||||
const kind = hit.object.type
|
const kind = hit.object.type
|
||||||
const kindOk = (selectFilter.value === 'Any') ||
|
const kindOk = (selectFilter.value === 'Any (S)') ||
|
||||||
((kind === 'Mesh' || kind === 'SkinnedMesh') && selectFilter.value === 'Faces') ||
|
((kind === 'Mesh' || kind === 'SkinnedMesh') && selectFilter.value === '(F)aces') ||
|
||||||
(kind === 'Line' && selectFilter.value === 'Edges') ||
|
(kind === 'Line' && selectFilter.value === '(E)dges') ||
|
||||||
(kind === 'Points' && selectFilter.value === 'Vertices');
|
(kind === 'Points' && selectFilter.value === '(V)ertices');
|
||||||
return hit.object.visible && !hit.object.userData.noHit && kindOk;
|
return hit.object.visible && !hit.object.userData.noHit && kindOk;
|
||||||
}) as Intersection<MObject3D> | undefined;
|
}) as Intersection<MObject3D> | undefined;
|
||||||
//console.log('Hit', hit)
|
//console.log('Hit', hit)
|
||||||
@@ -359,36 +359,70 @@ function updateDistances() {
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add keyboard shortcuts
|
||||||
|
window.addEventListener('keydown', (event) => {
|
||||||
|
if (event.key === 's') {
|
||||||
|
if(selectFilter.value == 'Any (S)') toggleSelection();
|
||||||
|
else {
|
||||||
|
selectFilter.value = 'Any (S)';
|
||||||
|
if(!selectionEnabled.value) toggleSelection();
|
||||||
|
}
|
||||||
|
} else if (event.key === 'f') {
|
||||||
|
if(selectFilter.value == '(F)aces') toggleSelection();
|
||||||
|
else {
|
||||||
|
selectFilter.value = '(F)aces';
|
||||||
|
if(!selectionEnabled.value) toggleSelection();
|
||||||
|
}
|
||||||
|
} else if (event.key === 'e') {
|
||||||
|
if(selectFilter.value == '(E)dges') toggleSelection();
|
||||||
|
else {
|
||||||
|
selectFilter.value = '(E)dges';
|
||||||
|
if(!selectionEnabled.value) toggleSelection();
|
||||||
|
}
|
||||||
|
} else if (event.key === 'v') {
|
||||||
|
if(selectFilter.value == '(V)ertices') toggleSelection();
|
||||||
|
else {
|
||||||
|
selectFilter.value = '(V)ertices';
|
||||||
|
if(!selectionEnabled.value) toggleSelection();
|
||||||
|
}
|
||||||
|
} else if (event.key === 'b') {
|
||||||
|
toggleShowBoundingBox();
|
||||||
|
} else if (event.key === 'd') {
|
||||||
|
toggleShowDistances();
|
||||||
|
} else if (event.key === 'h') {
|
||||||
|
toggleHighlightNextSelection();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="select-parent">
|
<div class="select-parent">
|
||||||
<v-btn icon @click="toggleSelection" :color="selectionEnabled ? 'surface-light' : ''">
|
<v-btn icon @click="toggleSelection" :color="selectionEnabled ? 'surface-light' : ''">
|
||||||
<v-tooltip activator="parent">{{ selectionEnabled ? 'Disable selection mode' : 'Enable selection mode' }}
|
<v-tooltip activator="parent">{{ selectionEnabled ? 'Disable (s)election mode' : 'Enable (s)election mode' }}
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
<svg-icon type="mdi" :path="mdiCursorDefaultClick"/>
|
<svg-icon type="mdi" :path="mdiCursorDefaultClick"/>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-tooltip :text="'Select only ' + selectFilter.toString().toLocaleLowerCase()" :open-on-click="false">
|
<v-tooltip :text="'Select only ' + selectFilter.toString().toLocaleLowerCase()" :open-on-click="false">
|
||||||
<template v-slot:activator="{ props }">
|
<template v-slot:activator="{ props }">
|
||||||
<!-- TODO: Keyboard shortcuts for fast selection (& other tools) -->
|
|
||||||
<v-select v-bind="props" class="select-only" variant="underlined"
|
<v-select v-bind="props" class="select-only" variant="underlined"
|
||||||
:items="['Any', 'Faces', 'Edges', 'Vertices']"
|
:items="['Any (S)', '(F)aces', '(E)dges', '(V)ertices']"
|
||||||
v-model="selectFilter"/>
|
v-model="selectFilter"/>
|
||||||
</template>
|
</template>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<v-btn icon @click="toggleHighlightNextSelection" :color="highlightNextSelection[0] ? 'surface-light' : ''">
|
<v-btn icon @click="toggleHighlightNextSelection" :color="highlightNextSelection[0] ? 'surface-light' : ''">
|
||||||
<v-tooltip activator="parent">Highlight the next clicked element in the models list</v-tooltip>
|
<v-tooltip activator="parent">(H)ighlight the next clicked element in the models list</v-tooltip>
|
||||||
<svg-icon type="mdi" :path="mdiFeatureSearch"/>
|
<svg-icon type="mdi" :path="mdiFeatureSearch"/>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn icon @click="toggleShowBoundingBox" :color="showBoundingBox ? 'surface-light' : ''">
|
<v-btn icon @click="toggleShowBoundingBox" :color="showBoundingBox ? 'surface-light' : ''">
|
||||||
<v-tooltip activator="parent">{{ showBoundingBox ? 'Hide selection bounds' : 'Show selection bounds' }}
|
<v-tooltip activator="parent">{{ showBoundingBox ? 'Hide selection (b)ounds' : 'Show selection (b)ounds' }}
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
<svg-icon type="mdi" :path="mdiCubeOutline"/>
|
<svg-icon type="mdi" :path="mdiCubeOutline"/>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn icon @click="toggleShowDistances" :color="showDistances ? 'surface-light' : ''">
|
<v-btn icon @click="toggleShowDistances" :color="showDistances ? 'surface-light' : ''">
|
||||||
<v-tooltip activator="parent">
|
<v-tooltip activator="parent">
|
||||||
{{ showDistances ? 'Hide selection distances' : 'Show distances (when a pair of features is selected)' }}
|
{{ showDistances ? 'Hide selection (d)istances' : 'Show (d)istances (when a pair of features is selected)' }}
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
<svg-icon type="mdi" :path="mdiRuler"/>
|
<svg-icon type="mdi" :path="mdiRuler"/>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ function entries(lines: { [id: number]: Line3DData }): [string, Line3DData][] {
|
|||||||
|
|
||||||
defineExpose({elem, onElemReady, scene, renderer, addLine3D, removeLine3D});
|
defineExpose({elem, onElemReady, scene, renderer, addLine3D, removeLine3D});
|
||||||
|
|
||||||
let {disableTap} = inject('disableTap');
|
let {disableTap} = inject<{ disableTap: Ref<boolean> }>('disableTap');
|
||||||
watch(disableTap, (value) => {
|
watch(disableTap, (value) => {
|
||||||
// Rerender not auto triggered? This works anyway...
|
// Rerender not auto triggered? This works anyway...
|
||||||
if (value) elem.value?.setAttribute('disable-tap', '');
|
if (value) elem.value?.setAttribute('disable-tap', '');
|
||||||
|
|||||||
Reference in New Issue
Block a user