├── README.md ├── basic-example ├── Cakefile ├── code.coffee └── index.html ├── edit-in-webpage └── index.html └── multiple-views ├── Cakefile ├── code.coffee └── index.html /README.md: -------------------------------------------------------------------------------- 1 | threejs-examples 2 | ================ 3 | 4 | Collection of small Three.js examples relevant to math visualization 5 | -------------------------------------------------------------------------------- /basic-example/Cakefile: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | {print} = require 'util' 3 | {spawn, exec} = require 'child_process' 4 | 5 | log = (message, explanation) -> 6 | console.log message + ' ' + (explanation or '') 7 | 8 | build = (watch, callback) -> 9 | if typeof watch is 'function' 10 | callback = watch 11 | watch = false 12 | options = ['-c','-m','code.coffee'] 13 | options.unshift '-w' if watch 14 | 15 | coffee = spawn 'coffee', options 16 | coffee.stdout.on 'data', (data) -> print data.toString() 17 | coffee.stderr.on 'data', (data) -> log data.toString() 18 | coffee.on 'exit', (status) -> callback?() if status is 0 19 | 20 | task 'sbuild', 'generate javascript files.', -> 21 | build -> log "Done building." -------------------------------------------------------------------------------- /basic-example/code.coffee: -------------------------------------------------------------------------------- 1 | 2 | # The Mathematics 3 | 4 | gcd = (a,b,depth=0) -> 5 | switch 6 | when a > b then gcd(a-b,b,depth+1) 7 | when a < b then gcd(a,b-a,depth+1) 8 | when a == b then [a, depth] 9 | else "error" 10 | 11 | canonicalize = (a,b) -> 12 | [g,d] = gcd(a,b) 13 | [a/g, b/g] 14 | 15 | 16 | # Helper Functions for Creating Three.js Objects 17 | 18 | remove_duplicates = (arr) -> 19 | output = {} 20 | output[arr[key]] = arr[key] for key in [0...arr.length] 21 | value for key, value of output 22 | 23 | gcd_geometry = (boxsize=10) -> 24 | M = boxsize 25 | S = [] 26 | for a in [1..M] 27 | for b in [1..M] 28 | S.push(canonicalize(a,b)) 29 | S = remove_duplicates(S) 30 | console.log(S) 31 | pair2line = (p,q) -> 32 | l = Math.min(M/p,M/q) 33 | [g,depth] = gcd(p,q) 34 | { from: [p,q,1], to: [l*p,l*q,l], color: depth/M } 35 | ( pair2line(p,q) for [p,q] in S ) 36 | 37 | drawline = (from,to,material) -> 38 | geometry = new THREE.Geometry() 39 | geometry.vertices[0] = new THREE.Vector3( from[0], from[1], from[2] ) 40 | geometry.vertices[1] = new THREE.Vector3( to[0], to[1], to[2] ) 41 | new THREE.Line(geometry, material, THREE.LineStrip) 42 | 43 | drawcube = (M,material) -> 44 | group = new THREE.Object3D() 45 | group.add(drawline(a,b,material)) for [a,b] in [ 46 | [[0,0,0], [M,0,0]], 47 | [[0,0,0], [0,M,0]], 48 | [[0,0,0], [0,0,M]], 49 | [[M,0,0], [M,0,M]], 50 | [[M,0,0], [M,M,0]], 51 | [[0,M,0], [0,M,M]], 52 | [[0,M,0], [M,M,0]], 53 | [[0,0,M], [M,0,M]], 54 | [[0,0,M], [0,M,M]], 55 | [[M,M,0], [M,M,M]], 56 | [[0,M,M], [M,M,M]], 57 | [[M,0,M], [M,M,M]] ] 58 | group 59 | 60 | 61 | # Setup Three.js 62 | 63 | init = (boxsize) -> 64 | renderer = new THREE.SVGRenderer() 65 | renderer.setSize( window.innerWidth, window.innerHeight ) 66 | document.body.appendChild( renderer.domElement ) 67 | 68 | alpha = 1 69 | aspect = window.innerWidth / window.innerHeight 70 | 71 | camera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 1, 1000 ) 72 | #camera = new THREE.OrthographicCamera( -alpha*boxsize*aspect, alpha*boxsize*aspect, alpha*boxsize, -alpha*boxsize, 1, 1000 ); 73 | 74 | camera.position.z = 50 75 | 76 | scene = new THREE.Scene() 77 | 78 | group = new THREE.Object3D() 79 | 80 | group.add(drawcube(boxsize, new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 2} ))) 81 | 82 | for line in gcd_geometry(boxsize) 83 | color = new THREE.Color() 84 | color.setHSL(line.color, 0.8, 0.4) 85 | material = new THREE.LineBasicMaterial( { color: color, dashSize: 3, gapSize: 1, linewidth: 2} ) 86 | group.add(drawline(line.from,line.to,material)) 87 | 88 | scene.add(group) 89 | 90 | group.rotation.x = 3.1415 * (- 0.5 ) 91 | group.position.x = -5 92 | group.position.y = -5 93 | 94 | render = () -> 95 | renderer.render( scene, camera ) 96 | 97 | controls = new THREE.OrbitControls( camera ) 98 | controls.addEventListener( 'change', render ) 99 | 100 | render 101 | 102 | 103 | # Main 104 | 105 | render = init(10) 106 | 107 | render() -------------------------------------------------------------------------------- /basic-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /edit-in-webpage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Interactive SVG Snapshot from Three.js Visualization 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 30 | 31 | 32 | 33 | 37 | 38 | 39 | 40 | 41 | 42 |

