Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

starting imageVision

  • Loading branch information...
commit 8215da1eb6a978bb8a46da92bbdb99bc0cd6c641 1 parent 18b9112
Felix Niklas authored
29 1_edge_detection/1_edge_detection.tmproj
View
@@ -3,10 +3,12 @@
<plist version="1.0">
<dict>
<key>currentDocument</key>
- <string>js/Kernel.js</string>
+ <string>css/style.css</string>
<key>documents</key>
<array>
<dict>
+ <key>expanded</key>
+ <true/>
<key>name</key>
<string>css</string>
<key>regexFolderFilter</key>
@@ -26,7 +28,7 @@
<key>filename</key>
<string>index.html</string>
<key>lastUsed</key>
- <date>2012-10-16T12:21:10Z</date>
+ <date>2012-10-17T09:04:24Z</date>
</dict>
<dict>
<key>expanded</key>
@@ -43,19 +45,33 @@
<integer>200</integer>
<key>metaData</key>
<dict>
- <key>index.html</key>
+ <key>css/style.css</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
- <integer>38</integer>
+ <integer>23</integer>
<key>line</key>
+ <integer>49</integer>
+ </dict>
+ <key>firstVisibleColumn</key>
+ <integer>0</integer>
+ <key>firstVisibleLine</key>
+ <integer>41</integer>
+ </dict>
+ <key>index.html</key>
+ <dict>
+ <key>caret</key>
+ <dict>
+ <key>column</key>
<integer>14</integer>
+ <key>line</key>
+ <integer>13</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
- <integer>4</integer>
+ <integer>2</integer>
</dict>
<key>js/Kernel.js</key>
<dict>
@@ -131,8 +147,9 @@
<key>openDocuments</key>
<array>
<string>index.html</string>
- <string>js/Kernel.js</string>
+ <string>css/style.css</string>
<string>js/application.js</string>
+ <string>js/Kernel.js</string>
<string>js/render.js</string>
<string>js/ui.js</string>
<string>js/utilities.js</string>
259 1_edge_detection/css/style.css
View
@@ -1,51 +1,228 @@
html {
min-height: 100%;
- font: 13px/21px "Helvetica Neue", Helvetica, Arial, sans-serif;
- color: #373737;
+ font: 16px/24px "Helvetica Neue", Helvetica, Arial, sans-serif;
+ color: #888;
line-height: 1.625;
- font-weight: 300;
- background: #fff;
+ font-weight: 400;
+ background: white;
}
body {
margin: 0;
- /* get rid of the anoying text selection - this is a webapp - no webpage */
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -o-user-select: none;
- user-select: none;
-}
-#controls {
+}
+header {
+ padding: 8px 21px;
+ font-size: 13px;
+ color: #bbb;
+}
+ header span {
+ padding: 8px 0;
+ display: inline-block;
+ }
+ .right {
+ float: right;
+ }
+article {
+ margin: 0 auto;
+ max-width: 1000px;
+}
+h1, h2 {
+ color: black;
+ font-weight: 500;
+ font-family: "Din", "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+h1 {
+ font-size: 3em;
+ text-align: center;
+}
+p, h2, pre {
+ max-width: 640px;
+ margin: 1.44em auto;
+ padding: 0 13px;
+}
+h2 {
+ margin-bottom: 0;
+}
+p {
+ line-height: 32px;
+}
+ h2 + p {
+ margin-top: 0.34em;
+ }
+a {
+ color: hsl(205,100%,50%);
+ font-weight: normal;
+ text-decoration: none;
+}
+canvas, img {
+ vertical-align: bottom;
+}
+pre {
+ padding: 13px;
+ color: black;
+ font-size: 13px;
+ background: hsl(200,10%,95%);
+}
+.demo {
+ margin-top: 1.33em;
+ margin-bottom: 1.33em;
+ position: relative;
+ display: -webkit-box;
+ -webkit-perspective: 1000px;
+ /* get rid of the anoying text selection - this is a webapp - no webpage */
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -o-user-select: none;
+ user-select: none;
+}
+ .source, .resultArea {
+ position: relative;
+ }
+ .flex {
+ display: inline-block;
+ }
+ .resultArea:before {
+ content: "";
width: 100%;
- padding: 13px 0 12px;
- color: white;
- background: #3d3d3d;
- border-top: 1px solid rgba(0,0,0,.55);
- border-bottom: 1px solid rgba(0,0,0,.55);
- text-shadow: 0 1px black;
- box-shadow:
- 0 1px rgba(255,255,255,.13) inset,
- 0 -1px rgba(255,255,255,.13) inset,
- 0 1px rgba(0, 0, 0, 0.13),
- 0 2px rgba(0, 0, 0, 0.05);
- position: fixed;
-}
-label { margin-left: 21px; padding-right: 5px; vertical-align: top; }
-input { line-height: 21px; }
-input[type=range] { vertical-align: middle; }
-canvas { vertical-align: bottom; }
-#holder { padding: 62px 13px 13px; }
-#statusBar {
- bottom: 0;
+ height: 100%;
+ position: absolute;
+ box-sizing: border-box;
+ background: hsl(200,10%,95%);
+ }
+ .indicator {
+ margin: -1px 0 0;
+ top: 0;
+ left: 0;
width: 100%;
- position: fixed;
+ height: 1px;
+ border: none;
+ background: red;
+ position: absolute;
z-index: 1;
- background: white;
+ opacity: 0;
+ box-shadow: 0 0 5px hsla(0,100%,50%,1);
+ -webkit-transition: opacity 250ms;
+ }
+ .progress .indicator {
+ opacity: 1;
+ }
+ .finished .indicator {
+ opacity: 0;
+ }
+ .indicator:after {
+ content: "";
+ position: absolute;
+ width: 100%;
+ height: 2px;
+ background: -webkit-linear-gradient(left, hsla(0,100%,50%,0), hsla(0,100%,50%,.55), hsla(0,100%,50%,0));
+ }
+ .result {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ }
+ .result.loaded {
+ -webkit-transition: left 1s ease-in-out, top 1s ease-in-out;
+ }
+ .result.finished {
+ -webkit-animation: flyBack 1s ease-in-out;
+ }
+ @-webkit-keyframes flyBack {
+ 50% { -webkit-transform: translateZ(144px) }
+ }
+ .curtain {
+ position: absolute;
+ width: 100%;
+ height: 0;
+ top: 0;
+ overflow: hidden;
+ }
+ .finished .curtain {
+ height: 100%;
+ }
+
+.operator {
+ padding: 0 21px;
+ position: relative;
+}
+ .operator hr {
+ margin: -50px 0 0;
+ height: 1px;
+ width: 100%;
+ left: 0;
+ top: 50%;
+ background: hsl(200,5%,55%);
+ border: none;
+ z-index: -1;
+ position: absolute;
+ }
+.element {
+ text-align: center;
+ position: relative;
+ color: hsl(200,5%,55%);
+ border: 1px solid hsl(200,5%,55%);
+ background: hsl(200,10%,87%);
+ margin-bottom: 13px;
+}
+.center {
+ display: -webkit-box;
+ -webkit-box-orient: vertical;
+ -webkit-box-pack: center;
+ -webkit-box-align: center;
+}
+.structuringElement {
+ /*margin-top: 96px;*/
+ width: 120px;
+ height: 120px;
+ overflow: hidden;
+ display: inline-block;
+ position: relative;
+ vertical-align: bottom;
+}
+ .structuringElement input {
+ width: 40px;
+ height: 40px;
+ padding: 0;
+ float: left;
+ background: none;
+ border: none;
+ color: white;
+ font-size: 100%;
+ text-align: center;
+ font-weight: bold;
+ outline: none;
+ cursor: default;
+ box-sizing: border-box;
+ }
+ .structuringElement.five input {
+ width: 24px;
+ height: 24px;
+ }
+ .structuringElement .checked {
+ color: inherit;
+ }
+ .controls {
+ padding: 3px 5px;
+ background: -webkit-linear-gradient(hsl(200,10%,87%), hsl(200,10%,83%));
+ border-top: 1px solid hsl(200,5%,55%);
+ }
+
+button {
+ display: block;
+ width: 100%;
+ text-align: center;
+ border: none;
+ color: white;
+ font-size: 21px;
+ padding: 8px 21px;
+ background: hsl(205,100%,50%);
+}
+
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: "";
}
- #statusBar div {
- padding: 5px 21px;
- color: black;
- background: rgba(255,0,0,.34);
- border-top: 1px solid red;
- display: block;
- }
+.clearfix:after {
+ clear: both;
+}
BIN  1_edge_detection/img/klein.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
120 1_edge_detection/index.html
View
@@ -1,32 +1,98 @@
<!DOCTYPE html>
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>Edge Detection</title>
- <link rel="stylesheet" href="css/style.css" />
-</head>
-<body>
-<div id="controls">
- <label for="file">File</label>
- <select id="file">
- <option value="360411_pixelio.png">360411_pixelio.png</option>
- <option value="jet.png">jet.png</option>
- </select>
- <label for="technic">Technic</label>
- <select id="technic">
- <option value="360411_pixelio.png">360411_pixelio.png</option>
- <option value="jet.png">jet.png</option>
- </select>
-</div>
-<div id="statusBar"></div>
-<div id="holder">
- <canvas id="render">Sorry, your browser doesn't support the technology used in this Demo. Please use an up-to-date browser.</canvas>
-</div>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Edge Detection</title>
+<link rel="stylesheet" href="css/style.css" />
+
+<header>
+ <span>Computer Vision Assignment by Felix Niklas</span>
+ <span class="right">18 Oct 2012</span>
+</header>
+<article>
+ <h1>Edge Detection</h1>
+ <h2>Assigment</h2>
+ <p>
+ Convolve the images with a <a href="#simple">(1) simple</a> and a <a href="#sobel">(2) sobel-filter</a>.
+ Add 128 to the result of the gradient image to show the <a href="#negative">(3) negative</a> values.
+ <a href="compare">(4) Compare the speed</a> of seperated convolution with the two dimensional convolution of the sobel-filter.
+ </p>
+ <p>
+ Render both the magnitude and the direction of the gradient.
+ </p>
+ <p>
+ Then combine the magnitude- and gradient visualization in one image by encoding the angle in color
+ whilest keeping the brightness either constant or encode the magnitude of the gradient in it.
+ </p>
+ <h2>Execution</h2>
+ <p>
+ I like how jQuery makes DOM-interactions simple. Because of that I'd like to solve this assignment building a similar library.
+ It should look like this:
+ </p>
+ <pre>π('test.png').grayscale().convolve([0,1,0,1,1,1,0,1,0]).appendTo('body');</pre>
+ <p>
+ Chaining is simple with javascript – you just have to return <code>this</code> in every function.
+ </p>
+ <p>
+ The challenge is that we read out pixels of an image and images aren't there instantly – we first have to load them.
+ This breaks the chain.
+ </p>
+ <p>
+ I found a solution in dustin diaz's <a href="http://www.dustindiaz.com/async-method-queues/">Queue library</a>.
+ It queues up function calls after one we have to wait for and then works them off as soon as the work is done.
+ </p>
+
+ <h2>Simple Filter</h2>
+ <section class="demo clearfix">
+ <div class="flex">
+ <div class="source">
+ <!--<img src="img/360411_pixelio.png">-->
+ <hr class="indicator">
+ </div>
+ </div>
+ <div class="flex center operator">
+ <hr>
+ <div class="element">
+ <div class="structuringElement">
+ <input value="0">
+ <input value="1" class="checked">
+ <input value="0">
+ <input value="1" class="checked">
+ <input value="1" class="checked">
+ <input value="1" class="checked">
+ <input value="0">
+ <input value="1" class="checked">
+ <input value="0">
+ </div>
+ <div class="controls">
+ <label for="structureSize">size</label>
+ <select for="structureSize1" class="structureSize">
+ <option value="9" selected>3x3</option>
+ <option value="25">5x5</option>
+ </select>
+ </div>
+ </div>
+ <button class="run">Run</button>
+ </div>
+ <div class="flex">
+ <div class="resultArea">
+ <div class="result">
+ <div class="curtain">
+ <!--<img src="img/360411_pixelio.png">-->
+ </div>
+ </div>
+ </div>
+ </div>
+ </section>
+</article>
+
+<!-- tools -->
+<script type="text/javascript" src="js/document-redraw.js"></script>
+<script type="text/javascript" src="js/queue.js"></script>
<!-- self-written JavaScript starts here -->
+<script type="text/javascript" src="js/imageVision.js"></script>
<script type="text/javascript" src="js/utilities.js"></script>
-<script type="text/javascript" src="js/render.js"></script>
-<script type="text/javascript" src="js/application.js"></script>
+<script type="text/javascript" src="js/Kernel.js"></script>
<script type="text/javascript" src="js/ui.js"></script>
-</body>
-</html>
+<!--<script type="text/javascript" src="js/render.js"></script>-->
+<script type="text/javascript" src="js/application.js"></script>
38 1_edge_detection/js/Kernel.js
View
@@ -2,13 +2,45 @@
Kernel
======
- a kernel is used to
*/
-function Kernel(kernel){
- this.kernel = kernel;
+function Kernel(element){
+ this.element = element;
+ this.init();
}
Kernel.prototype = {
+ init: function(){
+ this.size = this.element.length,
+ this.length = Math.sqrt(this.size);
+ this.center = Math.floor(this.length/2);
+ this.hotspot = Math.floor(this.size/2);
+ },
+ updatePos: function(pos, value){
+ this.element[pos] = value;
+ },
+ updateSize: function(size){
+ switch(size){
+ case 9:
+ // shrink the structure
+ this.element = [
+ this.element[6 ], this.element[7 ], this.element[8 ],
+ this.element[11], this.element[12], this.element[13],
+ this.element[16], this.element[17], this.element[18]
+ ];
+ break;
+ case 25:
+ // bloat up the structure
+ this.element = [
+ 0, 0 , 0 , 0 , 0,
+ 0, this.element[0], this.element[1], this.element[2], 0,
+ 0, this.element[3], this.element[4], this.element[5], 0,
+ 0, this.element[6], this.element[7], this.element[8], 0,
+ 0, 0 , 0 , 0 , 0
+ ];
+ break;
+ }
+ this.init();
+ },
process : function(data){
}
37 1_edge_detection/js/Queue.js
View
@@ -0,0 +1,37 @@
+function Queue() {
+ // store your callbacks
+ this._methods = [];
+ // keep a reference to your response
+ this._response = null;
+ // all queues start off unflushed
+ this._flushed = false;
+}
+
+Queue.prototype = {
+ // adds callbacks to your queue
+ add: function(fn) {
+ // if the queue had been flushed, return immediately
+ if (this._flushed) {
+ fn(this._response);
+
+ // otherwise push it on the queue
+ } else {
+ this._methods.push(fn);
+ }
+ },
+
+ flush: function(resp) {
+ // note: flush only ever happens once
+ if (this._flushed) {
+ return;
+ }
+ // store your response for subsequent calls after flush()
+ this._response = resp;
+ // mark that it's been flushed
+ this._flushed = true;
+ // shift 'em out and call 'em back
+ while (this._methods[0]) {
+ this._methods.shift()(resp);
+ }
+ }
+};
68 1_edge_detection/js/application.js
View
@@ -0,0 +1,68 @@
+var element = [
+ -1, 0, 1,
+ -2, 0, 2,
+ -1, 0, 1
+];
+var structure = new Kernel(element);
+
+//
+// Init
+// ----
+//
+// initializes the program
+//
+
+function init(){
+ // initialise the UI
+ UI.init(structure);
+
+ // start chained work
+ /* imageData(canvas).convolve([
+ 0, 0, 0
+ 0, 1, 0
+ 0, 1, 0
+ ]); */
+
+ var run = document.querySelector('.run');
+ run.onclick = startFakeProgress;
+
+ vision = imageVision('img/360411_pixelio.png').grayscale().convolve([0,0,0,-0.5,0,0.5,0,0,0], false, 128).appendTo('.source');
+}
+
+var progress;
+
+function startFakeProgress(){
+ progress = 0;
+
+ source.classList.add('progress');
+ source.classList.remove('finished');
+ result.classList.remove('finished');
+
+ placeResult();
+
+ work(function(i){
+ indicator.style.top = i*100 + "%";
+ curtain.style.height = i*100 + "%";
+
+ if(i >= 1){
+ source.classList.add('finished');
+ result.classList.add('finished');
+ source.classList.remove('progress');
+ result.style.left = 0;
+ result.style.top = 0;
+ indicator.style.top = "";
+ curtain.style.height = "";
+ }
+ });
+}
+
+function work(callback){
+ progress += 0.005;
+ callback(progress);
+ if(progress < 1){
+ setTimeout(work, 0, callback);
+ }
+}
+
+// get the ball rollin'
+init();
29 1_edge_detection/js/document-redraw.js
View
@@ -0,0 +1,29 @@
+/* ###
+
+redraw function to make sure that transitions are triggered
+
+### */
+!function(document){
+
+ // (C) WebReflection (As It Is) - Mit Style
+
+ // we all love function declarations
+ function redraw() {
+
+ // clientHeight returns 0 if not present in the DOM
+ // e.g. document.removeChild(document.documentElement);
+ // also some crazy guy may swap runtime the whole HTML element
+ // this is why the documentElement should be always discovered
+ // and if present, it should be a node of the document
+ // In all these cases the returned value is true
+ // otherwise what is there cannot really be considered as painted
+
+ return !!(document.documentElement || 0).clientHeight;
+ }
+
+ // ideally an Object.defineProperty
+ // unfortunately some engine will complain
+ // if used against DOM objects
+ document.redraw = redraw;
+
+}(document);
162 1_edge_detection/js/imageVision.js
View
@@ -0,0 +1,162 @@
+//(function( window, undefined ) {
+ var document = window.document;
+ var imgRegex = /.+\.(?:jpg|gif|png)$/;
+
+ var imageVision = function(src) {
+ return new imageVision.fn.init(src);
+ };
+
+ imageVision.fn = imageVision.prototype = {
+ constructor: imageVision,
+ load: function() {
+ this.canvas = document.createElement('canvas');
+ this.ctx = this.canvas.getContext('2d');
+
+ this.canvas.width = this.image.width;
+ this.canvas.height = this.image.height;
+
+ this.ctx.drawImage(this.image, 0, 0);
+
+ this.imgData = this.originalImgData = this.ctx.getImageData(0, 0, this.image.width, this.image.height);
+ this.queue.flush(this);
+
+ return this;
+ },
+ convolve: function( structure, progressCallback, boost ) {
+ this.queue.add( function( self ) {
+ var resultImgData = self.ctx.createImageData(self.imgData);
+ var sample = [];
+
+ for(var i=0, l=self.imgData.data.length; i<l; i++){
+ var value = self.fold(self.imgData.data, i, structure);
+
+ if(boost) value += boost;
+
+ resultImgData.data[i] = value;
+
+ if(i < 100) sample.push(value);
+ // progress callback
+ // if(progressCallback) progressCallback(i % structure.length*4);
+ }
+ console.log(JSON.stringify(sample));
+
+ // draw imgData to canvas
+ self.ctx.putImageData(resultImgData, 0, 0);
+
+ // save new imgData
+ self.imgData = resultImgData;
+
+ });
+ return this;
+ },
+ fold: function( data, position, structure ) {
+ var sum = 0;
+ var count = 1;
+ var center = Math.floor( Math.sqrt(structure.length)/2);
+
+ for(var i=0, l=structure.length; i<l; i++){
+ var multiplicator = structure[i];
+
+ if(multiplicator !== 0){
+ var x = Math.ceil(position/4) % this.image.width;
+ var y = Math.floor(position/data.length);
+ var structureX = ( i % structure.length ) - center;
+ var structureY = Math.ceil( i/structure.length ) - center;
+ var offset, value = 255;
+
+ if( ( x + structureX ) >= 0 && ( x + structureX ) < this.image.width &&
+ ( y + structureY ) >= 0 && ( y + structureY ) < this.image.height ){
+ offset = structureY * (this.image.width*4) + (structureX*4);
+ value = data[position + offset];
+ }
+
+ if(position >= 0 && position < 473){ console.log(x+structureX,( x + structureX ) >= 0 && ( x + structureX ) < this.image.width &&
+ ( y + structureY ) >= 0 && ( y + structureY ) < this.image.height ); };
+ //if(position > 427 && position < 500){ console.log("x %i, y %i, sx %i, sy %i, offset %i, pos %i, = %i", x, y, structureX,structureY, offset, position, value) };
+ //count += Math.abs(multiplicator);
+ }
+ }
+
+ return count === 0 ? 0 : sum/count;
+ //return count === 0 ? 0 : sum/count;
+ },
+ grayscale: function(){
+ this.queue.add( function( self ) {
+ var grayImgData = self.ctx.createImageData(self.imgData);
+
+ for(var i=0, n=0, l=self.imgData.data.length; i<l; i+=4, n++){
+ var r = self.imgData.data[i ];
+ var g = self.imgData.data[i+1];
+ var b = self.imgData.data[i+2];
+ var gray = Math.round(r * 0.3 + g * 0.59 + b * 0.11);
+
+ // weighted grayscale algorithm
+ grayImgData.data[i ] = gray;
+ grayImgData.data[i+1] = gray;
+ grayImgData.data[i+2] = gray;
+ grayImgData.data[i+3] = 255;
+ }
+
+ self.imgData = grayImgData;
+
+ // draw imgData to canvas
+ self.ctx.putImageData(self.imgData, 0, 0);
+ });
+ return this;
+ },
+ appendTo: function(selector) {
+ this.queue.add( function( self ) {
+ var context;
+
+ // DOMElement
+ if(selector.nodeType){
+ context = selector;
+ } else {
+ // selector
+ context = document.querySelector(selector);
+ }
+
+ context.appendChild(self.canvas);
+ });
+ return this;
+ }
+ };
+
+ imageVision.fn.init = function(source) {
+ var newImage = false;
+ /*
+ source can either be an img-element, a selector for an image or an url
+ */
+ if ( !source ) {
+ return this;
+ }
+ else if ( imgRegex.exec(source) ) {
+ // π(source)
+ this.image = new Image();
+ newImage = true;
+ }
+ else if ( source.nodeType ) {
+ // π(img DOMElement)
+ this.image = source;
+ }
+ else {
+ // π('img')
+ this.image = document.querySelector(source);
+ }
+
+ this.queue = new Queue;
+
+ if(this.image.complete && !newImage){
+ this.load();
+ } else {
+ this.image.onload = this.load.bind(this);
+ }
+
+ if(newImage) this.image.src = source;
+
+ return this.canvas;
+ };
+
+ imageVision.fn.init.prototype = imageVision.fn;
+ window= window.imageVision = imageVision;
+//})( window );
34 1_edge_detection/js/render.js
View
@@ -0,0 +1,34 @@
+var source = document.querySelector('.source');
+var sourceImage = source.querySelector('img');
+var indicator = source.querySelector('.indicator');
+var resultArea = document.querySelector('.resultArea');
+var result = resultArea.querySelector('.result');
+var curtain = result.querySelector('.curtain');
+
+sourceImage.onload = function(){
+ var width = sourceImage.clientWidth;
+ var height = sourceImage.clientHeight;
+ var ratio;
+
+ if(width > source.clientWidth){
+ height = source.clientWidth/width * source.clientHeight;
+ width = source.clientWidth;
+ sourceImage.width = width;
+ }
+
+ resultArea.style.width = source.style.width = width + "px";
+ resultArea.style.height = source.style.height = height + "px";
+}
+
+function placeResult(){
+ result.classList.remove('loaded');
+
+ var dx = resultArea.offsetLeft - source.offsetLeft;
+ var dy = resultArea.offsetTop - source.offsetTop;
+ result.style.left = -dx +"px";
+ result.style.top = -dy +"px";
+
+ document.redraw();
+
+ result.classList.add('loaded');
+}
35 1_edge_detection/js/simpleTemplating.js
View
@@ -0,0 +1,35 @@
+// Simple JavaScript Templating
+// John Resig - http://ejohn.org/ - MIT Licensed
+(function(){
+ var cache = {};
+
+ this.tmpl = function tmpl(str, data){
+ // Figure out if we're getting a template, or if we need to
+ // load the template - and be sure to cache the result.
+ var fn = !/\W/.test(str) ?
+ cache[str] = cache[str] ||
+ tmpl(document.getElementById(str).innerHTML) :
+
+ // Generate a reusable function that will serve as a template
+ // generator (and which will be cached).
+ new Function("obj",
+ "var p=[],print=function(){p.push.apply(p,arguments);};" +
+
+ // Introduce the data as local variables using with(){}
+ "with(obj){p.push('" +
+
+ // Convert the template into pure JavaScript
+ str
+ .replace(/[\r\t\n]/g, " ")
+ .split("<%").join("\t")
+ .replace(/((^|%>)[^\t]*)'/g, "$1\r")
+ .replace(/\t=(.*?)%>/g, "',$1,'")
+ .split("\t").join("');")
+ .split("%>").join("p.push('")
+ .split("\r").join("\\'")
+ + "');}return p.join('');");
+
+ // Provide some basic currying to the user
+ return data ? fn( data ) : fn;
+ };
+})();
100 1_edge_detection/js/ui.js
View
@@ -0,0 +1,100 @@
+//
+// canvasFilters UI
+//
+// by Felix Niklas @mrflix Oct 2011
+//
+
+// check for touch-based device to bind on 'touchstart'
+// instead of 'click' to speed up the responsivness
+var touchSupport = "ontouchstart" in window ? true : false;
+var clickOrTouch = touchSupport ? 'touchstart' : 'click';
+
+//
+// UI Object
+//
+// responsible for the DOM Element bindings.
+// it listens to changes in the UI and triggers correpsonding functions
+//
+
+var UI = {
+ init: function(structure){
+ this.structure = structure;
+ this.structuringElement = document.querySelector('.structuringElement');
+ this.structureSize = document.querySelector('.structureSize');
+
+ this.structuringElement.addEventListener(clickOrTouch, this.updateStructuringElement.bind(this));
+ this.structureSize.addEventListener('change', this.updateStructureSize.bind(this));
+
+ this.bindInputs();
+ },
+ bindInputs: function(){
+ this.inputs = this.structuringElement.querySelectorAll('input');
+
+ for(var i=0; i<this.inputs.length; i++)
+ this.inputs[i].addEventListener('input', this.updateStructure.bind(this));
+ },
+ findElementPos: function(target){
+ // find pos in structure element
+ for(var i=0, l=this.structuringElement.children.length; i<l; i++) {
+ if(this.structuringElement.children[i] === target){
+ return i;
+ }
+ }
+ },
+ updateStructure: function(event){
+ var pos = this.findElementPos(event.target);
+ var value = parseFloat(event.target.value);
+
+ this.structure.updatePos(pos, value);
+
+ event.target.className = value === 0 ? "" : "checked";
+ },
+ updateStructureSize: function(event){
+ var size = parseInt(event.target.value);
+
+ this.structuringElement.classList[ size === 9 ? 'remove' : 'add' ]("five");
+ this.structure.updateSize(size);
+
+ // shell needed to place all the new elements in
+ var structuringElements = document.createDocumentFragment();
+
+ for ( var i = 0, l = this.structure.size; i < l; i++ ) {
+ var el = document.createElement("input");
+ var value = this.structure.element[i];
+
+ if(value !== 0){
+ el.className = "checked";
+ }
+ el.value = value;
+
+ structuringElements.appendChild( el );
+ }
+
+ // remove all old elements
+ while (this.structuringElement.hasChildNodes()) {
+ this.structuringElement.removeChild(UI.structuringElement.lastChild);
+ }
+
+ // add new elements
+ this.structuringElement.appendChild(structuringElements);
+
+ this.bindInputs();
+ },
+ updateStructuringElement: function(event){
+ var pos = this.findElementPos(event.target);
+ var value = parseFloat(event.target.value);
+
+ if(event.altKey || event.metaKey){
+ value--;
+ } else {
+ value++;
+ }
+
+ structure.element[pos] = value;
+ event.target.value = value;
+
+ event.target.className = value === 0 ? "" : "checked";
+
+ //render();
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.