Procházet zdrojové kódy

feat: composable + story

master
valere před 3 měsíci
rodič
revize
8898e6fe37
6 změnil soubory, kde provedl 28 přidání a 284 odebrání
  1. +2
    -8
      src/components/StoryList.vue
  2. +0
    -260
      src/components/player/StoryDrawRect.vue
  3. +9
    -16
      src/components/player/StoryEditor.vue
  4. +17
    -0
      src/composables/EscapeKey.ts
  5. +0
    -0
      src/composables/IsMobile.ts
  6. +0
    -0
      src/composables/Viewer.ts

+ 2
- 8
src/components/StoryList.vue Zobrazit soubor

@@ -20,20 +20,14 @@
import { onMounted } from 'vue'
import StoryContainer from './StoryContainer.vue'
import { useStoryStore } from '@/stores/story'
import { useEscapeKey } from '@/composables/EscapeKey'

const store = useStoryStore()

const keyboardShortcut = () => {
// if press on escpae key
window.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return
store.closeStories()
})
}
useEscapeKey(store.closeStories)

onMounted(() => {
store.getStories()
keyboardShortcut()
})
</script>



+ 0
- 260
src/components/player/StoryDrawRect.vue Zobrazit soubor

@@ -1,260 +0,0 @@
<template>
<nav class="[&>*]:m-3 text-black w-48">
<div class="flex flex-col ui">
<div>
<button @click="drawRect">draw rect</button>
{{ selectedBounds }}
</div>
<button @click="goHome">home</button>
<button @click="addPoint">Add Point</button>
<button @click="addRectangle">Add Rectangle</button>
<div class="flex flex-col my-6">
<button
v-for="marker in sortedMarkers"
:key="marker.order"
@click="selectMarker(marker)"
:class="marker.id === selectedMarker.id ? 'text-green-500 text-bold' : ''"
>
{{ marker.name }}
</button>
</div>
<div v-if="isAMarkerSelected">
<input
ref="textInputMarkerName"
type="text"
v-model="selectedMarker.name"
class="w-40 my-4"
/>
<textarea v-model="selectedMarker.annotation" class="w-40 h-40"></textarea>
<button @click="saveMarker">Save</button>
<button @click="unselectMarker">Cancel</button>
</div>
</div>
</nav>
</template>

<script setup lang="ts">
import type { Marker } from '@/types/virages'
import { onMounted, ref, inject, nextTick, type Ref, computed } from 'vue'
import OpenSeadragon from 'openseadragon'

const props = defineProps<{ markers: Marker[] }>()
const Viewer = inject<Ref<OpenSeadragon.Viewer>>('Viewer')
const isAddingPoint = ref<boolean>(false)
const isAddingRectangle = ref<boolean>(false)
const selectedMarker = ref<Marker>({} as Marker)
const textInputMarkerName = ref<HTMLInputElement | null>(null)

const selectedBounds = ref(null)

const isAMarkerSelected = computed(() => {
return selectedMarker.value.id !== undefined
})
const sortedMarkers = computed(() => {
return [...props.markers].sort((a, b) => a.order - b.order)
})

const drawRect = () => {}

function convertZoomPointToBounds(zoom, pointX, pointY) {
const canvasWidth = Viewer?.value.canvas.offsetWidth
const canvasHeight = Viewer?.value.canvas.offsetHeight

const bounds = {
x: (pointX - canvasWidth / 2) / (canvasWidth / 2) / zoom,
y: (pointY - canvasHeight / 2) / (canvasHeight / 2) / zoom,
width: canvasWidth / zoom,
height: canvasHeight / zoom,
}

return bounds
}

const goHome = () => {
Viewer?.value.viewport.goHome(false)
}

const addPoint = () => {
unselectMarker()
isAddingPoint.value = true
document.querySelector('.openseadragon-canvas')?.classList.add('cursor-crosshair')
}

const addRectangle = () => {
unselectMarker()
isAddingRectangle.value = true
document.querySelector('.openseadragon-canvas')?.classList.add('cursor-crosshair')
}

const saveMarker = () => {
unselectMarker()
}

