Last active
August 10, 2021 17:48
-
-
Save Rlesjak/b65e84cdc8fa54b4e7301fa31c1eb589 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Demo Application</title> | |
<style> | |
#jscad{ | |
width: 15cm; | |
height: 15cm; | |
margin: 0; | |
outline: 1px solid black; | |
} | |
</style> | |
</head> | |
<body> | |
<script language="javascript" src="https://unpkg.com/@jscad/modeling" id="MODELING"></script> | |
<script language="javascript" src="./dist/jscad-regl-renderer.min.js" id="RENDERING"></script> | |
<div id="jscad"></div> | |
<script language="javascript"> | |
// ******************** | |
// The design to render. | |
// ******************** | |
const { booleans, colors, primitives, extrusions, hulls, text, transforms } = jscadModeling // modeling comes from the included MODELING library | |
const { union } = booleans | |
const { extrudeLinear } = extrusions | |
const { hullChain } = hulls | |
const { circle, sphere } = primitives | |
const { vectorText } = text | |
const { translate } = transforms | |
const demo = () => { | |
const flatText = buildFlatText('Hello World', 2, 2); | |
return flatText; | |
} | |
// Build text by creating the font strokes (2D), then extruding up (3D). | |
const buildFlatText = (message, extrusionHeight, characterLineWidth) => { | |
if (message === undefined || message.length === 0) return [] | |
const lineRadius = characterLineWidth / 2 | |
const lineCorner = circle({ radius: lineRadius }) | |
const lineSegmentPointArrays = vectorText({ x: 0, y: 0, input: message }) // line segments for each character | |
const lineSegments = [] | |
lineSegmentPointArrays.forEach((segmentPoints) => { // process the line segment | |
const corners = segmentPoints.map((point) => translate(point, lineCorner)) | |
lineSegments.push(hullChain(corners)) | |
}) | |
const message2D = union(lineSegments) | |
const message3D = extrudeLinear({ height: extrusionHeight }, message2D) | |
return translate([0, 0, 0], message3D) | |
} | |
</script> | |
<script language="javascript"> | |
// ******************** | |
// Renderer configuration and initiation. | |
// ******************** | |
const { prepareRender, drawCommands, cameras, controls, entitiesFromSolids } = jscadReglRenderer | |
const perspectiveCamera = cameras.perspective | |
const orbitControls = controls.orbit | |
const containerElement = document.getElementById("jscad") | |
const width = containerElement.clientWidth | |
const height = containerElement.clientHeight | |
const state = {} | |
// prepare the camera | |
state.camera = Object.assign({}, perspectiveCamera.defaults) | |
perspectiveCamera.setProjection(state.camera, state.camera, { width, height }) | |
perspectiveCamera.update(state.camera, state.camera) | |
// prepare the controls | |
state.controls = orbitControls.defaults | |
// prepare the renderer | |
const setupOptions = { | |
glOptions: { container: containerElement }, | |
} | |
const renderer = prepareRender(setupOptions) | |
const gridOptions = { | |
visuals: { | |
drawCmd: 'drawGrid', | |
show: true | |
}, | |
size: [500, 500], | |
ticks: [25, 5], | |
// color: [0, 0, 1, 1], | |
// subColor: [0, 0, 1, 0.5] | |
} | |
const axisOptions = { | |
visuals: { | |
drawCmd: 'drawAxis', | |
show: true | |
}, | |
size: 300, | |
// alwaysVisible: false, | |
// xColor: [0, 0, 1, 1], | |
// yColor: [1, 0, 1, 1], | |
// zColor: [0, 0, 0, 1] | |
} | |
const entities = entitiesFromSolids({}, demo()) | |
// assemble the options for rendering | |
const renderOptions = { | |
camera: state.camera, | |
drawCommands: { | |
drawAxis: drawCommands.drawAxis, | |
drawGrid: drawCommands.drawGrid, | |
drawLines: drawCommands.drawLines, | |
drawMesh: drawCommands.drawMesh | |
}, | |
// define the visual content | |
entities: [ | |
gridOptions, | |
axisOptions, | |
...entities | |
] | |
} | |
// the heart of rendering, as themes, controls, etc change | |
let updateView = true | |
const doRotatePanZoom = () => { | |
if (rotateDelta[0] || rotateDelta[1]) { | |
const updated = orbitControls.rotate({ controls: state.controls, camera: state.camera, speed: rotateSpeed }, rotateDelta) | |
state.controls = { ...state.controls, ...updated.controls } | |
updateView = true | |
rotateDelta = [0, 0] | |
} | |
if (panDelta[0] || panDelta[1]) { | |
const updated = orbitControls.pan({ controls:state.controls, camera:state.camera, speed: panSpeed }, panDelta) | |
state.controls = { ...state.controls, ...updated.controls } | |
panDelta = [0, 0] | |
state.camera.position = updated.camera.position | |
state.camera.target = updated.camera.target | |
updateView = true | |
} | |
if (zoomDelta) { | |
const updated = orbitControls.zoom({ controls:state.controls, camera:state.camera, speed: zoomSpeed }, zoomDelta) | |
state.controls = { ...state.controls, ...updated.controls } | |
zoomDelta = 0 | |
updateView = true | |
} | |
} | |
const updateAndRender = (timestamp) => { | |
doRotatePanZoom() | |
if (updateView) { | |
const updates = orbitControls.update({ controls: state.controls, camera: state.camera }) | |
state.controls = { ...state.controls, ...updates.controls } | |
updateView = state.controls.changed // for elasticity in rotate / zoom | |
state.camera.position = updates.camera.position | |
perspectiveCamera.update(state.camera) | |
renderer(renderOptions) | |
} | |
window.requestAnimationFrame(updateAndRender) | |
} | |
window.requestAnimationFrame(updateAndRender) | |
// convert HTML events (mouse movement) to viewer changes | |
let lastX = 0 | |
let lastY = 0 | |
const rotateSpeed = 0.002 | |
const panSpeed = 1 | |
const zoomSpeed = 0.08 | |
let rotateDelta = [0, 0] | |
let panDelta = [0, 0] | |
let zoomDelta = 0 | |
let pointerDown = false | |
const moveHandler = (ev) => { | |
if(!pointerDown) return | |
const dx = lastX - ev.pageX | |
const dy = ev.pageY - lastY | |
const shiftKey = (ev.shiftKey === true) || (ev.touches && ev.touches.length > 2) | |
if (shiftKey) { | |
panDelta[0] += dx | |
panDelta[1] += dy | |
} else { | |
rotateDelta[0] -= dx | |
rotateDelta[1] -= dy | |
} | |
lastX = ev.pageX | |
lastY = ev.pageY | |
ev.preventDefault() | |
} | |
const downHandler = (ev) => { | |
pointerDown = true | |
lastX = ev.pageX | |
lastY = ev.pageY | |
containerElement.setPointerCapture(ev.pointerId) | |
ev.preventDefault() | |
} | |
const upHandler = (ev) => { | |
pointerDown = false | |
containerElement.releasePointerCapture(ev.pointerId) | |
ev.preventDefault() | |
} | |
const wheelHandler = (ev) => { | |
zoomDelta += ev.deltaY | |
ev.preventDefault() | |
} | |
containerElement.onpointermove = moveHandler | |
containerElement.onpointerdown = downHandler | |
containerElement.onpointerup = upHandler | |
containerElement.onwheel = wheelHandler | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment