not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1686 lines
63 KiB

define(["easel","sugar-web/datastore","sugar-web/env","webL10n","humane"], function (easel, datastore, env, l10n, humane) {
env.getEnvironment(function(err, environment) {
var defaultLanguage = (typeof chrome != 'undefined' && chrome.app && chrome.app.runtime) ? chrome.i18n.getUILanguage() : navigator.language;
var language = environment.user ? environment.user.language : defaultLanguage;
l10n.language.code = language;
console.log('LANG ' + language);
});
function _(text) {
// copied from activity.js
translation = l10n.get(text);
if (translation == '') {
translation = text;
};
return translation;
};
var onAndroid = /Android/i.test(navigator.userAgent);
var smallScreen = (window.innerWidth < 700) || (window.innerHeight < 600);
var font = smallScreen ? "16px Arial" : "24px Arial";
var LINE_WIDTH = 3;
var BLACK = "#000000";
var WHITE = "#ffffff";
// Spanish names for historic reasons
var DIR_DOWN = "abajo";
var DIR_UP = "arriba";
var DIR_LEFT = "izq";
var DIR_RIGHT = "der";
var MODE_NORMAL = 'normal';
var MODE_WHISPER = 'despacio';
var SIZE_RESIZE_AREA = 40; // TODO style.GRID_CELL_SIZE / 2
var TYPE_GLOBE = 'GLOBE';
var TYPE_CLOUD = 'CLOUD';
var TYPE_EXCLAMATION = 'EXCLAMATION';
var TYPE_RECTANGLE = 'RECTANGLE';
// TYPE_WHISPER is saved as TYPE_GLOBE and mode MODE_WHISPER
var TYPE_WHISPER = 'WHISPER';
var DEFAULT_FONT_SIZE = 14;
toon = {};
function createAsyncBitmap(box, url, callback) {
// Async creation of bitmap from SVG data
// Works with Chrome, Safari, Firefox (untested on IE)
var img = new Image();
img.onload = function () {
bitmap = new createjs.Bitmap(img);
bitmap.setBounds(0, 0, img.width, img.height);
bitmap.mouseEnabled = false;
callback(box, bitmap);
};
img.onerror = function (errorMsg, url, lineNumber) {
callback(box, null);
};
img.src = url;
};
function createAsyncBitmapButton(globe, url, callback) {
// creates a square black button with a image inside
// is used for the corner controls in the globe
var img = new Image();
img.cont = null;
img.globe = globe;
img.onload = function () {
var bitmap = new createjs.Bitmap(img);
bitmap.setBounds(0, 0, img.width, img.height);
bounds = bitmap.getBounds();
var scale = SIZE_RESIZE_AREA / bounds.height;
bitmap.scaleX = scale;
bitmap.scaleY = scale;
if (this.cont == null) {
this.cont = new createjs.Container();
this.cont.name = 'button';
var hitArea = new createjs.Shape();
hitArea.graphics.beginFill("#000").drawRect(0, 0,
SIZE_RESIZE_AREA, SIZE_RESIZE_AREA);
this.cont.width = SIZE_RESIZE_AREA;
this.cont.height = SIZE_RESIZE_AREA;
this.cont.hitArea = hitArea;
this.cont.addChild(hitArea);
this.cont.addChild(bitmap);
callback(this.globe, this.cont);
};
};
img.src = url;
return img;
};
function Model(data, canvas, textpalette) {
this._data = data;
// this._data have the following fields:
// 'version':'1' (don't change, for compatibility with python version)
// 'boxs': [] array with the boxes information
// every item have the background properties and a array of globes
//
// The next properites are temporary and are not saved:
// 'images': are loaded async, then have no garatie of be present.
// we use the fact that the first box do not have a background
// image, and expect that when the user change to the next box
// the images will be charged.
// 'previews': loaded from the canvas, will be displayed on the sorting
// mode.
this._canvas = canvas;
this._textpalette = textpalette;
this.comicBox = null;
this._imageCounter = 0;
this._pageCounterDisplay = null;
this._prevButton = null;
this._nextButton = null;
this._boxSorter = null;
this._sortButton = null;
this._data['previews'] = [];
// wait dialog
this._waitMsg = document.getElementById("wait");
this.comicBox = new ComicBox(this._canvas, this);
this.init = function() {
this.activeBox = 0;
var comic_box_data = this._data['boxs'][this.activeBox];
this._imageCounter = this._data['boxs'].length;
if (this._data['boxs'].length == 1) {
if (comic_box_data['globes'].length == 0) {
console.log('EMPTY TOON');
// add a globe for the title
var titleGlobe = {
"direction": null, "text_font_description": "Sans 30",
"globe_type": "RECTANGLE", "height": 50, "width": 200,
"text_color": [0, 0, 0], "radio": 15, "text_width": 76,
"y": this._canvas.height / 2,
"x": this._canvas.width / 2,
"text_height": 8, "title_globe": true,
"text_text": _('Title')};
comic_box_data['globes'].push(titleGlobe);
};
};
this.comicBox.init(comic_box_data, this._data['images']);
this.comicBox.attachTextEditionPalette(this._textpalette);
this._updatePageCounter();
};
this.setData = function(data) {
this._data = data;
this._data['previews'] = [];
this.init();
};
this.showWait = function () {
this._waitMsg.style.display = 'block';
};
this.hideWait = function () {
this._waitMsg.style.display = 'none';
};
this.getTitle = function() {
var firstBoxData = this._data['boxs'][0];
for (var i = 0; i < firstBoxData['globes'].length; i ++) {
var globeData = firstBoxData['globes'][i];
if (globeData['title_globe']) {
return globeData['text_text'];
}
};
return '';
};
this.initSort = function(sortCanvas) {
this._canvas.style.display = 'none';
this._boxSorter = new BoxSorter(sortCanvas, this._data);
this._boxSorter.init();
if (this._pageCounterDisplay != null) {
// hide the page counter
this._pageCounterDisplay.parentNode.style.display = "none";
};
};
this.finishSort = function() {
var sortedBoxes = [];
// get a rray with the new order for the boxes, like [0, 3, 2, 1]
var newOrders = this._boxSorter.getSortOrder();
this.changeToEditMode();
for (var i = 0; i < newOrders.length; i++) {
sortedBoxes.push(this._data['boxs'][newOrders[i]]);
};
this._data['boxs'] = sortedBoxes;
};
this.changeToEditMode = function() {
this._boxSorter.hide();
this._canvas.style.display = 'block';
if (this._pageCounterDisplay != null) {
// hide the page counter
this._pageCounterDisplay.parentNode.style.display = "block";
};
};
this.changeBox = function(newOrder) {
if (newOrder >= 0 && newOrder < this._data['boxs'].length) {
this.updateData();
// load the new data
this.activeBox = newOrder;
this.comicBox.init(this._data['boxs'][this.activeBox],
this._data['images'], (this.activeBox > 0));
this._updatePageCounter();
};
};
this.removeBox = function() {
// remove the actual box */
this._data['boxs'].splice(this.activeBox, 1);
this._data['previews'] = [];
if (this.activeBox > this._data['boxs'].length - 1) {
this.activeBox --;
}
this.comicBox.init(this._data['boxs'][this.activeBox],
this._data['images'], (this.activeBox > 0));
this._updatePageCounter();
};
this.updateData = function() {
this._data['boxs'][this.activeBox] = this.comicBox.getJson();
};
this.initPreviews = function() {
// store the initial preview images
for (var i = 0; i < this._data['boxs'].length; i++) {
this.storePreview(i);
};
};
this.storePreview = function(boxOrder) {
var previewCanvas = document.createElement('canvas');
previewCanvas.width = this._canvas.width;
previewCanvas.height = this._canvas.height;
var previewComicBox = new ComicBox(previewCanvas);
var that = this;
previewComicBox.init(this._data['boxs'][boxOrder],
this._data['images'], false, {canvas: previewCanvas, order: boxOrder}, function(context) {
that._data['previews'][context.order] =
context.canvas.toDataURL("image/png");
});
};
this._updatePageCounter = function() {
if (this._pageCounterDisplay != null) {
this._pageCounterDisplay.innerHTML = (this.activeBox + 1) +
' ' + _('of') + ' ' + this._data['boxs'].length;
};
if (this._prevButton != null) {
this._prevButton.disabled = (this.activeBox == 0);
};
if (this._nextButton != null) {
this._nextButton.disabled = (this.activeBox ==
(this._data['boxs'].length - 1));
};
if (this._sortButton != null) {
this._sortButton.disabled = this._data['boxs'].length < 3;
}
};
this.addGlobe = function(globeType) {
this.comicBox.addGlobe(globeType);
};
this.showPreviousBox = function() {
var prevBox = this.activeBox - 1;
this.changeBox(prevBox);
};
this.showNextBox = function() {
var nextBox = this.activeBox + 1;
this.changeBox(nextBox);
};
this.addImage = function(url) {
if (this._data['images'] == undefined) {
this._data['images'] = {};
};
this._imageCounter = this._imageCounter + 1;
var imageName = 'bAcKgRoUnD_' + this._imageCounter;
// verify if the name already exists
while (this._data['images'][imageName] != undefined) {
this._imageCounter = this._imageCounter + 1;
imageName = 'bAcKgRoUnD_' + this._imageCounter;
};
var emptyData = {'image_name': imageName, 'globes':[]};
this._data['boxs'].push(emptyData);
this._data['images'][imageName] = url;
this.changeBox(this._data['boxs'].length - 1);
};
this.getData = function() {
this.updateData();
return this._data;
};
this.attachPageCounterViewer = function(div) {
this._pageCounterDisplay = div.children[0];
this._updatePageCounter();
};
this.attachPrevNextButtons = function(prevButton, nextButton) {
this._prevButton = prevButton;
this._nextButton = nextButton;
this._updatePageCounter();
};
this.attachSortButton = function(sortButton) {
this._sortButton = sortButton;
this._updatePageCounter();
};
this.saveAsImage = function(columns) {
/* columns can be '0', '1', or '2'
if '0' means show the images in a single row */
this.showWait();
var cantBoxes = this._data['boxs'].length;
var MARGIN = 20;
if (columns == '0') {
var width = (this._canvas.width + MARGIN) * cantBoxes + MARGIN;
var height = this._canvas.height + MARGIN * 2;
} else if (columns == '1') {
var width = this._canvas.width + MARGIN * 2;
var height = (this._canvas.height + MARGIN) * cantBoxes + MARGIN;
} else if (columns == '2') {
var width = this._canvas.width * 2 + MARGIN * 3;
var height = (this._canvas.height + MARGIN) *
Math.ceil(cantBoxes / 2) + MARGIN;
};
// create the canvas where will draw all
var imageCanvas = document.createElement('canvas');
imageCanvas.width = width;
imageCanvas.height = height;
var ctx = imageCanvas.getContext("2d");
// add a white background
ctx.fillStyle="#FFFFFF";
ctx.fillRect(0, 0, width, height);
var currentbox = 0;
for (var i = 0; i < cantBoxes; i++) {
// load the bix image in a temp canvas
var that = this;
var tmpCanvas = document.createElement('canvas');
tmpCanvas.width = this._canvas.width;
tmpCanvas.height = this._canvas.height;
var tmpComicBox = new ComicBox(tmpCanvas);
tmpComicBox.init(this._data['boxs'][i],
this._data['images'], false, tmpCanvas, function(mycanvas) {
// add to the image canvas
var img = new Image();
img.src = mycanvas.toDataURL("image/png");
img.addEventListener("load", function() {
// calculate coordinates
if (columns == '0') {
var x = MARGIN + (that._canvas.width + MARGIN) * currentbox;
var y = MARGIN;
} else if (columns == '1') {
var x = MARGIN;
var y = MARGIN + (that._canvas.height + MARGIN) * currentbox;
} else if (columns == '2') {
var x = MARGIN + (currentbox % 2) * (that._canvas.width + MARGIN);
var y = MARGIN + Math.floor(currentbox / 2) * (that._canvas.height + MARGIN);
};
// draw image
ctx.drawImage(this, x, y);
if (currentbox++ >= cantBoxes-1) {
// save in datastore
var imgAsDataURL = imageCanvas.toDataURL("image/png");
var metadata = {
mimetype: "image/png",
title: "Image FotoToon",
activity: "org.olpcfrance.MediaViewerActivity",
timestamp: new Date().getTime(),
creation_time: new Date().getTime(),
file_size: 0
};
datastore.create(metadata, function(err) {
if (err) {
console.log("error saving image in journal");
humane.log(_("SavingError"));
} else {
console.log("image saved in journal.");
humane.log(_("ImageSaved"));
}
that.hideWait();
}, imgAsDataURL);
}
});
});
};
};
};
function ComicBox(canvas, model) {
/* model is only used to call the removeBox method,
the data is set in the init() method */
this.canvas = canvas;
this._model = model;
this._width = canvas.width - LINE_WIDTH * 2;
this._height = canvas.height - LINE_WIDTH * 2;
this.stage = new createjs.Stage(canvas);
// Enable touch interactions if supported on the current device
createjs.Touch.enable(this.stage);
this.globes = [];
this._globeSelected = null;
// reference to the text palette used to edit the text in the globes
this._textpalette = null;
this.init = function (data, imagesData, canRemove, context, callback) {
this._data = data;
this.imagesData = imagesData
this.canRemove = canRemove;
this.globes = [];
this.stage.removeAllChildren();
this._backContainer = new createjs.Container();
var background = new createjs.Shape();
background.graphics.setStrokeStyle(LINE_WIDTH, "round");
background.graphics.beginStroke(
BLACK).drawRect(LINE_WIDTH, LINE_WIDTH,
this._width, this._height);
this.stage.addChild(this._backContainer);
this._backContainer.addChild(background);
this._backContainer.cache(0, 0, this.canvas.width, this.canvas.height);
if (this._data != null) {
if (this._data['image_name'] != '' &&
this._data['image_name'] != undefined) {
this._image_x = this._data['img_x'];
this._image_y = this._data['img_y'];
this._image_width = this._data['img_w'];
this._image_height = this._data['img_h'];
this._image_name = this._data['image_name'];
this._slideshow_duration = this._data['slideshow_duration'];
if (this.imagesData != null) {
this._setBackgroundImageDataUrl(
this.imagesData[this._image_name], context, callback);
};
} else {
this._image_x = 0;
this._image_y = 0;
this._image_width = canvas.width;
this._image_height = canvas.height;
this._image_name = '';
this._slideshow_duration = 10;
this.createGlobes();
if (callback) callback(context);
};
};
this.stage.update();
};
this._setBackgroundImageDataUrl = function(imageUrl, context, callback) {
this._image_x = 0;
this._image_y = 0;
this._image_width = this._width;
this._image_height = this._height;
var img = new Image();
var that = this;
img.addEventListener("load", function() {
bitmap = new createjs.Bitmap(img);
bitmap.setBounds(0, 0, img.width, img.height);
// calculate scale
var scale_x = that._width / img.width;
var scale_y = that._height / img.height;
var scale = Math.min(scale_x, scale_y);
bitmap.mouseEnabled = false;
bitmap.x = LINE_WIDTH;
bitmap.y = LINE_WIDTH;
bitmap.scaleX = scale;
bitmap.scaleY = scale;
that._backContainer.addChildAt(bitmap, 0);
// add a trash button
if (that.canRemove) {
createAsyncBitmapButton(that, './icons/remove.svg',
function(comicBox, button) {
button.x = 0;
button.y = comicBox._height - button.height;
button.visible = true;
comicBox._removeButton = button;
comicBox._backContainer.addChildAt(button, 1);
comicBox._backContainer.updateCache();
button.on('click', function(event) {
comicBox.remove();
});
comicBox.createGlobes();
});
} else {
that._backContainer.updateCache();
that.createGlobes();
};
if (callback) {
callback(context);
}
});
img.src = imageUrl;
};
this.remove = function() {
console.log('remove');
this._model.removeBox();
};
this.attachTextEditionPalette = function(textpalette) {
this._textpalette = textpalette;
var box = this;
// NOTE: this not work on IE see here for more info:
// http://stackoverflow.com/questions/2823733/textarea-onchange-detection
this._textpalette.editorElem.addEventListener('input', function() {
if (box.getSelectedGlobe() != null) {
box.getSelectedGlobe().getTextViewer().setText(this.value);
};
}, false);;
var editor = this._textpalette.editorElem;
var colorButtons = this._textpalette.colorButtons;
for (var i = 0; i < colorButtons.length; i++) {
colorButtons[i].addEventListener('click', function(e) {
editor.style.color =
box.getSelectedGlobe().getTextViewer().setColor(this.value);
});
};
this._textpalette.incTextBtn.addEventListener('click', function(e) {
editor.style.fontSize =
box.getSelectedGlobe().getTextViewer().incSize() + "px";
});
this._textpalette.decTextBtn.addEventListener('click', function(e) {
editor.style.fontSize =
box.getSelectedGlobe().getTextViewer().decSize() + "px";
});
this._textpalette.boldTextBtn.addEventListener('click', function(e) {
var bold = box.getSelectedGlobe().getTextViewer().toggleBold();
if (bold) {
editor.style.fontWeight = 'bold';
} else {
editor.style.fontWeight = 'normal';
};
});
this._textpalette.italicTextBtn.addEventListener('click', function(e) {
var italic = box.getSelectedGlobe().getTextViewer().toggleItalic();
if (italic) {
editor.style.fontStyle = 'italic';
} else {
editor.style.fontStyle = 'normal';
};
});
};
this.popupTextEditionPalette = function() {
if (this._textpalette != null) {
this._textpalette.popUp();
this._textpalette.editorElem.focus();
};
};
this.getSelectedGlobe = function() {
return this._globeSelected;
};
this.isGlobeSelected = function(globe) {
return this._globeSelected == globe;
};
this.selectGlobe = function(globe) {
this._globeSelected = globe;
var textpalette = this._textpalette;
this.globes.forEach(
function (element, index, array) {
if (element != globe) {
element.setSelected(false);
} else {
if (textpalette != null) {
textpalette.setText(
element.getTextViewer().getText());
element.getTextViewer().applyTextProperties(
textpalette.editorElem);
};
};
});
};
this.addGlobe = function (globeType) {
var width = 100;
var height = 50;
globeData = {'globe_type': globeType, 'x': 100, 'y': 100,
'width': width, 'height': height,
'point_0': width / 2, 'point_1': height / 2,
'radio': 100, 'direction': DIR_DOWN,
'mode': MODE_NORMAL};
if (globeType == TYPE_WHISPER) {
globeData['globe_type'] = TYPE_GLOBE;
globeData['mode'] = MODE_WHISPER;
};
var globe = new Globe(this, globeData);
this.globes.push(globe);
this.stage.update();
};
this.getJson = function() {
jsonData = {};
jsonData['img_x'] = this._image_x;
jsonData['img_y'] = this._image_y;
jsonData['img_w'] = this._image_width;
jsonData['img_h'] = this._image_height;
jsonData['image_name'] = this._image_name;
jsonData['slideshow_duration'] = this._slideshow_duration;
jsonData['globes'] = [];
for (var n = 0; n < this.globes.length; n++) {
globe = this.globes[n];
globeData = {};
globeData['globe_type'] = globe._type;
globeData['x'] = globe._x;
globeData['y'] = globe._y;
globeData['width'] = globe._width;
globeData['height'] = globe._height;
if (globe._type != TYPE_RECTANGLE) {
globeData['point_0'] = globe._point[0];
globeData['point_1'] = globe._point[1];
};
if (globe._type == TYPE_GLOBE) {
globeData['mode'] = globe._mode;
};
globeData['radio'] = globe._radio;
globeData['direction'] = globe._direction;
globeData['title_globe'] = globe._isTitleGlobe;
// text properties
globeData['text_text'] = globe._textViewer.getText();
globeData['text_font_description'] =
globe._textViewer.getCairoFontFormat();
globeData['text_color'] =
globe._textViewer.HtmlToGdkColor(
globe._textViewer._color);
globeData['text_width'] = globe._textViewer._width;
globeData['text_height'] = globe._textViewer._height;
jsonData['globes'].push(globeData);
};
return jsonData;
};
this.createGlobes = function() {
var globes = this._data['globes'];
for (var n = 0; n < globes.length; n++) {
var globe = new Globe(this, globes[n]);
this.globes.push(globe);
};
this.stage.update();
};
};
function TextViewer(globe, globeData) {
this._globe = globe;
this._globeData = globeData;
this.init = function() {
this._text = '';
this._color = BLACK;
this._width = globe._width - 20;
this._height = SIZE_RESIZE_AREA / 2;
this._size = DEFAULT_FONT_SIZE;
this._bold = false;
this._italic = false;
if (this._globeData != null) {
/* example of the text data in the json globe data stored
{"text_font_description": "Sans 10",
"text_text": "Hmm, esto parece estar funcionando",
"text_color": [0, 0, 0],
"text_width": 78, "text_height": 22}
NOTE: color components are in the range 0-65535
https://developer.gnome.org/pygtk/stable/class-gdkcolor.html#constructor-gdkcolor
*/
if (this._globeData['text_text'] != undefined) {
this._text = this._globeData['text_text'];
};
if (this._globeData['text_font_description'] != undefined) {
this.ReadHtmlFontFormat(
this._globeData['text_font_description']);
};
if (this._globeData['text_color'] != undefined) {
this._color = this.GdkToHtmlColor(
this._globeData['text_color']);
};
if (this._globeData['text_width'] != undefined) {
this._width = this._globeData['text_width'];
};
if (this._globeData['text_height'] != undefined) {
this._height = this._globeData['text_height'];
};
this._textView = null;
};
};
this.GdkToHtmlColor = function(color) {
// int array [r, g, b] are int in the range 0-65535
// returns a str with the format "#rrggbb"
rh = (color[0] / 65535 * 255).toString(16);
gh = (color[1] / 65535 * 255).toString(16);
bh = (color[2] / 65535 * 255).toString(16);
// Number.toString() can return a single char.
if (rh.length < 2) { rh = '0' + rh};
if (gh.length < 2) { gh = '0' + gh};
if (bh.length < 2) { bh = '0' + bh};
return "#" + rh + gh + bh;
};
this.HtmlToGdkColor = function(rgb) {
// rgb is a str with the format "#rrggbb"
// return a array [r, g, b] with int in the range 0-65535
rh = rgb.substr(1, 2);
gh = rgb.substr(3, 2);
bh = rgb.substr(5, 2);
r = parseInt(rh, 16) / 255 * 65535;
g = parseInt(gh, 16) / 255 * 65535;
b = parseInt(bh, 16) / 255 * 65535;
return [r, g, b];
};
this.ReadHtmlFontFormat = function(cairoFormat) {
// get a str with format "Sans 10" or "Sans bold 10"
// return a str with format "10px Sans" or "bold 10px Sans"
var parts = cairoFormat.split(' ');
var family = parts[0];
if (parts.length == 2) {
size = parts[1];
style = '';
} else {
style = parts[1] + ' ';
size = parts[2];
};
this._size = Number(size);
this._family = family;
this._bold = style.toLowerCase().indexOf('bold') > -1;
this._italic = style.toLowerCase().indexOf('italic') > -1;
};
this.getCairoFontFormat = function() {
// return a str with format "Sans 10" or "Sans bold 10"
var cairoFormat = this._family;
if (this._bold) {
cairoFormat = cairoFormat + ' ' + 'bold';
};
if (this._italic) {
cairoFormat = cairoFormat + ' ' + 'italic';
};
return cairoFormat + ' ' + this._size;
};
this.getFontDescription = function() {
// return a str with format "10px Sans" or "bold 10px Sans"
var cairoFormat = '';
if (this._bold) {
cairoFormat = cairoFormat + ' ' + 'bold';
};
if (this._italic) {
cairoFormat = cairoFormat + ' ' + 'italic';
};
return cairoFormat + ' ' + this._size + 'px ' + this._family;
};
this.update = function() {
if (this._textView != null) {
this._globe._stage.removeChild(this._textView);
};
this._textView = new createjs.Text(this._text,
this.getFontDescription(),
this._color);
this._textView.textAlign = 'center';
this._textView.lineWidth = this._globe._width * 2;
this._textView.x = this._globe._x;
this._textView.y = this._globe._y -
this._textView.getMeasuredHeight() / 2;
this._globe._stage.addChild(this._textView);
this._globe._stage.update();
};
this.getText = function() {
return this._text;
};
this.setText = function(text) {
this._text = text;
this.update();
};
this.setColor = function(color) {
this._color = color;
this.update();
return this._color;
};
this.incSize = function() {
if (this._size < 60) {
this._size = this._size + Math.round(this._size / 4);
this.update();
};
return this._size;
};
this.decSize = function() {
if (this._size > 10) {
this._size = this._size - Math.round(this._size / 4);
this.update();
};
return this._size;
};
this.toggleBold = function() {
this._bold = ! this._bold;
this.update();
return this._bold;
};
this.toggleItalic = function() {
this._italic = ! this._italic;
this.update();
return this._italic;
};
this.applyTextProperties = function(editor) {
// apply the viewer text properties to the editor
// (used when a globe is selected)
editor.style.fontSize = this._size + 'px';
editor.style.color = this._color;
if (this._italic) {
editor.style.fontStyle = 'italic';
} else {
editor.style.fontStyle = 'normal';
};
if (this._bold) {
editor.style.fontWeight = 'bold';
} else {
editor.style.fontWeight = 'normal';
};
};
this.remove = function() {
this._globe._stage.removeChild(this._textView);
};
this.init();
return this;
};
function Globe(box, globeData) {
this._box = box;
this._stage = box.stage;
this._shapeControls = null;
this._pointerControl = null;
this._resizeButton = null;
this._editButton = null;
this._rotateButton = null;
this._removeButton = null;
this._shapeChanged = true;
this._pointerChanged = true;
this.init = function() {
if (globeData == null) {
this._type = TYPE_GLOBE;
this._x = 100;
this._y = 100;
this._width = 100;
this._height = 50;
this._point = [this._width / 2,
this._height / 2];
this._radio = 100;
this._direction = DIR_DOWN;
this._textViewer = new TextViewer(this, null);
this._mode = MODE_NORMAL;
// title_globe can't be deleted
this._isTitleGlobe = false;
} else {
/* example of the json data stored
{"direction": "abajo", "text_font_description": "Sans 10",
"globe_type": "GLOBE",
"text_text": "Hmm, esto parece estar funcionando",
"height": 36.66666666666667, "width": 130.0,
"text_color": [0, 0, 0], "radio": 30, "mode": "normal",
"text_width": 78, "y": 63.0, "x": 202.0,
"text_height": 22, "title_globe": false, "point_0": 40.5,
"point_1": 54}
*/
this._type = globeData['globe_type'];
this._x = globeData['x'];
this._y = globeData['y'];
this._width = globeData['width'];
this._height = globeData['height'];
if (this._type != TYPE_RECTANGLE) {
this._point = [globeData['point_0'],
globeData['point_1']];
} else {
this._point = [0, 0];
};
if (this._type == TYPE_GLOBE) {
this._mode = globeData['mode'];
} else {
this._mode = MODE_NORMAL;
};
this._radio = globeData['radio'];
this._direction = globeData['direction'];
this._textViewer = new TextViewer(this, globeData);
this._isTitleGlobe = globeData['title_globe'];
};
this._shape = null;
};
this.createShape = function() {
if (this._shape != null) {
this._stage.removeChild(this._shape);
if (this._type == TYPE_CLOUD) {
this._stage.removeChild(this._shapeCircles);
};
};
var scale_x = this._width /this._radio;
var scale_y = this._height /this._radio;
var scaled_x = this._x / scale_x;
var scaled_y = this._y / scale_y;
if (this._type == TYPE_CLOUD) {
this.createShapeCloud(scaled_x, scaled_y, scale_x, scale_y);
} else if (this._type == TYPE_EXCLAMATION) {
this.createShapeExclamation(scaled_x, scaled_y, scale_x, scale_y);
} else if (this._type == TYPE_RECTANGLE) {
this.createShapeRectangle();
} else {
this.createShapeGlobe(scaled_x, scaled_y, scale_x, scale_y);
};
this._shape.on('click', function(event) {
this.setSelected(true);
}, this);
this._shape.on("pressmove",function(event) {
this._x = event.stageX;
this._y = event.stageY;
this.setSelected(true);
this.update();
}, this);
};
this.getSelected = function() {
return this._box.isGlobeSelected(this);
};
this.setSelected = function(selected) {
if (selected) {
this._box.selectGlobe(this);
this._shapeControls.visible = true;
if (this._type != TYPE_RECTANGLE) {
this._pointerControl.visible = true;
this._rotateButton.visible = true;
};
this._resizeButton.visible = true;
this._editButton.visible = true;
if (!this._isTitleGlobe) {
this._removeButton.visible = true;
};
} else {
this._shapeControls.visible = false;
if (this._type != TYPE_RECTANGLE) {
this._pointerControl.visible = false;
this._rotateButton.visible = false;
};
this._resizeButton.visible = false;
this._editButton.visible = false;
if (!this._isTitleGlobe) {
this._removeButton.visible = false;
};
};
this._stage.update();
};
this.getTextViewer = function() {
return this._textViewer;
};
this.createShapeGlobe = function(x, y, scale_x, scale_y) {
switch (this._direction) {
case DIR_DOWN:
var begin = 100;
var end = 80;
break;
case DIR_RIGHT:
var begin = 10;
var end = 350;
break;
case DIR_LEFT:
var begin = 190;
var end = 170;
break;
case DIR_UP:
var begin = 280;
var end = 260;
};
this._shape = new createjs.Shape();
this._shape.name = 'globe';
this._stage.addChild(this._shape);
this._shape.graphics.setStrokeStyle(LINE_WIDTH, "round",
null, null, true);
this._shape.graphics.beginStroke(BLACK);
this._shape.graphics.beginFill(WHITE);
if (this._mode == MODE_WHISPER) {
this._shape.graphics.setStrokeDash([3]);
};
this._shape.graphics.arc(x, y, this._radio,
begin / (180.0) * Math.PI,
end / (180.0) * Math.PI)
point_pos = this.getPointPosition(true);
this._shape.graphics.lineTo(point_pos[0], point_pos[1]);
this._shape.graphics.closePath();
this._shape.graphics.endStroke();
this._shape.setTransform(0, 0, scale_x, scale_y);
};
this.createShapeRectangle = function() {
var x = this._x;
var y = this._y;
var w = this._width;
var h = this._height;
this._shape = new createjs.Shape();
this._shape.name = 'rect';
this._stage.addChild(this._shape);
this._shape.graphics.setStrokeStyle(LINE_WIDTH, "round",
null, null, true);
this._shape.graphics.beginStroke(BLACK);
this._shape.graphics.beginFill(WHITE);
this._shape.graphics.rect(x - w , y - h, w * 2, h * 2);
this._shape.graphics.endStroke();
};
this.createShapeCloud = function(x, y, scale_x, scale_y) {
this._shape = new createjs.Shape();
this._shape.name = 'cloud';
this._stage.addChild(this._shape);
this._shape.graphics.setStrokeStyle(LINE_WIDTH, "round",
null, null, true);
this._shape.graphics.beginStroke(BLACK);
this._shape.graphics.beginFill(WHITE);
var w = this._width / scale_x;
var h = this._height / scale_y;
var steps = 36;
var state = 0;
for (var i = 0; i < steps; i++) {
var alpha = 2.0 * i * (Math.PI / steps);
var sinalpha = Math.sin(alpha);
var cosalpha = Math.cos(alpha);
if (state == 0) {
var x1 = x + w * cosalpha;
var y1 = y + h * sinalpha;
} else if (state == 1) {
var x2 = x + w * cosalpha;
var y2 = y + h * sinalpha;
} else if (state == 2) {
var x3 = x + 0.8 * w * cosalpha;
var y3 = y + 0.8 * h * sinalpha;
};
if (state == 2) {
this._shape.graphics.bezierCurveTo(x1, y1, x2, y2, x3, y3);
};
state += 1;
if (state == 3) {
state = 0;
};
if (i == 0) {
this._shape.graphics.moveTo(x1, y1);
};
};
x1 = x + w * cosalpha;
y1 = y + h * sinalpha;
x2 = x + w;
y2 = y;
x3 = x + w;
y3 = y;
this._shape.graphics.bezierCurveTo(x1, y1, x2, y2, x3, y3);
this._shape.graphics.closePath();
this._shape.graphics.endStroke();
firstCirclePos = this.getCloudPointPosition();
this._shapeCircles = new createjs.Shape();
this._shapeCircles.name = 'cloud circles';
this._stage.addChild(this._shapeCircles);
this._shapeCircles.graphics.setStrokeStyle(LINE_WIDTH, "round");
this._shapeCircles.graphics.beginStroke(BLACK);
this._shapeCircles.graphics.beginFill(WHITE);
this._shapeCircles.graphics.arc(
firstCirclePos[0], firstCirclePos[1], 7,
0, 2 * Math.PI);
this._shapeCircles.graphics.endStroke();
secondCirclePos = this.getPointPosition(false);
this._shapeCircles.graphics.beginStroke(BLACK);
this._shapeCircles.graphics.beginFill(WHITE);
this._shapeCircles.graphics.arc(
secondCirclePos[0], secondCirclePos[1], 5,
0, 2 * Math.PI);
this._shapeCircles.graphics.endStroke();
this._shape.setTransform(0, 0, scale_x, scale_y);
};
this.getCloudPointPosition = function() {
var x = this._x;
var y = this._y;
var w = this._width;
var h = this._height;
switch (this._direction) {
case DIR_DOWN:
return [x + this._point[0] / 2,
y + h + this._point[1] / 2];
case DIR_RIGHT:
return [x + w + this._point[0] / 2,
y + this._point[1] / 2];
case DIR_LEFT:
return [x - w - this._point[0] / 2,
y + this._point[1] / 2];
case DIR_UP:
return [x + this._point[0] / 2,
y - h - this._point[1] / 2];
};
};
this.createShapeExclamation = function(x, y, scale_x, scale_y) {
this._shape = new createjs.Shape();
this._shape.name = 'exclamation';
this._stage.addChild(this._shape);
this._shape.graphics.setStrokeStyle(LINE_WIDTH, "round",
null, null, true);
this._shape.graphics.beginStroke(BLACK);
this._shape.graphics.beginFill(WHITE);
var w = this._width / scale_x;
var h = this._height / scale_y;
var steps = 24;
for (var i = 0; i < steps; i++) {
var alpha = 2.0 * i * (Math.PI / steps);
var sinalpha = Math.sin(alpha);
var cosalpha = Math.cos(alpha);
if (i % 2 > 0) {
xi = x + 0.8 * w * cosalpha;
yi = y + 0.8 * h * sinalpha;
} else {
xi = x + w * cosalpha;
yi = y + h * sinalpha;
};
if ((this._direction == DIR_DOWN && i == 6) ||
(this._direction == DIR_RIGHT && i == 0) ||
(this._direction == DIR_LEFT && i == 12) ||
(this._direction == DIR_UP && i == 18)) {
pos = this.getPointPosition(true);
xi = pos[0];
yi = pos[1];
};
if (i == 0) {
this._shape.graphics.moveTo(xi, yi);
} else {
this._shape.graphics.lineTo(xi, yi);
};
}
this._shape.graphics.closePath();
this._shape.graphics.endStroke();
this._shape.setTransform(0, 0, scale_x, scale_y);
};
this.createControls = function() {
var x = this._x;
var y = this._y;
var w = this._width;
var h = this._height;
if (this._shapeControls != null && this._shapeChanged) {
this._stage.removeChild(this._shapeControls);
this._shapeControls = null;
};
if (this._shapeControls == null) {
this._shapeControls = new createjs.Shape();
this._shapeControls.name = 'control_rect';
// draw dotted rectangle around the globe
this._shapeControls.graphics.setStrokeStyle(1, "round");
this._shapeControls.graphics.beginStroke(WHITE);
this._shapeControls.x = x;
this._shapeControls.y = y;
this._shapeControls.graphics.rect(- w ,- h, w * 2, h * 2);
this._shapeControls.graphics.setStrokeDash([2]);
this._shapeControls.graphics.beginFill("rgba(0, 0, 0, 0)");
this._shapeControls.graphics.beginStroke(BLACK);
this._shapeControls.graphics.rect(- w ,- h, w * 2, h * 2);
this._shapeControls.graphics.endStroke();
this._shapeControls.visible = this.getSelected();
this._stage.addChild(this._shapeControls);
} else {
this._shapeControls.visible = this.getSelected();
this._shapeControls.x = x;
this._shapeControls.y = y;
};
// point position
if (this._type != TYPE_RECTANGLE) {
if (this._pointerControl != null &&
(this._pointerChanged || this._shapeChanged)) {
this._stage.removeChild(this._pointerControl);
this._pointerControl = null;
};
if (this._pointerControl == null) {
this._pointerControl = new createjs.Shape();
this._pointerControl.x = x;
this._pointerControl.y = y;
point_pos = this.getPointPositionRelative();
this._pointerControl.graphics.beginStroke(BLACK);
this._pointerControl.graphics.arc(point_pos[0], point_pos[1],
SIZE_RESIZE_AREA / 2,
0, 2 * Math.PI);
this._pointerControl.graphics.endStroke();
var hitArea = new createjs.Shape();
hitArea.graphics.beginFill("#000").arc(
point_pos[0], point_pos[1], SIZE_RESIZE_AREA / 2,
0, 2 * Math.PI);
this._pointerControl.hitArea = hitArea;
this._pointerControl.visible = this.getSelected();
this._stage.addChild(this._pointerControl);
this._pointerControl.on("pressmove",function(event) {
this.setPointPosition(event.stageX, event.stageY);
this._box.selectGlobe(this);
this._pointerChanged = true;
this.update();
}, this);
} else {
this._pointerControl.x = x;
this._pointerControl.y = y;
this._pointerControl.visible = this.getSelected();
};
};
if (this._resizeButton == null) {
createAsyncBitmapButton(this, './icons/resize.svg',
function(globe, button) {
button.x = globe._x - globe._width - button.width / 2;
button.y = globe._y - globe._height - button.height / 2;
button.visible = globe.getSelected();
globe._resizeButton = button;
globe._stage.addChild(button);
globe._stage.update();
button.on('pressmove', function(event) {
this._width = Math.max(globe._x - event.stageX,
SIZE_RESIZE_AREA / 2);
this._height = Math.max(globe._y - event.stageY,
SIZE_RESIZE_AREA / 2);
this._shapeChanged = true;
this.update();
}, globe);
});
} else {
this._resizeButton.x = this._x - this._width - this._resizeButton.width / 2;
this._resizeButton.y = this._y - this._height - this._resizeButton.height / 2;
this._resizeButton.visible = this.getSelected();
};
if (this._editButton == null) {
createAsyncBitmapButton(this, './icons/edit.svg',
function(globe, button) {
button.x = globe._x + globe._width - button.width / 2;
button.y = globe._y - globe._height - button.height / 2;
button.visible = globe.getSelected();
globe._editButton = button;
globe._stage.addChild(button);
globe._stage.update();
button.on('click', function(event) {
globe._box.popupTextEditionPalette();
});
});
} else {
this._editButton.x = this._x + this._width - this._editButton.width / 2;
this._editButton.y = this._y - this._height - this._editButton.height / 2;
this._editButton.visible = this.getSelected();
};
if (this._type != TYPE_RECTANGLE) {
if (this._rotateButton == null) {
createAsyncBitmapButton(this, './icons/object_rotate_right.svg',
function(globe, button) {
button.x = globe._x + globe._width - button.width / 2;
button.y = globe._y + globe._height - button.height / 2;
button.visible = globe.getSelected();
globe._rotateButton = button;
globe._stage.addChild(button);
globe._stage.update();
button.on('click', function(event) {
globe.rotate();
});
});
} else {
this._rotateButton.x = this._x + this._width - this._rotateButton.width / 2;
this._rotateButton.y = this._y + this._height - this._rotateButton.height / 2;
this._rotateButton.visible = this.getSelected();
};
};
if (! this._isTitleGlobe) {
if (this._removeButton == null) {
createAsyncBitmapButton(this, './icons/remove.svg',
function(globe, button) {
button.x = globe._x - globe._width - button.width / 2;
button.y = globe._y + globe._height - button.height / 2;
button.visible = globe.getSelected();
globe._removeButton = button;
globe._stage.addChild(button);
globe._stage.update();
button.on('click', function(event) {
globe.remove();
});
});
} else {
this._removeButton.x = this._x - this._width - this._removeButton.width / 2;
this._removeButton.y = this._y + this._height - this._removeButton.height / 2;
this._removeButton.visible = this.getSelected();
};
};
this._shapeChanged = false;
this._pointerChanged = false;
};
this.rotate = function () {
switch (this._direction) {
case DIR_DOWN:
this._direction = DIR_LEFT;
break;
case DIR_RIGHT:
this._direction = DIR_DOWN;
break;
case DIR_LEFT:
this._direction = DIR_UP;
break;
case DIR_UP:
this._direction = DIR_RIGHT;
break;
};
var i = this._point[0];
this._point[0] = this._point[1]; this._point[1] = i;
this._pointerChanged = true;
this.update();
};
this.remove = function() {
var globeIndex = this._box.globes.indexOf(this);
if (globeIndex != -1) {
this._box.globes.splice(globeIndex, 1);
this._stage.removeChild(this._shape);
this._stage.removeChild(this._shapeControls);
if (this._type != TYPE_RECTANGLE) {
this._stage.removeChild(this._pointerControl);
this._stage.removeChild(this._rotateButton);
};
if (this._type == TYPE_CLOUD) {
this._stage.removeChild(this._shapeCircles);
};
this._stage.removeChild(this._resizeButton);
this._stage.removeChild(this._editButton);
this._stage.removeChild(this._removeButton);
this._textViewer.remove();
this._stage.update();
};
};
this.update = function() {
this.createShape();
this._textViewer.update();
this.createControls();
this._stage.update();
}
this.getPointPosition = function (scaled) {
var scale_x = 1;
var scale_y = 1;
if (scaled) {
scale_x = this._width / this._radio;
scale_y = this._height / this._radio;
};
var x = this._x / scale_x;
var y = this._y /scale_y;
var w = this._width / scale_x;
var h = this._height /scale_y;
switch (this._direction) {
case DIR_DOWN:
return [x + this._point[0] / scale_x,
y + h + this._point[1] / scale_y];
case DIR_RIGHT:
return [x + w + this._point[0] / scale_x,
y + this._point[1] / scale_y];
case DIR_LEFT:
return [x - w - this._point[0] / scale_x,
y + this._point[1] / scale_y];
case DIR_UP:
return [x + this._point[0] / scale_x,
y - h - this._point[1] / scale_y];
};
};
this.getPointPositionRelative = function () {
var w = this._width;
var h = this._height;
switch (this._direction) {
case DIR_DOWN:
return [this._point[0], h + this._point[1]];
case DIR_RIGHT:
return [w + this._point[0], this._point[1]];
case DIR_LEFT:
return [- w - this._point[0], this._point[1]];
case DIR_UP:
return [this._point[0], - h - this._point[1]];
};
};
this.setPointPosition = function (new_x, new_y) {
switch (this._direction) {
case DIR_DOWN:
this._point[0] = new_x - this._x;
this._point[1] = new_y - this._y - this._height;
break;
case DIR_RIGHT:
this._point[0] = new_x - this._x - this._width;
this._point[1] = new_y - this._y;
break;
case DIR_LEFT:
this._point[0] = - new_x + this._x - this._width;
this._point[1] = new_y - this._y;
break;
case DIR_UP:
this._point[0] = new_x - this._x;
this._point[1] = - new_y + this._y - this._height;
};
};
this.init();
this.update();
};
function BoxSorter(canvas, data) {
this.canvas = canvas;
this._data = data;
this._width = canvas.width - LINE_WIDTH * 2;
this._height = canvas.height - LINE_WIDTH * 2;
this._previewWidth = this._height * 4 / 3;
this._previewBitmaps = [];
this._deltaX = null;
this.stage = new createjs.Stage(canvas);
// Enable touch interactions if supported on the current device
createjs.Touch.enable(this.stage);
this.init = function () {
this.canvas.style.display = 'block';
this._backContainer = new createjs.Container();
var background = new createjs.Shape();
background.graphics.setStrokeStyle(LINE_WIDTH, "round");
background.graphics.beginStroke(
BLACK).drawRect(LINE_WIDTH, LINE_WIDTH,
this._width, this._height);
this.stage.addChild(this._backContainer);
this._backContainer.addChild(background);
this._backContainer.cache(0, 0, this.canvas.width, this.canvas.height);
this.loadPreviews();
this.stage.update();
};
this.hide = function() {
this.canvas.style.display = 'none';
};
this.loadPreviews = function () {
// create bitmaps for every box preview (if not avilable,
// use the background
for (var i = 0;i < this._data['boxs'].length; i++) {
var imageData = this._data['previews'][i];
if (imageData == undefined) {
var imageName = this._data['boxs'][i]['image_name'];
// if the preview was not loaded use the background
if (imageName != '' && imageName != undefined) {
imageData = this._data['images'][imageName];
};
};
if (imageData != undefined) {
this._createPreview(imageData, i);
};
};
};
this.getSortOrder = function() {
var newOrder = [0];
for (var i = 0; i < this._previewBitmaps.length; i++) {
newOrder.push(this._previewBitmaps[i]._order);
};
return newOrder;
};
this._createPreview = function(imageUrl, order) {
var img = new Image();
var that = this;
img.addEventListener("load", function() {
bitmap = new createjs.Bitmap(this);
bitmap.setBounds(0, 0, this.width, this.height);
bitmap._order = order;
// calculate scale
var scale_x = that._previewWidth / this.width;
var scale_y = that._height / this.height;
var scale = Math.min(scale_x, scale_y);
bitmap.x = that._previewWidth * order;
bitmap.y = LINE_WIDTH;
bitmap.scaleX = scale;
bitmap.scaleY = scale;
var hitArea = new createjs.Shape();
hitArea.graphics.beginFill("#000").drawRect(
0, 0, this.width, this.height);
bitmap.hitArea = hitArea;
// don't move first box
if (order > 0) {
that._previewBitmaps.push(bitmap);
bitmap.on('pressmove', function(event) {
console.log('TOON pressmove');
if (that._deltaX == null) {
that._deltaX = event.stageX - event.target.x;
// move the bitmap to the top
var thisBitmap = event.target;
that.stage.sortChildren(function (bitmapA, bitmapB) {
if (bitmapA == thisBitmap) {
return 1;
} else {
return 0;
};});
};
new_x = event.stageX - that._deltaX;
if (new_x > this._previewWidth / 2) {
event.target.x = new_x;
that.stage.update();
};
}, that);
bitmap.on('pressup', function(event) {
console.log('TOON pressup');
that._deltaX = null;
// sort the preview bitmaps
that._previewBitmaps.sort(function (bitmapA, bitmapB) {
return bitmapA.x - bitmapB.x;});
// adjust the positions
for (var i = 0; i < that._previewBitmaps.length; i++) {
that._previewBitmaps[i].x = that._previewWidth * (i + 1);
};
that.stage.update();
}, that);
};
that.stage.addChildAt(bitmap, 0);
that.stage.update();
});
img.src = imageUrl;
}
};
toon.Model = Model;
toon.TYPE_GLOBE = TYPE_GLOBE;
toon.TYPE_CLOUD = TYPE_CLOUD;
toon.TYPE_EXCLAMATION = TYPE_EXCLAMATION;
toon.TYPE_RECTANGLE = TYPE_RECTANGLE;
toon.TYPE_WHISPER = TYPE_WHISPER;
return toon;
});