Merge pull request #240 from juliandescottes/enhancement-pause-animation

Enhancement pause animation
This commit is contained in:
Julian Descottes 2014-12-21 16:52:13 +01:00
commit 1df5d0da38
11 changed files with 111 additions and 66 deletions

View File

@ -1,9 +1,5 @@
body { body {
background: radial-gradient(circle, #000, #373737); background: #1D1D1D;
/* 16/06/2013 : -webkit still needed for
safari, safari mobile and android browser and chrome for android
cf http://caniuse.com/css-gradients */
background: -webkit-radial-gradient(circle, #000, #373737);
} }
/* Browser fixes */ /* Browser fixes */

View File

@ -21,16 +21,8 @@ var Constants = {
DEFAULT_PEN_COLOR : '#000000', DEFAULT_PEN_COLOR : '#000000',
TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)', TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)',
OVERLAY_ONION_SKIN : 'onion-skin',
OVERLAY_LAYER_PREVIEW : 'layer-preview',
OVERLAY_DISABLED : 'no-overlay',
NO_PALETTE_ID : '__no-palette',
CURRENT_COLORS_PALETTE_ID : '__current-colors', CURRENT_COLORS_PALETTE_ID : '__current-colors',
// Used for Spectrum input
PREFERRED_COLOR_FORMAT : 'rgb',
/* /*
* Fake semi-transparent color used to highlight transparent * Fake semi-transparent color used to highlight transparent
* strokes and rectangles: * strokes and rectangles:
@ -43,22 +35,6 @@ var Constants = {
*/ */
TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)', TOOL_TARGET_HIGHLIGHT_COLOR: 'rgba(255, 255, 255, 0.2)',
/*
* Default entry point for piskel web service:
*/
STATIC : {
URL : {
SAVE : 'http://3.piskel-app.appspot.com/store',
GET : 'http://3.piskel-app.appspot.com/get'
}
},
APPENGINE : {
URL : {
SAVE : 'save'
}
},
IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-a.appspot.com/__/upload',
IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-a.appspot.com/img/',
ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0', ZOOMED_OUT_BACKGROUND_COLOR : '#A0A0A0',
@ -71,5 +47,10 @@ var Constants = {
EMPTY_FUNCTION : function () {}, EMPTY_FUNCTION : function () {},
// TESTS // TESTS
DRAWING_TEST_FOLDER : 'drawing' DRAWING_TEST_FOLDER : 'drawing',
// SERVICE URLS
APPENGINE_SAVE_URL : 'save',
IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload',
IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/'
}; };

View File

