fix: scaling and scrolling
This commit is contained in:
parent
6ee9176756
commit
b592ecb56b
|
@ -7,7 +7,17 @@
|
||||||
.devtools {
|
.devtools {
|
||||||
background-color: #444444;
|
background-color: #444444;
|
||||||
color: white;
|
color: white;
|
||||||
max-height: 100%;
|
height: 100%;
|
||||||
overflow-y: auto;
|
overflow: hidden;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.devtools > :global(.react-tabs) {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
> :global(.react-tabs__tab-panel) {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import {useRef, useState} from 'react';
|
import {useRef, useState} from 'react';
|
||||||
|
|
||||||
import {useEcs} from '@/context/ecs.js';
|
import {useEcs} from '@/context/ecs.js';
|
||||||
|
import useRect from '@/util/react-hooks/use-rect.js';
|
||||||
|
|
||||||
import styles from './tiles.module.css';
|
import styles from './tiles.module.css';
|
||||||
|
|
||||||
|
@ -11,8 +12,10 @@ export default function Tiles({
|
||||||
setLayer,
|
setLayer,
|
||||||
setStamp,
|
setStamp,
|
||||||
}) {
|
}) {
|
||||||
const offsetRef = useRef();
|
const wrapperRef = useRef();
|
||||||
const [selection, setSelection] = useState({x: 0, y: 0, w: 2, h: 2});
|
const imageRef = useRef();
|
||||||
|
const imageRect = useRect(imageRef);
|
||||||
|
const [selection, setSelection] = useState({x: 0, y: 0, w: 1, h: 1});
|
||||||
const [moveStart, setMoveStart] = useState();
|
const [moveStart, setMoveStart] = useState();
|
||||||
const [ecs] = useEcs();
|
const [ecs] = useEcs();
|
||||||
if (!ecs) {
|
if (!ecs) {
|
||||||
|
@ -25,6 +28,7 @@ export default function Tiles({
|
||||||
const {TileLayers} = master;
|
const {TileLayers} = master;
|
||||||
const {sourceJson, tileSize} = TileLayers.layer(0);
|
const {sourceJson, tileSize} = TileLayers.layer(0);
|
||||||
const {w, h} = sourceJson.meta.size;
|
const {w, h} = sourceJson.meta.size;
|
||||||
|
const factor = (imageRect?.width ?? 1) / w;
|
||||||
return (
|
return (
|
||||||
<div className={styles.tiles}>
|
<div className={styles.tiles}>
|
||||||
<form>
|
<form>
|
||||||
|
@ -57,7 +61,7 @@ export default function Tiles({
|
||||||
Brush:
|
Brush:
|
||||||
<select
|
<select
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
setLayer(event.target.value)
|
setBrush(event.target.value)
|
||||||
}}
|
}}
|
||||||
value={brush}
|
value={brush}
|
||||||
>
|
>
|
||||||
|
@ -65,40 +69,36 @@ export default function Tiles({
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
|
||||||
<div
|
<div
|
||||||
onMouseDown={(event) => {
|
onMouseDown={(event) => {
|
||||||
if (!offsetRef.current) {
|
const wrapperRect = wrapperRef.current.getBoundingClientRect();
|
||||||
return;
|
const {left, top} = wrapperRect;
|
||||||
}
|
|
||||||
const {left, top} = offsetRef.current.getBoundingClientRect();
|
|
||||||
if (
|
if (
|
||||||
event.clientX - left >= w
|
event.clientX - left >= (w * factor)
|
||||||
|| event.clientY - top >= h
|
|| event.clientY - top >= (h * factor)
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const x = Math.floor((event.clientX - left) / tileSize.x);
|
const x = Math.floor((event.clientX - left) / (tileSize.x * factor));
|
||||||
const y = Math.floor((event.clientY - top) / tileSize.y);
|
const y = Math.floor((event.clientY - top) / (tileSize.y * factor));
|
||||||
setMoveStart({x, y});
|
setMoveStart({x, y});
|
||||||
setSelection({x, y, w: 1, h: 1});
|
setSelection({x, y, w: 1, h: 1});
|
||||||
}}
|
}}
|
||||||
onMouseMove={(event) => {
|
onMouseMove={(event) => {
|
||||||
if (!offsetRef.current) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!moveStart) {
|
if (!moveStart) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const {x: sx, y: sy} = moveStart;
|
const {x: sx, y: sy} = moveStart;
|
||||||
const {left, top} = offsetRef.current.getBoundingClientRect();
|
const wrapperRect = wrapperRef.current.getBoundingClientRect();
|
||||||
|
const {left, top} = wrapperRect;
|
||||||
const x = Math.floor(
|
const x = Math.floor(
|
||||||
Math.max(0, Math.min(w - 1, (event.clientX - left)) / tileSize.x),
|
Math.max(0, Math.min((w * factor) - 1, (event.clientX - left)) / (tileSize.x * factor)),
|
||||||
);
|
);
|
||||||
const y = Math.floor(
|
const y = Math.floor(
|
||||||
Math.max(0, Math.min(h - 1, (event.clientY - top)) / tileSize.y),
|
Math.max(0, Math.min((h * factor) - 1, (event.clientY - top)) / (tileSize.y * factor)),
|
||||||
);
|
);
|
||||||
const mx = Math.min(sx, x);
|
const mx = Math.min(sx, x);
|
||||||
const my = Math.min(sy, y);
|
const my = Math.min(sy, y);
|
||||||
|
@ -119,19 +119,20 @@ export default function Tiles({
|
||||||
setStamp(stamp);
|
setStamp(stamp);
|
||||||
}}
|
}}
|
||||||
className={styles.selectionWrapper}
|
className={styles.selectionWrapper}
|
||||||
ref={offsetRef}
|
ref={wrapperRef}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={styles.selection}
|
className={styles.selection}
|
||||||
style={{
|
style={{
|
||||||
top: selection.y * tileSize.y,
|
top: selection.y * tileSize.y * factor,
|
||||||
left: selection.x * tileSize.x,
|
left: selection.x * tileSize.x * factor,
|
||||||
height: selection.h * tileSize.x,
|
height: selection.h * tileSize.x * factor,
|
||||||
width: selection.w * tileSize.y,
|
width: selection.w * tileSize.y * factor,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
alt="tileset"
|
alt="tileset"
|
||||||
|
ref={imageRef}
|
||||||
src={TileLayers.layer(0).source.replace('.json', '.png')}
|
src={TileLayers.layer(0).source.replace('.json', '.png')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
.selectionWrapper img {
|
.selectionWrapper img {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selection {
|
.selection {
|
||||||
|
|
16
app/util/react-hooks/use-rect.js
vendored
Normal file
16
app/util/react-hooks/use-rect.js
vendored
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import {useLayoutEffect, useState} from 'react'
|
||||||
|
import useResizeObserver from '@react-hook/resize-observer'
|
||||||
|
|
||||||
|
export default function useRect(target) {
|
||||||
|
const [rect, setRect] = useState();
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setRect(target.current.getBoundingClientRect())
|
||||||
|
}, [target]);
|
||||||
|
useResizeObserver(
|
||||||
|
target,
|
||||||
|
(entry) => {
|
||||||
|
setRect(entry.target.getBoundingClientRect());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return rect;
|
||||||
|
}
|
35
package-lock.json
generated
35
package-lock.json
generated
|
@ -15,6 +15,7 @@
|
||||||
"@pixi/react": "^7.1.2",
|
"@pixi/react": "^7.1.2",
|
||||||
"@pixi/spritesheet": "^7.4.2",
|
"@pixi/spritesheet": "^7.4.2",
|
||||||
"@pixi/tilemap": "^4.1.0",
|
"@pixi/tilemap": "^4.1.0",
|
||||||
|
"@react-hook/resize-observer": "^2.0.1",
|
||||||
"@remix-run/express": "^2.9.2",
|
"@remix-run/express": "^2.9.2",
|
||||||
"@remix-run/node": "^2.9.2",
|
"@remix-run/node": "^2.9.2",
|
||||||
"@remix-run/react": "^2.9.2",
|
"@remix-run/react": "^2.9.2",
|
||||||
|
@ -3020,6 +3021,11 @@
|
||||||
"integrity": "sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==",
|
"integrity": "sha512-Lg3PnLp0QXpxwLIAuuJboLeRaIhrgJjeuh797QADg3xz8wGLugQOS5DpsE8A6i6Adgzf+bacllkKZG3J0tGfDw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@juggle/resize-observer": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
|
||||||
|
},
|
||||||
"node_modules/@leodeslf/simplex-noise": {
|
"node_modules/@leodeslf/simplex-noise": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@leodeslf/simplex-noise/-/simplex-noise-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@leodeslf/simplex-noise/-/simplex-noise-1.0.0.tgz",
|
||||||
|
@ -3971,6 +3977,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-hook/latest": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-hook/latest/-/latest-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-hook/passive-layout-effect": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-hook/passive-layout-effect/-/passive-layout-effect-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-IwEphTD75liO8g+6taS+4oqz+nnroocNfWVHWz7j+N+ZO2vYrc6PV1q7GQhuahL0IOR7JccFTsFKQ/mb6iZWAg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@react-hook/resize-observer": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-hook/resize-observer/-/resize-observer-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-9PCX9grWfxdPizY8ohr+X4IkV1JhGMWr2Nm4ngbg6IcAIv0WBs7YoJcNBqYl22OqPHr5eOMItGcStZrmj2mbmQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@juggle/resize-observer": "^3.3.1",
|
||||||
|
"@react-hook/latest": "^1.0.2",
|
||||||
|
"@react-hook/passive-layout-effect": "^1.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@remix-run/dev": {
|
"node_modules/@remix-run/dev": {
|
||||||
"version": "2.9.2",
|
"version": "2.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@remix-run/dev/-/dev-2.9.2.tgz",
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
"@pixi/react": "^7.1.2",
|
"@pixi/react": "^7.1.2",
|
||||||
"@pixi/spritesheet": "^7.4.2",
|
"@pixi/spritesheet": "^7.4.2",
|
||||||
"@pixi/tilemap": "^4.1.0",
|
"@pixi/tilemap": "^4.1.0",
|
||||||
|
"@react-hook/resize-observer": "^2.0.1",
|
||||||
"@remix-run/express": "^2.9.2",
|
"@remix-run/express": "^2.9.2",
|
||||||
"@remix-run/node": "^2.9.2",
|
"@remix-run/node": "^2.9.2",
|
||||||
"@remix-run/react": "^2.9.2",
|
"@remix-run/react": "^2.9.2",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user