DIR : /home/kozerus/public_html/jkwii/js/jsdoit/Kira-Kira-Camera/index.js
/home/kozerus/public_html/jkwii/js/jsdoit/Kira-Kira-Camera
// forked from akm2's "Motion Detection" http://jsdo.it/akm2/2VGa
// forked from akm2's "Slit Scan Camera" http://jsdo.it/akm2/gmjx
// forked from akm2's "Scanner Camera" http://jsdo.it/akm2/63bn
/**
* requestAnimationFrame polyfill by Erik Möller
* fixes from Paul Irish and Tino Zijdel
*
* @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* @see http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
*/
(function(e){var t=0;var n=["ms","moz","webkit","o"];var r="requestAnimationFrame";var i="cancelAnimationFrame";for(var s=0;s<n.length&&!e[r];++s){e[r]=e[n[s]+"RequestAnimationFrame"];e[i]=e[n[s]+"CancelAnimationFrame"]||e[n[s]+"CancelRequestAnimationFrame"]}if(!e.requestAnimationFrame)e[r]=function(n,r){var i=(new Date).getTime();var s=Math.max(0,16-(i-t));var o=e.setTimeout(function(){n(i+s)},s);t=i+s;return o};if(!e[i])e[i]=function(e){clearTimeout(e)}})(window);
// window.URL
window.URL = window.URL || window.webkitURL;
// navigator.getUserMedia
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
// Config
var CANVAS_WIDTH = 465,
CANVAS_HEIGHT = 348,
MAX_NUM = 1500,
GRAVITY = 0.045;
// Vars
var video, canvas, context,
pastImageData = null,
destImageData,
particles = [],
pool = [],
threshold = 50,
showMap = false,
gui;
/**
* Init
*/
function init() {
if (!navigator.getUserMedia) {
alert('getUserMedia() Not supported');
return;
}
canvas = document.getElementById('c');
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
canvas.style.top = ((document.getElementById('container').offsetHeight - CANVAS_HEIGHT) / 2 | 0) + 'px';
context = canvas.getContext('2d');
context.fillStyle = 'hotpink';
destImageData = context.createImageData(CANVAS_WIDTH, CANVAS_HEIGHT);
video = document.createElement('video');
video.autoplay = true;
Kirakira.initialize(12, 4);
navigator.getUserMedia({ video: true }, function(stream) {
video.addEventListener('canplaythrough', function(e) {
gui = new dat.GUI();
gui.width = 250;
gui.add(window, 'threshold', 0, 255).step(1).name('Threshold');
gui.add(window, 'toggleDisplay').name('Toggle display');
gui.close();
setTimeout(update, 1000);
}, false);
video.src = window.URL.createObjectURL(stream);
}, function(e) {
alert('Error: ' + (e.code === e.PERMISSION_DENIED ? 'Permission denied' : 'Unknown'));
});
}
/**
* マップ表示を切替
*/
function toggleDisplay(e) {
showMap = !showMap;
}
/**
* Update
*/
function update() {
var W = CANVAS_WIDTH,
H = CANVAS_HEIGHT,
currImageData,
p;
context.save();
context.translate(W, 0);
context.scale(-1, 1);
context.drawImage(video, 0, 0, W, H);
context.restore();
currImageData = context.getImageData(0, 0, W, H);
if (pastImageData) {
var TWO_PI = Math.PI * 2,
destPixels = destImageData.data,
currPixels = currImageData.data,
pastPixels = pastImageData.data,
pastAverage, currAverage,
diff, isDiff,
x, y, yi, i, i1, i2;
for (y = 0, i = 0; y < H; y++) {
yi = y * W;
for (x = 0; x < W; x++, i += 4) {
i1 = i + 1;
i2 = i + 2;
pastAverage = (pastPixels[i] + pastPixels[i1] + pastPixels[i2]) / 3;
currAverage = (currPixels[i] + currPixels[i1] + currPixels[i2]) / 3;
diff = pastAverage - currAverage;
if (diff < 0) diff *= -1;
isDiff = diff > threshold;
// 差があれば一定の確立でパーティクルを生成
if (isDiff && Math.random() < 0.005 && particles.length < MAX_NUM) {
p = pool.length ? pool.shift() : new Particle(); // 生成済みのパーティクルがあれば使い回す
mag = 0.5 + 2.5 * Math.random();
magAngle = TWO_PI * Math.random();
p.init(
x, y,
mag * Math.cos(magAngle),
mag * Math.sin(magAngle),
0.5 + 0.5 * Math.random(), // scale
TWO_PI * Math.random() //angle
);
particles.push(p);
}
// 表示用
destPixels[i] = destPixels[i + 1] = destPixels[i + 2] = isDiff ? 255 : 0;
destPixels[i + 3] = 255;
}
}
}
if (showMap) context.putImageData(destImageData, 0, 0);
pastImageData = currImageData;
var G = GRAVITY,
symbols = Kirakira.symbols,
symbolNum = Kirakira.symbols.length,
radius = Kirakira.radius,
size = Kirakira.size,
dScale, dSize, dSizeHalf;
for (i = 0, len = particles.length; i < len; i++) {
p = particles[i];
p.vy += G;
p.x += p.vx;
p.y += p.vy;
p.scale -= 0.02 * Math.random();
p.angle += Math.random();
if (p.x + radius < 0 || p.x - radius > W || p.y + radius < 0 || p.y - radius > H || p.scale <= 0) {
pool.push(p); // 使い回すためプール
particles.splice(i, 1);
len--;
i--;
continue;
}
dScale = p.scale;
if (Math.random() < 0.5) dScale *= 0.2;
dSize = size * dScale;
dSizeHalf = dSize * 0.5;
context.save();
context.globalCompositeOperation = 'lighter';
context.translate(p.x, p.y);
context.rotate(p.angle);
context.drawImage(symbols[symbolNum * Math.random() | 0], 0, 0, size, size, -dSizeHalf, -dSizeHalf, dSize, dSize);
context.restore();
}
requestAnimationFrame(update);
}
/**
* Particle
*/
function Particle(x, y, vx, vy, scale, angle) {
this.init(x, y, vx, vy, scale, angle);
}
Particle.prototype.init = function(x, y, vx, vy, scale, angle) {
this.x = x || 0;
this.y = y || 0;
this.vx = vx || 0;
this.vy = vy || 0;
this.scale = scale || 0;
this.angle = angle || 0;
};
/**
* Kirakira
*/
var Kirakira = (function() {
var VERTEX_NUMS = [4, 6, 8, 10, 12];
return {
symbols: [],
radius: 0,
blur: 0,
size: 0,
initialize: function(radius, blur) {
this.radius = radius;
this.blur = blur;
this.size = (this.radius + this.blur) * 2;
for (var i = 0, len = VERTEX_NUMS.length; i < len; i++) {
this.symbols.push(this._createSymbol(VERTEX_NUMS[i], this.radius, this.blur));
}
},
_createSymbol: function createSymbol(vertexNum, radius, blur) {
var canvas = document.createElement('canvas');
canvas.width = canvas.height = this.size;
var context = canvas.getContext('2d');
context.fillStyle = 'rgba(255, 255, 255, 1)';
context.shadowBlur = blur;
context.shadowColor = 'rgba(255, 255, 255, 0.75)';
var center = this.size / 2;
var r, a;
context.beginPath();
for (var i = 1, len = vertexNum * 2; i <= len; i++) {
r = i % 2 ? this.radius * 0.1 : this.radius;
a = i / len * Math.PI * 2;
context[i === 1 ? 'moveTo' : 'lineTo'](center + r * Math.cos(a), center + r * Math.sin(a));
}
context.fill();
return canvas;
}
};
})();
// Init
window.addEventListener('load', init, false);
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer