Trying new pinch to zoom mode

This commit is contained in:
Peaceultime 2024-07-25 15:46:38 +02:00
parent 4b901a87d7
commit 1c9812c3a8
7 changed files with 68 additions and 20 deletions

10
app.vue
View File

@ -6,6 +6,8 @@ function toggleLeftPanel(_: Event): void {
</script> </script>
<script setup lang="ts"> <script setup lang="ts">
const { path } = useRoute();
const { data: tags } = await useAsyncData('descriptions', queryContent('/tags').findOne); const { data: tags } = await useAsyncData('descriptions', queryContent('/tags').findOne);
provide('tags/descriptions', tags); provide('tags/descriptions', tags);
@ -14,7 +16,7 @@ onMounted(() => {
icon = document.querySelector('.site-nav-bar .clickable-icon'); icon = document.querySelector('.site-nav-bar .clickable-icon');
icon?.removeEventListener('click', toggleLeftPanel); icon?.removeEventListener('click', toggleLeftPanel);
icon?.addEventListener('click', toggleLeftPanel); icon?.addEventListener('click', toggleLeftPanel);
}) });
</script> </script>
<template> <template>
@ -29,9 +31,9 @@ onMounted(() => {
</svg> </svg>
</div> </div>
<div class="gap-3"> <div class="gap-3">
<NuxtLink class="site-nav-bar-text" aria-label="Accueil" :href="'/'">Accueil</NuxtLink> <NuxtLink class="site-nav-bar-text" aria-label="Accueil" :href="'/'" ><img src="" /></NuxtLink>
<NuxtLink class="site-nav-bar-text" aria-label="Systeme" :href="'/explorer'">Systeme</NuxtLink> <NuxtLink class="site-nav-bar-text" aria-label="Systeme" :href="'/explorer'" :class="{'mod-active': path.startsWith('/explorer')}">Systeme</NuxtLink>
<NuxtLink class="site-nav-bar-text" aria-label="Outils" :href="'/tools'">Outils</NuxtLink> <NuxtLink class="site-nav-bar-text" aria-label="Outils" :href="'/tools'" :class="{'mod-active': path.startsWith('/tools')}">Outils</NuxtLink>
</div> </div>
</div> </div>
<div> <div>

View File

@ -51,24 +51,24 @@
.gap-1 > * .gap-1 > *
{ {
padding-left: .4em; margin-left: .4em;
padding-right: .4em; margin-right: .4em;
} }
.gap-1 > *:first-child, .gap-2 > *:first-child, .gap-3 > *:first-child .gap-1 > *:first-child, .gap-2 > *:first-child, .gap-3 > *:first-child
{ {
padding-left: 0; margin-left: 0;
} }
.gap-1 > *:last-child, .gap-2 > *:last-child, .gap-3 > *:last-child .gap-1 > *:last-child, .gap-2 > *:last-child, .gap-3 > *:last-child
{ {
padding-right: 0; margin-right: 0;
} }
.gap-2 > * .gap-2 > *
{ {
padding-left: .8em; margin-left: .8em;
padding-right: .8em; margin-right: .8em;
} }
.gap-3 > * .gap-3 > *
{ {
padding-left: 1.2em; margin-left: 1.2em;
padding-right: 1.2em; margin-right: 1.2em;
} }

View File

@ -45,7 +45,7 @@
--site-name-color-hover: var(--text-muted); --site-name-color-hover: var(--text-muted);
--site-name-font: inherit; --site-name-font: inherit;
--site-name-size: 18px; --site-name-size: 18px;
--site-name-weight: var(--font-medium); --site-name-weight: var(--font-normal);
--site-menu-icon-color: var(--text-faint); --site-menu-icon-color: var(--text-faint);
--site-menu-icon-color-hover: var(--text-normal); --site-menu-icon-color-hover: var(--text-normal);
--site-menu-icon-size: 24px; --site-menu-icon-size: 24px;
@ -4983,3 +4983,8 @@ body {
.site-nav-bar > div:last-child { .site-nav-bar > div:last-child {
justify-content: end; justify-content: end;
} }
.site-nav-bar-text.mod-active {
padding-bottom: .5em;
border-bottom: 3px solid var(--nav-item-border-color-active);
}

View File

@ -31,10 +31,12 @@ const results = computed(() => {
</div> </div>
<Teleport to="body" v-if="input !== ''"> <Teleport to="body" v-if="input !== ''">
<div class="search-results" :style="{top: (pos.bottom + 4) + 'px', left: pos.left + 'px', width: pos.width + 'px'}"> <div class="search-results" :style="{top: (pos.bottom + 4) + 'px', left: pos.left + 'px', width: pos.width + 'px'}">
<div class="suggestion-item" v-if="results.length > 0" v-for="result of results" :key="result._path" @mouseenter="(e) => (e.target as HTMLElement).classList.add('is-selected')" @mouseleave="(e) => (e.target as HTMLElement).classList.remove('is-selected')" @mousedown="navigateTo('/explorer' + result._path); input = ''"> <div class="suggestion-item" v-if="results.length > 0" v-for="result of results" :key="result._path" @mouseenter="(e) => (e.target as HTMLElement).classList.add('is-selected')" @mouseleave="(e) => (e.target as HTMLElement).classList.remove('is-selected')" @mousedown.prevent="navigateTo('/explorer' + result._path); input = ''">
<div class="suggestion-content"> <div class="suggestion-content">
<div class="suggestion-title"> <div class="suggestion-title">
<ProseA :href="result._path">
{{ result.title.substring(0, clear(result.title).indexOf(clear(input))) }}<span class="suggestion-highlight">{{ result.title.substring(clear(result.title).indexOf(clear(input)), clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}</span>{{ result.title.substring(clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }} {{ result.title.substring(0, clear(result.title).indexOf(clear(input))) }}<span class="suggestion-highlight">{{ result.title.substring(clear(result.title).indexOf(clear(input)), clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}</span>{{ result.title.substring(clear(result.title).indexOf(clear(input)) + clear(input).length + 1) }}
</ProseA>
</div> </div>
</div> </div>
</div> </div>

View File

@ -25,7 +25,7 @@ function darken(rgb: string): boolean
const props = defineProps<Props>(); const props = defineProps<Props>();
const classes: any = { 'canvas-node-group': props.node.type === 'group', 'is-themed': props.node.color !== undefined, 'mod-canvas-color-custom': (props.node?.color?.startsWith('#') ?? false) }; const classes: Record<string, boolean> = { 'canvas-node-group': props.node.type === 'group', 'is-themed': props.node.color !== undefined, 'mod-canvas-color-custom': (props.node?.color?.startsWith('#') ?? false) };
const size = Math.max(props.node.width, props.node.height); const size = Math.max(props.node.width, props.node.height);
if(props.node.color !== undefined) if(props.node.color !== undefined)

View File

@ -14,6 +14,8 @@ let centerX = ref(0), centerY = ref(0), canvas = ref<HTMLDivElement>();
let minX = ref(+Infinity), minY = ref(+Infinity), maxX = ref(-Infinity), maxY = ref(-Infinity); let minX = ref(+Infinity), minY = ref(+Infinity), maxX = ref(-Infinity), maxY = ref(-Infinity);
let bbox = ref<DOMRect>(); let bbox = ref<DOMRect>();
let lastPinchLength = 0;
let _minX = +Infinity, _minY = +Infinity, _maxX = -Infinity, _maxY = -Infinity; let _minX = +Infinity, _minY = +Infinity, _maxX = -Infinity, _maxY = -Infinity;
onMounted(async () => { onMounted(async () => {
@ -66,7 +68,7 @@ const onPointerDown = (event: PointerEvent) => {
} }
const onPointerMove = (event: PointerEvent) => { const onPointerMove = (event: PointerEvent) => {
if (event.isPrimary === false) return; if (event.isPrimary === false || dragging === false) return;
dispX.value -= (posX - event.clientX) / zoom.value; dispX.value -= (posX - event.clientX) / zoom.value;
dispY.value -= (posY - event.clientY) / zoom.value; dispY.value -= (posY - event.clientY) / zoom.value;
@ -79,11 +81,39 @@ const onPointerUp = (event: PointerEvent) => {
dragging = false; dragging = false;
document.removeEventListener('pointermove', onPointerMove); document.removeEventListener('pointermove', onPointerMove);
document.removeEventListener('pointerup', onPointerUp); document.removeEventListener('pointerup', onPointerUp);
document.removeEventListener('pointercancel', onPointerUp);
} }
const onWheel = (event: WheelEvent) => { const onWheel = (event: WheelEvent) => {
zoom.value = clamp(zoom.value * 1 + (event.deltaY * -0.001), minZoom.value, 3); zoom.value = clamp(zoom.value + (event.deltaY * -0.001), minZoom.value, 3);
}
const onTouchStart = (event: TouchEvent) => {
if(event.touches?.length === 2)
{
dragging = false;
lastPinchLength = length(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchend', onTouchEnd);
}
}
const onTouchEnd = (event: TouchEvent) => {
if(event.touches?.length !== 2)
dragging = true;
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
}
const onTouchMove = (event: TouchEvent) => {
if(event.touches?.length === 2)
{
const l = length(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
zoom.value = clamp(zoom.value + ((lastPinchLength - l) * -0.01), minZoom.value, 3);
lastPinchLength = l;
}
} }
const reset = (_: MouseEvent) => { const reset = (_: MouseEvent) => {
@ -98,6 +128,9 @@ function clamp(x: number, min: number, max: number): number {
return min; return min;
return x; return x;
} }
function length(x1: number, y1: number, x2: number, y2: number): number {
return Math.sqrt((x2 - x1)^2 + (y2 - y1)^2);
}
function edgePos(side: 'bottom' | 'top' | 'left' | 'right', pos: { x: number, y: number }, n: number): { x: number, y: number } { function edgePos(side: 'bottom' | 'top' | 'left' | 'right', pos: { x: number, y: number }, n: number): { x: number, y: number } {
switch (side) { switch (side) {
case "left": case "left":
@ -180,7 +213,7 @@ function getCenter(n: { x: number, y: number }, i: { x: number, y: number }, r:
</script> </script>
<template> <template>
<div ref="canvas" @pointerdown="onPointerDown" @wheel.passive="onWheel" @touchstart.prevent="" @dragstart.prevent="" <div ref="canvas" @pointerdown="onPointerDown" @wheel.passive="onWheel" @touchstart.prevent="onTouchStart" @dragstart.prevent=""
class="canvas-wrapper node-insert-event mod-zoomed-out" class="canvas-wrapper node-insert-event mod-zoomed-out"
:style="{ '--zoom-multiplier': (1 / Math.pow(zoom, 0.7)) }"> :style="{ '--zoom-multiplier': (1 / Math.pow(zoom, 0.7)) }">
<div class="canvas-controls" style="z-index: 999;"> <div class="canvas-controls" style="z-index: 999;">

View File

@ -11,6 +11,12 @@ export default defineNuxtConfig({
}, },
], ],
router: {
options: {
scrollBehaviorType: 'smooth'
}
},
css: ['~/assets/common.css', '~/assets/global.css'], css: ['~/assets/common.css', '~/assets/global.css'],
content: { content: {