Skip to content

Instantly share code, notes, and snippets.

@Rlesjak
Last active August 10, 2021 17:48
Show Gist options
  • Save Rlesjak/b65e84cdc8fa54b4e7301fa31c1eb589 to your computer and use it in GitHub Desktop.
Save Rlesjak/b65e84cdc8fa54b4e7301fa31c1eb589 to your computer and use it in GitHub Desktop.
<!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