Made node positions more general purpose

This commit is contained in:
thepaperpilot 2022-03-20 12:30:08 -05:00
parent 0acfebb412
commit b60d170657
7 changed files with 51 additions and 25 deletions

View file

@ -29,8 +29,9 @@ const layerKeys = computed(() => Object.keys(layers));
const useHeader = projInfo.useHeader;
function gatherLayerProps(layer: GenericLayer) {
const { display, minimized, minWidth, name, color, style, classes, links, minimizable } = layer;
return { display, minimized, minWidth, name, color, style, classes, links, minimizable };
const { display, minimized, minWidth, name, color, style, classes, links, minimizable, nodes } =
layer;
return { display, minimized, minWidth, name, color, style, classes, links, minimizable, nodes };
}
</script>

View file

@ -10,7 +10,7 @@
:class="[{ showGoBack }, unref(classes)]"
v-else
>
<Links :links="unref(links)">
<Links :links="unref(links)" ref="linksRef">
<component :is="component" />
</Links>
</div>
@ -24,11 +24,11 @@
import Links from "components/links/Links.vue";
import projInfo from "data/projInfo.json";
import { CoercableComponent, StyleValue } from "features/feature";
import { Link } from "features/links";
import { Link, LinkNode } from "features/links";
import { PersistentRef } from "game/persistence";
import player from "game/player";
import { computeComponent, processedPropType, wrapRef } from "util/vue";
import { computed, defineComponent, nextTick, PropType, toRefs, unref, watch } from "vue";
import { computed, defineComponent, nextTick, PropType, Ref, ref, toRefs, unref, watch } from "vue";
export default defineComponent({
components: { Links },
@ -61,7 +61,11 @@ export default defineComponent({
style: processedPropType<StyleValue>(String, Object, Array),
classes: processedPropType<Record<string, boolean>>(Object),
links: processedPropType<Link[]>(Array),
minimizable: processedPropType<boolean>(Boolean)
minimizable: processedPropType<boolean>(Boolean),
nodes: {
type: Object as PropType<Ref<Record<string, LinkNode | undefined>>>,
required: true
}
},
setup(props) {
const { display, index, minimized, minWidth, tab } = toRefs(props);
@ -80,6 +84,16 @@ export default defineComponent({
updateTab(minimized, minWidth)
);
const linksRef = ref<typeof Links | null>(null);
watch(
() => linksRef.value?.nodes,
nodes => {
if (nodes) {
props.nodes.value = nodes;
}
}
);
function updateTab(minimized: boolean, minWidth: number) {
const tabValue = tab.value();
if (tabValue != undefined) {
@ -102,6 +116,7 @@ export default defineComponent({
return {
component,
showGoBack,
linksRef,
unref,
goBack
};

View file

@ -17,10 +17,9 @@
<slot name="header" :shown="isOpen"> default header </slot>
</div>
<div class="modal-body">
<Links v-if="links" :links="links">
<Links :links="links" ref="linksRef">
<slot name="body" :shown="isOpen"> default body </slot>
</Links>
<slot name="body" v-else :shown="isOpen"> default body </slot>
</div>
<div class="modal-footer">
<slot name="footer" :shown="isOpen">
@ -40,7 +39,7 @@
</template>
<script setup lang="ts">
import { Link } from "features/links";
import { Link, LinkNode } from "features/links";
import { computed, ref, toRefs } from "vue";
import Links from "./links/Links.vue";
@ -60,7 +59,12 @@ function close() {
const isAnimating = ref(false);
defineExpose({ isOpen });
const linksRef = ref<typeof Links | null>(null);
const nodes = computed<Record<string, LinkNode | undefined> | null>(
() => linksRef.value?.nodes ?? null
);
defineExpose({ isOpen, nodes });
</script>
<style>

View file

@ -16,6 +16,7 @@
import {
Link,
LinkNode,
NodesInjectionKey,
RegisterLinkNodeInjectionKey,
UnregisterLinkNodeInjectionKey
} from "features/links";
@ -30,6 +31,8 @@ const resizeObserver = new ResizeObserver(updateNodes);
const nodes = ref<Record<string, LinkNode | undefined>>({});
defineExpose({ nodes });
const resizeListener = ref<Element | null>(null);
onMounted(() => {
@ -71,6 +74,7 @@ provide(RegisterLinkNodeInjectionKey, (id, element) => {
provide(UnregisterLinkNodeInjectionKey, id => {
nodes.value[id] = undefined;
});
provide(NodesInjectionKey, nodes);
let isDirty = true;
let boundingRect = resizeListener.value?.getBoundingClientRect();
@ -90,10 +94,11 @@ function updateNode(id: string) {
if (!node || boundingRect == null) {
return;
}
const linkStartRect = node.element.getBoundingClientRect();
const nodeRect = node.element.getBoundingClientRect();
node.x = linkStartRect.x + linkStartRect.width / 2 - boundingRect.x;
node.y = linkStartRect.y + linkStartRect.height / 2 - boundingRect.y;
node.y = nodeRect.x + nodeRect.width / 2 - boundingRect.x;
node.x = nodeRect.y + nodeRect.height / 2 - boundingRect.y;
node.rect = nodeRect;
}
</script>

View file

@ -1,9 +1,10 @@
import { Position } from "game/layers";
import { InjectionKey, SVGAttributes } from "vue";
import { InjectionKey, Ref, SVGAttributes } from "vue";
export interface LinkNode {
x?: number;
y?: number;
rect?: DOMRect;
element: HTMLElement;
}
@ -19,3 +20,5 @@ export const RegisterLinkNodeInjectionKey: InjectionKey<
> = Symbol("RegisterLinkNode");
export const UnregisterLinkNodeInjectionKey: InjectionKey<(id: string) => void> =
Symbol("UnregisterLinkNode");
export const NodesInjectionKey: InjectionKey<Ref<Record<string, LinkNode | undefined>>> =
Symbol("Nodes");

View file

@ -2,7 +2,6 @@ import ParticlesComponent from "./Particles.vue";
import { IEmitter } from "tsparticles-plugin-emitters/Options/Interfaces/IEmitter";
import { EmitterInstance } from "tsparticles-plugin-emitters/EmitterInstance";
import { EmitterContainer } from "tsparticles-plugin-emitters/EmitterContainer";
import { ICoordinates } from "tsparticles-engine";
import { Ref, shallowRef } from "vue";
import { registerGameComponent } from "game/settings";
import { jsx } from "features/feature";
@ -14,18 +13,17 @@ const containerRef: Ref<null | EmitterContainer> = shallowRef(null);
let emittersToAdd: {
resolve: (value: EmitterInstance | PromiseLike<EmitterInstance>) => void;
options: IEmitter & { particles: Required<IEmitter>["particles"] };
position: ICoordinates;
}[] = [];
export function addEmitter(
options: IEmitter & { particles: Required<IEmitter>["particles"] },
position: ICoordinates
options: IEmitter & { particles: Required<IEmitter>["particles"] }
): Promise<EmitterInstance> {
if (containerRef.value) {
return Promise.resolve(containerRef.value.addEmitter(options, position));
// TODO why does addEmitter require a position parameter
return Promise.resolve(containerRef.value.addEmitter(options));
}
return new Promise<EmitterInstance>(resolve => {
emittersToAdd.push({ resolve, options, position });
emittersToAdd.push({ resolve, options });
});
}
@ -36,8 +34,6 @@ export function removeEmitter(emitter: EmitterInstance) {
function onInit(container: EmitterContainer) {
containerRef.value = container;
emittersToAdd.forEach(({ resolve, options, position }) =>
resolve(container.addEmitter(options, position))
);
emittersToAdd.forEach(({ resolve, options }) => resolve(container.addEmitter(options)));
emittersToAdd = [];
}

View file

@ -7,7 +7,7 @@ import {
setDefault,
StyleValue
} from "features/feature";
import { Link } from "features/links";
import { Link, LinkNode } from "features/links";
import {
Computable,
GetComputableType,
@ -17,7 +17,7 @@ import {
} from "util/computed";
import { createLazyProxy } from "util/proxies";
import { createNanoEvents, Emitter } from "nanoevents";
import { ref, unref } from "vue";
import { Ref, ref, unref } from "vue";
import { globalBus } from "./events";
import { persistent, PersistentRef } from "./persistence";
import player from "./player";
@ -63,6 +63,7 @@ export interface BaseLayer {
emitter: Emitter<LayerEvents>;
on: OmitThisParameter<Emitter<LayerEvents>["on"]>;
emit: <K extends keyof LayerEvents>(event: K, ...args: Parameters<LayerEvents[K]>) => void;
nodes: Ref<Record<string, LinkNode | undefined>>;
}
export type Layer<T extends LayerOptions> = Replace<
@ -97,6 +98,7 @@ export function createLayer<T extends LayerOptions>(
const emitter = (layer.emitter = createNanoEvents<LayerEvents>());
layer.on = emitter.on.bind(emitter);
layer.emit = emitter.emit.bind(emitter);
layer.nodes = ref({});
layer.minimized = persistent(false);