const selectMarker = (marker: Marker) => {
document.querySelectorAll('.marker-selected').forEach((el) => {
el.classList.remove('marker-selected')
})
const theMarker = document.querySelector('.marker-id-' + marker.id)
theMarker?.classList.add('marker-selected')
// Viewer?.value.viewport.fitBoundsWithConstraints(new OpenSeadragon.Rect(marker.bounds), false)
Viewer?.value.viewport.zoomTo(marker.zoom, undefined, false)
Viewer?.value.viewport.panTo(new OpenSeadragon.Point(marker.point.x, marker.point.y))
console.log('marker', marker)
selectedMarker.value = marker
nextTick(() => {
textInputMarkerName.value?.focus()
})
}

const unselectMarker = () => {
selectedMarker.value = {} as Marker
document.querySelector('.marker-selected')?.classList.remove('marker-selected')
}

const injectMarker = (marker: Marker) => {
const overlay = document.createElement('button')
overlay.className = `marker-id-${marker.id} marker`
overlay.title = marker.name
overlay.onfocus = function () {
selectMarker(marker)
}
overlay.addEventListener('click', function () {
selectMarker(marker)
})
overlay.addEventListener('mouseover', function () {
Viewer?.value.setMouseNavEnabled(false)
// Viewer.value.gestureSettingsMouse.dragToPan = false
})
overlay.addEventListener('mouseout', function () {
Viewer?.value.setMouseNavEnabled(true)
})

// Injection de l'overlay
Viewer?.value.addOverlay({
element: overlay,
location: new OpenSeadragon.Point(marker.point.x, marker.point.y),
})
}

const createMarkerOnClick = () => {
Viewer?.value.addHandler('canvas-click', (event) => {
// adding point
if (isAddingPoint.value) {
console.log('adding point')
const point = Viewer?.value.viewport.pointFromPixel(event.position)
const zoom = Viewer?.value.viewport.getZoom()
const bounds = Viewer?.value.viewport.getBounds()
console.log('bounds', bounds)
console.log('zoom', zoom)
console.log('point', point)
const newMarker: Marker = {
id: props.markers.length,
order: props.markers.length,
name: '',
bounds: bounds,
point: new OpenSeadragon.Point(point.x, point.y),
zoom: zoom,
annotation: '',
}
injectMarker(newMarker)
isAddingPoint.value = false
document.querySelector('.openseadragon-canvas')?.classList.remove('cursor-crosshair')
selectMarker(newMarker)
} else if (isAddingRectangle.value) {
const point = Viewer?.value.viewport.pointFromPixel(event.position)
const zoom = Viewer?.value.viewport.getZoom()
const bounds = Viewer?.value.viewport.getBounds()
} else if (isAMarkerSelected.value) {
unselectMarker()
}
})
}

const editMarkerOnDragOrZoom = () => {
Viewer?.value.addHandler('canvas-drag', (event) => {
if (isAMarkerSelected.value) {
Viewer.value.gestureSettingsMouse.dragToPan = false
const point = Viewer?.value.viewport.pointFromPixel(event.position)
selectedMarker.value.point = point
selectedMarker.value.bounds = Viewer?.value.viewport.getBounds()
const overlay = document.querySelector('.marker-id-' + selectedMarker.value.id)
Viewer?.value.updateOverlay(overlay as Element, point)
}
})

Viewer?.value.addHandler('canvas-release', () => {
Viewer.value.gestureSettingsMouse.dragToPan = true
})

Viewer?.value.addHandler('zoom', (event) => {
if (isAMarkerSelected.value) {
selectedMarker.value.zoom = event.zoom
selectedMarker.value.bounds = Viewer?.value.viewport.getBounds()
}
})
}

const loadStory = (markers: Marker[]) => {
markers.forEach((marker) => {
injectMarker(marker)
})
}

const keyboardShortcut = () => {
// if press on escpae key
window.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return
unselectMarker()
goHome()
})
}

