Issue 24 : Layers

!! NOT STABLE !!
Initial implementation. No UI update yet.
Check js/model/Piskel.js and js/model/Layer.js for an overview of the new
API.

Piskels can be saved on the existing service.

Previous piskels cannot be loaded. This should be fixed soon.
This commit is contained in:
jdescottes
2013-09-22 21:02:43 +02:00
parent 4f6863eb8a
commit 6528c7724b
24 changed files with 572 additions and 230 deletions

View File

@@ -1,7 +1,7 @@
(function () {
var ns = $.namespace("pskl.controller");
ns.AnimatedPreviewController = function (framesheet, container, dpi) {
this.framesheet = framesheet;
ns.AnimatedPreviewController = function (piskelController, container, dpi) {
this.piskelController = piskelController;
this.container = container;
this.elapsedTime = 0;
@@ -39,11 +39,11 @@
var index = Math.floor(this.elapsedTime / (1000/this.fps));
if (index != this.currentIndex) {
this.currentIndex = index;
if (!this.framesheet.hasFrameAtIndex(this.currentIndex)) {
if (!this.piskelController.hasFrameAt(this.currentIndex)) {
this.currentIndex = 0;
this.elapsedTime = 0;
}
this.renderer.render(this.framesheet.getFrameByIndex(this.currentIndex));
this.renderer.render(this.piskelController.getFrameAt(this.currentIndex));
}
};
@@ -52,8 +52,8 @@
*/
ns.AnimatedPreviewController.prototype.calculateDPI_ = function () {
var previewSize = 200,
framePixelHeight = this.framesheet.getCurrentFrame().getHeight(),
framePixelWidth = this.framesheet.getCurrentFrame().getWidth();
framePixelHeight = this.piskelController.getCurrentFrame().getHeight(),
framePixelWidth = this.piskelController.getCurrentFrame().getWidth();
// TODO (julz) : should have a utility to get a Size from framesheet easily (what about empty framesheets though ?)
//return pskl.PixelUtils.calculateDPIForContainer($(".preview-container"), framePixelHeight, framePixelWidth);

View File

@@ -1,15 +1,15 @@
(function () {
var ns = $.namespace("pskl.controller");
ns.DrawingController = function (framesheet, container) {
ns.DrawingController = function (piskelController, container) {
/**
* @public
*/
this.framesheet = framesheet;
this.piskelController = piskelController;
/**
* @public
*/
this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(framesheet.getCurrentFrame());
this.overlayFrame = pskl.model.Frame.createEmptyFromFrame(piskelController.getCurrentFrame());
/**
* @private
@@ -36,7 +36,7 @@
};
ns.DrawingController.prototype.init = function () {
this.renderer.render(this.framesheet.getCurrentFrame());
this.renderer.render(this.piskelController.getCurrentFrame());
this.overlayRenderer.render(this.overlayFrame);
this.initMouseBehavior();
@@ -114,7 +114,7 @@
this.currentToolBehavior.applyToolAt(
coords.col, coords.row,
this.getCurrentColor_(),
this.framesheet.getCurrentFrame(),
this.piskelController.getCurrentFrame(),
this.overlayFrame,
this.wrapEvtInfo_(event)
);
@@ -135,7 +135,7 @@
this.currentToolBehavior.moveToolAt(
coords.col, coords.row,
this.getCurrentColor_(),
this.framesheet.getCurrentFrame(),
this.piskelController.getCurrentFrame(),
this.overlayFrame,
this.wrapEvtInfo_(event)
);
@@ -149,7 +149,7 @@
this.currentToolBehavior.moveUnactiveToolAt(
coords.col, coords.row,
this.getCurrentColor_(),
this.framesheet.getCurrentFrame(),
this.piskelController.getCurrentFrame(),
this.overlayFrame,
this.wrapEvtInfo_(event)
);
@@ -176,7 +176,7 @@
this.currentToolBehavior.releaseToolAt(
coords.col, coords.row,
this.getCurrentColor_(),
this.framesheet.getCurrentFrame(),
this.piskelController.getCurrentFrame(),
this.overlayFrame,
this.wrapEvtInfo_(event)
);
@@ -247,7 +247,7 @@
};
ns.DrawingController.prototype.renderFrame = function () {
var frame = this.framesheet.getCurrentFrame();
var frame = this.piskelController.getCurrentFrame();
var serializedFrame = frame.serialize();
if (this.serializedFrame != serializedFrame) {
if (!frame.isSameSize(this.overlayFrame)) {
@@ -278,8 +278,8 @@
leftSectionWidth = $('.left-column').outerWidth(true),
rightSectionWidth = $('.right-column').outerWidth(true),
availableViewportWidth = $('#main-wrapper').width() - leftSectionWidth - rightSectionWidth,
framePixelHeight = this.framesheet.getCurrentFrame().getHeight(),
framePixelWidth = this.framesheet.getCurrentFrame().getWidth();
framePixelHeight = this.piskelController.getCurrentFrame().getHeight(),
framePixelWidth = this.piskelController.getCurrentFrame().getWidth();
if (pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)) {
availableViewportWidth = availableViewportWidth - (framePixelWidth * Constants.GRID_STROKE_WIDTH);
@@ -300,7 +300,7 @@
this.renderer.updateDPI(dpi);
this.overlayRenderer.updateDPI(dpi);
var currentFrameHeight = this.framesheet.getCurrentFrame().getHeight();
var currentFrameHeight = this.piskelController.getCurrentFrame().getHeight();
var canvasHeight = currentFrameHeight * dpi;
if (pskl.UserSettings.get(pskl.UserSettings.SHOW_GRID)) {
canvasHeight += Constants.GRID_STROKE_WIDTH * currentFrameHeight;

View File

@@ -3,6 +3,14 @@
ns.NotificationController = function () {};
/**
* @public
*/
ns.NotificationController.prototype.init = function() {
$.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this));
$.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this));
};
/**
* @private
*/
@@ -28,12 +36,4 @@
message.remove();
}
};
/**
* @public
*/
ns.NotificationController.prototype.init = function() {
$.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this));
$.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this));
};
})();

