Public
Edited
Jul 17, 2024
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const renderer = new THREE.WebGLRenderer({antialias: true});
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableZoom = false;
controls.enablePan = false;
invalidation.then(() => (controls.dispose(), renderer.dispose()));
renderer.setSize(width, height);
renderer.setPixelRatio(devicePixelRatio);
controls.addEventListener("change", () => {
renderer.render(scene, camera);
colorPositions.forEach((positionObject, i) => {
const clone = positionObject.group.clone();
const projectedVec = clone.position.project(camera);
const x = ( projectedVec.x + 1) * width / 2;
const y = ( Math.abs(projectedVec.y - 1)) * height / 2;
const indicatorElement = document.getElementById(`indicator-${i}`);
indicatorElement.style.left = `${x}px`
indicatorElement.style.top = `${y}px`
})
});
renderer.render(scene, camera);
const circleSize = 24;
return html`
<style>
.overlay {
position: absolute;
top: 0;
pointer-events: none;
width: 100%;
height: 100%;
}

.indicator {
position: absolute;
left: 0;
top: 0;
pointer-events: all;
}
.indicator-inner {
width: ${circleSize}px;
height: ${circleSize}px;
border-radius: ${circleSize / 2}px;
margin-left: -${circleSize / 2}px;
margin-top: -${circleSize / 2}px;
cursor: pointer;
}
}
</style>

<div style="width: ${width}px; height: ${height}px;">
${renderer.domElement}
<div class="overlay">
${colorPositions.map((positionObject, i) => {
const clone = positionObject.group.clone();
const projectedVec = clone.position.project(camera);
const x = ( projectedVec.x + 1) * width / 2;
const y = ( Math.abs(projectedVec.y - 1)) * height / 2;
return`
<div
class="indicator"
style="left: ${x}px; top: ${y}px;"
id="indicator-${i}"
>
<div
class="indicator-inner"
style="background-color: ${positionObject.color}"
>${positionObject.color}</div>
</div>
`;
})}
</div>
</div>
` ;
}
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(cylinder);
const circle = createCircle(16);
circle.rotation.x = Math.PI / 2;
scene.add(circle);
const lightnessGeometry = new THREE.Geometry();
lightnessGeometry.vertices.push(
new THREE.Vector3( 0, 0.5, 0 ),
new THREE.Vector3( 0, -0.5, 0 ),
);
const line = new THREE.Line( lightnessGeometry, lineMaterial );
scene.add(line);
// color cube
const primaryColors = [
"#FF0000", // red
"#ffff00", // yellow
"#00ff00", // green
"#00ffff", // cyan
"#0000ff", // blue
"#ff00ff", // magenta
];
primaryColors.forEach(color => {
const cubeHsl = rgbToHsl(hexToRgb(color));
const cubeHue = cubeHsl[0];
const cubeHueAngle = degreesToRadians(cubeHue);
const saturationOffset = mapToRange(cubeHsl[1], [0, 100], [0, 1]);
const lightnessOffset = mapToRange(cubeHsl[2], [0, 100], [-0.5, 0.5]);

const cubeGeometry = new THREE.BoxGeometry( 0.1, 0.1, 0.1 );
cubeGeometry.translate(
Math.sin(cubeHueAngle) * saturationOffset,
lightnessOffset,
Math.cos(cubeHueAngle) * saturationOffset
);
const cubeMaterial = new THREE.MeshBasicMaterial( {color: color} );
var cube = new THREE.Mesh( cubeGeometry, cubeMaterial );

scene.add(cube);
});
colorPositions.forEach(o => {
scene.add(o);
});

return scene;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
getColorPositions = (colors) => {
const colorPositions = [];
colors.forEach(color => {
const hsl = rgbToHsl(hexToRgb(color));
const hue = hsl[0];
const hueAngle = degreesToRadians(hue);
const saturationOffset = mapToRange(hsl[1], [0, 100], [0, 1]);
const lightnessOffset = mapToRange(hsl[2], [0, 100], [-0.5, 0.5]);

const vec = new THREE.Vector3(
Math.sin(hueAngle) * saturationOffset,
lightnessOffset,
Math.cos(hueAngle) * saturationOffset
);

var group = new THREE.Group();
group.position.set(vec.x, vec.y, vec.z)
colorPositions.push({
group: group,
color: color
});
});
return colorPositions;
}
Insert cell
colorPositions = getColorPositions(['#FEFEFD', '#DE8DA1', '#E4A6A5', '#7C7A82', '#2B223F']);
Insert cell
Insert cell
Insert cell
Insert cell
_ = require("lodash")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more