forked from profectus/Profectus
Made node positions more general purpose
This commit is contained in:
parent
0acfebb412
commit
b60d170657
7 changed files with 51 additions and 25 deletions
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 = [];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue