|
|
|
<template>
|
|
|
|
<QuickNav />
|
|
|
|
|
|
|
|
<!-- CONTENT -->
|
|
|
|
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
|
|
|
<!-- Breadcrumb -->
|
|
|
|
<div class="mb-8">
|
|
|
|
<!-- Back -->
|
|
|
|
<div class="text-lg text-center font-light relative px-7">
|
|
|
|
<h1
|
|
|
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
|
|
|
@click="$router.back()"
|
|
|
|
>
|
|
|
|
<fa icon="chevron-left" class="fa-fw"></fa>
|
|
|
|
</h1>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<!-- Heading -->
|
|
|
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
|
|
|
|
Achievements & Statistics
|
|
|
|
</h1>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div>
|
|
|
|
Here is a view of the activity you can see.
|
|
|
|
<ul class="list-disc list-inside">
|
|
|
|
<li>Each identity and claim has a unique position.</li>
|
|
|
|
<!-- eslint-disable prettier/prettier --><!-- If we format prettier then there is extra space at the start of the line. -->
|
|
|
|
<li>Each will show at their time of appearance relative to all others.</li>
|
|
|
|
<li>Note that the ones on the left and right edges are randomized
|
|
|
|
because their data isn't all visible to you.
|
|
|
|
</li>
|
|
|
|
<!-- eslint-enable -->
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="mt-3">
|
|
|
|
<div v-if="worldProperties.startTime">
|
|
|
|
<label>Time Range: </label>
|
|
|
|
{{ worldProperties.startTime }}
|
|
|
|
-
|
|
|
|
{{ worldProperties.endTime }}
|
|
|
|
</div>
|
|
|
|
<div v-if="worldProperties.animationDurationSeconds">
|
|
|
|
<label>Animation Time: </label>
|
|
|
|
{{ worldProperties.animationDurationSeconds }} seconds
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<button class="float-right text-blue-600" @click="captureGraphics()">Screenshot</button>
|
|
|
|
<div id="scene-container" class="h-screen"></div>
|
|
|
|
</section>
|
|
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
|
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
|
|
import { World } from "@/components/World/World.js";
|
|
|
|
import QuickNav from "@/components/QuickNav.vue";
|
|
|
|
|
|
|
|
interface RendererSVGType {
|
|
|
|
domElement: Element;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface Dictionary<T> {
|
|
|
|
[key: string]: T;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface Notification {
|
|
|
|
group: string;
|
|
|
|
type: string;
|
|
|
|
title: string;
|
|
|
|
text: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({ components: { World, QuickNav } })
|
|
|
|
export default class StatisticsView extends Vue {
|
|
|
|
$notify!: (notification: Notification, timeout?: number) => void;
|
|
|
|
|
|
|
|
world: World;
|
|
|
|
worldProperties: Dictionary<number> = {};
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
try {
|
|
|
|
const container = document.querySelector("#scene-container");
|
|
|
|
const newWorld = new World(container, this);
|
|
|
|
newWorld.start();
|
|
|
|
this.world = newWorld;
|
|
|
|
} catch (err: unknown) {
|
|
|
|
const error = err as Error;
|
|
|
|
this.$notify(
|
|
|
|
{
|
|
|
|
group: "alert",
|
|
|
|
type: "danger",
|
|
|
|
title: "Mounting Error",
|
|
|
|
text: error.message,
|
|
|
|
},
|
|
|
|
-1,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public captureGraphics() {
|
|
|
|
/**
|
|
|
|
* This yields an SVG that only shows white and black highlights
|
|
|
|
// from https://stackoverflow.com/questions/27632621/exporting-from-three-js-scene-to-svg-or-other-vector-format
|
|
|
|
**/
|
|
|
|
const rendererSVG = new SVGRenderer();
|
|
|
|
rendererSVG.setSize(window.innerWidth, window.innerHeight);
|
|
|
|
rendererSVG.render(this.world.scene, this.world.camera);
|
|
|
|
ExportToSVG(rendererSVG, "test.svg");
|
|
|
|
}
|
|
|
|
|
|
|
|
public setWorldProperty(propertyName: string, propertyValue: number) {
|
|
|
|
this.worldProperties[propertyName] = propertyValue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function ExportToSVG(rendererSVG: RendererSVGType, filename: string) {
|
|
|
|
const XMLS = new XMLSerializer();
|
|
|
|
const svgfile = XMLS.serializeToString(rendererSVG.domElement);
|
|
|
|
const svgData = svgfile;
|
|
|
|
const preface = '<?xml version="1.0" standalone="no"?>\r\n';
|
|
|
|
const svgBlob = new Blob([preface, svgData], {
|
|
|
|
type: "image/svg+xml;charset=utf-8",
|
|
|
|
});
|
|
|
|
const svgUrl = URL.createObjectURL(svgBlob);
|
|
|
|
const downloadLink = document.createElement("a");
|
|
|
|
|
|
|
|
downloadLink.href = svgUrl;
|
|
|
|
downloadLink.download = filename;
|
|
|
|
document.body.appendChild(downloadLink);
|
|
|
|
downloadLink.click();
|
|
|
|
document.body.removeChild(downloadLink);
|
|
|
|
}
|
|
|
|
</script>
|