View File

@@ -1,9 +1,35 @@
(function () {
var ns = $.namespace("pskl.controller");
ns.PaletteController = function () {
this.paletteRoot = null;
this.paletteColors = [];
ns.PaletteController = function () {};
/**
* @public
*/
ns.PaletteController.prototype.init = function() {
var transparentColorPalette = $(".palette-color[data-color=TRANSPARENT]");
transparentColorPalette.mouseup($.proxy(this.onPaletteColorClick_, this));
$.subscribe(Events.PRIMARY_COLOR_UPDATED, $.proxy(function(evt, color) {
this.updateColorPicker_(color, $('#color-picker'));
this.addColorToPalette_(color);
}, this));
$.subscribe(Events.SECONDARY_COLOR_UPDATED, $.proxy(function(evt, color) {
this.updateColorPicker_(color, $('#secondary-color-picker'));
this.addColorToPalette_(color);
}, this));
// Initialize colorpickers:
var colorPicker = $('#color-picker');
colorPicker.val(Constants.DEFAULT_PEN_COLOR);
colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this));
var secondaryColorPicker = $('#secondary-color-picker');
secondaryColorPicker.val(Constants.TRANSPARENT_COLOR);
secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this));
};
/**
@@ -13,29 +39,10 @@
var inputPicker = $(evt.target);
if(evt.data.isPrimary) {
$.publish(Events.PRIMARY_COLOR_SELECTED, [inputPicker.val()]);
}
else {
} else {
$.publish(Events.SECONDARY_COLOR_SELECTED, [inputPicker.val()]);
}
};
/**
* @private
*/
ns.PaletteController.prototype.addColorToPalette_ = function (color) {
if (this.paletteColors.indexOf(color) == -1 && color != Constants.TRANSPARENT_COLOR) {
this.paletteColors.push(color);
}
};
/**
* @private
*/
ns.PaletteController.prototype.addColorsToPalette_ = function (colors) {
for(var color in colors) {
this.addColorToPalette_(color);
}
};
/**
* @private
@@ -71,45 +78,6 @@
colorPicker[0].color.fromString(color);
}
};
/**
* @public
*/
ns.PaletteController.prototype.init = function(framesheet) {
this.paletteRoot = $("#palette");
this.framesheet = framesheet;
// Initialize palette:
this.addColorsToPalette_(this.framesheet.getUsedColors());
$.subscribe(Events.FRAMESHEET_RESET, $.proxy(function(evt) {
this.addColorsToPalette_(this.framesheet.getUsedColors());
}, this));
this.paletteRoot.mouseup($.proxy(this.onPaletteColorClick_, this));
$.subscribe(Events.PRIMARY_COLOR_UPDATED, $.proxy(function(evt, color) {
this.updateColorPicker_(color, $('#color-picker'));
this.addColorToPalette_(color);
}, this));
$.subscribe(Events.SECONDARY_COLOR_UPDATED, $.proxy(function(evt, color) {
this.updateColorPicker_(color, $('#secondary-color-picker'));
this.addColorToPalette_(color);
}, this));
// Initialize colorpickers:
var colorPicker = $('#color-picker');
colorPicker.val(Constants.DEFAULT_PEN_COLOR);
colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this));
var secondaryColorPicker = $('#secondary-color-picker');
secondaryColorPicker.val(Constants.TRANSPARENT_COLOR);
secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this));
};
})();

