/* * modernart.js -- Transforming ordinary pictures into dynamic art * Copyright (C) 2010 Niels Serup * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * A copy of the GNU Lesser General Public License is available at * . */ /* * Version 0.1.1 * Maintainer: Niels Serup */ /* * There is no real documentation for this script. Look at * to get an idea on how to * implement it. It's very easy. * This has currently only been tested in Conkeror, IceCat (like * Firefox) 3.67 and Chromium. */ /***************** *** CHANGELOG *** 0.1.1, September 25 2010 -- Now also works with images with absolute or fixed positions. 0.1.0, August 5 2010 -- Initial release. *****************/ createCode = function(dict) { for (x in dict) { try { dict[x].prototype.objectParent = dict; } catch (e) {}; } return dict; }; var modernart = createCode({ ModernArtRunner: function(imgElem, boxElems, lineElems, colorFunction) { this.imgElem = imgElem; this.boxElems = boxElems; this.lineElems = lineElems; this.colorFunctions = this.objectParent.colorFunctions; this.colorFunction = this.colorFunctions[colorFunction]; this.parent = this.imgElem.parentNode; this.timers = []; for (var i in this.boxElems) { for (var j in this.boxElems[i]) { this.boxElems[i][j].objectParent = this; this.parent.appendChild(this.boxElems[i][j]); } } for (var i in this.lineElems) this.parent.appendChild(this.lineElems[i]); var self = this; var timerPause = function() { for (var i in self.timers) self.timers[i].pause(); }; var timerResume = function() { for (var i in self.timers) self.timers[i].resume(); }; var timerToggle = function() { for (var i in self.timers) self.timers[i].toggle(); }; this.imgElem.pause = timerPause; this.imgElem.resume = timerResume; this.imgElem.toggle = timerToggle; this.parent.pause = timerPause; this.parent.resume = timerResume; this.parent.toggle = timerToggle; if (this.objectParent.customFunction) this.objectParent.customFunction(this); this.rgb = [0, 255, 0]; this.colorFunction(); }, Timer: function(func, delay) { this.func = func; this.delay = delay; this.resume(); }, colorFunctions: { flow: function() { var power = parseInt(this.imgElem.getSetting( 'modernflowpower')) || 25; var flowType = this.imgElem.getSetting( 'modernflowtype') || 'stop'; var flowIgnore = flowType == 'stop'; var xPower = parseInt(power / this.boxElems[0].length); var yPower = parseInt(power / this.boxElems.length); var flowRun = function() { var r = this.rgb[0]; var g = this.rgb[1]; var b = this.rgb[2]; if (r < 255 && g <= 0 && b >= 255) r += 10; else if (r > 0 && g >= 255 && b <= 0) r -= 10; else if (r >= 255 && g < 255 && b <= 0) g += 10; else if (r <= 0 && g > 0 && b >= 255) g -= 10; else if (r <= 0 && g >= 255 & b < 255) b += 10; else if (r >= 255 && g <= 0 && b > 0) b -= 10; this.rgb[0] = r; this.rgb[1] = g; this.rgb[2] = b; var tr, tg, tb; for (var i in this.boxElems) { for (var j in this.boxElems[i]) { if (flowIgnore) { if (r > 255) tr = 255; else tr = r; if (g > 255) tg = 255; else tg = g; if (b > 255) tb = 255; else tb = b; this.boxElems[i][j].style.setBackground( tr, tg, tb); } else this.boxElems[i][j].style.setBackground( r % 256, g % 256, b % 256); r += xPower; g += xPower; b += xPower; } r += yPower; g += yPower; b += yPower; } }; var self = this; this.timers.push(new this.objectParent.Timer( function() {flowRun.apply(self);}, 100)); }, individual: function() { var IndividualBox = function(boxElem) { this.elem = boxElem; this.objectParent = this.elem.objectParent; this.topParent = this.objectParent.objectParent; this.rgb = [this.topParent.randInt(255), this.topParent.randInt(255), this.topParent.randInt(255)]; this.way = [this.topParent.randInt(1) || -1, this.topParent.randInt(1) || -1, this.topParent.randInt(1) || -1]; this.generateSpeed(); var self = this; this.objectParent.timers.push( new this.topParent.Timer(function() {self.run()}, 100)); }; IndividualBox.prototype.generateSpeed = function() { this.spd = [this.topParent.randInt(5, 15), this.topParent.randInt(5, 15), this.topParent.randInt(5, 15)]; }; IndividualBox.prototype.run = function() { var rgb = this.rgb; var i; this.elem.style.setBackground(rgb[0], rgb[1], rgb[2]); for (i = 0; i < 3; i++) { rgb[i] += this.spd[i] * this.way[i]; if (this.rgb[i] >= 255) { rgb[i] = 255 - (this.spd[i] - (rgb[i] - 255)); this.generateSpeed(); this.way[i] *= -1; } else if (this.rgb[i] <= 0) { rgb[i] = this.rgb[i] + this.spd[i]; this.generateSpeed(); this.way[i] *= -1; } } for (i in rgb) this.rgb[i] = rgb[i]; }; for (var i in this.boxElems) { for (var j in this.boxElems[i]) new IndividualBox(this.boxElems[i][j]); } } }, applyEffectToImages: function() { var candidates = document.getElementsByTagName('img'); for (var i = 0, node; node = candidates[i++];) { if (node.className.indexOf('modernart') != -1) { if (arguments.length > 0) this.applyEffectToImage(node, arguments[0]); else this.applyEffectToImage(node); } } }, applyEffectToImage: function(imgElem) { var i, j; var size = [imgElem.offsetWidth, imgElem.offsetHeight]; var parent = imgElem.parentNode; var colorFunction = imgElem.getSetting('moderncolor') || 'flow'; var rectSize = parseInt(imgElem.getSetting('modernrect')) || 20; var lineWidth = parseInt(imgElem.getSetting('modernline')); if (isNaN(lineWidth)) lineWidth = 5; var opacity = parseFloat(imgElem.getSetting('modernopacity')) || 0.5; var numbers = parseInt(imgElem.getSetting('modernnumbers')); if (arguments.length > 1) this.customFunction = arguments[1]; else this.customFunction = null; if (!numbers) { numbers = []; var f = rectSize + lineWidth; for (i = 0; i < 2; i++) numbers.push(parseInt((size[i] + lineWidth) / f)); } else { var relativeTo = imgElem.getSetting( 'modernnumbersrel') || 'x'; if (relativeTo == 'x') { numbers = [numbers, parseInt(size[1] / (size[0] / numbers))]; rectSize = ((size[0] + lineWidth) / numbers[0] - lineWidth); } else { // y numbers = [parseInt(size[0] / (size[1] / numbers)), numbers]; rectSize = ((size[1] + lineWidth) / numbers[1] - lineWidth); } } if (lineWidth == 0) { rectSize = []; for (i = 0; i < 2; i++) rectSize.push(size[i] / numbers[i]); lineWidth = [0, 0]; } else { lineWidth = []; for (i = 0; i < 2; i++) lineWidth.push((size[i] - numbers[i] * rectSize) / (numbers[i] - 1)); rectSize = [rectSize, rectSize]; } var container = document.createElement('div'); container.className = imgElem.className; container.style.set('width', size[0] + 'px'); container.style.set('height', size[1] + 'px'); container.style.set('padding', '0'); container.style.set('display', 'inline-block'); container.style.set('float', 'none'); found_pos = imgElem.style.getPropertyValue('position'); container.style.set('position', imgElem.getSetting('modernposition') || found_pos || 'relative'); try { var property, value; for (i in imgElem.style) { property = imgElem.style[i]; value = imgElem.style.getPropertyValue(property); if (value) container.style.set(property, value); } } catch (e) {}; imgElem.style.set('border', 'none'); imgElem.style.set('margin', '0'); imgElem.style.set('left', '0'); imgElem.style.set('top', '0'); imgElem.style.set('background-color', '#000'); parent.insertBefore(container, imgElem); parent.removeChild(imgElem); container.appendChild(imgElem); var elemPos = [0, 0]; var boxElems = []; for (i = 0; i < numbers[1]; i++) { boxes = []; for (j = 0; j < numbers[0]; j++) { elem = document.createElement('div'); elem.style.set('width', rectSize[0] + 'px'); elem.style.set('height', rectSize[1] + 'px'); elem.style.set('background-color', 'transparent'); elem.style.set('position', 'absolute'); elem.style.set('left', elemPos[0] + 'px'); elem.style.set('top', elemPos[1] + 'px'); elem.style.set('margin', '0'); elem.style.set('padding', '0'); elem.style.set('border', 'none'); elem.style.setOpacity(opacity); boxes.push(elem); elemPos[0] += rectSize[0] + lineWidth[0]; } boxElems.push(boxes); elemPos[1] += rectSize[1] + lineWidth[1]; elemPos[0] = 0; } var lineElems = []; if (lineWidth[0] > 0) { var tempWidth, tempHeight, tempTop, tempLeft; for (i = 0; i < 2; i++) { elemPos = rectSize[i]; if (i == 0) { tempWidth = lineWidth[0]; tempHeight = size[1]; } else { tempWidth = size[0]; tempHeight = lineWidth[1]; } for (j = 0; j < numbers[i] - 1; j++) { if (i == 0) { tempLeft = elemPos; tempTop = 0; } else { tempLeft = 0; tempTop = elemPos; } elem = document.createElement('div'); elem.style.set('width', tempWidth + 'px'); elem.style.set('height', tempHeight + 'px'); elem.style.set('background-color', '#000'); elem.style.set('position', 'absolute'); elem.style.set('left', tempLeft + 'px'); elem.style.set('top', tempTop + 'px'); elem.style.set('margin', '0'); elem.style.set('padding', '0'); elem.style.set('border', 'none'); lineElems.push(elem); elemPos += rectSize[i] + lineWidth[i]; } } } new this.ModernArtRunner(imgElem, boxElems, lineElems, colorFunction); }, randInt: function() { // function([min, ]max) if (arguments.length == 0) return 0; var min, max; if (arguments.length > 1) { min = arguments[0]; max = arguments[1]; } else { min = 0; max = arguments[0]; } return Math.floor(Math.random() * (max + 1)) + min; } }); delete createCode; modernart.Timer.prototype.resume = function() { this.interval = setInterval(this.func, this.delay); this.running = true; }; modernart.Timer.prototype.pause = function() { clearInterval(this.interval); delete this.interval; this.running = false; }; modernart.Timer.prototype.toggle = function() { if (this.running) this.pause(); else this.resume(); }; HTMLElement.prototype.getSetting = function(property) { var string = this.className; var start, end; start = string.indexOf(property + ':'); if (start != -1) { end = string.indexOf(' ', start); if (end == -1) return string.substring(start + property.length + 1); else return string.substring(start + property.length + 1, end); } }; CSSStyleDeclaration.prototype.set = function(property, value) { this.setProperty(property, value, null); }; CSSStyleDeclaration.prototype.setOpacity = function(val) { this.set('opacity', val); this.set('-moz-opacity', val); this.set('-khtml-opacity', val); this.filter = 'alpha(opacity=' + val*100 + ')'; }; CSSStyleDeclaration.prototype.setBackground = function(r, g, b) { this.set('background-color', 'rgb('+r+', '+g+', '+b+')'); };