body {
	background-color: #000;
	margin: 0px;
	overflow: hidden;
}
const vshader = `
    precision highp float;

    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;

    attribute vec3 position;
    attribute vec3 translate;
    attribute vec4 color;
    attribute float scale;

    varying vec4 vColor;

    void main() {
        vec4 mvPosition = modelViewMatrix * vec4( translate, 1.0 );
        mvPosition.xyz += position * scale;
        vColor = color;
        gl_Position = projectionMatrix * mvPosition;
    }
`;

const fshader = `
    precision highp float;

    varying vec4 vColor;

    void main() {
        gl_FragColor = vColor;
    }
`;

let renderer;
let camera;
let material;
let scene;
let circle;
let circleGeometry;
let circleTranslateArray;
let circleColorArray;
let circleScaleArray;
let circleMesh;
let controls;

renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.domElement.setAttribute("id", "scatterplot");
document.body.insertAdjacentElement('afterbegin', renderer.domElement);

camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight );

scene = new THREE.Scene();

circleGeometry = new THREE.CircleBufferGeometry( 5.0, 50 );

circle = new THREE.InstancedBufferGeometry();
circle.index = circleGeometry.index;
circle.attributes = circleGeometry.attributes;

circleTranslateArray = [0.0, 0.0, 0.0];
circleColorArray = [1.0, 0.0, 1.0, 1.0];
circleScaleArray = [1.0];

circle.addAttribute( 'scale', new THREE.InstancedBufferAttribute( new Float32Array(circleScaleArray), 1 ));
circle.addAttribute( 'translate', new THREE.InstancedBufferAttribute( new Float32Array(circleTranslateArray), 3 ));
circle.addAttribute( 'color', new THREE.InstancedBufferAttribute( new Float32Array(circleColorArray), 4 ));

material = new THREE.RawShaderMaterial({ 
    uniforms: {},
    vertexShader: vshader,
    fragmentShader: fshader
});

circleMesh = new THREE.Mesh( circle, material );
circleMesh.scale.set( 350, 350, 350 );

scene.add( circleMesh );

controls = new THREE.OrbitControls(camera, document.getElementById("scatterplot"));
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.mouseButtons = {
    LEFT: THREE.MOUSE.LEFT,
    MIDDLE: THREE.MOUSE.RIGHT
}
controls.rotateSpeed = 0.15;
controls.target = new THREE.Vector3(0,0,0);
controls.screenSpacePanning = false;
controls.enablePan = false;
controls.minDistance = 50;
controls.maxDistance = 1500;
controls.maxPolarAngle = Math.PI;
controls.minPolarAngle = 0;

window.addEventListener( 'resize', onWindowResize, false );

animate();

function animate() {
    requestAnimationFrame( animate );
    controls.update();
    renderer.render( scene, camera );
}

function onWindowResize( event ) {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( window.innerWidth, window.innerHeight );
}
View Compiled
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://threejs.org/build/three.js
  2. https://threejs.org/examples/js/controls/OrbitControls.js