[英]How to make items draggable and clickable?
我是 Matter JS 的新手,所以请耐心等待。 我从演示和其他来源整理了以下代码以满足我的需求:
function biscuits(width, height, items, gutter) {
const {
Engine,
Render,
Runner,
Composites,
MouseConstraint,
Mouse,
World,
Bodies,
} = Matter
const engine = Engine.create()
const world = engine.world
const render = Render.create({
element: document.getElementById('canvas'),
engine,
options: {
width,
height,
showAngleIndicator: true,
},
})
Render.run(render)
const runner = Runner.create()
Runner.run(runner, engine)
const columns = media({ bp: 'xs' }) ? 3 : 1
const stack = Composites.stack(
getRandom(gutter, gutter * 2),
gutter,
columns,
items.length,
0,
0,
(x, y, a, b, c, i) => {
const item = items[i]
if (!item) {
return null
}
const {
width: itemWidth,
height: itemHeight,
} = item.getBoundingClientRect()
const radiusAmount = media({ bp: 'sm' }) ? 100 : 70
const radius = item.classList.contains('is-biscuit-4')
? radiusAmount
: 0
const shape = item.classList.contains('is-biscuit-2')
? Bodies.circle(x, y, itemWidth / 2)
: Bodies.rectangle(x, y, itemWidth, itemHeight, {
chamfer: { radius },
})
return shape
}
)
World.add(world, stack)
function positionDomElements() {
Engine.update(engine, 20)
stack.bodies.forEach((block, index) => {
const item = items[index]
const xTrans = block.position.x - item.offsetWidth / 2 - gutter / 2
const yTrans = block.position.y - item.offsetHeight / 2 - gutter / 2
item.style.transform = `translate3d(${xTrans}px, ${yTrans}px, 0) rotate(${block.angle}rad)`
})
window.requestAnimationFrame(positionDomElements)
}
positionDomElements()
World.add(world, [
Bodies.rectangle(width / 2, 0, width, gutter, { isStatic: true }),
Bodies.rectangle(width / 2, height, width, gutter, { isStatic: true }),
Bodies.rectangle(width, height / 2, gutter, height, { isStatic: true }),
Bodies.rectangle(0, height / 2, gutter, height, { isStatic: true }),
])
const mouse = Mouse.create(render.canvas)
const mouseConstraint = MouseConstraint.create(engine, {
mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false,
},
},
})
World.add(world, mouseConstraint)
render.mouse = mouse
Render.lookAt(render, {
min: { x: 0, y: 0 },
max: { x: width, y: height },
})
}
我有一个 HTML 链接列表,它模仿 Matter JS 中项目的移动(positionDomElements 函数)。 我这样做是为了 SEO 目的,也是为了使导航可访问和可点击。
但是,因为我的画布位于 HTML 的顶部(不透明度为零),所以我需要能够使项目可点击和可拖动,以便我可以执行一些其他操作,例如导航到链接(和其他事件) .
我不知道该怎么做。 我四处寻找,但我没有任何运气。
是否可以让每个项目都可拖动(因为它已经是)并执行某种点击事件?
任何帮助或引导正确方向将不胜感激。
您的任务似乎是将物理添加到一组 DOM 导航列表节点。 您可能会觉得,matter.js 需要提供一个画布才能运行,如果您想忽略它,则需要隐藏画布或将其不透明度设置为 0。
实际上,您可以使用自己的更新循环无头地运行 MJS,而无需将元素注入引擎。 实际上,不需要与Matter.Render
或Matter.Runner
相关的任何内容,您可以调用Matter.Engine.update(engine);
使引擎在requestAnimationFrame
循环中前进一个刻度。 然后,您可以使用从 MJS 主体中提取的值来定位 DOM 元素。 你已经在做这两件事,所以主要是剪掉画布和渲染调用。
这是一个可运行的示例,您可以参考并适应您的用例。
定位是最难的部分; 确保 MJS 坐标与您的鼠标和元素坐标匹配需要一些大惊小怪。 MJS 将 x/y 坐标视为身体的中心,所以我使用body.vertices[0]
作为左上角,更好地匹配 DOM。 我想很多这些渲染决策都是特定于应用程序的,因此将其视为概念验证。
const listEls = document.querySelectorAll("#mjs-wrapper li"); const engine = Matter.Engine.create(); const stack = Matter.Composites.stack( // xx, yy, columns, rows, columnGap, rowGap, cb 0, 0, listEls.length, 1, 0, 0, (xx, yy, i) => { const {x, y, width, height} = listEls[i].getBoundingClientRect(); return Matter.Bodies.rectangle(x, y, width, height, { isStatic: i === 0 || i + 1 === listEls.length }); } ); Matter.Composites.chain(stack, 0.5, 0, -0.5, 0, { stiffness: 0.5, length: 20 }); const mouseConstraint = Matter.MouseConstraint.create( engine, {element: document.querySelector("#mjs-wrapper")} ); Matter.World.add(engine.world, [stack, mouseConstraint]); listEls.forEach(e => { e.style.position = "absolute"; e.addEventListener("click", e => console.log(e.target.textContent) ); }); (function update() { requestAnimationFrame(update); stack.bodies.forEach((block, i) => { const li = listEls[i]; const {x, y} = block.vertices[0]; li.style.top = `${y}px`; li.style.left = `${x}px`; li.style.transform = `translate(-50%, -50%) rotate(${block.angle}rad) translate(50%, 50%)`; }); Matter.Engine.update(engine); })();
* { box-sizing: border-box; margin: 0; padding: 0; } html, body { height: 100%; } body { min-width: 600px; } #mjs-wrapper { /* position this element */ margin: 1em; height: 100%; } #mjs-wrapper ul { font-size: 14pt; list-style: none; user-select: none; position: relative; } #mjs-wrapper li { background: #fff; border: 1px solid #555; display: inline-block; padding: 1em; cursor: move; } #mjs-wrapper li:hover { background: #f2f2f2; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script> <div id="mjs-wrapper"> <ul> <li>Foo</li> <li>Bar</li> <li>Baz</li> <li>Quux</li> <li>Garply</li> <li>Corge</li> </ul> </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.