@@ -1,197 +1,5 @@ | |||||
# virages.io | # virages.io | ||||
## ROADMAP | |||||
1. define a Marker in the viewport | |||||
- x | |||||
- y | |||||
2. define a ZoomArea | |||||
- x | |||||
- y | |||||
- w | |||||
- h | |||||
3. define a Mask | |||||
- Trace | |||||
## TOOLS | |||||
DSIGN SYSTEMS | |||||
- StoryLite | |||||
https://atlas-viewer-storybook.netlify.app/#/stories/testing-ensuremouseeventsareaccuratewhenboxchanges | |||||
- micr.io | |||||
https://i.micr.io/aoxENNv/en/poulpatore-bigjpg | |||||
BACK OFFICE | |||||
- https://atlas-viewer-storybook.netlify.app/#/stories/annotations-selectiondemo | |||||
- https://github.com/altert/OpenseadragonFabricjsOverlay | |||||
- https://dash.micr.io/u:ErWRfBqNb1ef0QEnIRPzkQ/tets/@aoxENNv/en | |||||
FRONT OFFICE | |||||
- https://canvas-panel.digirati.com/#/about | |||||
- https://canvas-panel.digirati.com/#/examples/fullpage?manifest=https://stephenwf.github.io/ocean-liners.json | |||||
- https://github.com/digirati-co-uk/canvas-panel/tree/master | |||||
CONCURENTS | |||||
- https://micr.io/ | |||||
- https://archief.ntr.nl/tuinderlusten/en.html | |||||
LOGO | |||||
Virages est un outils pour les historiens de l'art qui veulent expliquer/analyser des images (peintures) en très haute résolution | |||||
Concevez un logo minimaliste, moderne pour virages.io, incorporant un V, les couleurs CMJN & RGB. | |||||
ws apps : | |||||
- logo virages | |||||
ALL: https://storiiies-editor.cogapp.com/ | |||||
https://github.com/IIIF/awesome-iiif/tree/66f8c724ee7fdb44f750ed4d7cedad449bb5f7a3 | |||||
FRONT: OpenSeaDragon | |||||
FRONT OFFICE: https://annotorious.github.io/guides/annotorious-in-vue/ | |||||
BACK: vips (Zoomable or ZoomHub) | |||||
BACK office : https://annotorious.github.io/getting-started/ | |||||
https://github.com/IIIF/awesome-iiif | |||||
IIIF | |||||
Giga pixel | |||||
- [ ] load a picture from a props on mounted in a 2d canvas | |||||
- [ ] display that picture with a good ratio and cover the full window | |||||
- [ ] a method focusOn(x, y, zoom) will change the scale of the image targetting a specific point | |||||
- [ ] at any moment the picture is showing in a good ratio even when the window is resized | |||||
Watch an erotic dream world where desire, colorful fantasy and poetic body parts intertwine. | |||||
https://vimeo.com/ondemand/uneruedanssalongueur | |||||
calvitie | |||||
forme de nudité | |||||
ex : | |||||
- Hunter Thomson | |||||
- Gérard jugnot | |||||
- Sébastien Tellier | |||||
qu'apporte l'analyse | |||||
artistique ? | |||||
quel est son sens ? | |||||
l'analyse peint une âme à l'oeuvre, elle renvoit la passion à l'objet d'art. | |||||
En ce sens l'analyse peut enfermer l'oeuvre dans un cadre, dans des lignes droites comme elle peut démontrer son aura par l'interprétation voir la surpasser par la sur-interprétation. | |||||
un film aléatoire | |||||
https://shop.gandi.net/en/6514bca2-b7cc-11ec-87b3-00163eada87b/domain/suggest/7cf99682-e92f-45d9-a87c-01d4d07999ca?search=msledchildren.com | |||||
- [ ] display one picture !!!!!!!!! | |||||
- [ ] 2 dyn canvas size of the window | |||||
- [ ] 3 setView (position, zoom, duration) | |||||
- [ ] 4 crop selection | |||||
- [ ] 5 filters | |||||
- [ ] 6 journey | |||||
- [ ] 7 UI : https://www.nextrembrandt.com/ | |||||
- [ ] display 2 pictures | |||||
- [ ] overlay pictures | |||||
- [ ] freeway mode | |||||
- [ ] possible effect on art click https://tympanus.net/codrops/2023/03/14/fullscreen-clip-animation/ | |||||
# IA & painting Art: | |||||
- [ ] IA shcema to painting : https://github.com/alexjc/neural-doodle | |||||
- [ ] Depth Estimation of a painting | |||||
- [ ] Object Detection in painting | |||||
- [ ] Perspective Detection in painting | |||||
- [ ] Inpaint in ... well painting :) | |||||
### rembrandt: | |||||
https://www.youtube.com/results?search_query=tu+delft+rembrandt | |||||
### Depth map | |||||
Inpainting / Outpainting -> youtube | |||||
https://github.com/AUTOMATIC1111/stable-diffusion-webui | |||||
https://github.com/docker-mailserver/docker-mailserver | |||||
https://tresjs.org/examples/load-textures.html | |||||
https://atroposjs.com/docs/vue#whats-next | |||||
- découpe d'une image avec clip - d'abord basic ellipse ou cercle | |||||
MODULES: | |||||
- errance [tuiles + zoom + full screen] | |||||
- histoire [tuiles + scroll + zoom] | |||||
- analyse [click + zoom + animation | |||||
- épaisseurs [3d] | |||||
## Pourquoi virages alors que l'art génératif existe ? | |||||
Si visuellement l’art génératif illustre très bien un article, même en tâtonnant il est impossible d'avoir exactement ce que l'on désir. | |||||
C'est l'occasion à l'art visuel traditionnel de mettre en avant ce qui fait sa spécificité, l'intention de son auteur. | |||||
Le mot artiste ne veut rien dire. | |||||
Il n'y a pas d'artiste, | |||||
Il n'y a que de l'art et leurs auteurs. | |||||
### MARCHÉ : | |||||
https://www.tumblr.com | |||||
https://behance.net | |||||
https://vitali-studio.com | |||||
https://issuu.com | |||||
https://cargo.site | |||||
https://www.artsy.net/ | |||||
https://www.flickr.com | |||||
### THEMES: | |||||
plutôt que perdre du temps sur du web design fait et refait, | |||||
pourquoi ne pas créer des thèmes sur des modèles comme : | |||||
- https://www.apple.com/fr/newsroom/ | |||||
- https://www.louvre.fr/en/what-s-on/exhibitions/leonardo-da-vinci#exhibition-overview | |||||
- https://salvatormundirevisited.com/ | |||||
### CSS | |||||
backdrop-filter | |||||
Filter color on hover : | |||||
https://cosmicmagazine.com.au/ | |||||
Folio for photographie & paintings | |||||
OU | |||||
CMS pour portfolio au plus généralement site créatif (EvilSpins) | |||||
Virag.es is a fullstack "framework" since it's a CMS | |||||
Virag.es back should be build with the best back (prisma nest) framework & vue | |||||
## Photo | |||||
- meta | |||||
- raw compat | |||||
- correction ... | |||||
## Paintings | |||||
- explorable table | |||||
- compte-fils / thread counter (https://codesandbox.io/s/github/WebsiteBeaver/vue-magnifier) | |||||
- video ? | |||||
- animation half per half (comme pour Lucie 3) | |||||
- VHS effect : https://www.ssion.com/ | |||||
- painting light (filmer une peinture avec peu de lumière et avec une lumière à fond) | |||||
## Lister toutes les références & symbole dans une page qui s'appelerai Mythologie | |||||
## DESIGN / FEATURES : | ## DESIGN / FEATURES : | ||||
- mobile first -> scroll first | - mobile first -> scroll first | ||||
@@ -2,9 +2,9 @@ | |||||
<section :class="'story mode-' + story.displayMode"> | <section :class="'story mode-' + story.displayMode"> | ||||
<aside | <aside | ||||
v-if="story.displayMode === 'EDITOR'" | v-if="story.displayMode === 'EDITOR'" | ||||
class="story-tools fixed inline-block bg-white bg-opacity-50 m-10 z-10 top-0 left-0 w-7 h-7 md:w-auto md:h-auto overflow-hidden" | |||||
class="story-tools fixed inline-block bg-white bg-opacity-50 m-10 z-10 top-0 left-0" | |||||
> | > | ||||
<Editor :markers="props.story.markers" /> | |||||
<Editor :story="props.story" /> | |||||
</aside> | </aside> | ||||
<main class="story-openseadragon" ref="openSeadragonElt"></main> | <main class="story-openseadragon" ref="openSeadragonElt"></main> | ||||
<Article :story="props.story" /> | <Article :story="props.story" /> | ||||
@@ -16,9 +16,9 @@ import OpenSeadragon from 'openseadragon' | |||||
import '@/assets/plugins/openseadragon-scalebar.js' | import '@/assets/plugins/openseadragon-scalebar.js' | ||||
import '@/assets/plugins/openseadragon-bookmark-url.js' | import '@/assets/plugins/openseadragon-bookmark-url.js' | ||||
import { onMounted, ref, provide, onUnmounted } from 'vue' | import { onMounted, ref, provide, onUnmounted } from 'vue' | ||||
import type { Story } from '@/types/virages' | |||||
import type { Story, ViewerConfiguration } from '@/types/virages' | |||||
import Article from './StoryArticle.vue' | import Article from './StoryArticle.vue' | ||||
import Editor from './tools/StoryEditor.vue' | |||||
import Editor from './player/StoryEditor.vue' | |||||
const props = defineProps<{ story: Story }>() | const props = defineProps<{ story: Story }>() | ||||
const Viewer = ref() | const Viewer = ref() | ||||
@@ -26,26 +26,30 @@ const openSeadragonElt = ref() | |||||
provide('Viewer', Viewer) | provide('Viewer', Viewer) | ||||
const defaultViewerConfiguration: ViewerConfiguration = { | |||||
prefixUrl: 'https://openseadragon.github.io/openseadragon/images/', | |||||
crossOriginPolicy: 'Anonymous', | |||||
animationTime: 2, | |||||
showNavigator: false, | |||||
sequenceMode: false, | |||||
showNavigationControl: false, | |||||
drawer: 'canvas', | |||||
preventDefaultAction: true, | |||||
visibilityRatio: 0.5, | |||||
defaultZoomLevel: 1.2, | |||||
gestureSettingsMouse: { | |||||
scrollToZoom: true, | |||||
clickToZoom: false, | |||||
dblClickToZoom: false, | |||||
dragToPan: true, | |||||
}, | |||||
} | |||||
const initViewer = () => { | const initViewer = () => { | ||||
Viewer.value = OpenSeadragon({ | Viewer.value = OpenSeadragon({ | ||||
element: openSeadragonElt.value, | element: openSeadragonElt.value, | ||||
animationTime: 0.4, | |||||
prefixUrl: 'https://openseadragon.github.io/openseadragon/images/', | |||||
showNavigator: false, | |||||
sequenceMode: false, | |||||
tileSources: props.story.url, | tileSources: props.story.url, | ||||
showNavigationControl: false, | |||||
drawer: 'canvas', | |||||
preventDefaultAction: true, | |||||
visibilityRatio: 0.5, | |||||
crossOriginPolicy: 'Anonymous', | |||||
gestureSettingsMouse: { | |||||
scrollToZoom: true, | |||||
clickToZoom: false, | |||||
dblClickToZoom: false, | |||||
dragToPan: true, | |||||
}, | |||||
defaultZoomLevel: 1.2, | |||||
...defaultViewerConfiguration, | |||||
}) | }) | ||||
} | } | ||||
@@ -1,15 +1,15 @@ | |||||
<template> | <template> | ||||
<div class="story-list"> | <div class="story-list"> | ||||
<StoryContainer | <StoryContainer | ||||
v-for="story in stories" | |||||
v-for="story in store.stories" | |||||
:key="story.id" | :key="story.id" | ||||
:story="story" | :story="story" | ||||
@click="openStory(story)" | |||||
@click="store.openStory(story)" | |||||
/> | /> | ||||
</div> | </div> | ||||
<button | <button | ||||
v-if="isAppModeFullscreen" | |||||
@click="closeStories()" | |||||
v-if="store.isStoryOpen" | |||||
@click="store.closeStories()" | |||||
class="bg-white hover:text-lg transition text-black h-8 w-8 rounded-full fixed right-4 top-4 z-50" | class="bg-white hover:text-lg transition text-black h-8 w-8 rounded-full fixed right-4 top-4 z-50" | ||||
> | > | ||||
x | x | ||||
@@ -17,39 +17,22 @@ | |||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
import { onMounted, ref } from 'vue' | |||||
import type { Story } from '@/types/virages' | |||||
import { onMounted } from 'vue' | |||||
import StoryContainer from './StoryContainer.vue' | import StoryContainer from './StoryContainer.vue' | ||||
import datas from '@/assets/stories.json' | |||||
import { useStoryStore } from '@/stores/story' | |||||
const stories = ref<Story[]>(datas) | |||||
const isAppModeFullscreen = ref(false) | |||||
const openStory = (story: Story) => { | |||||
stories.value.forEach((story) => { | |||||
story.displayMode = 'HIDDEN' | |||||
}) | |||||
story.displayMode = 'EDITOR' | |||||
isAppModeFullscreen.value = true | |||||
document.body.classList.add('app-fullscreen') | |||||
} | |||||
const closeStories = () => { | |||||
stories.value.forEach((story) => { | |||||
story.displayMode = 'ARTICLE' | |||||
}) | |||||
isAppModeFullscreen.value = false | |||||
document.body.classList.remove('app-fullscreen') | |||||
} | |||||
const store = useStoryStore() | |||||
const keyboardShortcut = () => { | const keyboardShortcut = () => { | ||||
// if press on escpae key | // if press on escpae key | ||||
window.addEventListener('keydown', (e) => { | window.addEventListener('keydown', (e) => { | ||||
if (e.key !== 'Escape') return | if (e.key !== 'Escape') return | ||||
closeStories() | |||||
store.closeStories() | |||||
}) | }) | ||||
} | } | ||||
onMounted(() => { | onMounted(() => { | ||||
store.getStories() | |||||
keyboardShortcut() | keyboardShortcut() | ||||
}) | }) | ||||
</script> | </script> | ||||
@@ -29,21 +29,25 @@ | |||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
import type { Marker } from '@/types/virages' | |||||
import type { Story, Marker } from '@/types/virages' | |||||
import { onMounted, ref, inject, nextTick, type Ref, computed } from 'vue' | import { onMounted, ref, inject, nextTick, type Ref, computed } from 'vue' | ||||
import OpenSeadragon from 'openseadragon' | import OpenSeadragon from 'openseadragon' | ||||
import { useIsMobile } from '@/composable/IsMobile' | |||||
import { useViewer } from '@/composable/Viewer' | |||||
import { useStoryStore } from '@/stores/story' | |||||
const props = defineProps<{ markers: Marker[] }>() | |||||
const props = defineProps<{ story: Story }>() | |||||
const Viewer = inject<Ref<OpenSeadragon.Viewer>>('Viewer') | const Viewer = inject<Ref<OpenSeadragon.Viewer>>('Viewer') | ||||
const isAddingPoint = ref<boolean>(false) | const isAddingPoint = ref<boolean>(false) | ||||
const selectedMarker = ref<Marker>({} as Marker) | const selectedMarker = ref<Marker>({} as Marker) | ||||
const textInputMarkerName = ref<HTMLInputElement | null>(null) | const textInputMarkerName = ref<HTMLInputElement | null>(null) | ||||
const { zoomTo } = useViewer(Viewer) | |||||
const store = useStoryStore() | |||||
const isAMarkerSelected = computed(() => { | const isAMarkerSelected = computed(() => { | ||||
return selectedMarker.value.id !== undefined | return selectedMarker.value.id !== undefined | ||||
}) | }) | ||||
const sortedMarkers = computed(() => { | const sortedMarkers = computed(() => { | ||||
return [...props.markers].sort((a, b) => a.order - b.order) | |||||
return [...props.story.markers].sort((a, b) => a.order - b.order) | |||||
}) | }) | ||||
const goHome = () => { | const goHome = () => { | ||||
@@ -74,9 +78,12 @@ const selectMarker = (marker: Marker) => { | |||||
) | ) | ||||
Viewer?.value.viewport.fitBoundsWithConstraints(markerRectangle, false) | Viewer?.value.viewport.fitBoundsWithConstraints(markerRectangle, false) | ||||
selectedMarker.value = marker | selectedMarker.value = marker | ||||
// nextTick(() => { | |||||
// textInputMarkerName.value?.focus() | |||||
// }) | |||||
nextTick(() => { | |||||
const isMobile = useIsMobile() | |||||
if (!isMobile) { | |||||
textInputMarkerName.value?.focus() | |||||
} | |||||
}) | |||||
} | } | ||||
const unselectMarker = () => { | const unselectMarker = () => { | ||||
@@ -117,14 +124,15 @@ const createMarkerOnClick = () => { | |||||
const zoom = Viewer?.value.viewport.getZoom() | const zoom = Viewer?.value.viewport.getZoom() | ||||
const bounds = Viewer?.value.viewport.getBounds() | const bounds = Viewer?.value.viewport.getBounds() | ||||
const newMarker: Marker = { | const newMarker: Marker = { | ||||
id: props.markers.length, | |||||
order: props.markers.length, | |||||
id: props.story.markers.length, | |||||
order: props.story.markers.length, | |||||
name: '', | name: '', | ||||
bounds: bounds, | bounds: bounds, | ||||
point: new OpenSeadragon.Point(point.x, point.y), | point: new OpenSeadragon.Point(point.x, point.y), | ||||
zoom: zoom, | zoom: zoom, | ||||
annotation: '', | annotation: '', | ||||
} | } | ||||
store.addMarker(props.story, newMarker) | |||||
injectMarker(newMarker) | injectMarker(newMarker) | ||||
isAddingPoint.value = false | isAddingPoint.value = false | ||||
document.querySelector('.openseadragon-canvas')?.classList.remove('cursor-crosshair') | document.querySelector('.openseadragon-canvas')?.classList.remove('cursor-crosshair') | ||||
@@ -198,12 +206,13 @@ onMounted(() => { | |||||
nextTick(() => { | nextTick(() => { | ||||
Viewer?.value.clearOverlays() | Viewer?.value.clearOverlays() | ||||
// Viewer.value.viewport.defaultZoomLevel = 1 | // Viewer.value.viewport.defaultZoomLevel = 1 | ||||
loadStory(props.markers) | |||||
loadStory(props.story.markers) | |||||
createMarkerOnClick() | createMarkerOnClick() | ||||
editMarkerOnDragOrZoom() | editMarkerOnDragOrZoom() | ||||
keyboardShortcut() | keyboardShortcut() | ||||
initScalebar() | initScalebar() | ||||
initUrl() | initUrl() | ||||
zoomTo(6) // COMPOSABLE WORKS | |||||
}) | }) | ||||
}) | }) | ||||
</script> | </script> |
@@ -1,17 +0,0 @@ | |||||
# Story Editor | |||||
## Props: | |||||
story: Story (should be a state as Markers are CRUD ?) | |||||
## Ref: | |||||
selectedMarker: Marker | |||||
## Methods: | |||||
LoadStory | |||||
CreateMarker | |||||
SelectMarker | |||||
EditMarker | |||||
DeleteMarker |
@@ -1,83 +0,0 @@ | |||||
<template> | |||||
<nav class="[&>*]:m-3 text-black"> | |||||
<div class="flex flex-col ui"> | |||||
<h2>Current Marker</h2> | |||||
{{ currentMarker }} | |||||
<textarea :value="currentMarker.annotation"></textarea> | |||||
</div> | |||||
</nav> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import type { Marker } from '@/types/virages' | |||||
import { onMounted, ref, inject, nextTick } from 'vue' | |||||
import OpenSeadragon from 'openseadragon' | |||||
const props = defineProps<{ markers: Marker[] }>() | |||||
const Viewer = inject('Viewer') | |||||
const isEditMode = ref<boolean>(false) | |||||
const currentMarker = ref<Marker>({} as Marker) | |||||
const injectMarker = (marker: Marker) => { | |||||
const overlay = document.createElement('button') | |||||
overlay.className = `marker-id-${marker.id} w-8 h-8 rounded-full shadow-2xl bg-green-500 bg-opacity-50 hover:bg-green-600 hover:bg-opacity-100 z-index-20 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` | |||||
overlay.addEventListener('click', function () { | |||||
Viewer?.value.viewport.zoomTo(marker.zoom, undefined, false) | |||||
Viewer?.value.viewport.panTo(new OpenSeadragon.Point(marker.position.x, marker.position.y)) | |||||
selectMarker(marker) | |||||
}) | |||||
overlay.addEventListener('mouseover', function () { | |||||
Viewer?.value.setMouseNavEnabled(false) | |||||
}) | |||||
overlay.addEventListener('mouseout', function () { | |||||
Viewer?.value.setMouseNavEnabled(true) | |||||
}) | |||||
// Injection de l'overlay | |||||
Viewer?.value.addOverlay({ | |||||
element: overlay, | |||||
location: new OpenSeadragon.Point(marker.position.x, marker.position.y), | |||||
}) | |||||
} | |||||
const createMarkerOnClick = () => { | |||||
Viewer.value.addHandler('canvas-click', (e) => { | |||||
if (!isEditMode.value) return | |||||
const point = Viewer.value.viewport.pointFromPixel(e.position) | |||||
const zoom = Viewer.value.viewport.getZoom() | |||||
const newMarker: Marker = { | |||||
id: props.markers.length, // WIP | |||||
order: props.markers.length, // WIP | |||||
annotation: '', | |||||
position: { | |||||
x: point.x, | |||||
y: point.y, | |||||
}, | |||||
zoom: zoom, | |||||
} | |||||
injectMarker(newMarker) | |||||
isEditMode.value = false | |||||
}) | |||||
} | |||||
const loadStory = (markers: Marker[]) => { | |||||
markers.forEach((marker) => { | |||||
injectMarker(marker) | |||||
}) | |||||
} | |||||
onMounted(() => { | |||||
nextTick(() => { | |||||
Viewer.value.zoomPerClick = true | |||||
createMarkerOnClick() | |||||
loadStory(props.markers) | |||||
}) | |||||
}) | |||||
</script> | |||||
<style> | |||||
.ui button { | |||||
@apply border-2 border-black px-4 py-2 rounded-xl bg-slate-300; | |||||
} | |||||
</style> |
@@ -0,0 +1,13 @@ | |||||
import { computed } from 'vue' | |||||
export function useIsMobile() { | |||||
const userAgent = navigator.userAgent || navigator.vendor || window.opera | |||||
// Check for mobile user agents | |||||
const isMobile = computed(() => { | |||||
const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i | |||||
return mobileRegex.test(userAgent) | |||||
}) | |||||
return { isMobile } | |||||
} |
@@ -0,0 +1,10 @@ | |||||
import type OpenSeadragon from 'openseadragon' | |||||
import { type Ref } from 'vue' | |||||
export function useViewer(Viewer: Ref<OpenSeadragon.Viewer>) { | |||||
const zoomTo = (zoomLevel: number) => { | |||||
Viewer.value.viewport.zoomTo(zoomLevel, undefined, false) | |||||
} | |||||
return { zoomTo } | |||||
} |
@@ -1,19 +0,0 @@ | |||||
import type { Story } from '@/types/virages' | |||||
import { defineStore } from 'pinia' | |||||
export const useStories = defineStore('stories', { | |||||
state: (): Story => ({ | |||||
stories: [], | |||||
nextId: 0, | |||||
}), | |||||
getters: { | |||||
finishedStories(state) { | |||||
return state.stories.filter((todo) => todo.isFinished) | |||||
}, | |||||
}, | |||||
actions: { | |||||
action(data) { | |||||
this.stories.push({}) | |||||
}, | |||||
}, | |||||
}) |
@@ -0,0 +1,36 @@ | |||||
import type { Story } from '@/types/virages' | |||||
import { defineStore } from 'pinia' | |||||
import datas from '@/assets/stories.json' | |||||
export const useStoryStore = defineStore('story', { | |||||
state: () => ({ | |||||
stories: [] as Story[], | |||||
isStoryOpen: false, | |||||
}), | |||||
actions: { | |||||
getStories() { | |||||
this.stories = datas | |||||
}, | |||||
openStory(story: Story) { | |||||
this.stories.forEach((story) => { | |||||
story.displayMode = 'HIDDEN' | |||||
}) | |||||
story.displayMode = 'EDITOR' | |||||
this.isStoryOpen = true | |||||
document.body.classList.add('app-fullscreen') | |||||
}, | |||||
closeStories() { | |||||
this.stories.forEach((story) => { | |||||
story.displayMode = 'ARTICLE' | |||||
}) | |||||
this.isStoryOpen = false | |||||
document.body.classList.remove('app-fullscreen') | |||||
}, | |||||
getStoryById(id: number) { | |||||
return this.stories.find((story) => story.id === id) | |||||
}, | |||||
addMarker(story: Story, marker: Marker) { | |||||
story.markers.push(marker) | |||||
}, | |||||
}, | |||||
}) |
@@ -5,7 +5,7 @@ export interface Story { | |||||
url: string // absolute or relative url (../public/deepzoom) | url: string // absolute or relative url (../public/deepzoom) | ||||
markers: Marker[] | markers: Marker[] | ||||
displayMode: string // 'ARTICLE' | 'EDITOR' | 'PLAYER' | 'HIDDEN' | displayMode: string // 'ARTICLE' | 'EDITOR' | 'PLAYER' | 'HIDDEN' | ||||
date_art_creation: Date | |||||
// date_art_creation: Date | |||||
} | } | ||||
export interface Marker { | export interface Marker { | ||||
@@ -26,3 +26,22 @@ export interface Marker { | |||||
zoom: number | zoom: number | ||||
annotation: string | annotation: string | ||||
} | } | ||||
export interface ViewerConfiguration { | |||||
prefixUrl: string | |||||
crossOriginPolicy: string | |||||
animationTime: number | |||||
showNavigator: boolean | |||||
sequenceMode: boolean | |||||
showNavigationControl: boolean | |||||
drawer: string | |||||
preventDefaultAction: boolean | |||||
visibilityRatio: number | |||||
defaultZoomLevel: number | |||||
gestureSettingsMouse: { | |||||
scrollToZoom: boolean | |||||
clickToZoom: boolean | |||||
dblClickToZoom: boolean | |||||
dragToPan: boolean | |||||
} | |||||
} |