diff --git a/css/style.css b/css/style.css
index 7008f476..9136c5f0 100644
--- a/css/style.css
+++ b/css/style.css
@@ -76,13 +76,19 @@ ul, li {
list-style-type: none;
}
-#preview-list .preview-tile {
+.preview-tile {
padding : 10px;
overflow: hidden;
+ background-color: gray;
+}
+
+.preview-tile .canvas-container {
+ float: left;
}
.preview-tile .tile-view {
float: left;
+ border: blue 1px solid;
}
.preview-tile .tile-action {
@@ -99,9 +105,29 @@ ul, li {
}
#preview-list .preview-tile.selected {
- background-color: gray;
+ background-color: lightyellow;
}
+.canvas-container {
+ position: relative;
+ display: block;
+}
+
+.canvas-container .canvas-background {
+ background: url(../img/transparent_background.png) repeat;
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+
+.canvas {
+ position: relative;
+ z-index: 1;
+}
+
+/* Force apparition of scrollbars on leopard */
::-webkit-scrollbar {
-webkit-appearance: none;
width: 7px;
diff --git a/img/transparent_background.png b/img/transparent_background.png
new file mode 100644
index 00000000..4a1f7a8e
Binary files /dev/null and b/img/transparent_background.png differ
diff --git a/index.html b/index.html
index bd5efe8b..6f9ae98c 100644
--- a/index.html
+++ b/index.html
@@ -13,27 +13,29 @@
-
+
+
diff --git a/js/frameSheetModel.js b/js/frameSheetModel.js
new file mode 100644
index 00000000..5ea52a0d
--- /dev/null
+++ b/js/frameSheetModel.js
@@ -0,0 +1,76 @@
+
+var FrameSheetModel = (function() {
+
+ var inst;
+ var frames = [];
+ var width;
+ var height;
+
+ var createEmptyFrame_ = function() {
+ var emptyFrame = new Array(width);
+ for (var columnIndex=0; columnIndex < width; columnIndex++) {
+ emptyFrame[columnIndex] = new Array(height);
+ }
+ return emptyFrame;
+ };
+
+ return {
+ validate: function() {
+ return true; // I'm always right dude
+ },
+
+ // Could be use to pass around model using long GET param (good enough for simple models) and
+ // do some temporary locastorage
+ serialize: function() {
+ throw "FrameSheet.serialize Not implemented"
+ },
+
+ addEmptyFrame: function() {
+ frames.push(createEmptyFrame_());
+ },
+
+ getFrameCount: function() {
+ return frames.length;
+ },
+
+ getFrameByIndex: function(index) {
+ if (isNaN(index)) {
+ throw "Bad argument value for getFrameByIndex method: <" + index + ">"
+ } else if (index < 0 || index > frames.length) {
+ throw "Out of bound index for frameSheet object."
+ }
+
+ return frames[index];
+ },
+
+ removeFrameByIndex: function(index) {
+ if(index < 0 || index > inst.getFrameCount()) {
+ throw "Bad index value for removeFrameByIndex.";
+ }
+ frames.splice(index, 1);
+ },
+
+ duplicateFrameByIndex: function(frameToDuplicateIndex) {
+ var frame = inst.getFrameByIndex(frameToDuplicateIndex);
+ var clonedFrame = [];
+ for(var i=0, l=frame.length; i 1) {
+ if(tileNumber > 0 || frameSheet.getFrameCount() > 1) {
var canvasPreviewDeleteAction = document.createElement("button");
canvasPreviewDeleteAction.className = "tile-action"
canvasPreviewDeleteAction.innerHTML = "del"
- canvasPreviewDeleteAction.setAttribute('onclick', 'piskel.removeFrame('+ tileNumber +')');
- preview.appendChild(canvasPreviewDeleteAction);
+ canvasPreviewDeleteAction.addEventListener('click', function(evt) {
+ frameSheet.removeFrameByIndex(tileNumber);
+ animIndex = 0;
+ piskel.createPreviews();
+ });
+ previewTileRoot.appendChild(canvasPreviewDeleteAction);
}
- return preview;
+ return previewTileRoot;
},
refreshAnimatedPreview : function () {
- var context = $('animated-preview').getContext('2d');
- // erase canvas, verify proper way
- context.fillStyle = "white";
- context.fillRect(0, 0, 256, 256);
-
- context.drawImage(frames[animIndex++], 0, 0, 320, 320, 0, 0 , 256, 256);
- if (animIndex == frames.length) {
+ piskel.drawFrameToCanvas(frameSheet.getFrameByIndex(animIndex), previewCanvas, previewAnimationCanvasDpi);
+ animIndex++;
+ if (animIndex == frameSheet.getFrameCount()) {
animIndex = 0;
}
},
- setFrame : function (frameIndex) {
- index = frameIndex;
- $('canvas-container').innerHTML = "";
- $('canvas-container').appendChild(this.getCurrentCanvas());
- this.createPreviews();
- },
+ removeFrame: function(frameIndex) {
+ frameSheet.removeFrameByIndex(frameIndex);
- removeFrame: function(frameIndex) {
- index = frameIndex - 1 < 0 ? 0 : frameIndex - 1;
- animIndex = 0;
- frames.splice(frameIndex, 1);
- $('canvas-container').innerHTML = "";
- $('canvas-container').appendChild(this.getCurrentCanvas());
- this.createPreviews();
+ this.setActiveFrameAndRedraw(frameIndex - 1);
},
duplicateFrame: function(frameIndex) {
- index = frameIndex + 1;
- animIndex = 0;
- var duplicateCanvas = frames[frameIndex].cloneNode(true);
- // Copy canvas content:
- var context = duplicateCanvas.getContext('2d');
- context.drawImage(frames[frameIndex], 0, 0);
+ frameSheet.duplicateFrameByIndex(frameIndex);
- // Insert cloned node into frame collection:
- frames.splice(frameIndex + 1, 0, duplicateCanvas);
- $('canvas-container').innerHTML = "";
- $('canvas-container').appendChild(this.getCurrentCanvas());
- this.createPreviews();
+ this.setActiveFrameAndRedraw(frameIndex + 1);
},
updateCursorInfo : function (event) {
@@ -155,26 +243,73 @@
onCanvasMousedown : function (event) {
isClicked = true;
- button = event.button;
var coords = this.getRelativeCoordinates(event.clientX, event.clientY);
- this.drawAt(coords.x, coords.y);
+ if(event.button == 0) {
+ this.drawAt(coords.x, coords.y, penColor);
+ } else {
+ // Right click used to delete.
+ isRightClicked = true;
+ this.drawAt(coords.x, coords.y, TRANSPARENT_COLOR);
+ }
+ },
+
+ onCanvasMousemove : function (event) {
+ //this.updateCursorInfo(event);
+ if (isClicked) {
+ var coords = this.getRelativeCoordinates(event.clientX, event.clientY);
+ if(isRightClicked) {
+ this.drawAt(coords.x, coords.y, TRANSPARENT_COLOR);
+ } else {
+ this.drawAt(coords.x, coords.y, penColor);
+ }
+ }
},
onCanvasMouseup : function (event) {
+ if(isClicked || isRightClicked) {
+ // A mouse button was clicked on the drawing canvas before this mouseup event,
+ // the user was probably drawing on the canvas.
+ // Note: The mousemove movement (and the mouseup) may end up outside
+ // of the drawing canvas.
+ this.createPreviews();
+ }
isClicked = false;
+ isRightClicked = false;
},
- drawAt : function (x, y) {
- if (x < 0 || y < 0 || x > 320 || y > 320) return;
- var context = this.getCurrentCanvas().getContext('2d');
- if (button == 0) {
- context.fillStyle = "black";
- } else {
- context.fillStyle = "white";
- }
+ drawAt : function (x, y, color) {
+ var pixelWidthIndex = (x - x%drawingCanvasDpi) / 10;
+ var pixelHeightIndex = (y - y%drawingCanvasDpi) / 10;
+
+ // Update model:
+ var currentFrame = frameSheet.getFrameByIndex(this.getActiveFrameIndex());
+
+ // TODO: make a better accessor for pixel state update:
+ // TODO: Make pen color dynamic:
+ currentFrame[pixelWidthIndex][pixelHeightIndex] = color;
+
+ // Update view:
+ // TODO: Create a per pixel update function for perf ?
+ this.drawFrameToCanvas(currentFrame, drawingAreaCanvas, drawingCanvasDpi);
+ },
- context.fillRect(x - x%brushSize, y - y%brushSize, brushSize, brushSize);
- this.createPreviews();
+ // TODO: move that to a FrameRenderer (/w cache) ?
+ drawFrameToCanvas: function(frame, canvasElement, dpi) {
+ var pixelColor, context = canvasElement.getContext('2d');
+ for(var col = 0, num_col = frame.length; col < num_col; col++) {
+ for(var row = 0, num_row = frame[col].length; row < num_row; row++) {
+ pixelColor = frame[col][row];
+
+ if(pixelColor == undefined || pixelColor == TRANSPARENT_COLOR) {
+ context.clearRect(col * dpi, row * dpi, dpi, dpi);
+ } else {
+ context.fillStyle = pixelColor;
+ context.fillRect(col * dpi, row * dpi, dpi, dpi);
+ }
+
+
+ }
+ }
},
onCanvasContextMenu : function (event) {
@@ -183,35 +318,13 @@
event.cancelBubble = true;
return false;
},
+
getRelativeCoordinates : function (x, y) {
- var canvas = this.getCurrentCanvas();
- var canvasRect = canvas.getBoundingClientRect();
+ var canvasRect = drawingAreaCanvas.getBoundingClientRect();
return {
x : x - canvasRect.left,
y : y - canvasRect.top
}
- },
-
- addFrame : function () {
- var canvas = document.createElement("canvas");
- canvas.setAttribute('width', '320');
- canvas.setAttribute('height', '320');
- canvas.setAttribute('onmousemove', 'piskel.onCanvasMousemove(arguments[0])');
- canvas.setAttribute('oncontextmenu', 'piskel.onCanvasContextMenu(arguments[0])');
- //canvas.setAttribute('onclick', 'piskel.onCanvasClick(arguments[0])');
- var context = canvas.getContext('2d');
-
- context.fillStyle = "white";
- context.fillRect(0, 0, 320, 320);
-
- if(frames[index]) { //is a valid canvas
- context.drawImage(frames[index], 0, 0, 320, 320, 0, 0 , 320, 320);
- }
-
- // TODO: We should probably store some metadata or enhance a domain object instead
- // of the rendered view ? It will allow to decouple view and model and clean a bunch of code above.
- frames.push(canvas);
- this.setFrame(frames.length - 1);
}
};