const initScalebar = () => {
Viewer.value.scalebar({
type: OpenSeadragon.ScalebarType.MAP,
pixelsPerMeter: 37792223.52,
minWidth: '74px',
location: OpenSeadragon.ScalebarLocation.BOTTOM_RIGHT,
color: 'black',
fontColor: 'black',
backgroundColor: 'rgba(255, 255, 255, 0.5)',
barThickness: 1,
stayInsideImage: false,
xOffset: 20,
yOffset: 20,
})
}

const initUrl = () => {
Viewer.value.bookmarkUrl()
}

onMounted(() => {
nextTick(() => {
Viewer?.value.clearOverlays()
// Viewer.value.viewport.defaultZoomLevel = 1
loadStory(props.markers)
createMarkerOnClick()
editMarkerOnDragOrZoom()
keyboardShortcut()
initScalebar()
initUrl()
})
})
</script>

<style>
.ui button {
@apply border-2 border-black px-4 py-2 rounded-xl bg-slate-300 hover:bg-neutral-100 m-1;
}
.ui input,
.ui textarea {
@apply border-2 border-black px-4 py-2;
}
.marker {
@apply w-8 h-8 rounded-full shadow-2xl bg-green-500 bg-opacity-50 hover:bg-green-600 hover:bg-opacity-100 hover:cursor-pointer pointer-events-auto hover:scale-150 transition-all border-2 border-white border-8 transform -translate-y-1/2 -translate-x-1/2;
}
.marker-selected {
@apply border-blue-400 border-8 bg-white animate-pulse hover:cursor-move hover:bg-white;
}
</style>

+ 9
- 16
src/components/player/StoryEditor.vue Zobrazit soubor

@@ -32,9 +32,10 @@
import type { Story, Marker } from '@/types/virages'
import { onMounted, ref, inject, nextTick, type Ref, computed } from 'vue'
import OpenSeadragon from 'openseadragon'
import { useIsMobile } from '@/composable/IsMobile'
import { useViewer } from '@/composable/Viewer'
import { useIsMobile } from '@/composables/IsMobile'
import { useViewer } from '@/composables/Viewer'
import { useStoryStore } from '@/stores/story'
import { useEscapeKey } from '@/composables/EscapeKey'

const props = defineProps<{ story: Story }>()
const Viewer = inject<Ref<OpenSeadragon.Viewer>>('Viewer')
@@ -52,6 +53,7 @@ const sortedMarkers = computed(() => {

const goHome = () => {
Viewer?.value.viewport.goHome(false)
unselectMarker()
}

const addPoint = () => {
@@ -173,15 +175,6 @@ const loadStory = (markers: Marker[]) => {
})
}

const keyboardShortcut = () => {
// if press on escpae key
window.addEventListener('keydown', (e) => {
if (e.key !== 'Escape') return
unselectMarker()
goHome()
})
}

const initScalebar = () => {
Viewer.value.scalebar({
type: OpenSeadragon.ScalebarType.MAP,
@@ -198,9 +191,10 @@ const initScalebar = () => {
})
}

const initUrl = () => {
Viewer.value.bookmarkUrl()
}
useEscapeKey(() => {
unselectMarker()
goHome()
})

onMounted(() => {
nextTick(() => {
@@ -209,9 +203,8 @@ onMounted(() => {
loadStory(props.story.markers)
createMarkerOnClick()
editMarkerOnDragOrZoom()
keyboardShortcut()
initScalebar()
initUrl()
Viewer.value.bookmarkUrl()
zoomTo(6) // COMPOSABLE WORKS
})
})


+ 17
- 0
src/composables/EscapeKey.ts Zobrazit soubor

@@ -0,0 +1,17 @@
import { onMounted, onUnmounted } from 'vue'

export function useEscapeKey(callback: () => void) {
const handleKeydown = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
callback()
}
}

onMounted(() => {
window.addEventListener('keydown', handleKeydown)
})

onUnmounted(() => {
window.removeEventListener('keydown', handleKeydown)
})
}

src/composable/IsMobile.ts → src/composables/IsMobile.ts Zobrazit soubor


src/composable/Viewer.ts → src/composables/Viewer.ts Zobrazit soubor


Načítá se…
Zrušit
Uložit