View File

@@ -0,0 +1,125 @@
(function () {
var ns = $.namespace('pskl.controller');
ns.PiskelController = function (piskel) {
this.setPiskel(piskel);
};
ns.PiskelController.prototype.setPiskel = function (piskel) {
this.piskel = piskel;
this.currentLayerIndex = 0;
this.currentFrameIndex = 0;
$.publish(Events.FRAMESHEET_RESET);
$.publish(Events.FRAME_SIZE_CHANGED);
};
ns.PiskelController.prototype.getHeight = function () {
return this.piskel.getHeight();
};
ns.PiskelController.prototype.getWidth = function () {
return this.piskel.getWidth();
};
ns.PiskelController.prototype.getCurrentLayer = function () {
return this.piskel.getLayerAt(this.currentLayerIndex);
};
ns.PiskelController.prototype.getCurrentFrame = function () {
var layer = this.getCurrentLayer();
return layer.getFrameAt(this.currentFrameIndex);
};
ns.PiskelController.prototype.getFrameAt = function (index) {
var frames = this.piskel.getLayers().map(function (l) {
return l.getFrameAt(index);
});
return pskl.utils.FrameUtils.merge(frames);
};
ns.PiskelController.prototype.hasFrameAt = function (index) {
return !!this.getCurrentLayer().getFrameAt(index);
};
// backward from framesheet
ns.PiskelController.prototype.getFrameByIndex =
ns.PiskelController.prototype.getMergedFrameAt;
ns.PiskelController.prototype.addEmptyFrame = function () {
var layers = this.piskel.getLayers();
layers.forEach(function (l) {
l.addFrame(this.createEmptyFrame_());
}.bind(this));
};
ns.PiskelController.prototype.createEmptyFrame_ = function () {
var w = this.piskel.getWidth(), h = this.piskel.getHeight();
return new pskl.model.Frame(w, h);
};
ns.PiskelController.prototype.removeFrameAt = function (index) {
var layers = this.piskel.getLayers();
layers.forEach(function (l) {
l.removeFrameAt(index);
});
// Current frame index is impacted if the removed frame was before the current frame
if (this.currentFrameIndex >= index) {
this.setCurrentFrameIndex(this.currentFrameIndex - 1);
}
$.publish(Events.FRAMESHEET_RESET);
};
ns.PiskelController.prototype.duplicateFrameAt = function (index) {
var layers = this.piskel.getLayers();
layers.forEach(function (l) {
l.duplicateFrameAt(index);
});
};
ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) {
var layers = this.piskel.getLayers();
layers.forEach(function (l) {
l.moveFrame(fromIndex, toIndex);
});
};
ns.PiskelController.prototype.getFrameCount = function () {
var layer = this.piskel.getLayerAt(0);
return layer.length();
};
ns.PiskelController.prototype.setCurrentFrameIndex = function (index) {
this.currentFrameIndex = index;
$.publish(Events.FRAMESHEET_RESET);
};
ns.PiskelController.prototype.setCurrentLayerIndex = function (index) {
this.currentLayerIndex = index;
$.publish(Events.FRAMESHEET_RESET);
};
ns.PiskelController.prototype.createLayer = function (name) {
var layer = new pskl.model.Layer(name);
for (var i = 0 ; i < this.getFrameCount() ; i++) {
layer.addFrame(this.createEmptyFrame_());
}
this.piskel.addLayer(layer);
this.setCurrentLayerIndex(this.piskel.getLayers().length - 1);
};
ns.PiskelController.prototype.serialize = function () {
return pskl.utils.Serializer.serializePiskel(this.piskel);
};
ns.PiskelController.prototype.deserialize = function (json) {
try {
var piskel = pskl.utils.Serializer.deserializePiskel(json);
this.setPiskel(piskel);
} catch (e) {
console.error('Failed to deserialize');
console.error(e.stack);
}
};
})();

