autoformat

master
Tomáš Mládek 2021-04-22 11:33:33 +02:00
parent bfa569853b
commit 7bff008853
4 changed files with 131 additions and 83 deletions

View File

@ -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;

View File

@ -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 -->

View File

@ -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}`);

View File

@ -1,70 +1,91 @@
<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
:src="definition.files[0]" class="visible displayed loaded"
:style="{ :src="definition.files[0]"
top: `${Math.round(definition.top)}px`, :style="{
left: `${Math.round(definition.left)}px`, top: `${Math.round(definition.top)}px`,
width: isHorizontal ? `${Math.round(definition.width)}px` : 'auto', left: `${Math.round(definition.left)}px`,
height: isVertical ? `${Math.round(definition.height)}px` : 'auto', width: isHorizontal ? `${Math.round(definition.width)}px` : 'auto',
transform: `rotate(${definition.angle}deg)` height: isVertical ? `${Math.round(definition.height)}px` : 'auto',
}" transform: `rotate(${definition.angle}deg)`,
}"
/> />
<!--suppress RequiredAttributes --> <!--suppress RequiredAttributes -->
<img v-for="(file, idx) in dynamicFiles" <img
:key="`${idx}_${file.src}`" v-for="(file, idx) in dynamicFiles"
:data-src="file.src" :key="`${idx}_${file.src}`"
:style="{ :data-src="file.src"
top: `${Math.round(file.top)}px`, :style="{
left: `${Math.round(file.left)}px`, top: `${Math.round(file.top)}px`,
width: `${Math.round(definition.width)}px`, left: `${Math.round(file.left)}px`,
height: `${Math.round(definition.height)}px`, width: `${Math.round(definition.width)}px`,
transform: `rotate(${definition.angle}deg)` height: `${Math.round(definition.height)}px`,
}" 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 {