MX.Map = function(){ var base = this; var parent = document.querySelector("#map") var canvas = document.createElement("canvas") var ctx = canvas.getContext("2d") var w, h var visible = parent.style.display == "block" if (visible) resize() var center = {x:0,y:0} var gridSpace; var zoom = 3.0 var gridStroke = '#ddd' var boxFill = '#fff' var boxStroke = '#000' var playerColor = '#888' var xmin, xmax, ymin, ymax, xpos, ypos, scale, side; var tube = base.tube = new Tube () this.zoom = function(n){ if (n) zoom = n; return zoom } this.recenter = function(){ center.x = cam.x; center.y = cam.z } function resize(){ var rect = parent.getBoundingClientRect() w = canvas.width = ~~rect.width h = canvas.height = ~~rect.height } this.on = function(){ base.tube.on.apply(base.tube, arguments) } this.off = function(){ base.tube.off.apply(base.tube, arguments) } this.update = function(){ if (! visible) return; this.draw() } this.bounds = function(){ gridSpace = pow(10, ~~(zoom-0.25) + 0.25) side = Math.pow(10, zoom+1) scale = w / side xpos = center.x // -cam.x ypos = center.y // cam.z xmin = side/-2 - xpos xmax = side/2 - xpos ymin = side/-2 - ypos ymax = side/2 - ypos } this.draw = function(){ ctx.clearRect(0,0,w,h) ctx.fillStyle = "#fff" ctx.fillRect(0,0,w,h) this.bounds() this.grid() this.boxes() this.player() } this.grid = function(){ ctx.strokeStyle = gridStroke ctx.lineWidth = 1 ctx.fillStyle = "transparent" var x0 = norm(0, xmin, xmax) var y0 = norm(0, ymin, ymax) var xg = norm(gridSpace, xmin, xmax) var yg = norm(gridSpace, ymin, ymax) var xgw = (xg-x0) var xmod = mod(x0, xgw) var ymod = mod(y0, xgw) var xend = 1 + xgw var yend = h/w + xgw var xline, yline; for (var x = -xmod; x < xend; x += xgw) { xline = x * w line(xline, 0, xline, h) } for (var y = -ymod; y < yend; y += xgw) { yline = y * w line(0, yline, w, yline) } function line(x0,y0,x1,y1) { ctx.beginPath() ctx.moveTo(x0, y0) ctx.lineTo(x1, y1) ctx.stroke() } } this.player = function(){ ctx.save() ctx.translate(~~(w/2),~~(h/2)); ctx.lineWidth = 0.5 var tx = ((-xpos) * scale), ty = ((-ypos) * scale); ctx.translate(tx, ty) var obj_scale = (1) * scale var tx = ~~((cam.x) * obj_scale), ty = ~~((cam.z) * obj_scale); ctx.translate(-tx, ty) ctx.rotate(-cam.rotationY) var radius = 5 ctx.fillStyle = playerColor; ctx.beginPath(); ctx.arc(0, 0, radius, 0, 2*Math.PI, false); ctx.fill(); ctx.beginPath(); ctx.moveTo(0,0) ctx.lineTo(-radius,0) ctx.lineTo(0,radius*3) ctx.lineTo(radius,0) ctx.moveTo(0,0) ctx.fill() ctx.fillStyle = "transparent" ctx.restore() } this.boxes = function(){ ctx.save() ctx.translate(~~(w/2),~~(h/2)); ctx.lineWidth = 0.5 var tx = ((-xpos) * scale), ty = ((-ypos) * scale); ctx.translate(tx, ty) scene.inner.children.forEach(function(obj){ if (obj.type == "BoxDimensions" || obj.type == "ScaleBox") { ctx.save() ctx.fillStyle = obj.color ctx.strokeStyle = "#222" var obj_scale = (obj.scale || 1) * scale var tx = ~~((obj.x) * scale), ty = ~~((obj.z) * scale); ctx.translate(-tx, ty) ctx.rotate(-obj.rotationY) var ww = ~~(obj.width/2 * obj_scale) var hh = ~~(obj.depth/2 * obj_scale) ctx.beginPath(); ctx.moveTo(ww, hh) ctx.lineTo(ww, -hh) ctx.lineTo(-ww, -hh) ctx.lineTo(-ww, hh) ctx.closePath() ctx.fill() ctx.stroke() ctx.restore() } if (obj.type == "Image" || obj.type == "Cutout") { ctx.save() ctx.strokeStyle = "#444" var obj_scale = (obj.scale || 1) * scale var tx = ~~((obj.x) * scale), ty = ~~((obj.z) * scale); ctx.translate(-tx, ty) ctx.rotate(-obj.rotationY) var ww = ~~(obj.width/2 * obj_scale) ctx.beginPath(); ctx.moveTo(ww, 0) ctx.lineTo(-ww, 0) ctx.closePath() ctx.stroke() ctx.restore() } }) ctx.restore() } var dragging = false, mx = 0, my = 0, mdx = 0, mdy = 0, cx, cy, creating = false, moving = false; function positionFromMouse(e) { var rect = canvas.getBoundingClientRect() cx = center.x cy = center.y mx = e.pageX - rect.left my = e.pageY - rect.top mdx = (mx - w/2) / scale + cx mdy = (my - h/2) / scale + cy } canvas.addEventListener("mousedown", function(e){ e.stopPropagation() dragging = true positionFromMouse(e) if (e.shiftKey) { creating = true } hud.update( mdx, mdy ) base.tube("mousedown", e, -mdx, mdy) }) document.addEventListener("mousemove", function(e){ if (dragging) { e.stopPropagation() var rect = canvas.getBoundingClientRect() var mnx = e.pageX - rect.left var mny = e.pageY - rect.top mdx = (mnx - mx) / scale mdy = (mny - my) / scale if (creating) { hud.update( mdx, mdy ) } else if (moving) { cam.x = cx - mdx cam.z = cy + mdy } else { center.x = cx - mdx center.y = cy - mdy hud.update(center.x, center.y) } base.tube("mousedrag", e, -mdx, mdy) } else { positionFromMouse(e) hud.update( mdx, mdy ) base.tube("mousemove", e, -mdx, mdy) } }) document.addEventListener("mouseup", function(e){ creating = dragging = moving = false; base.tube("mouseup", e) }) canvas.addEventListener("contextmenu", function(e){ e.preventDefault() e.stopPropagation() dragging = true positionFromMouse(e) moving = true cx = cam.x = -mdx cy = cam.z = mdy hud.update( mdx, mdy ) base.tube("contextmenu", e) }) canvas.addEventListener( 'mousewheel', onDocumentMouseWheel, false ); canvas.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false); function onDocumentMouseWheel (e) { e.preventDefault() e.stopPropagation() var delta = 0 // WebKit if ( event.wheelDeltaY ) { delta = - event.wheelDeltaY * 0.0003; } // Opera / Explorer 9 else if ( event.wheelDelta ) { delta = - event.wheelDelta * 0.0003; } // Firefox else if ( event.detail ) { delta = event.detail * 0.01; } if (! e.shiftKey) { zoom += delta } positionFromMouse(e) base.tube("mousewheel", e, mdx, mdy, delta) map.update() } window.addEventListener('resize', resize) this.toggle = function(){ (visible = ! visible) ? base.show() : base.hide() } this.show = function(){ parent.style.display = "block" resize() } this.hide = function(){ parent.style.display = "none" } var hud = new function(){ var el = document.querySelector("#map .hud") this.update = function(){ el.innerHTML = Array.prototype.slice.call(arguments,0).map(function(s){ return typeof s == "number" ? Math.round(s) : s }).join(" ") } } hud.update() this.update() document.querySelector("#map .el").appendChild(canvas) }