437 lines
15 KiB
JavaScript
437 lines
15 KiB
JavaScript
|
/*
|
||
|
* 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
|
||
|
* <http://www.gnu.org/licenses/lgpl-3.0.html>.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Version 0.1.1
|
||
|
* Maintainer: Niels Serup <ns@metanohi.org>
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* There is no real documentation for this script. Look at
|
||
|
* <http://nohix.metanohi.org/modernart.htm> 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+')');
|
||
|
};
|