<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>Circle Class</title> <style type='text/css'> * { margin: 0; padding: 0; position: absolute; } </style> <script type='text/javascript'> /* This program is free software. It comes without any warranty, to the extent permitted by applicable law. You can redistribute it and/or modify it under the terms of the Do What The Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See http://sam.zoy.org/wtfpl/COPYING for more details. */ /* This JS class attempts to make an interactive site with the canvas element. In time this will not only be a cirlce class, but more like an object class. The fun stuff happens at the end of this file. */ function Circle(posX, posY, radius, fillColor, borderWidth, borderColor, visible) { // Default to defaults if nothing is specified if (posX == undefined) var posX = 0 if (posY == undefined) var posY = 0 if (radius == undefined) var radius = 50 if (fillColor == undefined) var fillColor = '#ddd' if (borderWidth == undefined) var borderWidth = 2 if (borderColor == undefined) var borderColor = '#444' if (visible == undefined) var visible = true this.visible = visible // Get number in order of creation this.num = objects.length // Create canvas element this.element = document.createElement('canvas') if (!this.visible) this.hide() this.element.style.zIndex = this.num + 2 wrapper.appendChild(this.element) this.context = this.element.getContext('2d') // Append to global objects objects.splice(objects.length, objects.length, this) this.state = 'normal' this.globalstate = 'normal' this.savedstate = 'hover' this.x = posX this.y = posY this.radius = radius this.fillColor = fillColor this.borderWidth = borderWidth this.borderColor = borderColor var i for (i in style_states) { this[style_states[i]] = {} this[style_states[i]].x = false this[style_states[i]].y = false this[style_states[i]].radius = false this[style_states[i]].fillColor = false this[style_states[i]].borderWidth = false this[style_states[i]].borderColor = false } for (i in event_states) { this[event_states[i]] = '' //'dbg.innerHTML+=" '+event_states[i]+'"' } // Keep track of mousedown events this.mousedown_done = false // Keep track of hovering this.hovering = false this.create() } Circle.prototype.create = function() { var posX, posY, radius, fillColor, borderWidth, borderColor, i posX = this.get('x') posY = this.get('y') radius = this.get('radius') fillColor = this.get('fillColor') borderWidth = this.get('borderWidth') borderColor = this.get('borderColor') var mn = radius * 2 + borderWidth var mnh = mn / 2 this.element.width = mn this.element.height = mn this.element.style.width = mn + 'px' this.element.style.height = mn + 'px' this.element.style.left = posX - mnh + 'px' this.element.style.top = posY - mnh + 'px' // Create the circle this.context.beginPath() this.context.arc(mnh, mnh, radius, 0, Math.PI*2, true) if (typeof(fillColor) == 'string') this.context.fillStyle = fillColor else { if (fillColor[0] == 'linear') { var x1, y1, x2, y2 if (fillColor.length > 2) { var angle = (fillColor[2] + 45) % 360 // Center it if (angle >= 0 && angle < 90) { x1 = (angle / 90) * mn y1 = 0 x2 = ((90 - angle) / 90) * mn y2 = mn } else if (angle >= 90 && angle < 180) { x1 = mn y1 = ((angle - 90) / 90) * mn x2 = 0 y2 = ((90 - (angle - 90)) / 90) * mn } else if (angle >= 180 && angle < 270) { x1 = ((90 - (angle - 180)) / 90) * mn y1 = mn x2 = ((angle - 180) / 90) * mn y2 = 0 } else if (angle >= 270 && angle < 360) { x1 = 0 y1 = ((90 - (angle - 270)) / 90) * mn x2 = mn y2 = ((angle - 270) / 90) * mn } } else { x1 = mnh y1 = 0 x2 = mnh y2 = mn } var grad = this.context.createLinearGradient(x1, y1, x2, y2) } else { var lenpos, reallen, angle, x1, y1 if (fillColor.length > 2) { lenpos = (fillColor[2]) if (fillColor.length > 3) { angle = (fillColor[3] + 45) while (angle < 0) { angle += 360 } angle = angle % 360 } else angle = 0 } else { lenpos = 0 angle = 0 } reallen = lenpos * radius if (angle >= 0 && angle < 90) { x1 = mnh + Math.sin((angle - 45) * Math.PI / 180) * reallen y1 = mnh - Math.cos((angle - 45) * Math.PI / 180) * reallen } else if (angle >= 90 && angle < 180) { x1 = mnh + Math.cos((angle - 135) * Math.PI / 180) * reallen y1 = mnh + Math.sin((angle - 135) * Math.PI / 180) * reallen } else if (angle >= 180 && angle < 270) { x1 = mnh - Math.sin((angle - 225) * Math.PI / 180) * reallen y1 = mnh + Math.cos((angle - 225) * Math.PI / 180) * reallen } else if (angle >= 270 && angle < 360) { x1 = mnh - Math.cos((angle - 315) * Math.PI / 180) * reallen y1 = mnh - Math.sin((angle - 315) * Math.PI / 180) * reallen } var grad = this.context.createRadialGradient(x1, y1, 0, mnh, mnh, radius) } for (i in fillColor[1]) { grad.addColorStop(i / (fillColor[1].length - 1), fillColor[1][i]) } this.context.fillStyle = grad } this.context.lineWidth = borderWidth this.context.strokeStyle = borderColor // Clear the screen this.context.clearRect(0, 0, mn, mn) this.context.stroke() this.context.fill() } Circle.prototype.standby = function() { if (!this.visible) return false var posX, posY, radius, borderWidth posX = this.get('x') posY = this.get('y') radius = this.get('radius') borderWidth = this.get('borderWidth') if (!object_hover && Math.sqrt(Math.pow((x - posX), 2) + Math.pow((y - posY), 2)) < radius + borderWidth / 2) { // If the cursor is inside the circle // No more objects may react object_hover = true if (!this.hovering) this.eval(this.onmouseover) else if (x != ox || y != oy) this.eval(this.onmousemove) // We're hovering! this.hovering = true if (this.globalstate == 'onmousedown') { this.state = 'active' this.savedstate = 'active' if (!this.onmousedown_done) { this.onmousedown_done = true this.eval(this.onmousedown) } } else if (this.globalstate == 'onmouseup') { this.state = 'hover' this.savedstate = 'hover' this.eval(this.onmouseup) if (this.onmousedown_done) this.eval(this.onclick) this.onmousedown_done = false } else { // Last resort this.state = this.savedstate } } else { // If the cursor is outside the circle if (this.hovering) { // No more hovering.. this.hovering = false this.eval(this.onmouseout) } // Reset everything this.state = 'normal' if (this.globalstate == 'onmouseup') { this.savedstate = 'hover' this.onmousedown_done = false } } this.globalstate = 'normal' // Create it and draw it to the screen this.create() return true } Circle.prototype.eval = function(code) { var codetype = typeof(code) if (codetype == 'function') code = (code + '').split('function ')[1].split('{')[0] try { eval(code) return true } catch(e) { return false } } Circle.prototype.getobj = function() { if (this.state == 'normal') return this else return this[this.state] } Circle.prototype.get = function(circlevar) { var cobj = this.getobj() if (cobj[circlevar] === false) { if (this.state == 'active' && this.hover[circlevar] !== false) return this.hover[circlevar] else return this[circlevar] } else return cobj[circlevar] } Circle.prototype.set = function(circle_var, value) { this[circle_var] = value for (var i in event_states) { this[event_states[i]][circle_var] = value } } Circle.prototype.hide = function() { this.element.style.display = 'none' this.visible = false } Circle.prototype.show = function() { this.element.style.display = 'block' this.visible = true } Circle.prototype.raiseIndex = function(amount) { if (amount == undefined) var amount = 1 return this.changeIndex(amount) } Circle.prototype.lowerIndex = function(amount) { if (amount == undefined) var amount = 1 return this.changeIndex(-amount) } Circle.prototype.toTop = function() { return this.changeIndex(objects.length - this.num - 1) } Circle.prototype.toBottom = function() { return this.changeIndex(-this.num) } Circle.prototype.changeIndex = function(crement) { if (objects.length > this.num + crement && 0 <= this.num + crement) { objects.splice(this.num, 1) objects.splice(this.num + crement, 0, this) this.update_indexes() return true } else return false } Circle.prototype.remove = function() { objects.splice(this.num, 1) this.update_indexes() wrapper.removeChild(this.element) delete this } Circle.prototype.update_indexes = function() { for (var i in objects) { objects[i].num = i * 1 objects[i].element.style.zIndex = i * 1 + 2 } } function standby() { for (var i = objects.length - 1; i > -1; i--) { objects[i].standby() } object_hover = false ox = x oy = y timer = setTimeout('standby()') } window.onload = function() { // Globals x = 0 y = 0 ox = 0 oy = 0 objects = new Array() object_hover = false getwh() event_states = ['onmouseover', 'onmouseout', 'onmousemove', 'onmousedown', 'onmouseup', 'onclick'] style_states = ['hover', 'active'] globalstate = 'normal' // Creating the wrapper wrapper = document.createElement('div') wrapper.style.position = 'absolute' document.body.appendChild(wrapper) /*dbg = document.createElement('div') dbg.style.position = 'absolute' document.body.appendChild(dbg)*/ // Adjust on resize window.onresize = function() { getwh() } window.onmousedown = function() { for (var i in objects) { objects[i].globalstate = 'onmousedown' } } window.onmouseup = function() { for (var i in objects) { objects[i].globalstate = 'onmouseup' } } standby() loadobjects() } window.onmousemove = function(e) { if (!e) var e = window.event if (e.pageX || e.pageY) { x = e.pageX y = e.pageY } else if (e.clientX || e.clientY) { x = e.clientX + document.body.scrollLeft y = e.clientY + document.body.scrollTop } } function getwh() { if (self.innerHeight) { h = self.innerHeight w = self.innerWidth } else if (document.documentElement && document.documentElement.clientHeight) { h = document.documentElement.clientHeight w = document.documentElement.clientHeight } else if (document.body) { h = document.body.clientHeight w = document.body.clientWidth } } function loadobjects() { circ = new Circle(250, 250, 50, ['radial', ['#00ff00', '#dd33ee', '#888', '#00ffff']], 0, '#000') circ.hover.fillColor = ['radial', ['#0000ff', '#dd33ee', '#333', '#00ffff']] circ.active.fillColor = ['linear', ['#fff', '#000'], -45] circ2 = new Circle(270, 280, 30, '#eee', 5, '#333') circ2.hover.fillColor = '#ff00ff' circ2.active.fillColor = '#ff0000' circ3 = new Circle(260, 220, 25, ['radial', ['#fff', '#000']], 7, '#333') circ3.hover.fillColor = ['radial', ['#000', '#fff']] circ4 = new Circle(340, 290, 60, ['radial', ['rgb(221, 87, 42)', 'rgb(155, 60, 28)'], .6, -10], 0, '#333') circ4.hover.fillColor = ['radial', ['#fff', '#000'], .4, 40] // Below is a list of functions that can be used on a circle. /* changeIndex raiseIndex lowerIndex toTop toBottom hide show remove */ } </script> </head> <body></body> </html>