View File

@@ -1,8 +1,8 @@
(function () {
var ns = $.namespace("pskl.controller");
ns.PreviewFilmController = function (framesheet, container, dpi) {
ns.PreviewFilmController = function (piskelController, container, dpi) {
this.framesheet = framesheet;
this.piskelController = piskelController;
this.container = container;
this.dpi = this.calculateDPI_();
@@ -19,8 +19,8 @@
};
ns.PreviewFilmController.prototype.addFrame = function () {
this.framesheet.addEmptyFrame();
this.framesheet.setCurrentFrameIndex(this.framesheet.getFrameCount() - 1);
this.piskelController.addEmptyFrame();
this.piskelController.setCurrentFrameIndex(this.piskelController.getFrameCount() - 1);
this.updateScrollerOverflows();
};
@@ -68,7 +68,7 @@
// Manually remove tooltips since mouseout events were shortcut by the DOM refresh:
$(".tooltip").remove();
var frameCount = this.framesheet.getFrameCount();
var frameCount = this.piskelController.getFrameCount();
for (var i = 0, l = frameCount; i < l ; i++) {
this.container.append(this.createPreviewTile_(i));
@@ -110,8 +110,8 @@
var originFrameId = parseInt(ui.item.data("tile-number"), 10);
var targetInsertionId = $('.preview-tile').index(ui.item);
this.framesheet.moveFrame(originFrameId, targetInsertionId);
this.framesheet.setCurrentFrameIndex(targetInsertionId);
this.piskelController.moveFrame(originFrameId, targetInsertionId);
this.piskelController.setCurrentFrameIndex(targetInsertionId);
// TODO(grosbouddha): move localstorage request to the model layer?
$.publish(Events.LOCALSTORAGE_REQUEST);
@@ -123,13 +123,13 @@
* TODO(vincz): clean this giant rendering function & remove listeners.
*/
ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) {
var currentFrame = this.framesheet.getFrameByIndex(tileNumber);
var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber);
var previewTileRoot = document.createElement("li");
var classname = "preview-tile";
previewTileRoot.setAttribute("data-tile-number", tileNumber);
if (this.framesheet.getCurrentFrame() == currentFrame) {
if (this.piskelController.getCurrentFrame() == currentFrame) {
classname += " selected";
}
previewTileRoot.className = classname;
@@ -159,7 +159,7 @@
previewTileRoot.appendChild(canvasContainer);
if(tileNumber > 0 || this.framesheet.getFrameCount() > 1) {
if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) {
// Add 'remove frame' button.
var deleteButton = document.createElement("button");
deleteButton.setAttribute('rel', 'tooltip');
@@ -186,28 +186,28 @@
ns.PreviewFilmController.prototype.onPreviewClick_ = function (index, evt) {
// has not class tile-action:
if(!evt.target.classList.contains('tile-overlay')) {
this.framesheet.setCurrentFrameIndex(index);
this.piskelController.setCurrentFrameIndex(index);
}
};
ns.PreviewFilmController.prototype.onDeleteButtonClick_ = function (index, evt) {
this.framesheet.removeFrameByIndex(index);
this.piskelController.removeFrameAt(index);
$.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model
this.updateScrollerOverflows();
};
ns.PreviewFilmController.prototype.onAddButtonClick_ = function (index, evt) {
this.framesheet.duplicateFrameByIndex(index);
this.piskelController.duplicateFrameAt(index);
$.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model
this.framesheet.setCurrentFrameIndex(index + 1);
this.piskelController.setCurrentFrameIndex(index + 1);
this.updateScrollerOverflows();
};
/**
* Calculate the preview DPI depending on the framesheet size
* Calculate the preview DPI depending on the piskel size
*/
ns.PreviewFilmController.prototype.calculateDPI_ = function () {
var curFrame = this.framesheet.getCurrentFrame(),
var curFrame = this.piskelController.getCurrentFrame(),
frameHeight = curFrame.getHeight(),
frameWidth = curFrame.getWidth(),
maxFrameDim = Math.max(frameWidth, frameHeight);

View File

@@ -15,8 +15,8 @@
var SEL_SETTING_CLS = 'has-expanded-drawer';
var EXP_DRAWER_CLS = 'expanded';
ns.SettingsController = function (framesheet) {
this.framesheet = framesheet;
ns.SettingsController = function (piskelController) {
this.piskelController = piskelController;
this.drawerContainer = document.getElementById("drawer-container");
this.settingsContainer = $('[data-pskl-controller=settings]');
this.expanded = false;
@@ -48,7 +48,7 @@
ns.SettingsController.prototype.loadSetting = function (setting) {
this.drawerContainer.innerHTML = pskl.utils.Template.get(settings[setting].template);
(new settings[setting].controller(this.framesheet)).init();
(new settings[setting].controller(this.piskelController)).init();
this.settingsContainer.addClass(EXP_DRAWER_CLS);

View File

@@ -1,7 +1,7 @@
(function () {
var ns = $.namespace("pskl.controller.settings");
ns.GifExportController = function (framesheet) {
this.framesheet = framesheet;
ns.GifExportController = function (piskelController) {
this.piskelController = piskelController;
};
ns.GifExportController.prototype.init = function () {
@@ -61,7 +61,7 @@
};
ns.GifExportController.prototype.createRadioForDpi_ = function (dpi, template) {
var label = dpi[0]*this.framesheet.getWidth() + "x" + dpi[0]*this.framesheet.getHeight();
var label = dpi[0]*this.piskelController.getWidth() + "x" + dpi[0]*this.piskelController.getHeight();
var value = dpi[0];
var radioHTML = pskl.utils.Template.replace(template, {value : value, label : label});
var radio = pskl.utils.Template.createFromHTML(radioHTML);
@@ -86,12 +86,12 @@
var gif = new window.GIF({
workers: 2,
quality: 10,
width: this.framesheet.getWidth()*dpi,
height: this.framesheet.getHeight()*dpi
width: this.piskelController.getWidth()*dpi,
height: this.piskelController.getHeight()*dpi
});
for (var i = 0; i < this.framesheet.frames.length; i++) {
var frame = this.framesheet.frames[i];
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var frame = this.piskelController.getFrameAt(i);
var renderer = new pskl.rendering.CanvasRenderer(frame, dpi);
gif.addFrame(renderer.render(), {
delay: 1000 / fps