JSFiddle - React, Tailwind, and code Playground
CSS
body{
overflow: hidden;
margin: 0;
}
JavaScript
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import * as d3 from 'https://cdn.skypack.dev/d3';
const imgUrl = "https://i.ibb.co/KVbF40w/mesh-texture.png"
// INIT
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 20);
let renderer = new THREE.WebGLRenderer();
let view = d3.select(renderer.domElement)
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", event => {
camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(innerWidth, innerHeight);
})
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
// TEXTURE
const textureLoader = new THREE.TextureLoader();
textureLoader.crossOrigin = "Anonymous";
const myTexture = textureLoader.load(imgUrl);
const material = new THREE.MeshBasicMaterial({
map: myTexture,
});
const geometry = new THREE.PlaneGeometry( 10, 10 );
const mesh = new THREE.Mesh( geometry, material );
scene.add(mesh);
// d3 zoom INIT
const d3Zoom = d3.zoom().on("zoom", (event) => {
if (event.sourceEvent) {
onZoom(event);
}
});
d3Zoom.scaleTo(view, 20);
view.call(d3Zoom);
// ZOOM handler
const onZoom = (event) => {
const zoomDelta = event.sourceEvent.deltaY;
const zoomLevel = camera.position.z + zoomDelta * 0.1;
const vector = new THREE.Vector3(
( event.sourceEvent.clientX / window.innerWidth ) * 2 - 1,
-( event.sourceEvent.clientY / window.innerHeight ) * 2 + 1,
0.5
);
const distanceBefore = camera.position.distanceTo(vector);
const distanceAfter = new THREE.Vector3(
camera.position.x,
camera.position.y,
0,5
).distanceTo(vector);
const ratio = distanceAfter/distanceBefore;
// add P to the camera position
camera.position.clone().add(vector).normalize();
// then zoom
camera.position.set(camera.position.x, camera.position.y, zoomLevel);
// then subtract P *...