autoformat
This commit is contained in:
parent
bfa569853b
commit
7bff008853
4 changed files with 131 additions and 83 deletions
|
@ -1,32 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<SVGContent id="root" url="content/intro.svg" @set-background="setBackground"/>
|
<SVGContent
|
||||||
|
id="root"
|
||||||
|
url="content/intro.svg"
|
||||||
|
@set-background="setBackground"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent} from "vue";
|
import { defineComponent } from "vue";
|
||||||
import SVGContent from "@/components/SVGContent.vue";
|
import SVGContent from "@/components/SVGContent.vue";
|
||||||
import "normalize.css";
|
import "normalize.css";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "App",
|
name: "App",
|
||||||
components: {
|
components: {
|
||||||
SVGContent
|
SVGContent,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setBackground(background: string) {
|
setBackground(background: string) {
|
||||||
document.body.style.background = background;
|
document.body.style.background = background;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html, body {
|
html,
|
||||||
|
body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: black;
|
background: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body, #app, #root {
|
html,
|
||||||
|
body,
|
||||||
|
#app,
|
||||||
|
#root {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<audio ref="audio"
|
<audio ref="audio" :src="definition.src" loop preload="auto" />
|
||||||
:src="definition.src"
|
|
||||||
loop preload="auto"/>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent, PropType, ref, watch} from "vue";
|
import { defineComponent, PropType, ref, watch } from "vue";
|
||||||
import {BoundingBox} from "@/components/SVGContent.vue";
|
import { BoundingBox } from "@/components/SVGContent.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "AudioArea",
|
name: "AudioArea",
|
||||||
props: {
|
props: {
|
||||||
definition: {
|
definition: {
|
||||||
type: Object as PropType<AudioAreaDef>,
|
type: Object as PropType<AudioAreaDef>,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
bbox: {
|
bbox: {
|
||||||
type: Object as PropType<BoundingBox>,
|
type: Object as PropType<BoundingBox>,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
@ -34,38 +32,46 @@ export default defineComponent({
|
||||||
const onBBoxChange = () => {
|
const onBBoxChange = () => {
|
||||||
const x = props.bbox.x + props.bbox.w / 2;
|
const x = props.bbox.x + props.bbox.w / 2;
|
||||||
const y = props.bbox.y + props.bbox.h / 2;
|
const y = props.bbox.y + props.bbox.h / 2;
|
||||||
const distance = Math.sqrt(Math.pow(x - props.definition.cx, 2) + Math.pow(y - props.definition.cy, 2));
|
const distance = Math.sqrt(
|
||||||
|
Math.pow(x - props.definition.cx, 2) +
|
||||||
|
Math.pow(y - props.definition.cy, 2)
|
||||||
|
);
|
||||||
|
|
||||||
if (distance < props.definition.radius) {
|
if (distance < props.definition.radius) {
|
||||||
if (audio.value!.paused) {
|
if (audio.value!.paused) {
|
||||||
console.debug(`[AUDIOAREA] Entered audio area "${props.definition.src}", starting playback...`);
|
console.debug(
|
||||||
|
`[AUDIOAREA] Entered audio area "${props.definition.src}", starting playback...`
|
||||||
|
);
|
||||||
audio.value!.play();
|
audio.value!.play();
|
||||||
}
|
}
|
||||||
const volume = (props.definition.radius - distance) / props.definition.radius;
|
const volume =
|
||||||
audio.value!.volume = volume * (props.bbox.z < 1 ? (props.bbox.z * vol_x + vol_b) : 1);
|
(props.definition.radius - distance) / props.definition.radius;
|
||||||
|
audio.value!.volume =
|
||||||
|
volume * (props.bbox.z < 1 ? props.bbox.z * vol_x + vol_b : 1);
|
||||||
} else {
|
} else {
|
||||||
if (!audio.value!.paused) {
|
if (!audio.value!.paused) {
|
||||||
console.debug(`[AUDIOAREA] Left audio area "${props.definition.src}", pausing playback...`);
|
console.debug(
|
||||||
|
`[AUDIOAREA] Left audio area "${props.definition.src}", pausing playback...`
|
||||||
|
);
|
||||||
audio.value!.pause();
|
audio.value!.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
watch(props.bbox, onBBoxChange, {deep: true});
|
watch(props.bbox, onBBoxChange, { deep: true });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
audio
|
audio,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface AudioAreaDef {
|
export interface AudioAreaDef {
|
||||||
id: string,
|
id: string;
|
||||||
cx: number,
|
cx: number;
|
||||||
cy: number,
|
cy: number;
|
||||||
radius: number,
|
radius: number;
|
||||||
src: string
|
src: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
|
|
@ -5,10 +5,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="content" ref="root">
|
<div class="content" ref="root">
|
||||||
<div class="video-scrolls">
|
<div class="video-scrolls">
|
||||||
<VideoScroll v-for="scroll in scrolls" :definition="scroll" :key="scroll.id"/>
|
<VideoScroll
|
||||||
|
v-for="scroll in scrolls"
|
||||||
|
:definition="scroll"
|
||||||
|
:key="scroll.id"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AudioArea v-for="audio in audioAreas" :definition="audio" :bbox="bbox" :key="audio.id"/>
|
<AudioArea
|
||||||
|
v-for="audio in audioAreas"
|
||||||
|
:definition="audio"
|
||||||
|
:bbox="bbox"
|
||||||
|
:key="audio.id"
|
||||||
|
/>
|
||||||
<div class="dev devpanel">
|
<div class="dev devpanel">
|
||||||
<div>
|
<div>
|
||||||
<span>Current viewport position:</span>
|
<span>Current viewport position:</span>
|
||||||
|
@ -382,10 +391,10 @@ export default defineComponent({
|
||||||
|
|
||||||
if (gp) {
|
if (gp) {
|
||||||
if (gp.buttons[7].pressed) {
|
if (gp.buttons[7].pressed) {
|
||||||
gamePadZoomSpeed += .1;
|
gamePadZoomSpeed += 0.1;
|
||||||
}
|
}
|
||||||
if (gp.buttons[5].pressed) {
|
if (gp.buttons[5].pressed) {
|
||||||
gamePadZoomSpeed -= .1;
|
gamePadZoomSpeed -= 0.1;
|
||||||
}
|
}
|
||||||
if (gamePadZoomSpeed < 1) {
|
if (gamePadZoomSpeed < 1) {
|
||||||
gamePadZoomSpeed = 1;
|
gamePadZoomSpeed = 1;
|
||||||
|
@ -469,11 +478,14 @@ async function processScrolls(svg: XMLDocument): Promise<VideoScrollDef[]> {
|
||||||
direction as VideoScrollDirection
|
direction as VideoScrollDirection
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
console.error(`Unknown direction definition: "${direction}" (in #${el.id})`);
|
console.error(
|
||||||
|
`Unknown direction definition: "${direction}" (in #${el.id})`
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return direction as VideoScrollDirection;
|
return direction as VideoScrollDirection;
|
||||||
}).filter((d) => Boolean(d)) as VideoScrollDirection[];
|
})
|
||||||
|
.filter((d) => Boolean(d)) as VideoScrollDirection[];
|
||||||
|
|
||||||
console.debug(`[SVG/VIDEOSCROLLS] Fetching ${filesURL}...`);
|
console.debug(`[SVG/VIDEOSCROLLS] Fetching ${filesURL}...`);
|
||||||
const fileFetch = await fetch(`content/${filesURL}`);
|
const fileFetch = await fetch(`content/${filesURL}`);
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="video-scroll" ref="root" v-if="definition.directions.length > 0">
|
<div class="video-scroll" ref="root" v-if="definition.directions.length > 0">
|
||||||
<img class="visible displayed loaded"
|
<img
|
||||||
|
class="visible displayed loaded"
|
||||||
:src="definition.files[0]"
|
:src="definition.files[0]"
|
||||||
:style="{
|
:style="{
|
||||||
top: `${Math.round(definition.top)}px`,
|
top: `${Math.round(definition.top)}px`,
|
||||||
left: `${Math.round(definition.left)}px`,
|
left: `${Math.round(definition.left)}px`,
|
||||||
width: isHorizontal ? `${Math.round(definition.width)}px` : 'auto',
|
width: isHorizontal ? `${Math.round(definition.width)}px` : 'auto',
|
||||||
height: isVertical ? `${Math.round(definition.height)}px` : 'auto',
|
height: isVertical ? `${Math.round(definition.height)}px` : 'auto',
|
||||||
transform: `rotate(${definition.angle}deg)`
|
transform: `rotate(${definition.angle}deg)`,
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!--suppress RequiredAttributes -->
|
<!--suppress RequiredAttributes -->
|
||||||
<img v-for="(file, idx) in dynamicFiles"
|
<img
|
||||||
|
v-for="(file, idx) in dynamicFiles"
|
||||||
:key="`${idx}_${file.src}`"
|
:key="`${idx}_${file.src}`"
|
||||||
:data-src="file.src"
|
:data-src="file.src"
|
||||||
:style="{
|
:style="{
|
||||||
|
@ -20,51 +22,70 @@
|
||||||
left: `${Math.round(file.left)}px`,
|
left: `${Math.round(file.left)}px`,
|
||||||
width: `${Math.round(definition.width)}px`,
|
width: `${Math.round(definition.width)}px`,
|
||||||
height: `${Math.round(definition.height)}px`,
|
height: `${Math.round(definition.height)}px`,
|
||||||
transform: `rotate(${definition.angle}deg)`
|
transform: `rotate(${definition.angle}deg)`,
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {defineComponent, PropType} from "vue";
|
import { defineComponent, PropType } from "vue";
|
||||||
import {rotate} from "@/utils";
|
import { rotate } from "@/utils";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "VideoScroll",
|
name: "VideoScroll",
|
||||||
props: {
|
props: {
|
||||||
definition: {
|
definition: {
|
||||||
type: Object as PropType<VideoScrollDef>,
|
type: Object as PropType<VideoScrollDef>,
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
dynamicFiles(): { top: number, left: number, src: string }[] {
|
dynamicFiles(): { top: number; left: number; src: string }[] {
|
||||||
return this.definition.files.slice(1).map((src: string, idx: number) => {
|
return this.definition.files.slice(1).map((src: string, idx: number) => {
|
||||||
const cy = this.definition.top +
|
const cy =
|
||||||
(this.isVertical ? (this.definition.height * (idx + 1) * this.verticalDirection) : 0);
|
this.definition.top +
|
||||||
const cx = this.definition.left +
|
(this.isVertical
|
||||||
(this.isHorizontal ? (this.definition.width * (idx + 1) * this.horizontalDirection) : 0);
|
? this.definition.height * (idx + 1) * this.verticalDirection
|
||||||
const [left, top] = rotate(cx, cy, this.definition.left, this.definition.top, this.definition.angle);
|
: 0);
|
||||||
return {top, left, src};
|
const cx =
|
||||||
|
this.definition.left +
|
||||||
|
(this.isHorizontal
|
||||||
|
? this.definition.width * (idx + 1) * this.horizontalDirection
|
||||||
|
: 0);
|
||||||
|
const [left, top] = rotate(
|
||||||
|
cx,
|
||||||
|
cy,
|
||||||
|
this.definition.left,
|
||||||
|
this.definition.top,
|
||||||
|
this.definition.angle
|
||||||
|
);
|
||||||
|
return { top, left, src };
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isHorizontal(): boolean {
|
isHorizontal(): boolean {
|
||||||
return this.definition.directions.some(
|
return this.definition.directions.some(
|
||||||
(dir: VideoScrollDirection) => dir === VideoScrollDirection.LEFT || dir === VideoScrollDirection.RIGHT
|
(dir: VideoScrollDirection) =>
|
||||||
|
dir === VideoScrollDirection.LEFT ||
|
||||||
|
dir === VideoScrollDirection.RIGHT
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
isVertical(): boolean {
|
isVertical(): boolean {
|
||||||
return this.definition.directions.some(
|
return this.definition.directions.some(
|
||||||
(dir: VideoScrollDirection) => dir === VideoScrollDirection.UP || dir === VideoScrollDirection.DOWN
|
(dir: VideoScrollDirection) =>
|
||||||
|
dir === VideoScrollDirection.UP || dir === VideoScrollDirection.DOWN
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
horizontalDirection(): number {
|
horizontalDirection(): number {
|
||||||
return this.definition.directions.includes(VideoScrollDirection.RIGHT) ? 1 : -1;
|
return this.definition.directions.includes(VideoScrollDirection.RIGHT)
|
||||||
|
? 1
|
||||||
|
: -1;
|
||||||
},
|
},
|
||||||
verticalDirection(): number {
|
verticalDirection(): number {
|
||||||
return this.definition.directions.includes(VideoScrollDirection.DOWN) ? 1 : -1;
|
return this.definition.directions.includes(VideoScrollDirection.DOWN)
|
||||||
}
|
? 1
|
||||||
|
: -1;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const observer = new IntersectionObserver((entries, _) => {
|
const observer = new IntersectionObserver((entries, _) => {
|
||||||
|
@ -73,7 +94,9 @@ export default defineComponent({
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
element.classList.add("visible");
|
element.classList.add("visible");
|
||||||
if (!element.src) {
|
if (!element.src) {
|
||||||
console.debug(`[VIDEOSCROLL] Intersected, loading ${element.dataset.src}`);
|
console.debug(
|
||||||
|
`[VIDEOSCROLL] Intersected, loading ${element.dataset.src}`
|
||||||
|
);
|
||||||
element.src = element.dataset.src!;
|
element.src = element.dataset.src!;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
element.classList.add("displayed");
|
element.classList.add("displayed");
|
||||||
|
@ -93,32 +116,31 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (this.$refs.root){
|
if (this.$refs.root) {
|
||||||
Array.from((this.$refs.root as Element).children).forEach((el) => {
|
Array.from((this.$refs.root as Element).children).forEach((el) => {
|
||||||
observer.observe(el);
|
observer.observe(el);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export enum VideoScrollDirection {
|
export enum VideoScrollDirection {
|
||||||
RIGHT = "right",
|
RIGHT = "right",
|
||||||
LEFT = "left",
|
LEFT = "left",
|
||||||
UP = "up",
|
UP = "up",
|
||||||
DOWN = "down"
|
DOWN = "down",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VideoScrollDef {
|
export interface VideoScrollDef {
|
||||||
id: string,
|
id: string;
|
||||||
top: number,
|
top: number;
|
||||||
left: number,
|
left: number;
|
||||||
angle: number,
|
angle: number;
|
||||||
width: number,
|
width: number;
|
||||||
height: number,
|
height: number;
|
||||||
directions: VideoScrollDirection[],
|
directions: VideoScrollDirection[];
|
||||||
files: string[]
|
files: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
|
@ -129,7 +151,7 @@ export interface VideoScrollDef {
|
||||||
background: grey;
|
background: grey;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity .5s;
|
transition: opacity 0.5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-scroll img.visible {
|
.video-scroll img.visible {
|
||||||
|
|
Loading…
Reference in a new issue