@ -5,6 +5,7 @@ var Events = {
SELECT_TOOL : "SELECT_TOOL", SELECT_TOOL : "SELECT_TOOL",
TOOL_RELEASED : "TOOL_RELEASED", TOOL_RELEASED : "TOOL_RELEASED",
TOOL_PRESSED : "TOOL_PRESSED",
SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR", SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR",
SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR", SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR",
PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED', PRIMARY_COLOR_SELECTED : 'PRIMARY_COLOR_SELECTED',

View File

@ -1,5 +1,5 @@
(function () { (function () {
var ns = $.namespace("pskl.controller"); var ns = $.namespace('pskl.controller');
// Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE // Preview is a square of PREVIEW_SIZE x PREVIEW_SIZE
var PREVIEW_SIZE = 200; var PREVIEW_SIZE = 200;
@ -11,6 +11,11 @@
this.elapsedTime = 0; this.elapsedTime = 0;
this.currentIndex = 0; this.currentIndex = 0;
this.renderFlag = true;
this.fpsRangeInput = $('#preview-fps');
this.fpsCounterDisplay = $('#display-fps');
this.setFPS(Constants.DEFAULT.FPS); this.setFPS(Constants.DEFAULT.FPS);
var frame = this.piskelController.getCurrentFrame(); var frame = this.piskelController.getCurrentFrame();
@ -22,10 +27,10 @@
// the oninput event won't work on IE10 unfortunately, but at least will provide a // the oninput event won't work on IE10 unfortunately, but at least will provide a
// consistent behavior across all other browsers that support the input type range // consistent behavior across all other browsers that support the input type range
// see https://bugzilla.mozilla.org/show_bug.cgi?id=853670 // see https://bugzilla.mozilla.org/show_bug.cgi?id=853670
$("#preview-fps").on('input change', this.onFPSSliderChange.bind(this)); this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this));
document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px'; document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';
this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin"); this.toggleOnionSkinEl = document.querySelector('.preview-toggle-onion-skin');
this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this)); this.toggleOnionSkinEl.addEventListener('click', this.toggleOnionSkin_.bind(this));
pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this)); pskl.app.shortcutService.addShortcut('alt+O', this.toggleOnionSkin_.bind(this));
@ -33,6 +38,9 @@
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this)); $.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
$.subscribe(Events.TOOL_RELEASED, this.setRenderFlag_.bind(this, true));
$.subscribe(Events.TOOL_PRESSED, this.setRenderFlag_.bind(this, false));
this.updateZoom_(); this.updateZoom_();
this.updateOnionSkinPreview_(); this.updateOnionSkinPreview_();
this.updateContainerDimensions_(); this.updateContainerDimensions_();
@ -78,14 +86,16 @@
}; };
ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) { ns.AnimatedPreviewController.prototype.onFPSSliderChange = function (evt) {
this.setFPS(parseInt($("#preview-fps")[0].value, 10)); this.setFPS(parseInt(this.fpsRangeInput[0].value, 10));
}; };
ns.AnimatedPreviewController.prototype.setFPS = function (fps) { ns.AnimatedPreviewController.prototype.setFPS = function (fps) {
if (fps) { if (typeof fps === 'number') {
this.fps = fps; this.fps = fps;
$("#preview-fps").val(this.fps); this.fpsRangeInput.val(this.fps);
$("#display-fps").html(this.fps + " FPS"); this.fpsRangeInput.blur();
this.fpsCounterDisplay.html(this.fps + ' FPS');
} }
}; };
@ -94,7 +104,24 @@
}; };
ns.AnimatedPreviewController.prototype.render = function (delta) { ns.AnimatedPreviewController.prototype.render = function (delta) {
this.elapsedTime += delta; if (this.renderFlag) {
this.elapsedTime += delta;
if (this.fps === 0) {
this._renderSelectedFrame();
} else {
this._renderCurrentAnimationFrame();
}
}
};
ns.AnimatedPreviewController.prototype._renderSelectedFrame = function (delta) {
// the selected frame is the currentFrame from the PiskelController perspective
var selectedFrameIndex = this.piskelController.getCurrentFrameIndex();
var selectedFrame = this.piskelController.getFrameAt(selectedFrameIndex);
this.renderer.render(selectedFrame);
};
ns.AnimatedPreviewController.prototype._renderCurrentAnimationFrame = function (delta) {
var index = Math.floor(this.elapsedTime / (1000/this.fps)); var index = Math.floor(this.elapsedTime / (1000/this.fps));
if (index != this.currentIndex) { if (index != this.currentIndex) {
this.currentIndex = index; this.currentIndex = index;
@ -112,9 +139,8 @@
*/ */
ns.AnimatedPreviewController.prototype.calculateZoom_ = function () { ns.AnimatedPreviewController.prototype.calculateZoom_ = function () {
var frame = this.piskelController.getCurrentFrame(); var frame = this.piskelController.getCurrentFrame();
var previewSize = 200, var hZoom = PREVIEW_SIZE / frame.getHeight(),
hZoom = previewSize / frame.getHeight(), wZoom = PREVIEW_SIZE / frame.getWidth();
wZoom = previewSize / frame.getWidth();
return Math.min(hZoom, wZoom); return Math.min(hZoom, wZoom);
}; };
@ -139,16 +165,20 @@
width = frame.getWidth() * zoom; width = frame.getWidth() * zoom;
} }
containerEl.style.height = height + "px"; containerEl.style.height = height + 'px';
containerEl.style.width = width + "px"; containerEl.style.width = width + 'px';
var horizontalPadding = (PREVIEW_SIZE - height) / 2; var horizontalPadding = (PREVIEW_SIZE - height) / 2;
containerEl.style.marginTop = horizontalPadding + "px"; containerEl.style.marginTop = horizontalPadding + 'px';
containerEl.style.marginBottom = horizontalPadding + "px"; containerEl.style.marginBottom = horizontalPadding + 'px';
var verticalPadding = (PREVIEW_SIZE - width) / 2; var verticalPadding = (PREVIEW_SIZE - width) / 2;
containerEl.style.marginLeft = verticalPadding + "px"; containerEl.style.marginLeft = verticalPadding + 'px';
containerEl.style.marginRight = verticalPadding + "px"; containerEl.style.marginRight = verticalPadding + 'px';
};
ns.AnimatedPreviewController.prototype.setRenderFlag_ = function (bool) {
this.renderFlag = bool;
}; };
ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () { ns.AnimatedPreviewController.prototype.toggleOnionSkin_ = function () {

View File

@ -31,8 +31,6 @@
"yOffset" : 0 "yOffset" : 0
}; };
console.log('DrawingController:getContainerWidth_', this.getContainerWidth_());
this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]); this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["canvas-overlay"]);
this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]); this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, renderingOptions, ["drawing-canvas"]);
this.onionSkinRenderer = new pskl.rendering.OnionSkinRenderer(this.container, renderingOptions, piskelController); this.onionSkinRenderer = new pskl.rendering.OnionSkinRenderer(this.container, renderingOptions, piskelController);
@ -153,7 +151,7 @@
this.dragHandler.startDrag(event.clientX, event.clientY); this.dragHandler.startDrag(event.clientX, event.clientY);
} else { } else {
this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame); this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame);
$.publish(Events.TOOL_PRESSED);
this.currentToolBehavior.applyToolAt( this.currentToolBehavior.applyToolAt(
coords.x, coords.x,
coords.y, coords.y,

View File

@ -65,7 +65,7 @@
if (cache[cacheKey]) { if (cache[cacheKey]) {
processedFrame = cache[cacheKey]; processedFrame = cache[cacheKey];
} else { } else {
var frameAsString = JSON.stringify(frame.getPixels()); var frameAsString = pskl.utils.hashCode(JSON.stringify(frame.getPixels()));
if (cache[frameAsString]) { if (cache[frameAsString]) {
processedFrame = this.outputCloner(cache[frameAsString], frame); processedFrame = this.outputCloner(cache[frameAsString], frame);
} else { } else {

View File

@ -19,9 +19,18 @@
ns.CanvasRenderer.prototype.render = function () { ns.CanvasRenderer.prototype.render = function () {
var canvas = this.createCanvas_(); var canvas = this.createCanvas_();
var context = canvas.getContext('2d'); var context = canvas.getContext('2d');
this.frame.forEachPixel(function (color, x, y) {
this.renderPixel_(color, x, y, context); for(var x = 0, width = this.frame.getWidth(); x < width; x++) {
}.bind(this)); for(var y = 0, height = this.frame.getHeight(); y < height; y++) {
var color = this.frame.getPixel(x, y);
var w = 1;
while (color === this.frame.getPixel(x, y+w)) {
w++;
}
this.renderLine_(color, x, y, w, context);
y = y + w - 1;
}
}
var scaledCanvas = this.createCanvas_(this.zoom); var scaledCanvas = this.createCanvas_(this.zoom);
var scaledContext = scaledCanvas.getContext('2d'); var scaledContext = scaledCanvas.getContext('2d');
@ -40,6 +49,13 @@
context.fillRect(x, y, 1, 1); context.fillRect(x, y, 1, 1);
}; };
ns.CanvasRenderer.prototype.renderLine_ = function (color, x, y, width, context) {
if(color != Constants.TRANSPARENT_COLOR) {
context.fillStyle = color;
context.fillRect(x, y, 1, width);
}
};
ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) { ns.CanvasRenderer.prototype.createCanvas_ = function (zoom) {
zoom = zoom || 1; zoom = zoom || 1;
var width = this.frame.getWidth() * zoom; var width = this.frame.getWidth() * zoom;

View File

@ -164,13 +164,6 @@
} }
}; };
ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) {
if(color != Constants.TRANSPARENT_COLOR) {
context.fillStyle = color;
context.fillRect(x, y, 1, 1);
}
};
/** /**
* Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered * Transform a screen pixel-based coordinate (relative to the top-left corner of the rendered
* frame) into a sprite coordinate in column and row. * frame) into a sprite coordinate in column and row.
@ -230,7 +223,12 @@
for(var x = 0, width = frame.getWidth(); x < width; x++) { for(var x = 0, width = frame.getWidth(); x < width; x++) {
for(var y = 0, height = frame.getHeight(); y < height; y++) { for(var y = 0, height = frame.getHeight(); y < height; y++) {
var color = frame.getPixel(x, y); var color = frame.getPixel(x, y);
this.renderPixel_(color, x, y, context); var w = 1;
while (color === frame.getPixel(x, y+w)) {
w++;
}
this.renderLine_(color, x, y, w, context);
y = y + w - 1;
} }
} }
@ -264,4 +262,18 @@
} }
displayContext.restore(); displayContext.restore();
}; };
ns.FrameRenderer.prototype.renderPixel_ = function (color, x, y, context) {
if(color != Constants.TRANSPARENT_COLOR) {
context.fillStyle = color;
context.fillRect(x, y, 1, 1);
}
};
ns.FrameRenderer.prototype.renderLine_ = function (color, x, y, width, context) {
if(color != Constants.TRANSPARENT_COLOR) {
context.fillStyle = color;
context.fillRect(x, y, 1, width);
}
};
})(); })();

View File

@ -35,6 +35,6 @@
callbacks.after(); callbacks.after();
}; };
pskl.utils.Xhr.post(Constants.APPENGINE.URL.SAVE, data, success, error); pskl.utils.Xhr.post(Constants.APPENGINE_SAVE_URL, data, success, error);
}; };
})(); })();

View File

@ -89,6 +89,18 @@ if (!Function.prototype.bind) {
} }
}; };
ns.hashCode = function(str) {
var hash = 0;
if (str.length !== 0) {
for (var i = 0, l = str.length; i < l; i++) {
var chr = str.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0; // Convert to 32bit integer
}
}
return hash;
};
var entityMap = { var entityMap = {
"&": "&amp;", "&": "&amp;",
"<": "&lt;", "<": "&lt;",
@ -97,7 +109,6 @@ if (!Function.prototype.bind) {
"'": '&#39;', "'": '&#39;',
"/": '&#x2F;' "/": '&#x2F;'
}; };
ns.escapeHtml= function (string) { ns.escapeHtml= function (string) {
return String(string).replace(/[&<>"'\/]/g, function (s) { return String(string).replace(/[&<>"'\/]/g, function (s) {
return entityMap[s]; return entityMap[s];

View File

@ -10,6 +10,6 @@
data-placement="bottom" data-placement="bottom"
class="piskel-icon-onion preview-toggle-onion-skin"></div> class="piskel-icon-onion preview-toggle-onion-skin"></div>
<span id="display-fps" class="display-fps"></span> <span id="display-fps" class="display-fps"></span>
<input id="preview-fps" class="range-fps" type="range" min="1" max="24"/> <input id="preview-fps" class="range-fps" type="range" min="0" max="24"/>
</div> </div>
</div> </div>