react-three-map 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -7
- package/dist/cjs/main.js.js +1 -0
- package/dist/es/main.js.mjs +5 -0
- package/dist/es/main.js.mjs.map +1 -0
- package/dist/es/main.js10.mjs +40 -0
- package/dist/es/main.js10.mjs.map +1 -0
- package/dist/es/main.js11.mjs +13 -0
- package/dist/es/main.js11.mjs.map +1 -0
- package/dist/es/main.js12.mjs +13 -0
- package/dist/es/main.js12.mjs.map +1 -0
- package/dist/es/main.js13.mjs +31 -0
- package/dist/es/main.js13.mjs.map +1 -0
- package/dist/es/main.js14.mjs +13 -0
- package/dist/es/main.js14.mjs.map +1 -0
- package/dist/es/main.js15.mjs +15 -0
- package/dist/es/main.js15.mjs.map +1 -0
- package/dist/es/main.js16.mjs +14 -0
- package/dist/es/main.js16.mjs.map +1 -0
- package/dist/es/main.js17.mjs +56 -0
- package/dist/es/main.js17.mjs.map +1 -0
- package/dist/es/main.js18.mjs +9 -0
- package/dist/es/main.js18.mjs.map +1 -0
- package/dist/es/main.js19.mjs +320 -0
- package/dist/es/main.js19.mjs.map +1 -0
- package/dist/es/main.js2.mjs +40 -0
- package/dist/es/main.js2.mjs.map +1 -0
- package/dist/es/main.js20.mjs +72 -0
- package/dist/es/main.js20.mjs.map +1 -0
- package/dist/es/main.js21.mjs +6 -0
- package/dist/es/main.js21.mjs.map +1 -0
- package/dist/es/main.js22.mjs +19 -0
- package/dist/es/main.js22.mjs.map +1 -0
- package/dist/es/main.js23.mjs +14 -0
- package/dist/es/main.js23.mjs.map +1 -0
- package/dist/es/main.js24.mjs +34 -0
- package/dist/es/main.js24.mjs.map +1 -0
- package/dist/es/main.js25.mjs +15 -0
- package/dist/es/main.js25.mjs.map +1 -0
- package/dist/es/main.js26.mjs +8 -0
- package/dist/es/main.js26.mjs.map +1 -0
- package/dist/es/main.js27.mjs +41 -0
- package/dist/es/main.js27.mjs.map +1 -0
- package/dist/es/main.js28.mjs +26 -0
- package/dist/es/main.js28.mjs.map +1 -0
- package/dist/es/main.js3.mjs +21 -0
- package/dist/es/main.js3.mjs.map +1 -0
- package/dist/es/main.js4.mjs +11 -0
- package/dist/es/main.js4.mjs.map +1 -0
- package/dist/es/main.js5.mjs +53 -0
- package/dist/es/main.js5.mjs.map +1 -0
- package/dist/es/main.js6.mjs +16 -0
- package/dist/es/main.js6.mjs.map +1 -0
- package/dist/es/main.js7.mjs +62 -0
- package/dist/es/main.js7.mjs.map +1 -0
- package/dist/es/main.js8.mjs +58 -0
- package/dist/es/main.js8.mjs.map +1 -0
- package/dist/es/main.js9.mjs +49 -0
- package/dist/es/main.js9.mjs.map +1 -0
- package/dist/es/vite.svg +1 -0
- package/index.html +13 -0
- package/package.json +16 -15
- package/src/canvas/canvas.tsx +49 -0
- package/src/canvas/coords-to-matrix.ts +19 -0
- package/src/canvas/create-events.ts +73 -0
- package/src/canvas/state-ref.ts +9 -0
- package/src/canvas/use-function.ts +10 -0
- package/src/canvas/use-on-add.ts +67 -0
- package/src/canvas/use-render.ts +27 -0
- package/src/main.ts +1 -0
- package/src/stories/canvas.stories.tsx +28 -0
- package/src/stories/my-scene.tsx +83 -0
- package/src/stories/no-map.stories.tsx +12 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
- package/tsconfig.node.json +10 -0
- package/dist/my-lib.es.js +0 -1538
- package/dist/my-lib.umd.js +0 -27
- /package/dist/{vite.svg → cjs/vite.svg} +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Events, RenderProps, RootState, createEvents as createFiberEvents } from "@react-three/fiber";
|
|
2
|
+
import { UseBoundStore } from "zustand";
|
|
3
|
+
|
|
4
|
+
type DomEvent = PointerEvent | MouseEvent | WheelEvent;
|
|
5
|
+
|
|
6
|
+
const DOM_EVENTS = {
|
|
7
|
+
onClick: ["click", false],
|
|
8
|
+
onContextMenu: ["contextmenu", false],
|
|
9
|
+
onDoubleClick: ["dblclick", false],
|
|
10
|
+
onWheel: ["wheel", true],
|
|
11
|
+
onPointerDown: ["pointerdown", true],
|
|
12
|
+
onPointerUp: ["pointerup", true],
|
|
13
|
+
onPointerLeave: ["pointerleave", true],
|
|
14
|
+
onPointerMove: ["pointermove", true],
|
|
15
|
+
onPointerCancel: ["pointercancel", true],
|
|
16
|
+
onLostPointerCapture: ["lostpointercapture", true],
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
/** ThreeLayer event manager for MapLibre and Mapbox */
|
|
20
|
+
export function createEvents() : RenderProps<HTMLCanvasElement>["events"] {
|
|
21
|
+
return (store: UseBoundStore<RootState>) => {
|
|
22
|
+
const { handlePointer } = createFiberEvents(store);
|
|
23
|
+
return {
|
|
24
|
+
priority: 1,
|
|
25
|
+
enabled: true,
|
|
26
|
+
compute(event: DomEvent, state: RootState) {
|
|
27
|
+
state.size.width = state.gl.domElement.width;
|
|
28
|
+
state.size.height = state.gl.domElement.height;
|
|
29
|
+
state.pointer.x = (event.offsetX / (state.size.width / window.devicePixelRatio)) * 2 - 1;
|
|
30
|
+
state.pointer.y = 1 - (event.offsetY / (state.size.height / window.devicePixelRatio)) * 2;
|
|
31
|
+
state.raycaster.camera = state.camera;
|
|
32
|
+
state.raycaster.ray.origin.setScalar(0).applyMatrix4(state.camera.projectionMatrixInverse);
|
|
33
|
+
state.raycaster.ray.direction
|
|
34
|
+
.set(state.pointer.x, state.pointer.y, 1)
|
|
35
|
+
.applyMatrix4(state.camera.projectionMatrixInverse)
|
|
36
|
+
.sub(state.raycaster.ray.origin)
|
|
37
|
+
.normalize();
|
|
38
|
+
},
|
|
39
|
+
connected: undefined,
|
|
40
|
+
handlers: Object.keys(DOM_EVENTS).reduce(
|
|
41
|
+
(acc, key) => ({ ...acc, [key]: handlePointer(key) }),
|
|
42
|
+
{}
|
|
43
|
+
) as unknown as Events,
|
|
44
|
+
update: () => {
|
|
45
|
+
const { events, internal } = store.getState();
|
|
46
|
+
if (internal.lastEvent?.current && events.handlers) {
|
|
47
|
+
events.handlers.onPointerMove(internal.lastEvent.current);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
connect: (target: HTMLElement) => {
|
|
51
|
+
const { set, events } = store.getState();
|
|
52
|
+
events.disconnect?.();
|
|
53
|
+
set((state) => ({ events: { ...state.events, connected: target } }));
|
|
54
|
+
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
|
|
55
|
+
const [eventName, passive] = DOM_EVENTS[name as keyof typeof DOM_EVENTS];
|
|
56
|
+
target.addEventListener(eventName, event, { passive });
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
disconnect: () => {
|
|
60
|
+
const { set, events } = store.getState();
|
|
61
|
+
if (events.connected) {
|
|
62
|
+
Object.entries(events.handlers ?? []).forEach(([name, event]) => {
|
|
63
|
+
if (events && events.connected instanceof HTMLElement) {
|
|
64
|
+
const [eventName] = DOM_EVENTS[name as keyof typeof DOM_EVENTS];
|
|
65
|
+
events.connected.removeEventListener(eventName, event);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
set((state) => ({ events: { ...state.events, connected: undefined } }));
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ReconcilerRoot, RootState } from "@react-three/fiber";
|
|
2
|
+
import { MutableRefObject } from "react";
|
|
3
|
+
import { MapInstance } from "react-map-gl";
|
|
4
|
+
|
|
5
|
+
export type StateRef = MutableRefObject<{
|
|
6
|
+
map: MapInstance;
|
|
7
|
+
root: ReconcilerRoot<HTMLCanvasElement>;
|
|
8
|
+
state?: RootState;
|
|
9
|
+
} | undefined>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
export const useFunction = <T extends (...args: any[]) => any>(callback: T): T => {
|
|
5
|
+
const callbackRef = useRef(callback);
|
|
6
|
+
callbackRef.current = callback;
|
|
7
|
+
return useCallback((...args: any[]) => {
|
|
8
|
+
return callbackRef.current(...args);
|
|
9
|
+
}, []) as T;
|
|
10
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { RenderProps, createRoot } from "@react-three/fiber";
|
|
2
|
+
import { MapInstance } from "react-map-gl";
|
|
3
|
+
import { createEvents } from "./create-events";
|
|
4
|
+
import { StateRef } from "./state-ref";
|
|
5
|
+
import { useFunction } from "./use-function";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
|
|
8
|
+
export function useOnAdd (ref: StateRef, renderProps: RenderProps<HTMLCanvasElement>) {
|
|
9
|
+
|
|
10
|
+
const [mounted, setMounted] = useState(false);
|
|
11
|
+
|
|
12
|
+
const onAdd = useFunction((map: MapInstance, gl: WebGLRenderingContext)=>{
|
|
13
|
+
|
|
14
|
+
const canvas = map.getCanvas();
|
|
15
|
+
const root = createRoot(canvas);
|
|
16
|
+
root.configure({
|
|
17
|
+
frameloop: "never",
|
|
18
|
+
dpr: window.devicePixelRatio,
|
|
19
|
+
shadows: true,
|
|
20
|
+
events: createEvents(),
|
|
21
|
+
...renderProps,
|
|
22
|
+
gl: {
|
|
23
|
+
context: gl,
|
|
24
|
+
depth: true,
|
|
25
|
+
autoClear: false,
|
|
26
|
+
antialias: true,
|
|
27
|
+
...renderProps?.gl,
|
|
28
|
+
},
|
|
29
|
+
onCreated: (state) => {
|
|
30
|
+
ref.current = {
|
|
31
|
+
state,
|
|
32
|
+
map,
|
|
33
|
+
root,
|
|
34
|
+
}
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
36
|
+
state.gl.forceContextLoss = () => { };
|
|
37
|
+
},
|
|
38
|
+
camera: {
|
|
39
|
+
matrixAutoUpdate: false,
|
|
40
|
+
},
|
|
41
|
+
size: {
|
|
42
|
+
width: canvas.clientWidth,
|
|
43
|
+
height: canvas.clientHeight,
|
|
44
|
+
top: 0,
|
|
45
|
+
left: 0,
|
|
46
|
+
...renderProps?.size,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
ref.current = {
|
|
51
|
+
map,
|
|
52
|
+
root,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setTimeout(()=>setMounted(true));
|
|
56
|
+
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const onRemove = useFunction(()=>{
|
|
60
|
+
setTimeout(()=>{
|
|
61
|
+
if(!ref.current) return;
|
|
62
|
+
ref.current.root.unmount();
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
return {onAdd, onRemove, mounted};
|
|
67
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Matrix4 } from "three";
|
|
2
|
+
import { StateRef } from "./state-ref";
|
|
3
|
+
import { useFunction } from "./use-function";
|
|
4
|
+
import { useMap } from "react-map-gl/maplibre";
|
|
5
|
+
|
|
6
|
+
export function useRender(
|
|
7
|
+
m4: Matrix4, ref: StateRef
|
|
8
|
+
) {
|
|
9
|
+
|
|
10
|
+
const map = useMap()
|
|
11
|
+
|
|
12
|
+
const render = useFunction((_gl: WebGL2RenderingContext, matrix: number[])=>{
|
|
13
|
+
if(!map.current) return;
|
|
14
|
+
if(!ref.current?.state) return;
|
|
15
|
+
const camera = ref.current.state.camera;
|
|
16
|
+
const gl = ref.current.state.gl;
|
|
17
|
+
const advance = ref.current.state.advance;
|
|
18
|
+
camera.projectionMatrix.fromArray(matrix).multiply(m4);
|
|
19
|
+
camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert();
|
|
20
|
+
gl.resetState();
|
|
21
|
+
advance(Date.now() * 0.001, true);
|
|
22
|
+
map.current.triggerRepaint();
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
return render;
|
|
26
|
+
|
|
27
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './canvas/canvas';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ThemeState, useLadleContext } from "@ladle/react";
|
|
2
|
+
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
3
|
+
import Map from 'react-map-gl/maplibre';
|
|
4
|
+
import { Canvas } from "../canvas/canvas";
|
|
5
|
+
import { MyScene } from "./my-scene";
|
|
6
|
+
|
|
7
|
+
export function BasicSetup() {
|
|
8
|
+
const theme = useLadleContext().globalState.theme;
|
|
9
|
+
const mapStyle = theme === ThemeState.Dark
|
|
10
|
+
? "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
|
|
11
|
+
: "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"
|
|
12
|
+
return <div style={{ height: '100vh' }}>
|
|
13
|
+
<Map
|
|
14
|
+
antialias
|
|
15
|
+
initialViewState={{
|
|
16
|
+
latitude: 51.5073218,
|
|
17
|
+
longitude: -0.1276473,
|
|
18
|
+
zoom: 22
|
|
19
|
+
}}
|
|
20
|
+
mapStyle={mapStyle}
|
|
21
|
+
>
|
|
22
|
+
<Canvas latitude={51.5073218} longitude={-0.1276473}>
|
|
23
|
+
<MyScene />
|
|
24
|
+
</Canvas>
|
|
25
|
+
</Map>
|
|
26
|
+
</div>
|
|
27
|
+
}
|
|
28
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Box, Plane, useHelper } from "@react-three/drei";
|
|
2
|
+
import { MeshProps, useFrame } from '@react-three/fiber';
|
|
3
|
+
import 'maplibre-gl/dist/maplibre-gl.css';
|
|
4
|
+
import { useRef, useState } from 'react';
|
|
5
|
+
import { CameraHelper, MathUtils, Mesh, OrthographicCamera } from "three";
|
|
6
|
+
|
|
7
|
+
export function MyScene() {
|
|
8
|
+
return <>
|
|
9
|
+
<Lights />
|
|
10
|
+
<Floor />
|
|
11
|
+
<MyBox position={[-1.2, 1.5, 0]} />
|
|
12
|
+
<MyBox position={[1.2, 1.5, 0]} />
|
|
13
|
+
<MyBox position={[1.2, 1.5, 2.4]} />
|
|
14
|
+
</>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
function MyBox(props: MeshProps) {
|
|
19
|
+
const [hovered, hover] = useState(false);
|
|
20
|
+
const [clicked, click] = useState(false);
|
|
21
|
+
const mesh = useRef<Mesh>(null)
|
|
22
|
+
|
|
23
|
+
useFrame((_st, dt)=>{
|
|
24
|
+
if(!mesh.current) return;
|
|
25
|
+
mesh.current.rotateY(dt);
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Box
|
|
30
|
+
{...props}
|
|
31
|
+
ref={mesh}
|
|
32
|
+
args={[1, 1, 1]}
|
|
33
|
+
receiveShadow
|
|
34
|
+
castShadow
|
|
35
|
+
scale={props.scale || clicked ? props.scale || 1.5 : 1}
|
|
36
|
+
onClick={() => click(!clicked)}
|
|
37
|
+
onPointerOver={() => hover(true)}
|
|
38
|
+
onPointerOut={() => hover(false)}
|
|
39
|
+
>
|
|
40
|
+
<meshStandardMaterial
|
|
41
|
+
color={hovered ? "red" : "orange"}
|
|
42
|
+
metalness={.75}
|
|
43
|
+
roughness={.5}
|
|
44
|
+
/>
|
|
45
|
+
</Box>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
function Lights() {
|
|
49
|
+
const cam = useRef<OrthographicCamera>(null);
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
useHelper(cam as any, CameraHelper)
|
|
52
|
+
const camSize = 5;
|
|
53
|
+
return <>
|
|
54
|
+
<ambientLight intensity={0.5} />
|
|
55
|
+
<directionalLight
|
|
56
|
+
castShadow
|
|
57
|
+
position={[2.5, 50, 5]}
|
|
58
|
+
intensity={1.5}
|
|
59
|
+
shadow-mapSize={1024}
|
|
60
|
+
shadow-bias={-0.005}
|
|
61
|
+
>
|
|
62
|
+
<orthographicCamera
|
|
63
|
+
ref={cam}
|
|
64
|
+
attach="shadow-camera"
|
|
65
|
+
args={[-camSize, camSize, -camSize, camSize, 0.1, 100]}
|
|
66
|
+
rotation={[0,90*MathUtils.DEG2RAD,0]}
|
|
67
|
+
/>
|
|
68
|
+
</directionalLight>
|
|
69
|
+
<pointLight position={[-10, 0, -20]} color="white" intensity={1} />
|
|
70
|
+
<pointLight position={[0, -10, 0]} intensity={1} />
|
|
71
|
+
</>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function Floor() {
|
|
75
|
+
return <Plane
|
|
76
|
+
args={[50, 50]}
|
|
77
|
+
position={[0, 0, 0]}
|
|
78
|
+
rotation={[-90 * MathUtils.DEG2RAD, 0, 0]}
|
|
79
|
+
receiveShadow
|
|
80
|
+
>
|
|
81
|
+
<shadowMaterial opacity={.5} />
|
|
82
|
+
</Plane>
|
|
83
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MapControls } from "@react-three/drei"
|
|
2
|
+
import { Canvas } from "@react-three/fiber"
|
|
3
|
+
import { MyScene } from "./my-scene"
|
|
4
|
+
|
|
5
|
+
export const NoMap = () => {
|
|
6
|
+
return <div style={{ height: '100vh' }}>
|
|
7
|
+
<Canvas camera={{position: [0,10,0]}} shadows="basic">
|
|
8
|
+
<MyScene />
|
|
9
|
+
<MapControls makeDefault />
|
|
10
|
+
</Canvas>
|
|
11
|
+
</div>
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
"jsx": "react-jsx",
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
22
|
+
},
|
|
23
|
+
"include": ["src"],
|
|
24
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
|
25
|
+
}
|