|
1 | 1 | <script lang="ts"> |
2 | 2 | import Icon from "@iconify/svelte"; |
3 | | - import { Body, Box, Edge, Vec2, World } from "planck"; |
| 3 | + import { Body, Box, Edge, MouseJoint, Vec2, World } from "planck"; |
4 | 4 | import { onMount } from "svelte"; |
5 | 5 | import Tooltip from "../utils/Tooltip.svelte"; |
6 | 6 |
|
|
91 | 91 | clearInterval(interval); |
92 | 92 | data.boxes = [] |
93 | 93 | } |
| 94 | +
|
| 95 | + function registerItemDrag(e: PointerEvent, box: Body) { |
| 96 | + let target = e.target as HTMLElement; |
| 97 | + target.setPointerCapture(e.pointerId); |
| 98 | +
|
| 99 | + console.log("dragging", target, box); |
| 100 | +
|
| 101 | + function getTarget(ev: PointerEvent) { |
| 102 | + let fontSize = parseFloat(window.getComputedStyle(target).fontSize); |
| 103 | + let boundingBox = divHolder.getBoundingClientRect(); |
| 104 | + return new Vec2( |
| 105 | + (ev.clientX - boundingBox.left - boundingBox.width / 2) / fontSize / 2, |
| 106 | + -(ev.clientY - boundingBox.bottom) / fontSize / 2 |
| 107 | + ) |
| 108 | + } |
| 109 | +
|
| 110 | + let joint: MouseJoint | null = null; |
| 111 | + world.queueUpdate((world) => { |
| 112 | + joint = new MouseJoint({ |
| 113 | + maxForce: 1000, |
| 114 | + target: getTarget(e), |
| 115 | + bodyA: world.createBody(), |
| 116 | + bodyB: box, |
| 117 | + }); |
| 118 | + world.createJoint(joint); |
| 119 | + }); |
| 120 | +
|
| 121 | + function onBoxPointerMove(ev: PointerEvent) { |
| 122 | + joint?.setTarget(getTarget(ev)); |
| 123 | + } |
| 124 | +
|
| 125 | + function onBoxPointerUp(ev: PointerEvent) { |
| 126 | + world.queueUpdate((world) => { |
| 127 | + if (joint) world.destroyJoint(joint); |
| 128 | + }); |
| 129 | + target.removeEventListener("pointermove", onBoxPointerMove); |
| 130 | + target.removeEventListener("pointerup", onBoxPointerUp); |
| 131 | + } |
| 132 | + |
| 133 | + target.addEventListener("pointermove", onBoxPointerMove); |
| 134 | + target.addEventListener("pointerup", onBoxPointerUp); |
| 135 | + } |
94 | 136 | </script> |
95 | 137 |
|
96 | 138 | <ul class="tech-stack" bind:this={divHolder}> |
97 | 139 | {#each data.boxes as box, index} |
98 | 140 | <li class="tech-stack-box" |
99 | | - style:transform={(data.counter, `translate(${box.getPosition().x * 2}em, ${-box.getPosition().y * 2}em) rotate(${-box.getAngle()}rad)`)} |
100 | | - style:--bg-color={items[index].color} |
101 | | - style:--size={`${items[index].priority}em`} |
102 | | - style={items[index].boxStyle} |
103 | | - aria-label={items[index].name}> |
| 141 | + style:transform={(data.counter, `translate(${box.getPosition().x * 2}em, ${-box.getPosition().y * 2}em) rotate(${-box.getAngle()}rad)`)} |
| 142 | + style:--bg-color={items[index].color} |
| 143 | + style:--size={`${items[index].priority}em`} |
| 144 | + style={items[index].boxStyle} |
| 145 | + aria-label={items[index].name} |
| 146 | + onpointerdown={(e) => registerItemDrag(e, box)} |
| 147 | + > |
104 | 148 | <Tooltip>{items[index].name}</Tooltip> |
105 | 149 | {#if items[index].iconURL} |
106 | 150 | <img src={items[index].iconURL} alt="" aria-hidden={true} /> |
|
0 commit comments