<div id='canvas'></div>
#canvas {
width: 100%;
height: 100vh;
border: 1px #000 solid;
}
let isDown = false;
/*lasso parameter*/
const tempVec0 = new THREE.Vector2();
const tempVec1 = new THREE.Vector2();
const tempVec2 = new THREE.Vector2();
let prevX = -Infinity;
let prevY = -Infinity;
const selectionPoints = [];
let selectionShapeNeedsUpdate = false;
let selectionNeedsUpdate = false;
let selectionShape;
function init() {
var pW = $("#canvas").width();
var pH = $("#canvas").height();
scene = new THREE.Scene();
selectionShape = new THREE.Line();
selectionShape.material.color.set(0xE6FF00).convertSRGBToLinear();
selectionShape.renderOrder = 1;
selectionShape.position.z = -2;
selectionShape.depthTest = false;
selectionShape.scale.setScalar(1);
camera = new THREE.PerspectiveCamera(45, pW / pH, 1, 100);
camera.position.z = 2;
//camera.updateProjectionMatrix();
camera.add(selectionShape);
renderer = new THREE.WebGLRenderer();
renderer.setSize(pW, pH);
$("#canvas").append(renderer.domElement);
/*
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.noRotate = true;
controls.enablePan = false;
controls.update();
controls.minDistance = 3;
controls.enableDamping = false;
controls.noRotate = true;
controls.noPan = true;
controls.zoomSpeed = 1;
controls.update();
*/
renderer.domElement.addEventListener("pointerdown", e => {
prevX = e.clientX;
prevY = e.clientY;
isDown = true;
selectionPoints.length = 0;
});
renderer.domElement.addEventListener("pointermove", e => {
if (isDown) {
const ex = e.clientX;
const ey = e.clientY;
var domRect = renderer.domElement.getBoundingClientRect();
nx = ((e.clientX - domRect.left) / (domRect.right - domRect.left)) * 2 - 1;
ny = -((e.clientY - domRect.top) / (domRect.bottom - domRect.top)) * 2 + 1;
// If the mouse hasn't moved a lot since the last point
if (Math.abs(ex - prevX) >= 3 || Math.abs(ey - prevY) >= 3) {
const i = selectionPoints.length / 3 - 1;
const i3 = i * 3;
let doReplace = false;
if (selectionPoints.length > 3) {
// prev segment direction
tempVec0.set(selectionPoints[i3 - 3], selectionPoints[i3 - 3 + 1]);
tempVec1.set(selectionPoints[i3], selectionPoints[i3 + 1]);
tempVec1.sub(tempVec0).normalize();
// this segment direction
tempVec0.set(selectionPoints[i3], selectionPoints[i3 + 1]);
tempVec2.set(nx, ny);
tempVec2.sub(tempVec0).normalize();
const dot = tempVec1.dot(tempVec2);
doReplace = dot > 0.99;
}
if (doReplace) {
selectionPoints[i3] = nx; //nx;
selectionPoints[i3 + 1] = ny; //ny;
} else {
//selectionPoints.push(nx, ny, 0);
selectionPoints.push(nx, ny, 0);
}
selectionShapeNeedsUpdate = true;
selectionShape.visible = true;
prevX = nx;
prevY = ny;
selectionNeedsUpdate = true;
}
}
});
renderer.domElement.addEventListener("pointerup", e => {
isDown = false;
return false;
});
}
function render() {
requestAnimationFrame(render);
renderer.render(scene, camera);
const ogLength = selectionPoints.length;
selectionPoints.push(selectionPoints[0], selectionPoints[1], selectionPoints[2]);
selectionShape.geometry.setAttribute('position', new THREE.Float32BufferAttribute(selectionPoints, 3, false));
selectionPoints.length = ogLength;
if (selectionNeedsUpdate) {
selectionNeedsUpdate = false;
if (selectionPoints.length > 0) {
updateSelection();
}
}
const yScale = Math.tan(THREE.MathUtils.DEG2RAD * camera.fov / 2) * -2;
selectionShape.scale.set(- yScale * camera.aspect, - yScale, 1);
}
function updateSelection() {
scene.add(selectionShape);
}
$(function () {
init();
render();
window.addEventListener("resize", function () {
camera.aspect = $("#canvas").width() / $("#canvas").height();
camera.updateProjectionMatrix();
renderer.setSize($("#canvas").width(), $("#canvas").height());
});
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.