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;
|
const useHeader = projInfo.useHeader;
|
||||||
|
|
||||||
function gatherLayerProps(layer: GenericLayer) {
|
function gatherLayerProps(layer: GenericLayer) {
|
||||||
const { display, minimized, minWidth, name, color, style, classes, links, minimizable } = layer;
|
const { display, minimized, minWidth, name, color, style, classes, links, minimizable, nodes } =
|
||||||
return { display, minimized, minWidth, name, color, style, classes, links, minimizable };
|
layer;
|
||||||
|
return { display, minimized, minWidth, name, color, style, classes, links, minimizable, nodes };
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
:class="[{ showGoBack }, unref(classes)]"
|
:class="[{ showGoBack }, unref(classes)]"
|
||||||
v-else
|
v-else
|
||||||
>
|
>
|
||||||
<Links :links="unref(links)">
|
<Links :links="unref(links)" ref="linksRef">
|
||||||
<component :is="component" />
|
<component :is="component" />
|
||||||
</Links>
|
</Links>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,11 +24,11 @@
|
||||||
import Links from "components/links/Links.vue";
|
import Links from "components/links/Links.vue";
|
||||||
import projInfo from "data/projInfo.json";
|
import projInfo from "data/projInfo.json";
|
||||||
import { CoercableComponent, StyleValue } from "features/feature";
|
import { CoercableComponent, StyleValue } from "features/feature";
|
||||||
import { Link } from "features/links";
|
import { Link, LinkNode } from "features/links";
|
||||||
import { PersistentRef } from "game/persistence";
|
import { PersistentRef } from "game/persistence";
|
||||||
import player from "game/player";
|
import player from "game/player";
|
||||||
import { computeComponent, processedPropType, wrapRef } from "util/vue";
|
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({
|
export default defineComponent({
|
||||||
components: { Links },
|
components: { Links },
|
||||||
|
@ -61,7 +61,11 @@ export default defineComponent({
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
style: processedPropType<StyleValue>(String, Object, Array),
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
classes: processedPropType<Record<string, boolean>>(Object),
|
||||||
links: processedPropType<Link[]>(Array),
|
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) {
|
setup(props) {
|
||||||
const { display, index, minimized, minWidth, tab } = toRefs(props);
|
const { display, index, minimized, minWidth, tab } = toRefs(props);
|
||||||
|
@ -80,6 +84,16 @@ export default defineComponent({
|
||||||
updateTab(minimized, minWidth)
|
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) {
|
function updateTab(minimized: boolean, minWidth: number) {
|
||||||
const tabValue = tab.value();
|
const tabValue = tab.value();
|
||||||
if (tabValue != undefined) {
|
if (tabValue != undefined) {
|
||||||
|
@ -102,6 +116,7 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
component,
|
component,
|
||||||
showGoBack,
|
showGoBack,
|
||||||
|
linksRef,
|
||||||
unref,
|
unref,
|
||||||
goBack
|
goBack
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
<slot name="header" :shown="isOpen"> default header </slot>
|
<slot name="header" :shown="isOpen"> default header </slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<Links v-if="links" :links="links">
|
<Links :links="links" ref="linksRef">
|
||||||
<slot name="body" :shown="isOpen"> default body </slot>
|
<slot name="body" :shown="isOpen"> default body </slot>
|
||||||
</Links>
|
</Links>
|
||||||
<slot name="body" v-else :shown="isOpen"> default body </slot>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<slot name="footer" :shown="isOpen">
|
<slot name="footer" :shown="isOpen">
|
||||||
|
@ -40,7 +39,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Link } from "features/links";
|
import { Link, LinkNode } from "features/links";
|
||||||
import { computed, ref, toRefs } from "vue";
|
import { computed, ref, toRefs } from "vue";
|
||||||
import Links from "./links/Links.vue";
|
import Links from "./links/Links.vue";
|
||||||
|
|
||||||
|
@ -60,7 +59,12 @@ function close() {
|
||||||
|
|
||||||
const isAnimating = ref(false);
|
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>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
import {
|
import {
|
||||||
Link,
|
Link,
|
||||||
LinkNode,
|
LinkNode,
|
||||||
|
NodesInjectionKey,
|
||||||
RegisterLinkNodeInjectionKey,
|
RegisterLinkNodeInjectionKey,
|
||||||
UnregisterLinkNodeInjectionKey
|
UnregisterLinkNodeInjectionKey
|
||||||
} from "features/links";
|
} from "features/links";
|
||||||
|
@ -30,6 +31,8 @@ const resizeObserver = new ResizeObserver(updateNodes);
|
||||||
|
|
||||||
const nodes = ref<Record<string, LinkNode | undefined>>({});
|
const nodes = ref<Record<string, LinkNode | undefined>>({});
|
||||||
|
|
||||||
|
defineExpose({ nodes });
|
||||||
|
|
||||||
const resizeListener = ref<Element | null>(null);
|
const resizeListener = ref<Element | null>(null);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -71,6 +74,7 @@ provide(RegisterLinkNodeInjectionKey, (id, element) => {
|
||||||
provide(UnregisterLinkNodeInjectionKey, id => {
|
provide(UnregisterLinkNodeInjectionKey, id => {
|
||||||
nodes.value[id] = undefined;
|
nodes.value[id] = undefined;
|
||||||
});
|
});
|
||||||
|
provide(NodesInjectionKey, nodes);
|
||||||
|
|
||||||
let isDirty = true;
|
let isDirty = true;
|
||||||
let boundingRect = resizeListener.value?.getBoundingClientRect();
|
let boundingRect = resizeListener.value?.getBoundingClientRect();
|
||||||
|
@ -90,10 +94,11 @@ function updateNode(id: string) {
|
||||||
if (!node || boundingRect == null) {
|
if (!node || boundingRect == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const linkStartRect = node.element.getBoundingClientRect();
|
const nodeRect = node.element.getBoundingClientRect();
|
||||||
|
|
||||||
node.x = linkStartRect.x + linkStartRect.width / 2 - boundingRect.x;
|
node.y = nodeRect.x + nodeRect.width / 2 - boundingRect.x;
|
||||||
node.y = linkStartRect.y + linkStartRect.height / 2 - boundingRect.y;
|
node.x = nodeRect.y + nodeRect.height / 2 - boundingRect.y;
|
||||||
|
node.rect = nodeRect;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Position } from "game/layers";
|
import { Position } from "game/layers";
|
||||||
import { InjectionKey, SVGAttributes } from "vue";
|
import { InjectionKey, Ref, SVGAttributes } from "vue";
|
||||||
|
|
||||||
export interface LinkNode {
|
export interface LinkNode {
|
||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
|
rect?: DOMRect;
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,3 +20,5 @@ export const RegisterLinkNodeInjectionKey: InjectionKey<
|
||||||
> = Symbol("RegisterLinkNode");
|
> = Symbol("RegisterLinkNode");
|
||||||
export const UnregisterLinkNodeInjectionKey: InjectionKey<(id: string) => void> =
|
export const UnregisterLinkNodeInjectionKey: InjectionKey<(id: string) => void> =
|
||||||
Symbol("UnregisterLinkNode");
|
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 { IEmitter } from "tsparticles-plugin-emitters/Options/Interfaces/IEmitter";
|
||||||
import { EmitterInstance } from "tsparticles-plugin-emitters/EmitterInstance";
|
import { EmitterInstance } from "tsparticles-plugin-emitters/EmitterInstance";
|
||||||
import { EmitterContainer } from "tsparticles-plugin-emitters/EmitterContainer";
|
import { EmitterContainer } from "tsparticles-plugin-emitters/EmitterContainer";
|
||||||
import { ICoordinates } from "tsparticles-engine";
|
|
||||||
import { Ref, shallowRef } from "vue";
|
import { Ref, shallowRef } from "vue";
|
||||||
import { registerGameComponent } from "game/settings";
|
import { registerGameComponent } from "game/settings";
|
||||||
import { jsx } from "features/feature";
|
import { jsx } from "features/feature";
|
||||||
|
@ -14,18 +13,17 @@ const containerRef: Ref<null | EmitterContainer> = shallowRef(null);
|
||||||
let emittersToAdd: {
|
let emittersToAdd: {
|
||||||
resolve: (value: EmitterInstance | PromiseLike<EmitterInstance>) => void;
|
resolve: (value: EmitterInstance | PromiseLike<EmitterInstance>) => void;
|
||||||
options: IEmitter & { particles: Required<IEmitter>["particles"] };
|
options: IEmitter & { particles: Required<IEmitter>["particles"] };
|
||||||
position: ICoordinates;
|
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
export function addEmitter(
|
export function addEmitter(
|
||||||
options: IEmitter & { particles: Required<IEmitter>["particles"] },
|
options: IEmitter & { particles: Required<IEmitter>["particles"] }
|
||||||
position: ICoordinates
|
|
||||||
): Promise<EmitterInstance> {
|
): Promise<EmitterInstance> {
|
||||||
if (containerRef.value) {
|
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 => {
|
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) {
|
function onInit(container: EmitterContainer) {
|
||||||
containerRef.value = container;
|
containerRef.value = container;
|
||||||
emittersToAdd.forEach(({ resolve, options, position }) =>
|
emittersToAdd.forEach(({ resolve, options }) => resolve(container.addEmitter(options)));
|
||||||
resolve(container.addEmitter(options, position))
|
|
||||||
);
|
|
||||||
emittersToAdd = [];
|
emittersToAdd = [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
setDefault,
|
setDefault,
|
||||||
StyleValue
|
StyleValue
|
||||||
} from "features/feature";
|
} from "features/feature";
|
||||||
import { Link } from "features/links";
|
import { Link, LinkNode } from "features/links";
|
||||||
import {
|
import {
|
||||||
Computable,
|
Computable,
|
||||||
GetComputableType,
|
GetComputableType,
|
||||||
|
@ -17,7 +17,7 @@ import {
|
||||||
} from "util/computed";
|
} from "util/computed";
|
||||||
import { createLazyProxy } from "util/proxies";
|
import { createLazyProxy } from "util/proxies";
|
||||||
import { createNanoEvents, Emitter } from "nanoevents";
|
import { createNanoEvents, Emitter } from "nanoevents";
|
||||||
import { ref, unref } from "vue";
|
import { Ref, ref, unref } from "vue";
|
||||||
import { globalBus } from "./events";
|
import { globalBus } from "./events";
|
||||||
import { persistent, PersistentRef } from "./persistence";
|
import { persistent, PersistentRef } from "./persistence";
|
||||||
import player from "./player";
|
import player from "./player";
|
||||||
|
@ -63,6 +63,7 @@ export interface BaseLayer {
|
||||||
emitter: Emitter<LayerEvents>;
|
emitter: Emitter<LayerEvents>;
|
||||||
on: OmitThisParameter<Emitter<LayerEvents>["on"]>;
|
on: OmitThisParameter<Emitter<LayerEvents>["on"]>;
|
||||||
emit: <K extends keyof LayerEvents>(event: K, ...args: Parameters<LayerEvents[K]>) => void;
|
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<
|
export type Layer<T extends LayerOptions> = Replace<
|
||||||
|
@ -97,6 +98,7 @@ export function createLayer<T extends LayerOptions>(
|
||||||
const emitter = (layer.emitter = createNanoEvents<LayerEvents>());
|
const emitter = (layer.emitter = createNanoEvents<LayerEvents>());
|
||||||
layer.on = emitter.on.bind(emitter);
|
layer.on = emitter.on.bind(emitter);
|
||||||
layer.emit = emitter.emit.bind(emitter);
|
layer.emit = emitter.emit.bind(emitter);
|
||||||
|
layer.nodes = ref({});
|
||||||
|
|
||||||
layer.minimized = persistent(false);
|
layer.minimized = persistent(false);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue