201 lines
4.1 KiB
Vue
201 lines
4.1 KiB
Vue
|
<template>
|
||
|
<div class="compass-widget">
|
||
|
<div class="compass-row-helper">
|
||
|
<div class="compass-label compass-label-left">{{ leftLabel }}</div>
|
||
|
<div class="compass-container">
|
||
|
<div class="compass-label compass-label-top">{{ topLabel }}</div>
|
||
|
<div class="compass">
|
||
|
<div class="compass-x-axis"></div>
|
||
|
<div class="compass-y-axis"></div>
|
||
|
<div
|
||
|
class="compass-marker compass-select-marker"
|
||
|
:style="{
|
||
|
bottom: markerBottom,
|
||
|
left: markerLeft,
|
||
|
}"
|
||
|
></div>
|
||
|
<div class="context-markers"></div>
|
||
|
</div>
|
||
|
<div class="compass-label compass-label-bottom">{{ bottomLabel }}</div>
|
||
|
</div>
|
||
|
<div class="compass-label compass-label-right">{{ rightLabel }}</div>
|
||
|
</div>
|
||
|
|
||
|
<div class="compass-fields">
|
||
|
<div class="compass-field">
|
||
|
<label for="compass_field_x_{{ widget.name }}">
|
||
|
{{ xLabel }}
|
||
|
</label>
|
||
|
<input
|
||
|
type="number"
|
||
|
v-model.number="xVal"
|
||
|
:min="-xRange"
|
||
|
:max="xRange"
|
||
|
/>
|
||
|
</div>
|
||
|
<div class="compass-field">
|
||
|
<label for="compass_field_y_{{ widget.name }}">
|
||
|
{{ yLabel }}
|
||
|
</label>
|
||
|
<input
|
||
|
type="number"
|
||
|
v-model.number="yVal"
|
||
|
:min="-yRange"
|
||
|
:max="yRange"
|
||
|
/>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts">
|
||
|
import { asDict } from "@/lib/entity";
|
||
|
import { IEntry } from "@/types/base";
|
||
|
import { defineComponent, PropType, ref } from "vue";
|
||
|
|
||
|
export default defineComponent({
|
||
|
name: "Compass",
|
||
|
props: {
|
||
|
attributes: {
|
||
|
type: Array as PropType<[string, IEntry][]>,
|
||
|
required: true,
|
||
|
},
|
||
|
xAttrName: {
|
||
|
type: String,
|
||
|
required: true,
|
||
|
},
|
||
|
yAttrName: {
|
||
|
type: String,
|
||
|
required: true,
|
||
|
},
|
||
|
xLabel: {
|
||
|
type: String,
|
||
|
default: "X",
|
||
|
},
|
||
|
yLabel: {
|
||
|
type: String,
|
||
|
default: "Y",
|
||
|
},
|
||
|
xRange: {
|
||
|
type: Number,
|
||
|
default: 100,
|
||
|
},
|
||
|
yRange: {
|
||
|
type: Number,
|
||
|
default: 100,
|
||
|
},
|
||
|
},
|
||
|
computed: {
|
||
|
topLabel(): string | undefined {
|
||
|
return this.yLabel.includes("//")
|
||
|
? this.yLabel.split("//")[1]
|
||
|
: undefined;
|
||
|
},
|
||
|
bottomLabel(): string | undefined {
|
||
|
return this.yLabel.includes("//")
|
||
|
? this.yLabel.split("//")[0]
|
||
|
: undefined;
|
||
|
},
|
||
|
leftLabel(): string | undefined {
|
||
|
return this.xLabel.includes("//")
|
||
|
? this.xLabel.split("//")[0]
|
||
|
: undefined;
|
||
|
},
|
||
|
rightLabel(): string | undefined {
|
||
|
return this.xLabel.includes("//")
|
||
|
? this.xLabel.split("//")[1]
|
||
|
: undefined;
|
||
|
},
|
||
|
markerBottom(): string {
|
||
|
return `${((this.yVal + this.yRange) / (this.yRange * 2)) * 100}%`;
|
||
|
},
|
||
|
markerLeft(): string {
|
||
|
return `${((this.xVal + this.xRange) / (this.xRange * 2)) * 100}%`;
|
||
|
},
|
||
|
},
|
||
|
setup(props) {
|
||
|
const attrs = asDict(props.attributes);
|
||
|
const xVal = ref(parseInt(attrs[props.xAttrName]) || -1);
|
||
|
const yVal = ref(parseInt(attrs[props.yAttrName]) || -1);
|
||
|
|
||
|
return {
|
||
|
xVal,
|
||
|
yVal,
|
||
|
};
|
||
|
},
|
||
|
});
|
||
|
</script>
|
||
|
|
||
|
<style lang="scss" scoped>
|
||
|
.compass-container {
|
||
|
width: 100%;
|
||
|
}
|
||
|
|
||
|
.compass {
|
||
|
position: relative;
|
||
|
|
||
|
width: 100%;
|
||
|
padding-top: 100%; /* 1:1 Aspect Ratio */
|
||
|
}
|
||
|
|
||
|
.compass-row-helper {
|
||
|
display: flex;
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
.compass-label {
|
||
|
margin: 0.5em;
|
||
|
text-align: center;
|
||
|
}
|
||
|
|
||
|
.compass-marker {
|
||
|
position: absolute;
|
||
|
width: 1.5%;
|
||
|
height: 1.5%;
|
||
|
background: red;
|
||
|
}
|
||
|
|
||
|
.context-markers div {
|
||
|
opacity: 25%;
|
||
|
}
|
||
|
|
||
|
.compass-x-axis {
|
||
|
position: absolute;
|
||
|
top: 50%;
|
||
|
left: 0;
|
||
|
height: 0;
|
||
|
width: 100%;
|
||
|
border: 1px dashed gray;
|
||
|
}
|
||
|
|
||
|
.compass-y-axis {
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
left: 50%;
|
||
|
width: 0;
|
||
|
height: 100%;
|
||
|
border: 1px dashed gray;
|
||
|
}
|
||
|
|
||
|
.compass-fields {
|
||
|
display: flex;
|
||
|
justify-content: center;
|
||
|
margin: 1rem 0;
|
||
|
|
||
|
.compass-field {
|
||
|
margin: 0 1em;
|
||
|
text-align: center;
|
||
|
|
||
|
label {
|
||
|
display: inline-block;
|
||
|
margin: 0 0.5em;
|
||
|
}
|
||
|
|
||
|
input {
|
||
|
width: 4em;
|
||
|
font-family: monospace;
|
||
|
text-align: left;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</style>
|