Visualization

43 | 44 | 45 |

Snap!

46 | 47 |

Snapshot

48 | 49 | 53 | 54 |
55 |
56 |
57 |
58 | 59 | 68 | 69 |

Editor

70 | 188 | 189 |

Run!

190 | 191 | 208 | 209 | 210 | 247 | 248 | -------------------------------------------------------------------------------- /multiple-views/Cakefile: -------------------------------------------------------------------------------- 1 | fs = require 'fs' 2 | {print} = require 'util' 3 | {spawn, exec} = require 'child_process' 4 | 5 | log = (message, explanation) -> 6 | console.log message + ' ' + (explanation or '') 7 | 8 | build = (watch, callback) -> 9 | if typeof watch is 'function' 10 | callback = watch 11 | watch = false 12 | options = ['-c','-m','code.coffee'] 13 | options.unshift '-w' if watch 14 | 15 | coffee = spawn 'coffee', options 16 | coffee.stdout.on 'data', (data) -> print data.toString() 17 | coffee.stderr.on 'data', (data) -> log data.toString() 18 | coffee.on 'exit', (status) -> callback?() if status is 0 19 | 20 | task 'sbuild', 'generate javascript files.', -> 21 | build -> log "Done building." -------------------------------------------------------------------------------- /multiple-views/code.coffee: -------------------------------------------------------------------------------- 1 | 2 | # The Mathematics 3 | 4 | gcd = (a,b,depth=0) -> 5 | switch 6 | when a > b then gcd(a-b,b,depth+1) 7 | when a < b then gcd(a,b-a,depth+1) 8 | when a == b then [a, depth] 9 | else "error" 10 | 11 | canonicalize = (a,b) -> 12 | [g,d] = gcd(a,b) 13 | [a/g, b/g] 14 | 15 | 16 | # Helper Functions for Creating Three.js Objects 17 | 18 | remove_duplicates = (arr) -> 19 | output = {} 20 | output[arr[key]] = arr[key] for key in [0...arr.length] 21 | value for key, value of output 22 | 23 | gcd_geometry = (boxsize=10) -> 24 | M = boxsize 25 | S = [] 26 | for a in [1..M] 27 | for b in [1..M] 28 | S.push(canonicalize(a,b)) 29 | S = remove_duplicates(S) 30 | console.log(S) 31 | pair2line = (p,q) -> 32 | l = Math.min(M/p,M/q) 33 | [g,depth] = gcd(p,q) 34 | { from: [p,q,1], to: [l*p,l*q,l], color: depth/M } 35 | ( pair2line(p,q) for [p,q] in S ) 36 | 37 | drawline = (from,to,material) -> 38 | geometry = new THREE.Geometry() 39 | geometry.vertices[0] = new THREE.Vector3( from[0], from[1], from[2] ) 40 | geometry.vertices[1] = new THREE.Vector3( to[0], to[1], to[2] ) 41 | new THREE.Line(geometry, material, THREE.LineStrip) 42 | 43 | drawcube = (M,material) -> 44 | group = new THREE.Object3D() 45 | group.add(drawline(a,b,material)) for [a,b] in [ 46 | [[0,0,0], [M,0,0]], 47 | [[0,0,0], [0,M,0]], 48 | [[0,0,0], [0,0,M]], 49 | [[M,0,0], [M,0,M]], 50 | [[M,0,0], [M,M,0]], 51 | [[0,M,0], [0,M,M]], 52 | [[0,M,0], [M,M,0]], 53 | [[0,0,M], [M,0,M]], 54 | [[0,0,M], [0,M,M]], 55 | [[M,M,0], [M,M,M]], 56 | [[0,M,M], [M,M,M]], 57 | [[M,0,M], [M,M,M]] ] 58 | group 59 | 60 | 61 | from_rgb = (triple) -> 62 | new THREE.Color().setRGB( triple[0], triple[1], triple[2] ) 63 | 64 | # Setup Three.js 65 | 66 | init = (boxsize) -> 67 | renderer = new THREE.WebGLRenderer() 68 | renderer.setSize( window.innerWidth, window.innerHeight ) 69 | document.body.appendChild( renderer.domElement ) 70 | 71 | alpha = 1 72 | aspect = window.innerWidth / window.innerHeight 73 | 74 | camera = new THREE.PerspectiveCamera( 25, window.innerWidth / window.innerHeight, 1, 1000 ) 75 | #camera = new THREE.OrthographicCamera( -alpha*boxsize*aspect, alpha*boxsize*aspect, alpha*boxsize, -alpha*boxsize, 1, 1000 ); 76 | 77 | camera.position.z = 50 78 | 79 | scene = new THREE.Scene() 80 | 81 | group = new THREE.Object3D() 82 | 83 | group.add(drawcube(boxsize, new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 2} ))) 84 | 85 | for line in gcd_geometry(boxsize) 86 | color = new THREE.Color() 87 | color.setHSL(line.color, 0.8, 0.4) 88 | material = new THREE.LineBasicMaterial( { color: color, dashSize: 3, gapSize: 1, linewidth: 2} ) 89 | group.add(drawline(line.from,line.to,material)) 90 | 91 | scene.add(group) 92 | 93 | group.rotation.x = 3.1415 * (- 0.5 ) 94 | group.position.x = -5 95 | group.position.y = -5 96 | 97 | render = () -> 98 | views = { left: { 99 | left: 0, 100 | bottom: 0, 101 | width: 0.67, 102 | height: 1, 103 | background: [0.5, 0.5, 0.7] 104 | }, bottom_right: { 105 | left: 0.67, 106 | bottom: 0, 107 | width: 0.33, 108 | height: 0.5, 109 | background: [0.5, 0.7, 0.5] 110 | }, top_right: { 111 | left: 0.67, 112 | bottom: 0.5, 113 | width: 0.33, 114 | height: 0.5, 115 | background: [0.7, 0.5, 0.5] 116 | } 117 | } 118 | 119 | render_view = (view, scene, camera) -> 120 | left = Math.floor( window.innerWidth * view.left ) 121 | bottom = Math.floor( window.innerHeight * view.bottom ) 122 | width = Math.floor( window.innerWidth * view.width ) 123 | height = Math.floor( window.innerHeight * view.height ) 124 | 125 | renderer.setSize(window.innerWidth, window.innerHeight) 126 | renderer.setViewport(left,bottom,width,height) 127 | renderer.setScissor(left,bottom,width,height) 128 | renderer.enableScissorTest(true) 129 | renderer.setClearColor(from_rgb(view.background)) 130 | 131 | camera.aspect = width / height 132 | camera.updateProjectionMatrix() 133 | 134 | renderer.render( scene, camera ) 135 | 136 | render_view(views.left, scene, camera) 137 | render_view(views.top_right, scene, camera) 138 | render_view(views.bottom_right, scene, camera) 139 | 140 | controls = new THREE.OrbitControls( camera ) 141 | controls.addEventListener( 'change', render ) 142 | 143 | render 144 | 145 | 146 | # Main 147 | 148 | render = init(10) 149 | 150 | render() -------------------------------------------------------------------------------- /multiple-views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | --------------------------------------------------------------------------------