Skip to content

Instantly share code, notes, and snippets.

@plmrry
Last active May 17, 2017 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plmrry/523e6419099925af76557c807e9dc95e to your computer and use it in GitHub Desktop.
Save plmrry/523e6419099925af76557c807e9dc95e to your computer and use it in GitHub Desktop.
Tracking 3D Coordinates
license: mit

This example tracks the coordinates of a point in three-dimensional space using an SVG overlay.

Ideally, the callout line would be shortened by the radius of the circle plus some margin.

<html>
<head>
<title>Tracking</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 2;
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor( 'white' )
renderer.setSize( window.innerWidth, window.innerHeight );
const appDiv = document.createElement('div');
document.body.appendChild(appDiv);
appDiv.appendChild( renderer.domElement );
const canvas = document.querySelector('canvas');
const ndc_to_canvas = {
x: d3.scaleLinear().domain([-1, 1]).range([0, canvas.width]),
y: d3.scaleLinear().domain([-1, 1]).range([canvas.height, 0])
}
const svg_ns = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(svg_ns, "svg");
svg.style.position = "absolute";
svg.style.left = 0;
svg.style.top = 0;
svg.style.width = canvas.width;
svg.style.height = canvas.height;
svg.height = canvas.height;
appDiv.appendChild(svg);
const CIRCLE_RADIUS = 10;
const FONT_SIZE = 10;
const TEXT_POSITION = {
x: 500,
y: 100
}
const circleG = document.createElementNS(svg_ns, "g");
const circle = document.createElementNS(svg_ns, "circle")
circle.setAttribute('r', CIRCLE_RADIUS)
circle.style.fill = "none";
circle.style.stroke = 'black'
circleG.appendChild(circle)
svg.appendChild(circleG)
const line = document.createElementNS(svg_ns, "line")
line.setAttribute('x1', TEXT_POSITION.x)
line.setAttribute('y1', TEXT_POSITION.y)
line.setAttribute('x2', 300)
line.setAttribute('y2', 300)
line.style.stroke = "black";
svg.appendChild(line)
const textG = document.createElementNS(svg_ns, "g")
const text = document.createElementNS(svg_ns, "text");
textG.appendChild(text)
textG.setAttribute("transform", `translate(${TEXT_POSITION.x}, ${TEXT_POSITION.y})`);
text.textContent = "Something We Care About"
text.style.fontSize = `${FONT_SIZE}px`
text.style.lineHeight = `${FONT_SIZE}px`
text.style.textTransform = "uppercase"
text.setAttribute('text-anchor', 'end')
text.setAttribute('dx', '-5px')
text.setAttribute('dy', `${FONT_SIZE/4}px`)
svg.appendChild(textG)
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0xbbbbbb, wireframe: true } );
var cube = new THREE.Mesh( geometry, material );
function makePoint() {
var geometry = new THREE.SphereGeometry( 0.02, 30, 30 );
var material = new THREE.MeshBasicMaterial( {color: 0x000000} );
var sphere = new THREE.Mesh( geometry, material );
sphere.position.y = 0.5
sphere.position.x = 0.4
return sphere;
}
const point = makePoint()
cube.add(point)
scene.add( cube );
const velocity = 0.02;
const ticks = Stream(next => {
function tick() {
next()
requestAnimationFrame(tick)
}
tick()
})
const koob = Stream(out => {
const rotation = { x: 0, y: 0 };
ticks.listen(tick => {
rotation.x += 1;
rotation.y += 1;
out(rotation)
})
})
const raycaster = new THREE.Raycaster();
ticks.listen(function () {
cube.rotation.x += velocity;
cube.rotation.y += velocity;
renderer.render(scene, camera);
const world = point.getWorldPosition();
// this is in Normalized Device Coords;
const camera_ndc = world.project(camera);
const screen_x = ndc_to_canvas.x(camera_ndc.x);
const screen_y = ndc_to_canvas.y(camera_ndc.y);
const screen = new THREE.Vector2(screen_x, screen_y);
circleG.setAttribute('transform', `translate(${screen.x}, ${screen.y})`)
line.setAttribute('x2', screen.x)
line.setAttribute('y2', screen.y)
})
function Stream(start) {
return {
listen: start
}
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment