feat: double click on surface to add a point

feat/type-attributes
Tomáš Mládek 2023-01-24 19:29:35 +01:00
parent 1539860da8
commit c690992f93
1 changed files with 74 additions and 26 deletions

View File

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import UpObject from "../components/display/UpObject.svelte"; import UpObject from "../components/display/UpObject.svelte";
import { queryOnce } from "../lib/api"; import { putEntityAttribute, putEntry, queryOnce } from "../lib/api";
import Selector from "../components/utils/Selector.svelte"; import Selector from "../components/utils/Selector.svelte";
import { onMount } from "svelte"; import { onMount } from "svelte";
import type { ZoomTransform } from "d3"; import type { ZoomTransform } from "d3";
@ -8,6 +8,7 @@
import UpObjectCard from "../components/display/UpObjectCard.svelte"; import UpObjectCard from "../components/display/UpObjectCard.svelte";
import BlobPreview from "../components/display/BlobPreview.svelte"; import BlobPreview from "../components/display/BlobPreview.svelte";
import { i18n } from "../i18n"; import { i18n } from "../i18n";
import type { IValue } from "upend/types";
const urlSearch = window.location.href.substring( const urlSearch = window.location.href.substring(
window.location.href.indexOf("?") window.location.href.indexOf("?")
@ -31,29 +32,34 @@
y: number; y: number;
} }
let points: IPoint[] = []; let points: IPoint[] = [];
async function loadPoints() {
points = [];
const result = await queryOnce(`(matches ? (in "${x}" "${y}") ?)`);
points = Object.entries(result.objects)
.map(([address, obj]) => {
let objX = parseInt(String(obj.get(x)));
let objY = parseInt(String(obj.get(y)));
if (objX && objY) {
return {
address,
x: objX,
y: objY,
};
}
})
.filter(Boolean);
}
$: { $: {
if (x && y) { if (x && y) {
points = []; loadPoints();
queryOnce(`(matches ? (in "${x}" "${y}") ?)`).then((result) => {
points = Object.entries(result.objects)
.map(([address, obj]) => {
let objX = parseInt(String(obj.get(x)));
let objY = parseInt(String(obj.get(y)));
if (objX && objY) {
return {
address,
x: objX,
y: objY,
};
}
})
.filter(Boolean);
});
} }
} }
let selectorCoords: [number, number] | null = null;
onMount(async () => { onMount(async () => {
const d3 = await import("d3"); const d3 = await import("d3");
@ -96,7 +102,7 @@
.on("zoom", zoomed); .on("zoom", zoomed);
function zoomed({ transform }: { transform: ZoomTransform }) { function zoomed({ transform }: { transform: ZoomTransform }) {
const points = d3.select(".points"); const points = d3.select(".content");
points.style( points.style(
"transform", "transform",
`translate(${transform.x}px, ${transform.y}px) scale(${transform.k})` `translate(${transform.x}px, ${transform.y}px) scale(${transform.k})`
@ -116,15 +122,40 @@
// not using offsetXY because `translate` transforms on .inner mess it up // not using offsetXY because `translate` transforms on .inner mess it up
const viewBBox = (view.node() as HTMLElement).getBoundingClientRect(); const viewBBox = (view.node() as HTMLElement).getBoundingClientRect();
const [x, y] = d3 const [x, y] = d3
.zoomTransform(d3.select(".points").node() as HTMLElement) .zoomTransform(d3.select(".content").node() as HTMLElement)
.invert([ev.clientX - viewBBox.left, ev.clientY - viewBBox.top]); .invert([ev.clientX - viewBBox.left, ev.clientY - viewBBox.top]);
currentX = xScale.invert(x); currentX = xScale.invert(x);
currentY = yScale.invert(y); currentY = yScale.invert(y);
}); });
d3.select(".view").call(zoom); d3.select(".view")
.call(zoom)
.on("dblclick.zoom", (ev: MouseEvent) => {
selectorCoords = [currentX, currentY];
});
loaded = true; loaded = true;
}); });
async function onSelectorInput(ev: CustomEvent<IValue>) {
const [xValue, yValue] = selectorCoords;
selectorCoords = null;
console.log("HERE");
await Promise.all(
[
[x, xValue],
[y, yValue],
].map(([axis, value]: [string, number]) =>
putEntityAttribute(ev.detail.c as string, axis, {
t: "Number",
c: value,
})
)
);
console.log("THERE");
await loadPoints();
console.log("OVERHER");
}
</script> </script>
<div class="surface"> <div class="surface">
@ -147,14 +178,14 @@
{$i18n.t("Current position")}: {$i18n.t("Current position")}:
<div class="label"> <div class="label">
<em>X:</em> <em>X:</em>
{x} = {(Math.round(currentX * 100) / 100).toLocaleString("en", { {x || "?"} = {(Math.round(currentX * 100) / 100).toLocaleString("en", {
useGrouping: false, useGrouping: false,
minimumFractionDigits: 2, minimumFractionDigits: 2,
})} })}
</div> </div>
<div class="label"> <div class="label">
<em>Y:</em> <em>Y:</em>
{y} = {(Math.round(currentY * 100) / 100).toLocaleString("en", { {y || "?"} = {(Math.round(currentY * 100) / 100).toLocaleString("en", {
useGrouping: false, useGrouping: false,
minimumFractionDigits: 2, minimumFractionDigits: 2,
})} })}
@ -172,7 +203,24 @@
<Spinner centered="absolute" /> <Spinner centered="absolute" />
</div> </div>
{/if} {/if}
<div class="points"> <div class="content">
{#if selectorCoords !== null}
<div
class="point selector"
style="
left: {selectorCoords[0]}px;
top: {viewHeight - selectorCoords[1]}px"
>
<Selector
type="value"
valueTypes={["Address"]}
on:input={onSelectorInput}
on:focus={(ev) => {
if (!ev.detail) selectorCoords = null;
}}
/>
</div>
{/if}
{#each points as point} {#each points as point}
<div <div
class="point" class="point"
@ -180,7 +228,7 @@
> >
<div class="inner"> <div class="inner">
{#if viewMode == "link"} {#if viewMode == "link"}
<UpObject point link address={point.address} /> <UpObject link address={point.address} />
{:else if viewMode == "card"} {:else if viewMode == "card"}
<UpObjectCard address={point.address} /> <UpObjectCard address={point.address} />
{:else if viewMode == "preview"} {:else if viewMode == "preview"}
@ -239,7 +287,7 @@
font-size: 1rem; font-size: 1rem;
} }
.points { .content {
transform-origin: 0 0; transform-origin: 0 0;
} }