2021-08-19 00:25:49 -05:00
|
|
|
<template>
|
|
|
|
<g
|
|
|
|
class="boardnode"
|
2021-08-20 00:47:56 -05:00
|
|
|
:style="{ opacity: dragging?.id === node.id ? 0.5 : 1 }"
|
2021-08-19 00:25:49 -05:00
|
|
|
:transform="`translate(${position.x},${position.y})`"
|
2021-08-20 00:47:56 -05:00
|
|
|
@mouseenter="mouseEnter"
|
|
|
|
@mouseleave="mouseLeave"
|
|
|
|
@mousedown="e => $emit('startDragging', e, node.id)"
|
2021-08-19 00:25:49 -05:00
|
|
|
>
|
2021-08-20 00:47:56 -05:00
|
|
|
<circle
|
|
|
|
v-if="canAccept"
|
|
|
|
:r="size + 8"
|
|
|
|
:fill="backgroundColor"
|
|
|
|
:stroke="receivingNode ? '#0F0' : '#0F03'"
|
|
|
|
:stroke-width="2"
|
|
|
|
/>
|
2021-08-19 00:25:49 -05:00
|
|
|
|
|
|
|
<circle :r="size" :fill="fillColor" :stroke="outlineColor" :stroke-width="4" />
|
|
|
|
|
|
|
|
<circle
|
|
|
|
v-if="progressDisplay === ProgressDisplay.Fill"
|
|
|
|
:r="size * progress"
|
|
|
|
:fill="progressColor"
|
|
|
|
/>
|
|
|
|
<circle
|
|
|
|
v-else
|
|
|
|
:r="size + 4.5"
|
|
|
|
class="progressRing"
|
|
|
|
fill="transparent"
|
|
|
|
:stroke-dasharray="(size + 4.5) * 2 * Math.PI"
|
|
|
|
:stroke-width="5"
|
|
|
|
:stroke-dashoffset="(size + 4.5) * 2 * Math.PI - progress * (size + 4.5) * 2 * Math.PI"
|
|
|
|
:stroke="progressColor"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<text :fill="titleColor" class="node-title">{{ title }}</text>
|
|
|
|
</g>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import themes from "@/data/themes";
|
|
|
|
import { ProgressDisplay } from "@/game/enums";
|
|
|
|
import player from "@/game/player";
|
|
|
|
import { BoardNode, NodeType } from "@/typings/features/board";
|
2021-08-20 00:47:56 -05:00
|
|
|
import { getNodeTypeProperty } from "@/util/features";
|
2021-08-19 00:25:49 -05:00
|
|
|
import { InjectLayerMixin } from "@/util/vue";
|
|
|
|
import { defineComponent, PropType } from "vue";
|
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
name: "BoardNode",
|
|
|
|
mixins: [InjectLayerMixin],
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
ProgressDisplay,
|
|
|
|
lastMousePosition: { x: 0, y: 0 },
|
2021-08-20 00:47:56 -05:00
|
|
|
hovering: false
|
2021-08-19 00:25:49 -05:00
|
|
|
};
|
|
|
|
},
|
2021-08-20 00:47:56 -05:00
|
|
|
emits: ["startDragging", "endDragging"],
|
2021-08-19 00:25:49 -05:00
|
|
|
props: {
|
|
|
|
node: {
|
|
|
|
type: Object as PropType<BoardNode>,
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
nodeType: {
|
|
|
|
type: Object as PropType<NodeType>,
|
|
|
|
required: true
|
2021-08-20 00:47:56 -05:00
|
|
|
},
|
|
|
|
dragging: {
|
|
|
|
type: Object as PropType<BoardNode>
|
|
|
|
},
|
|
|
|
dragged: {
|
|
|
|
type: Object as PropType<{ x: number; y: number }>,
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
receivingNode: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
2021-08-19 00:25:49 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
draggable(): boolean {
|
2021-08-20 00:47:56 -05:00
|
|
|
return getNodeTypeProperty(this.nodeType, this.node, "draggable");
|
2021-08-19 00:25:49 -05:00
|
|
|
},
|
|
|
|
position(): { x: number; y: number } {
|
2021-08-20 00:47:56 -05:00
|
|
|
return this.draggable && this.dragging?.id === this.node.id
|
2021-08-19 00:25:49 -05:00
|
|
|
? {
|
|
|
|
x: this.node.position.x + Math.round(this.dragged.x / 25) * 25,
|
|
|
|
y: this.node.position.y + Math.round(this.dragged.y / 25) * 25
|
|
|
|
}
|
|
|
|
: this.node.position;
|
|
|
|
},
|
|
|
|
size(): number {
|
2021-08-20 00:47:56 -05:00
|
|
|
let size: number = getNodeTypeProperty(this.nodeType, this.node, "size");
|
|
|
|
if (this.receivingNode) {
|
|
|
|
size *= 1.25;
|
|
|
|
} else if (this.hovering) {
|
|
|
|
size *= 1.15;
|
|
|
|
}
|
|
|
|
return size;
|
2021-08-19 00:25:49 -05:00
|
|
|
},
|
|
|
|
title(): string {
|
2021-08-20 00:47:56 -05:00
|
|
|
return getNodeTypeProperty(this.nodeType, this.node, "title");
|
2021-08-19 00:25:49 -05:00
|
|
|
},
|
|
|
|
progress(): number {
|
2021-08-20 00:47:56 -05:00
|
|
|
return getNodeTypeProperty(this.nodeType, this.node, "progress") || 0;
|
2021-08-19 00:25:49 -05:00
|
|
|
},
|
|
|
|
backgroundColor(): string {
|
|
|
|
return themes[player.theme].variables["--background"];
|
|
|
|
},
|
|
|
|
outlineColor(): string {
|
|
|
|
return (
|
2021-08-20 00:47:56 -05:00
|
|
|
getNodeTypeProperty(this.nodeType, this.node, "outlineColor") ||
|
2021-08-19 00:25:49 -05:00
|
|
|
themes[player.theme].variables["--separator"]
|
|
|
|
);
|
|
|
|
},
|
|
|
|
fillColor(): string {
|
|
|
|
return (
|
2021-08-20 00:47:56 -05:00
|
|
|
getNodeTypeProperty(this.nodeType, this.node, "fillColor") ||
|
2021-08-19 00:25:49 -05:00
|
|
|
themes[player.theme].variables["--secondary-background"]
|
|
|
|
);
|
|
|
|
},
|
|
|
|
progressColor(): string {
|
2021-08-20 00:47:56 -05:00
|
|
|
return getNodeTypeProperty(this.nodeType, this.node, "progressColor") || "none";
|
2021-08-19 00:25:49 -05:00
|
|
|
},
|
|
|
|
titleColor(): string {
|
|
|
|
return (
|
2021-08-20 00:47:56 -05:00
|
|
|
getNodeTypeProperty(this.nodeType, this.node, "titleColor") ||
|
2021-08-19 00:25:49 -05:00
|
|
|
themes[player.theme].variables["--color"]
|
|
|
|
);
|
|
|
|
},
|
|
|
|
progressDisplay(): ProgressDisplay {
|
|
|
|
return (
|
2021-08-20 00:47:56 -05:00
|
|
|
getNodeTypeProperty(this.nodeType, this.node, "progressDisplay") ||
|
2021-08-19 00:25:49 -05:00
|
|
|
ProgressDisplay.Outline
|
|
|
|
);
|
2021-08-20 00:47:56 -05:00
|
|
|
},
|
|
|
|
canAccept(): boolean {
|
|
|
|
if (this.dragging == null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return typeof this.nodeType.canAccept === "boolean"
|
|
|
|
? this.nodeType.canAccept
|
|
|
|
: this.nodeType.canAccept(this.node, this.dragging);
|
2021-08-19 00:25:49 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2021-08-20 00:47:56 -05:00
|
|
|
mouseEnter() {
|
|
|
|
this.hovering = true;
|
2021-08-19 00:25:49 -05:00
|
|
|
},
|
2021-08-20 00:47:56 -05:00
|
|
|
mouseLeave() {
|
|
|
|
this.hovering = false;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
onDraggableChanged() {
|
|
|
|
if (this.dragging && !this.draggable) {
|
|
|
|
this.$emit("endDragging", this.node.id);
|
2021-08-19 00:25:49 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
.boardnode {
|
|
|
|
cursor: pointer;
|
|
|
|
transition-duration: 0s;
|
|
|
|
}
|
|
|
|
|
|
|
|
.node-title {
|
|
|
|
text-anchor: middle;
|
|
|
|
dominant-baseline: middle;
|
|
|
|
font-family: monospace;
|
|
|
|
font-size: 200%;
|
|
|
|
}
|
|
|
|
|
|
|
|
.progressRing {
|
|
|
|
transform: rotate(-90deg);
|
|
|
|
}
|
|
|
|
</style>
|