Rework SVGRect and Doors

This commit is contained in:
Jörn-Michael Miehe 2023-09-22 19:02:51 +00:00
parent de5fff311c
commit cfea9b051f
3 changed files with 89 additions and 76 deletions

View file

@ -1,5 +1,10 @@
<template> <template>
<SVGRect :rectangle="door.position" @click.left="on_click" /> <SVGRect
style="cursor: pointer"
:rectangle="door.position"
@click.left="on_click"
>
</SVGRect>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -32,9 +37,3 @@ export default class extends Vue {
} }
} }
</script> </script>
<style scoped>
rect {
cursor: pointer;
}
</style>

View file

@ -1,5 +1,22 @@
<template> <template>
<foreignObject
:x="Math.round(parent_aspect_ratio * rectangle.left)"
:y="rectangle.top"
:width="Math.round(parent_aspect_ratio * rectangle.width)"
:height="rectangle.height"
:style="`transform: scaleX(${1 / parent_aspect_ratio})`"
>
<div
v-if="variant !== undefined"
xmlns="http://www.w3.org/1999/xhtml"
class="px-4 is-flex is-align-items-center is-justify-content-center is-size-1 has-text-weight-bold"
>
<slot name="default" />
</div>
</foreignObject>
<rect <rect
ref="rect"
v-bind="$attrs"
:class="variant !== undefined ? variant : ''" :class="variant !== undefined ? variant : ''"
:x="rectangle.left" :x="rectangle.left"
:y="rectangle.top" :y="rectangle.top"
@ -12,7 +29,13 @@
import { Rectangle } from "@/lib/rectangle"; import { Rectangle } from "@/lib/rectangle";
import { Options, Vue } from "vue-class-component"; import { Options, Vue } from "vue-class-component";
type RectColor = "primary" | "link" | "info" | "success" | "warning" | "danger"; type BulmaVariant =
| "primary"
| "link"
| "info"
| "success"
| "warning"
| "danger";
@Options({ @Options({
props: { props: {
@ -24,14 +47,56 @@ type RectColor = "primary" | "link" | "info" | "success" | "warning" | "danger";
}, },
}) })
export default class extends Vue { export default class extends Vue {
public variant?: RectColor; public variant?: BulmaVariant;
public rectangle!: Rectangle; public rectangle!: Rectangle;
private refreshKey = 0;
declare $refs: {
rect: unknown;
};
private refresh() {
window.setTimeout(() => {
// don't loop endlessly
if (this.refreshKey < 10000) {
this.refreshKey++;
}
}, 100);
}
public get parent_aspect_ratio(): number {
this.refreshKey; // read it just to force recompute on change
if (
!(this.$refs.rect instanceof SVGRectElement) ||
this.$refs.rect.parentElement === null
) {
this.refresh();
return 1;
}
const parent = this.$refs.rect.parentElement;
const result = parent.clientWidth / parent.clientHeight;
// force recompute for suspicious results
if (result === 0 || result === Infinity) {
this.refresh();
return 1;
}
return result;
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "@/bulma-vars"; @import "@/bulma-vars";
foreignObject > div {
height: inherit;
}
rect { rect {
fill: transparent; fill: transparent;
fill-opacity: 0.3; fill-opacity: 0.3;

View file

@ -1,35 +1,24 @@
<template> <template>
<SVGRect <SVGRect
style="cursor: text"
:rectangle="door.position" :rectangle="door.position"
:variant="editing ? 'success' : 'primary'" :variant="editing ? 'success' : 'primary'"
/> @click.left="on_click"
<foreignObject
:x="Math.round(parent_aspect_ratio * door.position.left)"
:y="door.position.top"
:width="Math.round(parent_aspect_ratio * door.position.width)"
:height="door.position.height"
:style="`transform: scaleX(${1 / parent_aspect_ratio})`"
> >
<div <input
xmlns="http://www.w3.org/1999/xhtml" v-if="editing"
class="px-4 is-flex is-align-items-center is-justify-content-center" v-model="day_str"
@click.left="on_click" ref="day_input"
> class="input is-large"
<input type="number"
v-if="editing" :min="MIN_DAY"
v-model="day_str" placeholder="Tag"
ref="day_input" @keydown="on_keydown"
class="input is-large" />
type="number" <div v-else class="has-text-danger">
:min="MIN_DAY" {{ door.day > 0 ? door.day : "*" }}
placeholder="Tag"
@keydown="on_keydown"
/>
<div v-else class="is-size-1 has-text-weight-bold has-text-danger">
{{ door.day > 0 ? door.day : "*" }}
</div>
</div> </div>
</foreignObject> </SVGRect>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -52,48 +41,18 @@ export default class extends Vue {
public day_str = ""; public day_str = "";
public editing = false; public editing = false;
private refreshKey = 0;
declare $refs: { declare $refs: {
day_input: HTMLInputElement | unknown; day_input: HTMLInputElement | unknown;
}; };
private refresh() {
window.setTimeout(() => {
// don't loop endlessly
if (this.refreshKey < 10000) {
this.refreshKey++;
}
}, 100);
}
public get parent_aspect_ratio(): number {
this.refreshKey; // read it just to force recompute on change
if (!(this.$el instanceof Text) || this.$el.parentElement === null) {
this.refresh();
return 1;
}
const parent = this.$el.parentElement;
const result = parent.clientWidth / parent.clientHeight;
// force recompute for suspicious results
if (result === 0 || result === Infinity) {
this.refresh();
return 1;
}
return result;
}
private toggle_editing() { private toggle_editing() {
this.day_str = String(this.door.day); this.day_str = String(this.door.day);
this.editing = !this.editing; this.editing = !this.editing;
} }
public on_click(event: MouseEvent) { public on_click(event: MouseEvent) {
if (event.target === null || !(event.target instanceof HTMLDivElement)) { if (event.target === null || !(event.target instanceof SVGRectElement)) {
return; return;
} }
@ -131,13 +90,3 @@ export default class extends Vue {
} }
} }
</script> </script>
<style lang="scss" scoped>
foreignObject {
cursor: text;
> div {
height: inherit;
}
}
</style>