mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Merge pull request #472 from juliandescottes/export-tabs
Fix #446: Split export panel in tabs
This commit is contained in:
commit
5a0d5da5f4
@ -56,6 +56,6 @@
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.settings-section--application-general > .settings-item > label {
|
||||
.settings-section-application > .settings-item > label {
|
||||
display: block;
|
||||
}
|
@ -57,17 +57,17 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
.scaling-factor {
|
||||
.export-scale {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.scaling-factor-input {
|
||||
.export-scale .scale-input {
|
||||
margin: 5px;
|
||||
vertical-align: middle;
|
||||
width: 145px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.scaling-factor-text {
|
||||
.export-scale .scale-text {
|
||||
height: 31px;
|
||||
display: inline-block;
|
||||
line-height: 30px;
|
||||
@ -77,3 +77,88 @@
|
||||
border-radius: 3px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.export-resize {
|
||||
margin: 10px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.export-resize > * {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.export-resize > *:not(:last-child) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.export-resize > .resize-field {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.export-resize > .resize-label {
|
||||
height: 23px;
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.export-tabs {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.export-tabs:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
z-index: 0;
|
||||
background-color: gold;
|
||||
}
|
||||
|
||||
.export-tab {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
border: 1px solid transparent;
|
||||
/* Make sure the tab and its border are positioned above the :after element; */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.export-tab.selected,
|
||||
.export-tab:hover {
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.export-tab.selected {
|
||||
border-color: gold gold #444 gold;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.export-info {
|
||||
padding: 10px 5px 0px;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.export-panel-section {
|
||||
padding: 5px;
|
||||
margin-top: 10px;
|
||||
border: 1px solid #5d5d5d;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.export-panel-gif .export-panel-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.export-panel-gif .button {
|
||||
margin-right: 5px;
|
||||
width: 75px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
.drawer-content {
|
||||
overflow: hidden;
|
||||
background-color: #444;
|
||||
height: 650px;
|
||||
height: 550px;
|
||||
max-height: 100%;
|
||||
width: 280px;
|
||||
border-top-left-radius: 4px;
|
||||
@ -72,7 +72,6 @@
|
||||
}
|
||||
|
||||
.settings-title {
|
||||
color : gold;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
text-transform: uppercase;
|
||||
|
@ -52,7 +52,6 @@ body {
|
||||
}
|
||||
|
||||
.checkbox-fix {
|
||||
vertical-align: -2px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
/* reset for firefox */
|
||||
height: 17px;
|
||||
height: 16px;
|
||||
background: #222;
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,10 @@
|
||||
@@include('templates/settings/save.html', {})
|
||||
@@include('templates/settings/import.html', {})
|
||||
@@include('templates/settings/export.html', {})
|
||||
@@include('templates/settings/export/png.html', {})
|
||||
@@include('templates/settings/export/gif.html', {})
|
||||
@@include('templates/settings/export/zip.html', {})
|
||||
@@include('templates/settings/export/misc.html', {})
|
||||
|
||||
<script type="text/javascript">
|
||||
@@include('piskel-boot.js', {})
|
||||
|
@ -12,7 +12,7 @@
|
||||
},
|
||||
'export' : {
|
||||
template : 'templates/settings/export.html',
|
||||
controller : ns.exportimage.ImageExportController
|
||||
controller : ns.exportimage.ExportController
|
||||
},
|
||||
'import' : {
|
||||
template : 'templates/settings/import.html',
|
||||
|
124
src/js/controller/settings/exportimage/ExportController.js
Normal file
124
src/js/controller/settings/exportimage/ExportController.js
Normal file
@ -0,0 +1,124 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings.exportimage');
|
||||
|
||||
var tabs = {
|
||||
'png' : {
|
||||
template : 'templates/settings/export/png.html',
|
||||
controller : ns.PngExportController
|
||||
},
|
||||
'gif' : {
|
||||
template : 'templates/settings/export/gif.html',
|
||||
controller : ns.GifExportController
|
||||
},
|
||||
'zip' : {
|
||||
template : 'templates/settings/export/zip.html',
|
||||
controller : ns.ZipExportController
|
||||
},
|
||||
'misc' : {
|
||||
template : 'templates/settings/export/misc.html',
|
||||
controller : ns.MiscExportController
|
||||
}
|
||||
};
|
||||
|
||||
ns.ExportController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
this.onSizeInputChange_ = this.onSizeInputChange_.bind(this);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.ExportController.prototype.init = function () {
|
||||
// Initialize zoom controls
|
||||
this.scaleInput = document.querySelector('.export-scale .scale-input');
|
||||
this.addEventListener(this.scaleInput, 'change', this.onScaleChange_);
|
||||
this.addEventListener(this.scaleInput, 'input', this.onScaleChange_);
|
||||
|
||||
this.widthInput = document.querySelector('.export-resize .resize-width');
|
||||
this.heightInput = document.querySelector('.export-resize .resize-height');
|
||||
var scale = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
|
||||
this.sizeInputWidget = new pskl.widgets.SizeInput({
|
||||
widthInput : this.widthInput,
|
||||
heightInput : this.heightInput,
|
||||
initWidth : this.piskelController.getWidth() * scale,
|
||||
initHeight : this.piskelController.getHeight() * scale,
|
||||
onChange : this.onSizeInputChange_
|
||||
});
|
||||
|
||||
this.onSizeInputChange_();
|
||||
|
||||
// Initialize tabs and panel
|
||||
this.exportPanel = document.querySelector('.export-panel');
|
||||
this.exportTabs = document.querySelector('.export-tabs');
|
||||
this.addEventListener(this.exportTabs, 'click', this.onTabsClicked_);
|
||||
|
||||
var tab = pskl.UserSettings.get(pskl.UserSettings.EXPORT_TAB);
|
||||
this.selectTab(tab);
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.destroy = function () {
|
||||
this.sizeInputWidget.destroy();
|
||||
this.currentController.destroy();
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.selectTab = function (tabId) {
|
||||
if (!tabs[tabId] || this.currentTab == tabId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.currentController) {
|
||||
this.currentController.destroy();
|
||||
}
|
||||
|
||||
this.exportPanel.innerHTML = pskl.utils.Template.get(tabs[tabId].template);
|
||||
this.currentController = new tabs[tabId].controller(this.piskelController, this);
|
||||
this.currentController.init();
|
||||
this.currentTab = tabId;
|
||||
pskl.UserSettings.set(pskl.UserSettings.EXPORT_TAB, tabId);
|
||||
|
||||
var selectedTab = this.exportTabs.querySelector('.selected');
|
||||
if (selectedTab) {
|
||||
selectedTab.classList.remove('selected');
|
||||
}
|
||||
this.exportTabs.querySelector('[data-tab-id="' + tabId + '"]').classList.add('selected');
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.onTabsClicked_ = function (e) {
|
||||
var tabId = pskl.utils.Dom.getData(e.target, 'tabId');
|
||||
this.selectTab(tabId);
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.onScaleChange_ = function () {
|
||||
var value = parseFloat(this.scaleInput.value);
|
||||
if (!isNaN(value)) {
|
||||
if (Math.round(this.getExportZoom()) != value) {
|
||||
this.sizeInputWidget.setWidth(this.piskelController.getWidth() * value);
|
||||
}
|
||||
pskl.UserSettings.set(pskl.UserSettings.EXPORT_SCALING, value);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.updateScaleText_ = function (scale) {
|
||||
scale = scale.toFixed(1);
|
||||
var scaleText = document.querySelector('.export-scale .scale-text');
|
||||
scaleText.innerHTML = scale + 'x';
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.onSizeInputChange_ = function () {
|
||||
var zoom = this.getExportZoom();
|
||||
if (isNaN(zoom)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateScaleText_(zoom);
|
||||
|
||||
this.scaleInput.value = Math.round(zoom);
|
||||
if (zoom >= 1 && zoom <= 32) {
|
||||
this.onScaleChange_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ExportController.prototype.getExportZoom = function () {
|
||||
return parseInt(this.widthInput.value, 10) / this.piskelController.getWidth();
|
||||
};
|
||||
})();
|
@ -3,51 +3,35 @@
|
||||
|
||||
var URL_MAX_LENGTH = 30;
|
||||
var MAX_GIF_COLORS = 256;
|
||||
var MAX_EXPORT_ZOOM = 20;
|
||||
var DEFAULT_EXPORT_ZOOM = 10;
|
||||
var MAGIC_PINK = '#FF00FF';
|
||||
var WHITE = '#FFFFFF';
|
||||
|
||||
ns.GifExportController = function (piskelController) {
|
||||
ns.GifExportController = function (piskelController, exportController) {
|
||||
this.piskelController = piskelController;
|
||||
this.exportController = exportController;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.GifExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
/**
|
||||
* List of Resolutions applicable for Gif export
|
||||
* @static
|
||||
* @type {Array} array of Objects {zoom:{Number}, default:{Boolean}}
|
||||
*/
|
||||
ns.GifExportController.RESOLUTIONS = [];
|
||||
for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) {
|
||||
ns.GifExportController.RESOLUTIONS.push({
|
||||
zoom : i
|
||||
});
|
||||
}
|
||||
|
||||
ns.GifExportController.prototype.init = function () {
|
||||
|
||||
this.uploadStatusContainerEl = document.querySelector('.gif-upload-status');
|
||||
this.previewContainerEl = document.querySelector('.gif-export-preview');
|
||||
this.widthInput = document.querySelector('.export-gif-resize-width');
|
||||
this.heightInput = document.querySelector('.export-gif-resize-height');
|
||||
this.uploadButton = document.querySelector('.gif-upload-button');
|
||||
this.downloadButton = document.querySelector('.gif-download-button');
|
||||
|
||||
this.sizeInputWidget = new pskl.widgets.SizeInput(
|
||||
this.widthInput, this.heightInput,
|
||||
this.piskelController.getWidth(), this.piskelController.getHeight());
|
||||
|
||||
this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_);
|
||||
this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_);
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.destroy = function () {
|
||||
this.sizeInputWidget.destroy();
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.getZoom_ = function () {
|
||||
return this.exportController.getExportZoom();
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) {
|
||||
evt.preventDefault();
|
||||
var zoom = this.getZoom_();
|
||||
@ -98,10 +82,6 @@
|
||||
this.previewContainerEl.innerHTML = '<div><img style="max-width:32px;" src="' + src + '"/></div>';
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.getZoom_ = function () {
|
||||
return parseInt(this.widthInput.value, 10) / this.piskelController.getWidth();
|
||||
};
|
||||
|
||||
ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) {
|
||||
var currentColors = pskl.app.currentColorsService.getCurrentColors();
|
||||
|
||||
@ -172,7 +152,6 @@
|
||||
return transparentColor;
|
||||
};
|
||||
|
||||
// FIXME : JD : HORRIBLE COPY/PASTA (JD later : where???)
|
||||
ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) {
|
||||
if (imageUrl) {
|
||||
var linkTpl = '<a class="image-link" href="{{link}}" target="_blank">{{shortLink}}</a>';
|
||||
|
@ -1,48 +0,0 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings.exportimage');
|
||||
|
||||
ns.ImageExportController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
this.pngExportController = new ns.PngExportController(piskelController);
|
||||
this.gifExportController = new ns.GifExportController(piskelController);
|
||||
this.cExportController = new ns.CExportController(piskelController);
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ImageExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.ImageExportController.prototype.init = function () {
|
||||
// Output Scaling Factor
|
||||
var scalingFactorInput = document.querySelector('.scaling-factor-input');
|
||||
scalingFactorInput.value = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
|
||||
this.addEventListener(scalingFactorInput, 'change', this.onScalingFactorChange_);
|
||||
this.addEventListener(scalingFactorInput, 'input', this.onScalingFactorChange_);
|
||||
this.updateScalingFactorText_(scalingFactorInput.value);
|
||||
|
||||
this.pngExportController.init();
|
||||
this.gifExportController.init();
|
||||
this.cExportController.init();
|
||||
};
|
||||
|
||||
ns.ImageExportController.prototype.destroy = function () {
|
||||
this.pngExportController.destroy();
|
||||
this.gifExportController.destroy();
|
||||
this.cExportController.destroy();
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.ImageExportController.prototype.onScalingFactorChange_ = function (evt) {
|
||||
var target = evt.target;
|
||||
var value = Math.round(parseFloat(target.value));
|
||||
if (!isNaN(value)) {
|
||||
this.updateScalingFactorText_(value);
|
||||
pskl.UserSettings.set(pskl.UserSettings.EXPORT_SCALING, value);
|
||||
} else {
|
||||
target.value = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageExportController.prototype.updateScalingFactorText_ = function (scale) {
|
||||
var scalingFactorText = document.querySelector('.scaling-factor-text');
|
||||
scalingFactorText.innerHTML = scale + 'x';
|
||||
};
|
||||
})();
|
@ -3,19 +3,19 @@
|
||||
|
||||
var BLACK = '#000000';
|
||||
|
||||
ns.CExportController = function (piskelController) {
|
||||
ns.MiscExportController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.CExportController, pskl.controller.settings.AbstractSettingController);
|
||||
pskl.utils.inherit(ns.MiscExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.CExportController.prototype.init = function () {
|
||||
ns.MiscExportController.prototype.init = function () {
|
||||
|
||||
var downloadButton = document.querySelector('.c-download-button');
|
||||
this.addEventListener(downloadButton, 'click', this.onCDownloadButtonClick_);
|
||||
};
|
||||
|
||||
ns.CExportController.prototype.onCDownloadButtonClick_ = function (evt) {
|
||||
ns.MiscExportController.prototype.onCDownloadButtonClick_ = function (evt) {
|
||||
var fileName = this.getPiskelName_() + '.c';
|
||||
var cName = this.getPiskelName_().replace(' ','_');
|
||||
var width = this.piskelController.getWidth();
|
||||
@ -62,11 +62,11 @@
|
||||
}.bind(this), 'application/text');
|
||||
};
|
||||
|
||||
ns.CExportController.prototype.getPiskelName_ = function () {
|
||||
ns.MiscExportController.prototype.getPiskelName_ = function () {
|
||||
return this.piskelController.getPiskel().getDescriptor().name;
|
||||
};
|
||||
|
||||
ns.CExportController.prototype.rgbToCHex = function (r, g, b, a) {
|
||||
ns.MiscExportController.prototype.rgbToCHex = function (r, g, b, a) {
|
||||
var hexStr = '0x';
|
||||
hexStr += ('00' + a.toString(16)).substr(-2);
|
||||
hexStr += ('00' + b.toString(16)).substr(-2);
|
@ -1,25 +1,16 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings.exportimage');
|
||||
|
||||
var URL_MAX_LENGTH = 60;
|
||||
|
||||
ns.PngExportController = function (piskelController) {
|
||||
ns.PngExportController = function (piskelController, exportController) {
|
||||
this.piskelController = piskelController;
|
||||
this.exportController = exportController;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.PngExportController.prototype.init = function () {
|
||||
this.pngFilePrefixInput = document.querySelector('.zip-prefix-name');
|
||||
this.pngFilePrefixInput.value = 'sprite_';
|
||||
|
||||
this.splitByLayersCheckbox = document.querySelector('.zip-split-layers-checkbox');
|
||||
|
||||
var downloadButton = document.querySelector('.png-download-button');
|
||||
this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_);
|
||||
|
||||
var zipButton = document.querySelector('.zip-generate-button');
|
||||
this.addEventListener(zipButton, 'click', this.onZipButtonClick_);
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) {
|
||||
@ -27,10 +18,10 @@
|
||||
|
||||
var outputCanvas = this.getFramesheetAsCanvas();
|
||||
|
||||
var scalingFactor = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
|
||||
if (scalingFactor > 1) {
|
||||
var width = outputCanvas.width * scalingFactor;
|
||||
var height = outputCanvas.height * scalingFactor;
|
||||
var zoom = this.exportController.getExportZoom();
|
||||
if (zoom != 1) {
|
||||
var width = outputCanvas.width * zoom;
|
||||
var height = outputCanvas.height * zoom;
|
||||
outputCanvas = pskl.utils.ImageResizer.resize(outputCanvas, width, height, false);
|
||||
}
|
||||
|
||||
@ -39,54 +30,6 @@
|
||||
});
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.onZipButtonClick_ = function () {
|
||||
var zip = new window.JSZip();
|
||||
|
||||
if (this.splitByLayersCheckbox.checked) {
|
||||
this.splittedExport_(zip);
|
||||
} else {
|
||||
this.mergedExport_(zip);
|
||||
}
|
||||
|
||||
var fileName = this.getPiskelName_() + '.zip';
|
||||
|
||||
var blob = zip.generate({
|
||||
type : 'blob'
|
||||
});
|
||||
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.mergedExport_ = function (zip) {
|
||||
var paddingLength = ('' + this.piskelController.getFrameCount()).length;
|
||||
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||
var render = this.piskelController.renderFrameAt(i, true);
|
||||
var canvas = pskl.utils.CanvasUtils.createFromImage(render);
|
||||
var basename = this.pngFilePrefixInput.value;
|
||||
var id = pskl.utils.StringUtils.leftPad(i, paddingLength, '0');
|
||||
var filename = basename + id + '.png';
|
||||
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
||||
}
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.splittedExport_ = function (zip) {
|
||||
var layers = this.piskelController.getLayers();
|
||||
var framePaddingLength = ('' + this.piskelController.getFrameCount()).length;
|
||||
var layerPaddingLength = ('' + layers.length).length;
|
||||
for (var j = 0; this.piskelController.hasLayerAt(j); j++) {
|
||||
var layer = this.piskelController.getLayerAt(j);
|
||||
var layerid = pskl.utils.StringUtils.leftPad(j, layerPaddingLength, '0');
|
||||
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||
var render = pskl.utils.LayerUtils.renderFrameAt(layer, i, true);
|
||||
var canvas = pskl.utils.CanvasUtils.createFromImage(render);
|
||||
var basename = this.pngFilePrefixInput.value;
|
||||
var frameid = pskl.utils.StringUtils.leftPad(i + 1, framePaddingLength, '0');
|
||||
var filename = 'l' + layerid + '_' + basename + frameid + '.png';
|
||||
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.getPiskelName_ = function () {
|
||||
return this.piskelController.getPiskel().getDescriptor().name;
|
||||
};
|
||||
@ -95,25 +38,4 @@
|
||||
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
|
||||
return renderer.renderAsCanvas();
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) {
|
||||
if (imageUrl) {
|
||||
var linkTpl = '<a class="image-link" href="{{link}}" target="_blank">{{shortLink}}</a>';
|
||||
var linkHtml = pskl.utils.Template.replace(linkTpl, {
|
||||
link : imageUrl,
|
||||
shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...')
|
||||
});
|
||||
this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml;
|
||||
} else {
|
||||
// FIXME : Should display error message instead
|
||||
}
|
||||
};
|
||||
|
||||
ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) {
|
||||
if (url.length > maxLength) {
|
||||
url = url.substring(0, maxLength);
|
||||
url += suffix;
|
||||
}
|
||||
return url;
|
||||
};
|
||||
})();
|
||||
|
@ -0,0 +1,74 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.settings.exportimage');
|
||||
|
||||
ns.ZipExportController = function (piskelController, exportController) {
|
||||
this.piskelController = piskelController;
|
||||
this.exportController = exportController;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ZipExportController, pskl.controller.settings.AbstractSettingController);
|
||||
|
||||
ns.ZipExportController.prototype.init = function () {
|
||||
this.pngFilePrefixInput = document.querySelector('.zip-prefix-name');
|
||||
this.pngFilePrefixInput.value = 'sprite_';
|
||||
|
||||
this.splitByLayersCheckbox = document.querySelector('.zip-split-layers-checkbox');
|
||||
|
||||
var zipButton = document.querySelector('.zip-generate-button');
|
||||
this.addEventListener(zipButton, 'click', this.onZipButtonClick_);
|
||||
};
|
||||
|
||||
ns.ZipExportController.prototype.onZipButtonClick_ = function () {
|
||||
var zip = new window.JSZip();
|
||||
|
||||
if (this.splitByLayersCheckbox.checked) {
|
||||
this.splittedExport_(zip);
|
||||
} else {
|
||||
this.mergedExport_(zip);
|
||||
}
|
||||
|
||||
var fileName = this.getPiskelName_() + '.zip';
|
||||
|
||||
var blob = zip.generate({
|
||||
type : 'blob'
|
||||
});
|
||||
|
||||
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
|
||||
};
|
||||
|
||||
ns.ZipExportController.prototype.mergedExport_ = function (zip) {
|
||||
var paddingLength = ('' + this.piskelController.getFrameCount()).length;
|
||||
var zoom = this.exportController.getExportZoom();
|
||||
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||
var render = this.piskelController.renderFrameAt(i, true);
|
||||
var canvas = pskl.utils.ImageResizer.scale(render, zoom);
|
||||
var basename = this.pngFilePrefixInput.value;
|
||||
var id = pskl.utils.StringUtils.leftPad(i, paddingLength, '0');
|
||||
var filename = basename + id + '.png';
|
||||
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
||||
}
|
||||
};
|
||||
|
||||
ns.ZipExportController.prototype.splittedExport_ = function (zip) {
|
||||
var layers = this.piskelController.getLayers();
|
||||
var framePaddingLength = ('' + this.piskelController.getFrameCount()).length;
|
||||
var layerPaddingLength = ('' + layers.length).length;
|
||||
var zoom = this.exportController.getExportZoom();
|
||||
for (var j = 0; this.piskelController.hasLayerAt(j); j++) {
|
||||
var layer = this.piskelController.getLayerAt(j);
|
||||
var layerid = pskl.utils.StringUtils.leftPad(j, layerPaddingLength, '0');
|
||||
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||
var render = pskl.utils.LayerUtils.renderFrameAt(layer, i, true);
|
||||
var canvas = pskl.utils.ImageResizer.scale(render, zoom);
|
||||
var basename = this.pngFilePrefixInput.value;
|
||||
var frameid = pskl.utils.StringUtils.leftPad(i + 1, framePaddingLength, '0');
|
||||
var filename = 'l' + layerid + '_' + basename + frameid + '.png';
|
||||
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.ZipExportController.prototype.getPiskelName_ = function () {
|
||||
return this.piskelController.getPiskel().getDescriptor().name;
|
||||
};
|
||||
})();
|
@ -20,9 +20,12 @@
|
||||
this.resizeContentCheckbox = this.container.querySelector('.resize-content-checkbox');
|
||||
this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox');
|
||||
|
||||
var initWidth = this.piskelController.getWidth();
|
||||
var initHeight = this.piskelController.getHeight();
|
||||
this.sizeInputWidget = new pskl.widgets.SizeInput(this.widthInput, this.heightInput, initWidth, initHeight);
|
||||
this.sizeInputWidget = new pskl.widgets.SizeInput({
|
||||
widthInput: this.widthInput,
|
||||
heightInput: this.heightInput,
|
||||
initWidth: this.piskelController.getWidth(),
|
||||
initHeight: this.piskelController.getHeight(),
|
||||
});
|
||||
|
||||
var settings = pskl.UserSettings.get('RESIZE_SETTINGS');
|
||||
var origin = ns.AnchorWidget.ORIGIN[settings.origin] || ns.AnchorWidget.ORIGIN.TOPLEFT;
|
||||
|
@ -6,6 +6,7 @@
|
||||
this.isRunning = false;
|
||||
this.previousTime = 0;
|
||||
this.callbacks = [];
|
||||
this.loop_ = this.loop_.bind(this);
|
||||
};
|
||||
|
||||
ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) {
|
||||
@ -35,7 +36,7 @@
|
||||
var delta = currentTime - this.previousTime;
|
||||
this.executeCallbacks_(delta);
|
||||
this.previousTime = currentTime;
|
||||
this.requestAnimationFrame.call(window, this.loop_.bind(this));
|
||||
this.requestAnimationFrame.call(window, this.loop_);
|
||||
};
|
||||
|
||||
ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
LAYER_PREVIEW : 'LAYER_PREVIEW',
|
||||
LAYER_OPACITY : 'LAYER_OPACITY',
|
||||
EXPORT_SCALING: 'EXPORT_SCALING',
|
||||
EXPORT_TAB: 'EXPORT_TAB',
|
||||
PEN_SIZE : 'PEN_SIZE',
|
||||
RESIZE_SETTINGS: 'RESIZE_SETTINGS',
|
||||
KEY_TO_DEFAULT_VALUE_MAP_ : {
|
||||
@ -30,6 +31,7 @@
|
||||
'LAYER_OPACITY' : 0.2,
|
||||
'LAYER_PREVIEW' : true,
|
||||
'EXPORT_SCALING' : 1,
|
||||
'EXPORT_TAB' : 'png',
|
||||
'PEN_SIZE' : 1,
|
||||
'RESIZE_SETTINGS': {
|
||||
maintainRatio : true,
|
||||
|
@ -1,16 +1,29 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.widgets');
|
||||
ns.SizeInput = function (widthInput, heightInput, initWidth, initHeight) {
|
||||
this.widthInput = widthInput;
|
||||
this.heightInput = heightInput;
|
||||
this.initWidth = initWidth;
|
||||
this.initHeight = initHeight;
|
||||
|
||||
/**
|
||||
* Synchronize two "number" inputs to stick to their initial ratio.
|
||||
* The synchronization can be disabled/enabled on the fly.
|
||||
*
|
||||
* @param {Object} options
|
||||
* - {Element} widthInput
|
||||
* - {Element} heightInput
|
||||
* - {Number} initWidth
|
||||
* - {Number} initHeight
|
||||
* - {Function} onChange
|
||||
*/
|
||||
ns.SizeInput = function (options) {
|
||||
this.widthInput = options.widthInput;
|
||||
this.heightInput = options.heightInput;
|
||||
this.initWidth = options.initWidth;
|
||||
this.initHeight = options.initHeight;
|
||||
this.onChange = options.onChange;
|
||||
|
||||
this.syncEnabled = true;
|
||||
this.lastInput = this.widthInput;
|
||||
|
||||
this.widthInput.value = initWidth;
|
||||
this.heightInput.value = initHeight;
|
||||
this.widthInput.value = this.initWidth;
|
||||
this.heightInput.value = this.initHeight;
|
||||
|
||||
pskl.utils.Event.addEventListener(this.widthInput, 'keyup', this.onSizeInputKeyUp_, this);
|
||||
pskl.utils.Event.addEventListener(this.heightInput, 'keyup', this.onSizeInputKeyUp_, this);
|
||||
@ -33,6 +46,16 @@
|
||||
this.syncEnabled = false;
|
||||
};
|
||||
|
||||
ns.SizeInput.prototype.setWidth = function (width) {
|
||||
this.widthInput.value = width;
|
||||
this.synchronize_(this.widthInput);
|
||||
};
|
||||
|
||||
ns.SizeInput.prototype.setHeight = function (height) {
|
||||
this.heightInput.value = height;
|
||||
this.synchronize_(this.heightInput);
|
||||
};
|
||||
|
||||
ns.SizeInput.prototype.onSizeInputKeyUp_ = function (evt) {
|
||||
var target = evt.target;
|
||||
if (this.syncEnabled) {
|
||||
@ -57,5 +80,9 @@
|
||||
} else if (sizeInput === this.heightInput) {
|
||||
this.widthInput.value = Math.round(value * this.initWidth / this.initHeight);
|
||||
}
|
||||
|
||||
if (this.onChange) {
|
||||
this.onChange();
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -114,10 +114,11 @@
|
||||
// Settings sub-controllers
|
||||
"js/controller/settings/AbstractSettingController.js",
|
||||
"js/controller/settings/ApplicationSettingsController.js",
|
||||
"js/controller/settings/exportimage/ImageExportController.js",
|
||||
"js/controller/settings/exportimage/GifExportController.js",
|
||||
"js/controller/settings/exportimage/PngExportController.js",
|
||||
"js/controller/settings/exportimage/CExportController.js",
|
||||
"js/controller/settings/exportimage/ZipExportController.js",
|
||||
"js/controller/settings/exportimage/MiscExportController.js",
|
||||
"js/controller/settings/exportimage/ExportController.js",
|
||||
"js/controller/settings/resize/AnchorWidget.js",
|
||||
"js/controller/settings/resize/ResizeController.js",
|
||||
"js/controller/settings/resize/DefaultSizeController.js",
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script type="text/html" id="templates/settings/application.html">
|
||||
<form action="" method="POST" name="application-settings-form">
|
||||
<div class="settings-section settings-section--application-general">
|
||||
<div class="settings-section settings-section-application">
|
||||
<div class="settings-title">
|
||||
General
|
||||
</div>
|
||||
|
@ -1,72 +1,25 @@
|
||||
<script type="text/html" id="templates/settings/export.html">
|
||||
<div class="settings-section">
|
||||
<div class="settings-title">
|
||||
Export Spritesheet
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<div class="settings-description">PNG with all frames side by side.</div>
|
||||
<div class="scaling-factor"
|
||||
title="Scale the exported PNG spritesheet"
|
||||
<div class="settings-section settings-section-export">
|
||||
<div class="settings-title">Export</div>
|
||||
<div class="settings-item export-scale" title="Scale the exported PNG spritesheet"
|
||||
rel="tooltip"
|
||||
data-placement="top">
|
||||
<label for="scaling-factor">Scale</label>
|
||||
<input type="range" class="scaling-factor-input" name="scaling-factor" min="1" max="32" step="1"/>
|
||||
<span class="scaling-factor-text"></span>
|
||||
</div>
|
||||
<button type="button" class="button button-primary png-download-button">Download PNG</button>
|
||||
<label for="scale-input">Scale</label>
|
||||
<input type="range" class="scale-input" name="scale-input" min="1" max="32" step="1"/>
|
||||
<span class="scale-text"></span>
|
||||
</div>
|
||||
<div class="settings-title">
|
||||
Export as ZIP
|
||||
<div class="settings-item export-resize">
|
||||
<span class="resize-label">Resolution</span>
|
||||
<input type="text" class="textfield resize-field resize-width" autocomplete="off" name="resize-width"/>
|
||||
<div class="resize-label">x</div>
|
||||
<input type="text" class="textfield resize-field resize-height" autocomplete="off" name="resize-height"/>
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<div class="settings-description">ZIP with one PNG file per frame.</div>
|
||||
<div class="settings-description">File names will start with the prefix below.</div>
|
||||
<div class="settings-item">
|
||||
<label>Prefix</label>
|
||||
<input type="text" class="zip-prefix-name textfield" autocomplete="off" placeholder="PNG file prefix ...">
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<label>
|
||||
<input class="zip-split-layers-checkbox checkbox-fix" type="checkbox" />
|
||||
Split by layers
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
|
||||
</div>
|
||||
<div class="settings-title">
|
||||
Export as C File
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<div class="settings-description">C file with frame rendered as array.</div>
|
||||
<button type="button" class="button button-primary c-download-button">Download C file</button>
|
||||
</div>
|
||||
<div class="settings-title">
|
||||
Export to Animated GIF
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<form action="" method="POST" class="gif-export-form">
|
||||
<div class="settings-item">
|
||||
<label>Select resolution:</label>
|
||||
<div class="resize-section">
|
||||
<span class="resize-section-title">Width</span>
|
||||
<input type="text" class="textfield export-size-field export-gif-resize-width" autocomplete="off" name="resize-width"/>
|
||||
<span>px</span>
|
||||
</div>
|
||||
<div class="resize-section">
|
||||
<span class="resize-section-title">Height</span>
|
||||
<input type="text" class="textfield export-size-field export-gif-resize-height" autocomplete="off" name="resize-height"/>
|
||||
<span>px</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-item">
|
||||
<button type="button" class="button button-primary gif-download-button">Download GIF</button>
|
||||
<button type="button" class="button button gif-upload-button">Get public URL</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="gif-upload">
|
||||
<div class="gif-export-preview"></div>
|
||||
<div class="gif-upload-status"></div>
|
||||
</div>
|
||||
<div class="export-tabs">
|
||||
<div class="export-tab" data-tab-id="png">PNG</div>
|
||||
<div class="export-tab" data-tab-id="gif">GIF</div>
|
||||
<div class="export-tab" data-tab-id="zip">Zip</div>
|
||||
<div class="export-tab" data-tab-id="misc">Others</div>
|
||||
</div>
|
||||
<div class="export-panel"></div>
|
||||
</div>
|
||||
</script>
|
||||
|
19
src/templates/settings/export/gif.html
Normal file
19
src/templates/settings/export/gif.html
Normal file
@ -0,0 +1,19 @@
|
||||
<script type="text/html" id="templates/settings/export/gif.html">
|
||||
<div class="export-panel-gif">
|
||||
<div class="export-info">
|
||||
Convert your sprite to an animated GIF. Opacity will not be preserved. Colors might be resampled.
|
||||
</div>
|
||||
<div class="export-panel-section">
|
||||
<button type="button" class="button button-primary gif-download-button">Download</button>
|
||||
<div>Download as an animated GIF.</div>
|
||||
</div>
|
||||
<div class="export-panel-section">
|
||||
<button type="button" class="button button-primary gif-upload-button">Upload</button>
|
||||
<div>Upload as an animated GIF to a public URL.</div>
|
||||
</div>
|
||||
<div class="gif-upload">
|
||||
<div class="gif-export-preview"></div>
|
||||
<div class="gif-upload-status"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
16
src/templates/settings/export/misc.html
Normal file
16
src/templates/settings/export/misc.html
Normal file
@ -0,0 +1,16 @@
|
||||
<script type="text/html" id="templates/settings/export/misc.html">
|
||||
<div class="export-panel-misc">
|
||||
<div class="export-info">
|
||||
Less usual export formats. Feedback and improvements welcome.
|
||||
</div>
|
||||
<div class="export-panel-section">
|
||||
<div style="padding-bottom: 5px">
|
||||
<span style="color: gold;">Export as C File: </span>
|
||||
<span style="font-weight: normal; text-shadow: none; font-style: italic">
|
||||
C file with frame rendered as array.
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" class="button button-primary c-download-button">Download C file</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
8
src/templates/settings/export/png.html
Normal file
8
src/templates/settings/export/png.html
Normal file
@ -0,0 +1,8 @@
|
||||
<script type="text/html" id="templates/settings/export/png.html">
|
||||
<div class="export-panel-png">
|
||||
<div class="export-info">Export your animation as a PNG spritesheet containing all frames.</div>
|
||||
<div class="export-panel-section">
|
||||
<button type="button" class="button button-primary png-download-button">Download PNG</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
17
src/templates/settings/export/zip.html
Normal file
17
src/templates/settings/export/zip.html
Normal file
@ -0,0 +1,17 @@
|
||||
<script type="text/html" id="templates/settings/export/zip.html">
|
||||
<div class="export-panel-zip">
|
||||
<div class="export-info">ZIP archive containing one PNG for each frame. File names will start with the prefix below.</div>
|
||||
<div class="export-panel-section">
|
||||
<div style="display: flex; line-height: 23px;">
|
||||
<label style="flex-shrink: 0; padding-right:5px;">Prefix</label>
|
||||
<input type="text" style="flex: 1;" class="zip-prefix-name textfield"
|
||||
autocomplete="off" placeholder="PNG file prefix ...">
|
||||
</div>
|
||||
<div style="margin: 5px 0;">
|
||||
<input id="zip-split-layers" class="zip-split-layers-checkbox checkbox-fix" type="checkbox" />
|
||||
<label for="zip-split-layers">Split by layers</label>
|
||||
</div>
|
||||
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
@ -1,5 +1,5 @@
|
||||
<script type="text/template" id="templates/settings/import.html">
|
||||
<div class="settings-section">
|
||||
<div class="settings-section settings-section-import">
|
||||
<div class="settings-title">
|
||||
Load from Browser
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script type="text/html" id="templates/settings/resize.html">
|
||||
<div class="settings-section">
|
||||
<div class="settings-section settings-section-resize">
|
||||
<!-- RESIZE DRAWING SECTION -->
|
||||
<div class="settings-title">
|
||||
Resize
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script type="text/template" id="templates/settings/save.html">
|
||||
<div class="settings-section setting-save-section">
|
||||
<div class="settings-section settings-section-save">
|
||||
<form action="" method="POST" class="save-form" name="save-form">
|
||||
<div class="settings-title">Sprite Information</div>
|
||||
<div class="settings-item">
|
||||
|
Loading…
Reference in New Issue
Block a user