diff --git a/engine/dist/emptyproject.html b/engine/dist/emptyproject.html
index 00d84a7a0..54eaec399 100644
--- a/engine/dist/emptyproject.html
+++ b/engine/dist/emptyproject.html
@@ -14,7 +14,7 @@
diff --git a/engine/dist/wickengine.js b/engine/dist/wickengine.js
index 9566efc2e..a8d44fa8c 100644
--- a/engine/dist/wickengine.js
+++ b/engine/dist/wickengine.js
@@ -1,5 +1,5 @@
/*Wick Engine https://github.com/Wicklets/wick-engine*/
-var WICK_ENGINE_BUILD_VERSION = "2021.1.18.12.6.20";
+var WICK_ENGINE_BUILD_VERSION = "2023.1.20.21.34.33";
/*!
* Paper.js v0.12.4 - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
@@ -45737,10 +45737,11 @@ Wick = {
version: window.WICK_ENGINE_BUILD_VERSION || "dev",
resourcepath: '../dist/',
_originals: {} // Eventually store a single instance of each type of Wick.Base object (see Wick.Base constructor).
-
};
-console.log('Wick Engine version "' + Wick.version + '" is available.'); // Ensure that the Wick namespace is accessible in environments where globals are finicky (react, webpack, etc)
+console.log('Wick Engine version "' + Wick.version + '" is available.');
+
+// Ensure that the Wick namespace is accessible in environments where globals are finicky (react, webpack, etc)
window.Wick = Wick;
/*
* Copyright 2020 WICKLETS LLC
@@ -45768,45 +45769,41 @@ Wick.Clipboard = class {
static get LOCALSTORAGE_KEY() {
return 'wick_engine_clipboard';
}
-
static get PASTE_OFFSET() {
// how many pixels should we shift objects over when we paste (canvas only)
return 20;
}
+
/**
* Create a new Clipboard object.
*/
-
-
constructor() {
this._copyLocation = null;
this._copyLayerIndex = 0;
this._originalObjects = [];
}
+
/**
* The data of copied objects, stored as JSON.
* @type {Object}
*/
-
-
get clipboardData() {
var json = localStorage[Wick.Clipboard.LOCALSTORAGE_KEY];
if (!json) return null;
return JSON.parse(json);
}
-
set clipboardData(clipboardData) {
localStorage[Wick.Clipboard.LOCALSTORAGE_KEY] = JSON.stringify(clipboardData);
}
+
/**
* Replace the current contents of the clipboard with new objects.
* @param {Wick.Base[]} objects - the objects to copy to the clipboard
*/
-
-
copyObjectsToClipboard(project, objects) {
- if (!project || !project instanceof Wick.Project) console.error('copyObjectsToClipboard(): project is required'); // Get the playhead position of the "first" frame in the list of objects
+ if (!project || !project instanceof Wick.Project) console.error('copyObjectsToClipboard(): project is required');
+ // Get the playhead position of the "first" frame in the list of objects
var playheadCopyOffset = null;
objects.filter(object => {
return object instanceof Wick.Frame;
@@ -45814,10 +45811,12 @@ Wick.Clipboard = class {
if (playheadCopyOffset === null || frame.start < playheadCopyOffset) {
playheadCopyOffset = frame.start;
}
- }); // Keep track of where objects were originally copied from
+ });
- this._copyLocation = project.activeFrame && project.activeFrame.uuid; // Keep track of the topmost layer of the selection (we use this later to position frames)
+ // Keep track of where objects were originally copied from
+ this._copyLocation = project.activeFrame && project.activeFrame.uuid;
+ // Keep track of the topmost layer of the selection (we use this later to position frames)
this._copyLayerIndex = Infinity;
objects.filter(object => {
return object instanceof Wick.Frame || object instanceof Wick.Tween;
@@ -45825,16 +45824,19 @@ Wick.Clipboard = class {
return frame.parentLayer.index;
}).forEach(i => {
this._copyLayerIndex = Math.min(this._copyLayerIndex, i);
- }); // Make deep copies of every object
+ });
+ // Make deep copies of every object
var exportedData = objects.map(object => {
return object.export();
- }); // Save references to the original objects
+ });
+ // Save references to the original objects
this._originalObjects = objects.map(object => {
return object;
- }); // Shift frames and tweens so that they copy from the relative position of the first frame
+ });
+ // Shift frames and tweens so that they copy from the relative position of the first frame
var startPlayheadPosition = Number.MAX_SAFE_INTEGER;
exportedData.forEach(data => {
if (data.object.classname === 'Frame') {
@@ -45842,7 +45844,6 @@ Wick.Clipboard = class {
startPlayheadPosition = data.object.start;
}
}
-
if (data.object.classname === 'Tween') {
if (data.object.playheadPosition < startPlayheadPosition) {
startPlayheadPosition = data.object.playheadPosition;
@@ -45854,43 +45855,40 @@ Wick.Clipboard = class {
data.object.start -= startPlayheadPosition - 1;
data.object.end -= startPlayheadPosition - 1;
}
-
if (data.object.classname === 'Tween') {
data.object.playheadPosition -= startPlayheadPosition - 1;
}
- }); // Set the new clipboard data
+ });
+ // Set the new clipboard data
this.clipboardData = exportedData;
}
+
/**
* Paste the content of the clipboard into the project.
* @param {Wick.Project} project - the project to paste objects into.
* @returns {boolean} True if there is something to paste in the clipboard, false if the clipboard is empty.
*/
-
-
pasteObjectsFromClipboard(project) {
if (!project || !project instanceof Wick.Project) console.error('pasteObjectsFromClipboard(): project is required');
-
if (!this.clipboardData) {
return false;
- } // Prevent crash when pasting into an empty space
-
+ }
+ // Prevent crash when pasting into an empty space
if (!project.activeFrame) {
project.insertBlankFrame();
- } // Always paste in-place if the original objects are no longer visible
-
+ }
+ // Always paste in-place if the original objects are no longer visible
var pasteInPlace = true;
-
this._originalObjects.forEach(origObj => {
if (origObj.parentFrame && origObj.parentFrame.onScreen) {
pasteInPlace = false;
}
- }); // Use this value later to position frames on the corrent pasted layer
-
+ });
+ // Use this value later to position frames on the corrent pasted layer
var layerIndicesMoved = project.activeLayer.index - this._copyLayerIndex;
project.selection.clear();
var objectsToSelect = [];
@@ -45902,35 +45900,33 @@ Wick.Clipboard = class {
object._originalLayerIndex += layerIndicesMoved;
object.start += project.focus.timeline.playheadPosition - 1;
object.end += project.focus.timeline.playheadPosition - 1;
- } // Paste tweens at the position of the playhead
-
+ }
+ // Paste tweens at the position of the playhead
if (object instanceof Wick.Tween) {
object._originalLayerIndex += layerIndicesMoved;
object.playheadPosition += project.focus.timeline.playheadPosition - 1;
}
-
project.addObject(object);
- object.identifier = object._getUniqueIdentifier(object.identifier); // Add offset to Paths and Clips if pasteInPlace is NOT enabled.
+ object.identifier = object._getUniqueIdentifier(object.identifier);
+ // Add offset to Paths and Clips if pasteInPlace is NOT enabled.
if (!pasteInPlace && (object instanceof Wick.Path || object instanceof Wick.Clip)) {
object.view.render(); //This render call updates the json, I think... so without this call the path loses its data somehow :(
-
object.x += Wick.Clipboard.PASTE_OFFSET;
object.y += Wick.Clipboard.PASTE_OFFSET;
- } // Wait to select objects.
-
+ }
+ // Wait to select objects.
objectsToSelect.push(object);
- }); // Select newly added objects.
+ });
+ // Select newly added objects.
if (objectsToSelect.length > 0) {
project.selection.selectMultipleObjects(objectsToSelect);
}
-
return true;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -45964,82 +45960,71 @@ Wick.Color = class {
this._color = new paper.Color();
}
}
+
/**
* The red value of the color. Ranges from 0.0 to 1.0.
* @type {Number}
*/
-
-
get r() {
return this._color.red;
}
-
set r(r) {
this._color.red = r;
}
+
/**
* The green value of the color. Ranges from 0.0 to 1.0.
* @type {Number}
*/
-
-
get g() {
return this._color.green;
}
-
set g(g) {
this._color.green = g;
}
+
/**
* The blue value of the color. Ranges from 0.0 to 1.0.
* @type {Number}
*/
-
-
get b() {
return this._color.blue;
}
-
set b(b) {
this._color.blue = b;
}
+
/**
* The alpha value of the color. Ranges from 0.0 to 1.0.
* @type {Number}
*/
-
-
get a() {
return this._color.alpha;
}
-
set a(a) {
this._color.alpha = a;
}
+
/**
* The color as a hex string. Example: "#AABBCC"
* @type {String}
*/
-
-
get hex() {
return this._color.toCSS(true);
}
+
/**
* The color as an rgba string. Example: "rgba(r,g,b,a)"
*/
-
-
get rgba() {
return this._color.toCSS();
}
+
/**
* Adds together the r, g, and b values of both colors and produces a new color.
* @param {Wick.Color} color - the color to add to this color
* @returns {Wick.Color} the resulting color
*/
-
-
add(color) {
var newColor = new Wick.Color();
newColor.r = this.r + color.r;
@@ -46047,13 +46032,12 @@ Wick.Color = class {
newColor.b = this.b + color.b;
return newColor;
}
+
/**
* Multiplies the r, g, and b values of both colors to produce a new color.
* @param {Wick.Color} color - the color to multiply with this color
* @returns {Wick.Color} the resulting color
*/
-
-
multiply(n) {
var newColor = new Wick.Color();
newColor.r = this.r * n;
@@ -46061,18 +46045,16 @@ Wick.Color = class {
newColor.b = this.b * n;
return newColor;
}
+
/**
* Averages the r, g, and b values of two colors.
* @param {Wick.Color} colorA - a color to average with another color (order does not matter)
* @param {Wick.Color} colorB - a color to average with another color (order does not matter)
* @returns {Wick.Color} The resulting averaged color.
*/
-
-
static average(colorA, colorB) {
return colorA.multiply(0.5).add(colorB.multiply(0.5));
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -46104,30 +46086,28 @@ Wick.FileCache = class {
static get FILE_LOCALFORAGE_KEY_PREFIX() {
return 'filesrc_'; // This should never change.
}
+
/**
* Add a file to the cache.
* @param {string} src - The file source
* @param {string} uuid - The UUID of the file
*/
-
-
static addFile(src, uuid) {
this._files[uuid] = {
src: src
- }; // Save asset to localforage
+ };
+ // Save asset to localforage
localforage.setItem(this.getLocalForageKeyForUUID(uuid), src).then(() => {});
}
+
/**
* Get info for a file by its UUID.
* @param {string} uuid - The UUID of the file
* @returns {object} The file info
*/
-
-
static getFile(uuid) {
var file = this._files[uuid];
-
if (!file) {
console.error('Asset with UUID ' + uuid + ' was not found in FileCache!');
return null;
@@ -46135,24 +46115,23 @@ Wick.FileCache = class {
return file;
}
}
+
/**
* Removes a file from the FileCache with a given UUID.
* @param {string} uuid - the UUID of the file to remove.
*/
-
-
static removeFile(uuid) {
- delete this._files[uuid]; // Remove file from localforage
+ delete this._files[uuid];
+ // Remove file from localforage
localforage.removeItem(this.getLocalForageKeyForUUID(uuid)).then(() => {});
}
+
/**
* Loads all files from local forage associated with a previously saved project, if possible.
* @param {Wick.Project} project - the project that we want to load assets for.
* @param {function} callback - called when the assets are done being loaded.
*/
-
-
static loadFilesFromLocalforage(project, callback) {
Promise.all(project.getAssets().map(asset => {
return localforage.getItem(this.getLocalForageKeyForUUID(asset.uuid));
@@ -46160,48 +46139,40 @@ Wick.FileCache = class {
for (var i = 0; i < assets.length; i++) {
this.addFile(assets[i], project.getAssets()[i].uuid);
}
-
callback();
});
}
+
/**
* On object containing all files in WickFileCache.
* @returns {object} All the files in an object with the format:
*/
-
-
static getAllFiles() {
var files = [];
-
for (var uuid in this._files) {
files.push({
uuid: uuid,
src: this._files[uuid].src
});
}
-
return files;
}
+
/**
* Clear the cache.
*/
-
-
static clear() {
this._files = {};
}
-
static clearLocalforage() {
// Clear all files from localforage
for (var uuid in this._files) {
localforage.removeItem(this.getLocalForageKeyForUUID(uuid)).then(() => {});
}
}
-
static getLocalForageKeyForUUID(uuid) {
return this.FILE_LOCALFORAGE_KEY_PREFIX + uuid;
}
-
};
Wick.FileCache._files = {};
/*
@@ -46234,11 +46205,10 @@ Wick.History = class {
static get VERBOSE() {
return false;
}
+
/**
* An Enum of all types of state saves.
*/
-
-
static get StateType() {
return {
ALL_OBJECTS: 1,
@@ -46246,57 +46216,48 @@ Wick.History = class {
ONLY_VISIBLE_OBJECTS: 3
};
}
+
/**
* Creates a new history object
*/
-
-
constructor() {
this.reset();
this.lastHistoryPush = Date.now();
}
+
/**
* Resets history in the editor. This is non-reversible.
*/
-
-
reset() {
this._undoStack = [];
this._redoStack = [];
this._snapshots = {};
}
+
/**
* Returns all objects that are currently referenced by the history.
* @returns {Set} uuids of all objects currently referenced in the history.
*/
-
-
getObjectUUIDs() {
let objects = new Set();
-
for (let state of this._undoStack) {
objects = new Set([...objects, ...state.objects]);
}
-
for (let state of this._redoStack) {
objects = new Set([...objects, ...state.objects]);
}
-
return objects;
}
+
/**
* Push the current state of the ObjectCache to the undo stack.
* @param {number} filter - the filter to choose which objects to serialize. See Wick.History.StateType
* @param {string} actionName - Optional: Name of the action conducted to generate this state. If no name is presented, "Unknown Action" is presented in its place.
*/
-
-
pushState(filter, actionName) {
this._redoStack = [];
let now = Date.now();
-
let state = this._generateState(filter);
-
let objects = new Set(state.map(obj => obj.uuid));
let stateObject = {
state: this._generateState(filter),
@@ -46305,103 +46266,84 @@ Wick.History = class {
timeSinceLastPush: now - this.lastHistoryPush
};
this.lastHistoryPush = now;
-
this._undoStack.push(stateObject);
-
this._undoStack = this._undoStack.slice(-64); // get the last 64 items in the undo stack
}
+
/**
* Pop the last state in the undo stack off and apply the new last state to the project.
* @returns {boolean} True if the undo stack is non-empty, false otherwise
*/
-
-
popState() {
if (this._undoStack.length <= 1) {
return false;
}
-
var lastState = this._undoStack.pop();
-
this._redoStack.push(lastState);
+ var currentStateObject = this._undoStack[this._undoStack.length - 1];
- var currentStateObject = this._undoStack[this._undoStack.length - 1]; // 1.17.1 History update, pull actual state information out, aside from names.
-
+ // 1.17.1 History update, pull actual state information out, aside from names.
var currentState = currentStateObject;
-
if (currentStateObject.state) {
currentState = currentStateObject.state;
}
-
this._recoverState(currentState);
-
return true;
}
+
/**
* Recover a state that was undone.
* @returns {boolean} True if the redo stack is non-empty, false otherwise
*/
-
-
recoverState() {
if (this._redoStack.length === 0) {
return false;
}
-
var recoveredState = this._redoStack.pop().state;
-
this._undoStack.push(recoveredState);
-
this._recoverState(recoveredState);
-
return true;
}
+
/**
*
* @param {string} name - the name of the snapshot
* @param {number} filter - the filter to choose which objects to serialize. See Wick.History.StateType
*/
-
-
saveSnapshot(name, filter) {
this._snapshots[name] = this._generateState(filter || Wick.History.StateType.ALL_OBJECTS_WITHOUT_PATHS);
}
+
/**
* Save a state to the list of snapshots to be recovered at any time.
* @param {string} name - the name of the snapshot to recover
*/
-
-
loadSnapshot(name) {
this._recoverState(this._snapshots[name]);
}
+
/**
* The number of states currently stored for undoing.
* @type {number}
*/
-
-
get numUndoStates() {
return this._undoStack.length;
}
+
/**
* The number of states currently stored for redoing.
* @type {number}
*/
-
-
get numRedoStates() {
return this._redoStack.length;
- } // NOTE: State saving/recovery can be greatly optimized by only saving the state of the things that were actually changed.
-
+ }
+ // NOTE: State saving/recovery can be greatly optimized by only saving the state of the things that were actually changed.
_generateState(stateType) {
var objects = [];
-
if (stateType === undefined) {
stateType = Wick.History.StateType.ALL_OBJECTS;
}
-
if (stateType === Wick.History.StateType.ALL_OBJECTS) {
objects = this._getAllObjects();
} else if (stateType === Wick.History.StateType.ALL_OBJECTS_WITHOUT_PATHS) {
@@ -46412,61 +46354,64 @@ Wick.History = class {
console.error('Wick.History._generateState: A valid stateType is required.');
return;
}
-
if (Wick.History.VERBOSE) {
console.log('Wick.History._generateState: Serializing ' + objects.length + ' objects using mode=' + stateType);
}
-
return objects.map(object => {
// The object most likely was altered in some way, make sure those changes will be reflected in the autosave.
object.needsAutosave = true;
return object.serialize();
});
}
-
_recoverState(state) {
state.forEach(objectData => {
var object = Wick.ObjectCache.getObjectByUUID(objectData.uuid);
object.deserialize(objectData);
});
}
-
_getAllObjects() {
var objects = Wick.ObjectCache.getActiveObjects(this.project);
objects.push(this.project);
return objects;
- } // this is used for an optimization when snapshots are saved for preview playing.
-
+ }
+ // this is used for an optimization when snapshots are saved for preview playing.
_getAllObjectsWithoutPaths() {
return this._getAllObjects().filter(object => {
return !(object instanceof Wick.Path);
});
}
-
_getVisibleObjects() {
- var stateObjects = []; // the project itself (for focus, options, etc)
+ var stateObjects = [];
- stateObjects.push(this.project); // the assets in the project
+ // the project itself (for focus, options, etc)
+ stateObjects.push(this.project);
+ // the assets in the project
this.project.getAssets().forEach(asset => {
stateObjects.push(asset);
- }); // the focused clip
+ });
- stateObjects.push(this.project.focus); // the focused timeline
+ // the focused clip
+ stateObjects.push(this.project.focus);
- stateObjects.push(this.project.focus.timeline); // the selection
+ // the focused timeline
+ stateObjects.push(this.project.focus.timeline);
- stateObjects.push(this.project.selection); // layers on focused timeline
+ // the selection
+ stateObjects.push(this.project.selection);
+ // layers on focused timeline
this.project.activeTimeline.layers.forEach(layer => {
stateObjects.push(layer);
- }); // frames on focused timeline
+ });
+ // frames on focused timeline
this.project.activeTimeline.frames.forEach(frame => {
stateObjects.push(frame);
- }); // objects+tweens on active frames
+ });
+ // objects+tweens on active frames
this.project.activeFrames.forEach(frame => {
frame.paths.forEach(path => {
stateObjects.push(path);
@@ -46480,7 +46425,6 @@ Wick.History = class {
});
return stateObjects;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -46500,6 +46444,7 @@ Wick.History = class {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
// NOTE:
// This should probably not be global, and instead, each Wick.Project should own an ObjectCache.
// It's too hard to test if there's a shared ObjectCache between many projects.
@@ -46515,24 +46460,23 @@ WickObjectCache = class {
this._objects = {};
this._objectsNeedAutosave = {};
}
+
/**
* Add an object to the cache.
* @param {Wick.Base} object - the object to add
*/
-
-
addObject(object) {
this._objects[object.uuid] = object;
+
/*object.children.forEach(child => {
this.addObject(child);
});*/
}
+
/**
* Remove an object from the cache.
* @param {Wick.Base} object - the object to remove from the cache
*/
-
-
removeObject(object) {
if (object.classname === 'Project') {
object.destroy();
@@ -46541,37 +46485,32 @@ WickObjectCache = class {
delete this._objects[object.uuid];
}
+
/**
* Remove an object from the cache.
* @param {string} uuid - uuid of the object to remove from the cache
*/
-
-
removeObjectByUUID(uuid) {
delete this._objects[uuid];
}
+
/**
* Remove all objects from the Object Cache.
*/
-
-
clear() {
this._objects = {};
this._objectsNeedAutosave = {};
}
+
/**
* Get an object by its UUID.
* @returns {Wick.Base}
*/
-
-
getObjectByUUID(uuid) {
if (!uuid) {
console.error('ObjectCache: getObjectByUUID: uuid is required.');
}
-
var object = this._objects[uuid];
-
if (!object) {
console.error("Warning: object with uuid " + uuid + " was not found in the cache.");
return null;
@@ -46579,29 +46518,25 @@ WickObjectCache = class {
return object;
}
}
+
/**
* All objects in the cache.
* @returns {Wick.Base[]}
*/
-
-
getAllObjects() {
var allObjects = [];
-
for (var uuid in this._objects) {
allObjects.push(this._objects[uuid]);
}
-
return allObjects;
}
+
/**
* Remove all objects that are in the project, but are no longer linked to the root object.
* This is basically a garbage collection function. This function attempts to keep objects
* that are referenced in undo/redo.
* @param {Wick.Project} project - the project to use to determine which objects have no references
*/
-
-
removeUnusedObjects(project) {
var activeObjects = this.getActiveObjects(project);
let uuids = activeObjects.map(obj => obj.uuid);
@@ -46616,11 +46551,10 @@ WickObjectCache = class {
}
});
}
+
/**
* Removes all objects with the temporary flag set to true.
*/
-
-
removeTemporaryObjects() {
this.getAllObjects().forEach(obj => {
if (obj.temporary) {
@@ -46628,56 +46562,50 @@ WickObjectCache = class {
}
});
}
+
/**
* Get all objects that are referenced in the given project.
* @param {Wick.Project} project - the project to check if children are active in.
* @returns {Wick.Base[]} the active objects.
*/
-
-
getActiveObjects(project) {
// This does the same thing, but it's WAY faster.
return project.getChildrenRecursive().map(object => {
return this.getObjectByUUID(object.uuid);
});
}
+
/**
* Saves an object to be autosaved upon the next auto save.
* @param {Wick.Base} object object to be saved.
*/
-
-
markObjectToBeAutosaved(object) {
this._objectsNeedAutosave[object.uuid] = true;
}
+
/**
* Removes a given object from the list of objects that must be autosaved.
* @param {Wick.Base} object - the object to remove from the list of objects to be autosaved.
*/
-
-
clearObjectToBeAutosaved(object) {
delete this._objectsNeedAutosave[object.uuid];
}
+
/**
* Returns true if a given object is marked to be autosaved during the next autosave.
* @param {Wick.Base} object - the object to check for autosave
*/
-
-
objectNeedsAutosave(object) {
return Wick.ObjectCache._objectsNeedAutosave[object.uuid];
}
+
/**
* Returns an array of objects that currently need to be autosaved.
* @returns {Wick.Base[]} The objects that are marked to be autosaved.
*/
-
-
getObjectsNeedAutosaved() {
return Object.keys(this._objectsNeedAutosave).map(uuid => this.getObjectByUUID(uuid));
}
-
};
Wick.ObjectCache = new WickObjectCache();
/*
@@ -46719,11 +46647,10 @@ Wick.Transformation = class {
this.rotation = args.rotation === undefined ? 0 : args.rotation;
this.opacity = args.opacity === undefined ? 1 : args.opacity;
}
+
/**
* An object containing the values of this transformation.
*/
-
-
get values() {
return {
x: this.x,
@@ -46734,16 +46661,14 @@ Wick.Transformation = class {
opacity: this.opacity
};
}
+
/**
* Creates a copy of this transformation.
* @returns {Wick.Transformation} the copied transformation.
*/
-
-
copy() {
return new Wick.Transformation(this.values);
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -46763,6 +46688,7 @@ Wick.Transformation = class {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.ToolSettings = class {
static get DEFAULT_SETTINGS() {
return [{
@@ -46856,41 +46782,37 @@ Wick.ToolSettings = class {
options: ['none', 'behind', 'inside']
}];
}
+
/**
* Create a new ToolSettings object.
*/
-
-
constructor() {
this._settings = {};
-
this._onSettingsChangedCallback = () => {};
-
this.resetAllSettings();
this.loadSettingsFromLocalstorage();
}
+
/**
* Returns the appropriate key to use to store a tool setting by name.
* @param {String} settingName name of tool setting.
* @returns {String} Key to be used.
*/
-
-
getStorageKey(settingName) {
return "WICK.TOOLSETTINGS." + settingName;
}
+
/**
* Creates the tool settings at the start of the editor. Will open with previously used settings if they exist.
*/
-
-
createSetting(args) {
if (!args) console.error('createSetting: args is required');
if (!args.name) console.error('createSetting: args.name is required');
if (args.default === undefined) console.error('createSetting: args.default is required');
let name = args.name;
- let type = args.type; // Create a default setting to start.
+ let type = args.type;
+ // Create a default setting to start.
this._settings[args.name] = {
type: args.type,
name: args.name,
@@ -46902,68 +46824,57 @@ Wick.ToolSettings = class {
options: args.options
};
}
+
/**
* Update a value in the settings.
* @param {string} name - The name of the setting to update.
* @param {string|number|Color} value - The value of the setting to change to.
*/
-
-
setSetting(name, value) {
var setting = this._settings[name];
- if (!setting) return; // Check to make sure there's no type mismatch
+ if (!setting) return;
+ // Check to make sure there's no type mismatch
if (typeof value !== typeof setting.value) {
console.warn('Warning: Wick.ToolSettings: Type mismatch while setting ' + name);
console.warn(value);
return;
}
-
var min = setting.min;
-
if (min !== undefined) {
value = Math.max(min, value);
}
-
var max = setting.max;
-
if (max !== undefined) {
value = Math.min(max, value);
}
-
setting.value = value;
-
this._fireOnSettingsChanged(name, value);
-
if (setting.type === 'color') {
localforage.setItem(this.getStorageKey(name), value.rgba);
} else {
localforage.setItem(this.getStorageKey(name), value);
}
}
+
/**
* Retrieve a value in the settings.
* @param {string} name - The name of the setting to retrieve.
*/
-
-
getSetting(name) {
var setting = this._settings[name];
-
if (!setting) {
console.error("ToolSettings.getSetting: invalid setting: " + name);
return;
}
-
return setting.value;
}
+
/**
* Returns an object with the setting restrictions for a provided setting.
* @param {String} name name of tool setting
* @returns {Object} an object containing the values min, max, step and options where appropriate.
*/
-
-
getSettingRestrictions(name) {
var setting = this._settings[name];
if (!setting) console.error("ToolSettings.getSettingRestrictions: invalid setting: " + name);
@@ -46974,44 +46885,38 @@ Wick.ToolSettings = class {
options: setting.options
};
}
+
/**
* Returns an array containing all settings with all information.
* @returns {Object[]} Array of settings objects.
*/
-
-
getAllSettings() {
var allSettings = [];
-
for (var name in this._settings) {
allSettings.push(this._settings[name]);
}
-
return allSettings;
}
+
/**
* Receives a call back that will be provided the name and value of the setting that was changed.
*/
-
-
onSettingsChanged(callback) {
this._onSettingsChangedCallback = callback;
}
+
/**
* Reset settings to the deafults.
*/
-
-
resetAllSettings() {
Wick.ToolSettings.DEFAULT_SETTINGS.forEach(setting => {
this.createSetting(setting);
});
}
+
/**
* Load settings from localstorage if they exist.
*/
-
-
loadSettingsFromLocalstorage() {
Wick.ToolSettings.DEFAULT_SETTINGS.forEach(setting => {
// Get stored tool setting if it exists.
@@ -47031,11 +46936,9 @@ Wick.ToolSettings = class {
});
});
}
-
_fireOnSettingsChanged(name, value) {
this._onSettingsChangedCallback(name, value);
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -47055,40 +46958,38 @@ Wick.ToolSettings = class {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
GlobalAPI = class {
/**
* Defines all api members such as functions and properties.
* @type {string[]}
*/
static get apiMemberNames() {
- return ['stop', 'play', 'gotoAndStop', 'gotoAndPlay', 'gotoNextFrame', 'gotoPrevFrame', // These are currently disabled, they are very slow for some reason.
+ return ['stop', 'play', 'gotoAndStop', 'gotoAndPlay', 'gotoNextFrame', 'gotoPrevFrame',
+ // These are currently disabled, they are very slow for some reason.
// They are currently hacked in inside Tickable._runFunction
//'project','root','parent','parentObject',
'isMouseDown', 'mouseX', 'mouseY', 'mouseMoveX', 'mouseMoveY', 'key', 'keys', 'isKeyDown', 'keyIsDown', 'isKeyJustPressed', 'keyIsJustPressed', 'random', 'playSound', 'stopAllSounds', 'onEvent', 'hideCursor', 'showCursor', 'hitTestOptions'];
}
+
/**
* @param {object} scriptOwner The tickable object which owns the script being evaluated.
*/
-
-
constructor(scriptOwner) {
this.scriptOwner = scriptOwner;
}
+
/**
* Returns a list of api members bound to the script owner.
* @returns {object[]} Array of functions, properties, and api members.
*/
-
-
get apiMembers() {
var members = [];
GlobalAPI.apiMemberNames.forEach(name => {
var fn = this[name];
-
if (fn instanceof Function) {
fn = fn.bind(this);
}
-
members.push({
name: name,
fn: fn
@@ -47096,69 +46997,60 @@ GlobalAPI = class {
});
return members;
}
+
/**
* Stops the timeline of the object's parent clip.
*/
-
-
stop() {
this.scriptOwner.parentClip.stop();
}
+
/**
* Plays the timeline of the object's parent clip.
*/
-
-
play() {
this.scriptOwner.parentClip.play();
}
+
/**
* Moves the plahead of the parent clip to a frame and stops the timeline of that parent clip.
* @param {string | number} frame Frame name or number to move playhead to.
*/
-
-
gotoAndStop(frame) {
this.scriptOwner.parentClip.gotoAndStop(frame);
}
+
/**
* Moves the plahead of the parent clip to a frame and plays the timeline of that parent clip.
* @param {string | number} frame Frame name or number to move playhead to.
*/
-
-
gotoAndPlay(frame) {
this.scriptOwner.parentClip.gotoAndPlay(frame);
}
+
/**
* Moves the playhead of the parent clip of the object to the next frame.
*/
-
-
gotoNextFrame() {
this.scriptOwner.parentClip.gotoNextFrame();
}
+
/**
* Moves the playhead of the parent clip of this object to the previous frame.
*/
-
-
gotoPrevFrame() {
this.scriptOwner.parentClip.gotoPrevFrame();
}
-
hitTestOptions(options) {
this.scriptOwner.project.hitTestOptions = options;
}
+
/**
* Returns an object representing the project with properties such as width, height, framerate, background color, and name.
* @returns {object} Project object.
*/
-
-
get project() {
var project = this.scriptOwner.project && this.scriptOwner.project.root;
-
if (project) {
// Attach some aliases to the project settings
project.width = this.scriptOwner.project.width;
@@ -47168,219 +47060,197 @@ GlobalAPI = class {
project.name = this.scriptOwner.project.name;
project.hitTestOptions = this.scriptOwner.project.hitTestOptions;
}
-
return project;
}
+
/**
* @deprecated
* Legacy item which returns the project. Use 'project' instead.
*/
-
-
get root() {
return this.project;
}
+
/**
* Returns a reference to the current object's parent.
* @returns Current object's parent.
*/
-
-
get parent() {
return this.scriptOwner.parentClip;
}
+
/**
* @deprecated
* Legacy item which returns the parent clip. Use 'parent' instead.
*/
-
-
get parentObject() {
return this.scriptOwner.parentClip;
}
+
/**
* Returns the last key pressed down.
* @returns {string | null} Returns null if no key has been pressed yet.
*/
-
-
get key() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.currentKey;
}
+
/**
* Returns a list of all keys currently pressed down.
* @returns {string[]} All keys represented as strings. If no keys are pressed, an empty array is returned.
*/
-
-
get keys() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.keysDown;
}
+
/**
* Returns true if the given key is currently down.
* @param {string} key
* @returns {bool}
*/
-
-
isKeyDown(key) {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.isKeyDown(key);
}
+
/**
* @deprecated
* Legacy item, use 'isKeyDown' instead.
*/
-
-
keyIsDown(key) {
return this.isKeyDown(key.toLowerCase());
}
+
/**
* Returns true if the given key was just pressed within the last tick.
* @param {string} key
* @returns {bool}
*/
-
-
isKeyJustPressed(key) {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.isKeyJustPressed(key);
}
+
/**
* @deprecated
* Legacy item, use 'isKeyJustPressed' instead.
*/
-
-
keyIsJustPressed(key) {
return this.keyIsJustPressed(key.toLowerCase());
}
+
/**
* Returns true if the mouse is currently held down.
* @returns {bool | null} Returns null if the object does not have a project.
*/
-
-
isMouseDown() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.isMouseDown;
}
+
/**
* Returns the current x position of the mouse in relation to the canvas.
* @returns {number}
*/
-
-
get mouseX() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.mousePosition.x;
}
+
/**
* Returns the current y position of the mouse in relation to the canvas.
* @returns {number}
*/
-
-
get mouseY() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.mousePosition.y;
}
+
/**
* Returns the amount the mouse moved in the last tick on the x axis.
* @returns {number}
*/
-
-
get mouseMoveX() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.mouseMove.x;
}
+
/**
* Returns the amount the mouse moved in the last tick on the y axis.
* @returns {number}
*/
-
-
get mouseMoveY() {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.mouseMove.y;
}
+
/**
* Returns a new random object.
* @returns {GlobalAPI.Random}
*/
-
-
get random() {
return new GlobalAPI.Random();
}
+
/**
* Plays a sound which is currently in the asset library.
* @param {string} name - name of the sound asset in the library.
* @param {Object} options - options for the sound. See Wick.SoundAsset.play
* @returns {object} object representing the sound which was played.
*/
-
-
playSound(assetName, options) {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.playSound(assetName, options);
}
+
/**
* Stops sound(s) currently playing.
* @param {string} assetName - The name of the SoundAsset to stop.
* @param {number} id - (optional) The ID of the sound to stop. Returned by playSound. If an ID is not given, all instances of the given sound asset will be stopped.
*/
-
-
stopSound(assetName, id) {
if (!this.scriptOwner.project) return null;
return this.scriptOwner.project.stopSound(assetName, id);
}
+
/**
* Stops all currently playing sounds.
*/
-
-
stopAllSounds() {
if (!this.scriptOwner.project) return null;
this.scriptOwner.project.stopAllSounds();
}
+
/**
* Attach a function to an event with a given name.
* @param {string} name - the name of the event to attach the function to
* @param {function} fn - the function to attach to the event
*/
-
-
onEvent(name, fn) {
this.scriptOwner.onEvent(name, fn);
}
+
/**
* Hide the cursor while the project is running.
*/
-
-
hideCursor() {
if (!this.scriptOwner.project) return null;
this.scriptOwner.project.hideCursor = true;
}
+
/**
* Don't hide the cursor while the project is running.
*/
-
-
showCursor() {
if (!this.scriptOwner.project) return null;
this.scriptOwner.project.hideCursor = false;
}
-
};
GlobalAPI.Random = class {
constructor() {}
+
/**
* Returns a random integer (whole number) between two given numbers, 0 and a given number, or 0 and 1. The random number is inclusive of the maximum range.
* @param {number} min The minimum of the returned integer, or the maximum of the returned number if it is the only argument.
@@ -47388,8 +47258,6 @@ GlobalAPI.Random = class {
* @returns {number} A random number between num1 and num2, 0 and num1, or 0 and 1. Will return 0 if max is greater than min.
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
*/
-
-
integer(min, max) {
if (typeof min === 'undefined' && typeof max === 'undefined') {
min = 0;
@@ -47398,11 +47266,12 @@ GlobalAPI.Random = class {
max = Math.ceil(min);
min = 0;
}
+ if (max < min) return 0;
- if (max < min) return 0; // The maximum is inclusive and the minimum is inclusive
-
+ // The maximum is inclusive and the minimum is inclusive
return Math.floor(Math.random() * (max - min + 1) + min);
}
+
/**
* Returns a random floating point (decimal) number between two given numbers, 0 and a given number, or 0 and 1.
* @param {number} num1 The minimum of the returned number, or the maximum of the returned number if it is the only argument.
@@ -47410,8 +47279,6 @@ GlobalAPI.Random = class {
* @returns {number} A random number between num1 and num2, 0 and num1, or 0 and 1.
* https://stackoverflow.com/questions/4959975/generate-random-number-between-two-numbers-in-javascript
*/
-
-
float(num1, num2) {
if (typeof num1 !== "undefined" && typeof num2 !== "undefined") {
return Math.random() * (num2 - num1) + num1;
@@ -47421,19 +47288,17 @@ GlobalAPI.Random = class {
return Math.random();
}
}
+
/**
* Returns a random item from an array of items.
* @param {array} An array of objects.
* @returns {object | null} A random item contained in the array. Returns null if the given array has no items.
* https://stackoverflow.com/questions/4550505/getting-a-random-value-from-a-javascript-array
*/
-
-
choice(array) {
if (array.length <= 0) return null;
return array[Math.floor(Math.random() * array.length)];
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -47464,22 +47329,26 @@ BuiltinAssets = class {
width: 720,
height: 480
};
- var defaultCrosshairSize = 75; // Vcam outline (hidden when project plays)
+ var defaultCrosshairSize = 75;
- var vcamBorderPaths = [// Cam border
+ // Vcam outline (hidden when project plays)
+ var vcamBorderPaths = [
+ // Cam border
new paper.Path.Rectangle({
from: new paper.Point(-defaultVcamWH.width / 2, -defaultVcamWH.height / 2),
to: new paper.Point(defaultVcamWH.width / 2, defaultVcamWH.height / 2),
strokeWidth: 1,
strokeColor: '#000',
fillColor: 'rgba(74,144,226,0.19)'
- }), // Cam center crosshair (vertical line)
+ }),
+ // Cam center crosshair (vertical line)
new paper.Path.Line({
from: new paper.Point(0, -defaultCrosshairSize / 2),
to: new paper.Point(0, defaultCrosshairSize / 2),
strokeWidth: 1,
strokeColor: '#000'
- }), // Cam center crosshair (horizontal line)
+ }),
+ // Cam center crosshair (horizontal line)
new paper.Path.Line({
from: new paper.Point(-defaultCrosshairSize / 2, 0),
to: new paper.Point(defaultCrosshairSize / 2, 0),
@@ -47490,31 +47359,36 @@ BuiltinAssets = class {
vcam.activeFrame.addPath(new Wick.Path({
path: vcamPath
}));
- }); // Vcam black borders (only visible when project is playing and showBlackBorders is set to true)
+ });
+ // Vcam black borders (only visible when project is playing and showBlackBorders is set to true)
var borderSize = 10000;
- var blackBorderPaths = [// Black border top
+ var blackBorderPaths = [
+ // Black border top
new paper.Path.Rectangle({
from: new paper.Point(-borderSize, -borderSize),
to: new paper.Point(borderSize, -defaultVcamWH.height / 2),
strokeWidth: 1,
strokeColor: '#000',
fillColor: '#000'
- }), // Black border bottom
+ }),
+ // Black border bottom
new paper.Path.Rectangle({
from: new paper.Point(-borderSize, defaultVcamWH.height / 2),
to: new paper.Point(borderSize, borderSize),
strokeWidth: 1,
strokeColor: '#000',
fillColor: '#000'
- }), // Black border left
+ }),
+ // Black border left
new paper.Path.Rectangle({
from: new paper.Point(-borderSize, -borderSize),
to: new paper.Point(-defaultVcamWH.width / 2, borderSize),
strokeWidth: 1,
strokeColor: '#000',
fillColor: '#000'
- }), // Black border right
+ }),
+ // Black border right
new paper.Path.Rectangle({
from: new paper.Point(defaultVcamWH.width / 2, -borderSize),
to: new paper.Point(borderSize, borderSize),
@@ -47529,12 +47403,14 @@ BuiltinAssets = class {
vcam.activeLayer.getFrameAtPlayheadPosition(2).addPath(new Wick.Path({
path: vcamPath
}));
- }); // Blank frame
+ });
+ // Blank frame
vcam.activeLayer.addFrame(new Wick.Frame({
start: 3
- })); // Build script
+ }));
+ // Build script
var vcamScript = "";
vcamScript += "// Wick VCam Beta v0.02\n";
vcamScript += "\n";
@@ -47568,7 +47444,6 @@ BuiltinAssets = class {
vcam.removeScript('default');
return vcam;
}
-
};
Wick.BuiltinAssets = new BuiltinAssets();
/*
@@ -47589,30 +47464,34 @@ Wick.BuiltinAssets = new BuiltinAssets();
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.ExportUtils = class {
// https://stackoverflow.com/questions/12168909/blob-from-dataurl
static dataURItoBlob(dataURI) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
- var byteString = atob(dataURI.split(',')[1]); // separate out the mime component
+ var byteString = atob(dataURI.split(',')[1]);
- var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to an ArrayBuffer
+ // separate out the mime component
+ var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
- var ab = new ArrayBuffer(byteString.length); // create a view into the buffer
+ // write the bytes of the string to an ArrayBuffer
+ var ab = new ArrayBuffer(byteString.length);
- var ia = new Uint8Array(ab); // set the bytes of the buffer to the correct values
+ // create a view into the buffer
+ var ia = new Uint8Array(ab);
+ // set the bytes of the buffer to the correct values
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
- } // write the ArrayBuffer to a blob, and you're done
-
+ }
+ // write the ArrayBuffer to a blob, and you're done
var blob = new Blob([ab], {
type: mimeString
});
return blob;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -47632,6 +47511,7 @@ Wick.ExportUtils = class {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.AudioTrack = class {
/**
* @type {Wick.Project}
@@ -47639,46 +47519,40 @@ Wick.AudioTrack = class {
get project() {
return this._project;
}
-
set project(project) {
this._project = project;
}
+
/**
* Create a new AudioTrack
* @param {Wick.Project} project - the project to use audio from
*/
-
-
constructor(project) {
this._project = project;
}
+
/**
* Generate an AudioBuffer of all the project's sounds as one audio track.
* Can take sound information from a generated sequence.
* @param {Object} args - callback, onProgress, soundInfo
*/
-
-
toAudioBuffer(args) {
if (!args) args = {};
if (!args.callback) args.callback = () => {};
if (!args.onProgress) args.onProgress = (frame, maxFrames) => {};
-
let genBuffer = audioInfo => {
if (!audioInfo) args.callback(null);
-
if (audioInfo.length === 0) {
// No audio in the project, no AudioBuffer to create
args.callback(null);
return;
}
-
Wick.AudioTrack.generateProjectAudioBuffer(audioInfo, audioArraybuffer => {
args.callback(audioArraybuffer);
}, args.onProgress);
- }; // If audio information is passed in from a previous render, use that. Otherwise, render it again.
-
+ };
+ // If audio information is passed in from a previous render, use that. Otherwise, render it again.
if (args.soundInfo) {
genBuffer(args.soundInfo);
} else {
@@ -47688,19 +47562,17 @@ Wick.AudioTrack = class {
});
}
}
+
/**
* Create an AudioBuffer from given sounds.
* @param {object[]} projectAudioInfo - infor generated on sounds played in the project.
* @param {Function} callback - callback to recieve the generated AudioBuffer
* @param {Function} onProgress(message, progress) - A function which receive a message.
*/
-
-
static generateProjectAudioBuffer(projectAudioInfo, callback, onProgress) {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var ctx = new AudioContext();
let audiobuffers = [];
-
let mergeAudio = () => {
onProgress && onProgress("Merging Audio");
audiobuffers.sort((a, b) => {
@@ -47714,12 +47586,10 @@ Wick.AudioTrack = class {
});
callback(mergedAudioBuffer);
};
-
for (let i = 0; i < projectAudioInfo.length; i++) {
let audioInfo = projectAudioInfo[i];
this.base64ToAudioBuffer(audioInfo.src, ctx, audiobuffer => {
let offset = audioInfo.offset || 0; // Milliseconds to offset.
-
let offsetSeconds = offset / 1000; // Adjust to seconds.
let startSeconds = audioInfo.start / 1000;
@@ -47732,67 +47602,64 @@ Wick.AudioTrack = class {
let delayedAudiobuffer = this.addStartDelayToAudioBuffer(volumeAdjustedAudioBuffer, startSeconds, ctx);
onProgress && onProgress("Creating Audio " + (i + 1) + "/" + projectAudioInfo.length, (i + 1) / projectAudioInfo.length);
audiobuffers.push(delayedAudiobuffer);
-
if (audiobuffers.length >= projectAudioInfo.length) {
mergeAudio();
}
});
}
}
+
/*
* Merges multiple audiobuffers into a single audiobuffer.
* @param {AudioBuffer[]} buffers - the AudioBuffers to merge together
* @param {AudioContext} ac - An AudioContext instance
*/
-
-
static mergeBuffers(buffers, ac, onProgress) {
// original function from:
// https://github.com/meandavejustice/merge-audio-buffers/blob/master/index.js
+
var maxChannels = 0;
- var maxDuration = 0; // Send back an empty buffer if no information was sent in.
+ var maxDuration = 0;
+ // Send back an empty buffer if no information was sent in.
if (!buffers || buffers && buffers.length === 0) {
return ac.createBuffer(2, 1000, 48000);
- } // Review the incoming audio to determine output buffer size.
-
+ }
+ // Review the incoming audio to determine output buffer size.
for (let i = 0; i < buffers.length; i++) {
onProgress("Reviewing Audio " + (i + 1) + "/" + buffers.length, i + 1 + "/" + buffers.length);
-
if (buffers[i].numberOfChannels > maxChannels) {
maxChannels = buffers[i].numberOfChannels;
}
-
if (buffers[i].duration > maxDuration) {
maxDuration = buffers[i].duration;
}
- } // Create new output buffer.
-
+ }
+ // Create new output buffer.
var out = ac.createBuffer(maxChannels, ac.sampleRate * maxDuration, ac.sampleRate);
-
for (var i = 0; i < buffers.length; i++) {
- onProgress("Merging Audio " + (i + 1) + "/" + buffers.length, i + 1 + "/" + buffers.length); // Go through each channel of the new audio source and copy that data into the output buffer.
+ onProgress("Merging Audio " + (i + 1) + "/" + buffers.length, i + 1 + "/" + buffers.length);
+ // Go through each channel of the new audio source and copy that data into the output buffer.
for (var srcChannel = 0; srcChannel < buffers[i].numberOfChannels; srcChannel++) {
var outt = out.getChannelData(srcChannel);
var inn = buffers[i].getChannelData(srcChannel);
-
for (let j = 0; j < inn.length; j++) {
- let val = inn[j]; // Some sounds may have corrupted data... don't copy that over.
+ let val = inn[j];
+ // Some sounds may have corrupted data... don't copy that over.
if (val) {
outt[j] += val;
}
}
-
out.getChannelData(srcChannel).set(outt, 0);
}
}
-
return out;
}
+
/**
* Offsets an audio buffer by a number of seconds.
* @param {audioBuffer} originalBuffer - Buffer to offset.
@@ -47800,41 +47667,37 @@ Wick.AudioTrack = class {
* @param {AudioContext} ctx - Context to use.
* @returns {audioBuffer} - A copy of the audio buffer, offset by the provided number of seconds.
*/
-
-
static offsetAudioBuffer(originalBuffer, offsetSeconds, ctx) {
// Create a blank buffer with the length of the original buffer.
var offsetBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, originalBuffer.length, ctx.sampleRate);
let copyto = 0;
let copyfrom = 0;
-
if (offsetSeconds < 0) {
copyto = -1 * offsetSeconds * ctx.sampleRate;
} else {
copyfrom = offsetSeconds * ctx.sampleRate;
- } // Copy buffer information.
-
+ }
+ // Copy buffer information.
for (var srcChannel = 0; srcChannel < offsetBuffer.numberOfChannels; srcChannel++) {
// Retrieve sample data...
var offsetBufferChannelData = offsetBuffer.getChannelData(srcChannel);
- var originalBufferChannelData = originalBuffer.getChannelData(srcChannel); // Copy samples from the original buffer to the adjusted buffer, adjusting for the number of seconds to offset.
+ var originalBufferChannelData = originalBuffer.getChannelData(srcChannel);
+ // Copy samples from the original buffer to the adjusted buffer, adjusting for the number of seconds to offset.
for (var i = 0; i < offsetBufferChannelData.length; i++) {
if (i + copyfrom > originalBufferChannelData.length) {
break;
} else if (i + copyto > offsetBufferChannelData.length) {
break;
}
-
offsetBufferChannelData[i + copyto] = originalBufferChannelData[i + copyfrom];
}
-
offsetBuffer.getChannelData(srcChannel).set(offsetBufferChannelData, 0);
}
-
return offsetBuffer;
}
+
/**
* Crops an AudioBuffer to a given length.
* @param {AudioBuffer} originalBuffer - the buffer to crop
@@ -47842,26 +47705,25 @@ Wick.AudioTrack = class {
* @param {AudioContext} ctx - An AudioContext instance
* @returns {AudioBuffer} - The a copy of the buffer, cropped to the specified length.
*/
-
-
static cropAudioBuffer(originalBuffer, lengthSeconds, ctx) {
// Create a blank buffer with a length of the crop amount
- var croppedBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, ctx.sampleRate * lengthSeconds, ctx.sampleRate); // Copy data from the original buffer into the cropped buffer
+ var croppedBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, ctx.sampleRate * lengthSeconds, ctx.sampleRate);
+ // Copy data from the original buffer into the cropped buffer
for (var srcChannel = 0; srcChannel < croppedBuffer.numberOfChannels; srcChannel++) {
// Retrieve sample data...
var croppedBufferChannelData = croppedBuffer.getChannelData(srcChannel);
- var originalBufferChannelData = originalBuffer.getChannelData(srcChannel); // Copy samples from the original buffer to the cropped buffer
+ var originalBufferChannelData = originalBuffer.getChannelData(srcChannel);
+ // Copy samples from the original buffer to the cropped buffer
for (var i = 0; i < croppedBufferChannelData.length; i++) {
croppedBufferChannelData[i] = originalBufferChannelData[i];
}
-
croppedBuffer.getChannelData(srcChannel).set(croppedBufferChannelData, 0);
}
-
return croppedBuffer;
}
+
/**
* Adjusts the volume of an audio buffer.
* @param {*} originalBuffer - The original buffer to adjust.
@@ -47869,48 +47731,46 @@ Wick.AudioTrack = class {
* @param {*} ctx - The audio context to use for buffer generation.
* @returns {AudioBuffer} - Adjusted audio buffer with new volume.
*/
-
-
static adjustBufferVolume(originalBuffer, volume, ctx) {
// Create a blank buffer with the length of the original buffer.
- var adjustedBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, originalBuffer.length, ctx.sampleRate); // Volume should be at least 0.
+ var adjustedBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, originalBuffer.length, ctx.sampleRate);
+ // Volume should be at least 0.
volume = Math.max(volume, 0);
-
for (var srcChannel = 0; srcChannel < adjustedBuffer.numberOfChannels; srcChannel++) {
// Retrieve sample data...
var adjustedBufferChannelData = adjustedBuffer.getChannelData(srcChannel);
- var originalBufferChannelData = originalBuffer.getChannelData(srcChannel); // Copy samples from the original buffer to the adjusted buffer, adjusting for volume.
+ var originalBufferChannelData = originalBuffer.getChannelData(srcChannel);
+ // Copy samples from the original buffer to the adjusted buffer, adjusting for volume.
for (var i = 0; i < adjustedBufferChannelData.length; i++) {
adjustedBufferChannelData[i] = originalBufferChannelData[i] * volume;
}
-
adjustedBuffer.getChannelData(srcChannel).set(adjustedBufferChannelData, 0);
}
-
return adjustedBuffer;
}
+
/**
* Adds silence to the beginning of an AudioBuffer with a given length.
* @param {AudioBuffer} originalBuffer - the buffer to pad with silence
* @param {number} delaySeconds - the amount of time, in seconds, to delay the sound
* @param {AudioContext} ctx - An AudioContext instance
*/
-
-
static addStartDelayToAudioBuffer(originalBuffer, delaySeconds, ctx) {
// Create buffer with a length equal to the original buffer's length plus the requested delay
+
let lengthOfDelay = ctx.sampleRate * delaySeconds;
let lengthOfOriginalSound = ctx.sampleRate * originalBuffer.duration;
- var delayedBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, lengthOfDelay + lengthOfOriginalSound, ctx.sampleRate); // For each channel in the audiobuffer...
+ var delayedBuffer = ctx.createBuffer(originalBuffer.numberOfChannels, lengthOfDelay + lengthOfOriginalSound, ctx.sampleRate);
+ // For each channel in the audiobuffer...
for (var srcChannel = 0; srcChannel < originalBuffer.numberOfChannels; srcChannel++) {
// Retrieve sample data...
- var originalBufferChannelData = originalBuffer.getChannelData(srcChannel); // Copy samples from the original buffer to the delayed buffer with an offset equal to the delay
+ var originalBufferChannelData = originalBuffer.getChannelData(srcChannel);
+ // Copy samples from the original buffer to the delayed buffer with an offset equal to the delay
var delayOffset = ctx.sampleRate * delaySeconds;
-
try {
// Copy in the data from the original buffer into the delayed buffer, starting at the delayed position.
delayedBuffer.getChannelData(srcChannel).set(originalBufferChannelData, delayOffset);
@@ -47919,17 +47779,15 @@ Wick.AudioTrack = class {
console.error("A sound was not added to the project.");
}
}
-
return delayedBuffer;
}
+
/**
* Convert a base64 string of an audio file into an AudioBuffer.
* @param {string} base64 - a base64 dataURI of an audio file.
* @param {AudioContext} ctx - an AudioContext instance.
* @param {Function} callback - callback to recieve the generated AudioBuffer
*/
-
-
static base64ToAudioBuffer(base64, ctx, callback) {
let base64DataOnly = base64.split(',')[1];
let arraybuffer = Base64ArrayBuffer.decode(base64DataOnly);
@@ -47940,7 +47798,6 @@ Wick.AudioTrack = class {
console.log(e);
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -47972,21 +47829,19 @@ Wick.AutoSave = class {
static get AUTOSAVES_LIST_KEY() {
return 'autosaveList';
}
+
/**
* The prefix to use for keys to save project autosave data.
* @type {string}
*/
-
-
static get AUTOSAVE_DATA_PREFIX() {
return 'autosave_';
}
+
/**
* Saves a given project to localforage.
* @param {Wick.Project} project - the project to store in the AutoSave system.
*/
-
-
static save(project, callback) {
if (Wick.AutoSave.ENABLE_PERF_TIMERS) console.time('serialize step');
var autosaveData = this.generateAutosaveData(project);
@@ -47999,13 +47854,12 @@ Wick.AutoSave = class {
});
});
}
+
/**
* Loads a given project from localforage.
* @param {string} uuid - the UUID of the project to load from the AutoSave system.
* @param {function} callback
*/
-
-
static load(uuid, callback) {
this.readAutosaveData(uuid, autosaveData => {
this.generateProjectFromAutosaveData(autosaveData, project => {
@@ -48013,13 +47867,12 @@ Wick.AutoSave = class {
});
});
}
+
/**
* Deletes a project with a given UUID in the autosaves.
* @param {string} uuid - uuid of project ot delete.
* @param {function} callback
*/
-
-
static delete(uuid, callback) {
this.removeAutosaveFromList(uuid, () => {
this.deleteAutosaveData(uuid, () => {
@@ -48027,12 +47880,11 @@ Wick.AutoSave = class {
});
});
}
+
/**
* Generates an object that is writable to localforage from a project.
* @param {Wick.Project} project - The project to generate data for.
*/
-
-
static generateAutosaveData(project) {
if (Wick.AutoSave.ENABLE_PERF_TIMERS) console.time('generate objects list');
var objects = Wick.ObjectCache.getActiveObjects(project);
@@ -48050,32 +47902,32 @@ Wick.AutoSave = class {
lastModified: lastModified
};
}
+
/**
* Creates a project from data loaded from the autosave system
* @param {object} autosaveData - An autosave data object, use generateAutosaveData/readAutosaveData to get this object
*/
-
-
static generateProjectFromAutosaveData(autosaveData, callback) {
// Deserialize all objects in the project so they are added to the ObjectCache
autosaveData.objectsData.forEach(objectData => {
var object = Wick.Base.fromData(objectData);
- }); // Deserialize the project itself
+ });
- var project = Wick.Base.fromData(autosaveData.projectData); // Load source files for assets from localforage
+ // Deserialize the project itself
+ var project = Wick.Base.fromData(autosaveData.projectData);
+ // Load source files for assets from localforage
Wick.FileCache.loadFilesFromLocalforage(project, () => {
project.loadAssets(() => {
callback(project);
});
});
}
+
/**
* Adds autosaved project data to the list of autosaved projects.
* @param {Object} projectData -
*/
-
-
static addAutosaveToList(autosaveData, callback) {
this.getAutosavesList(list => {
list.push({
@@ -48087,12 +47939,11 @@ Wick.AutoSave = class {
});
});
}
+
/**
* Removes autosaved project data to the list of autosaved projects.
* @param {string} uuid -
*/
-
-
static removeAutosaveFromList(uuid, callback) {
this.getAutosavesList(list => {
list = list.filter(item => {
@@ -48103,72 +47954,66 @@ Wick.AutoSave = class {
});
});
}
+
/**
* Get the list of autosaved projects currently in the AutoSave system.
* @param {function} callback - function to be passed object containing all autosaved projects.
*/
-
-
static getAutosavesList(callback) {
localforage.getItem(this.AUTOSAVES_LIST_KEY).then(result => {
- var projectList = result || []; // Sort by lastModified
+ var projectList = result || [];
+ // Sort by lastModified
projectList.sort((a, b) => {
return b.lastModified - a.lastModified;
});
callback(projectList);
});
}
+
/**
* Updates the list of autosaved projects currently in the AutoSave system.
* @param {Object} autosaveList - the list of projects
* @param {function} callback - called when saving is finished
*/
-
-
static updateAutosavesList(autosaveList, callback) {
localforage.setItem(this.AUTOSAVES_LIST_KEY, autosaveList).then(result => {
callback();
});
}
+
/**
* Save project data into the autosave system.
* @param {Object} autosaveData - Autosave data of a project, use generateAutosaveData to create this object
*/
-
-
static writeAutosaveData(autosaveData, callback) {
localforage.setItem(this.AUTOSAVE_DATA_PREFIX + autosaveData.projectData.uuid, autosaveData).then(() => {
callback();
});
}
+
/**
* Load project data from the autosave system.
* @param {string} uuid - the UUID of the project to load
*/
-
-
static readAutosaveData(uuid, callback) {
localforage.getItem(this.AUTOSAVE_DATA_PREFIX + uuid).then(result => {
if (!result) {
console.error('Could not load autosaveData for project: ' + uuid);
}
-
callback(result);
});
}
+
/**
* Deletes project data from the autosave system.
* @param {string} uuid - the UUID of the project to delete
*/
-
-
static deleteAutosaveData(uuid, callback) {
localforage.removeItem(this.AUTOSAVE_DATA_PREFIX + uuid).then(() => {
callback();
});
}
-
};
Wick.AutoSave.ENABLE_PERF_TIMERS = false;
/*
@@ -48217,78 +48062,66 @@ Wick.WickFile = class {
}
};
}
+
/**
* Create a project from a wick file.
* @param {File} wickFile - Wick file containing project data.
* @param {function} callback - Function called when the project is created.
* @param {string} format - The format to return. Can be 'blob' or 'base64'.
*/
-
-
static fromWickFile(wickFile, callback, format) {
if (!format) {
format = 'blob';
}
-
if (format !== 'blob' && format !== 'base64') {
console.error('WickFile.toWickFile: invalid format: ' + format);
return;
}
-
var zip = new JSZip();
zip.loadAsync(wickFile, {
base64: format === 'base64'
}).then(contents => {
contents.files['project.json'].async('text').then(projectJSON => {
var projectData = JSON.parse(projectJSON);
-
if (!projectData.objects) {
// No metadata! This is a pre 1.0.9a project. Convert it.
console.log('Wick.WickFile: Converting old project format.');
projectData = Wick.WickFile.Alpha.convertJsonProject(projectData);
}
-
projectData.assets = [];
-
for (var uuid in projectData.objects) {
var data = projectData.objects[uuid];
var object = Wick.Base.fromData(data);
Wick.ObjectCache.addObject(object);
}
-
var project = Wick.Base.fromData(projectData.project);
Wick.ObjectCache.addObject(project);
var loadedAssetCount = 0;
let corruptedFiles = []; // Store a list of all files that are now missing.
- // Immediately end if the project has no assets.
+ // Immediately end if the project has no assets.
if (project.getAssets().length === 0) {
this._prepareProject(project);
-
callback(project);
} else {
// Make a copy of the assets, as we may get rid of some mid process.
let allAssets = project.getAssets().concat([]);
allAssets.forEach(assetData => {
var assetFile = contents.files['assets/' + assetData.uuid + '.' + assetData.fileExtension];
+
/**
* Checks if we've loaded all assets, logs an error if an error occurred
* while loading asset files.
*/
-
var checkProjectLoad = () => {
loadedAssetCount++;
-
if (loadedAssetCount === allAssets.length) {
// Throw an error if any corrupted files were found.
project.errorOccured && corruptedFiles.length > 0 && project.errorOccured("Corrupted Files Were Deleted: " + corruptedFiles);
-
this._prepareProject(project);
-
callback(project);
}
};
-
if (!assetFile) {
// Try removing the asset from the project here.
assetData.removeAllInstances();
@@ -48297,7 +48130,6 @@ Wick.WickFile = class {
checkProjectLoad();
return;
}
-
assetFile.async('base64').then(assetFileData => {
var assetSrc = 'data:' + assetData.MIMEType + ';base64,' + assetFileData;
Wick.FileCache.addFile(assetSrc, assetData.uuid);
@@ -48319,28 +48151,27 @@ Wick.WickFile = class {
callback(null);
});
}
+
/**
* Create a wick file from the project.
* @param {Wick.Project} project - the project to create a wick file from
* @param {function} callback - Function called when the file is created. Contains the file as a parameter.
* @param {string} format - The format to return. Can be 'blob' or 'base64'.
*/
-
-
static toWickFile(project, callback, format) {
if (!format) {
format = 'blob';
}
-
if (format !== 'blob' && format !== 'base64') {
console.error('WickFile.toWickFile: invalid format: ' + format);
return;
}
+ var zip = new JSZip();
- var zip = new JSZip(); // Create assets folder
-
- var assetsFolder = zip.folder("assets"); // Populate assets folder with files
+ // Create assets folder
+ var assetsFolder = zip.folder("assets");
+ // Populate assets folder with files
project.getAssets().filter(asset => {
return asset instanceof Wick.ImageAsset || asset instanceof Wick.SoundAsset || asset instanceof Wick.FontAsset || asset instanceof Wick.ClipAsset || asset instanceof Wick.SVGAsset;
}).forEach(asset => {
@@ -48357,42 +48188,36 @@ Wick.WickFile = class {
objectCacheSerialized[object.uuid] = object.serialize();
});
var projectSerialized = project.serialize();
-
for (var uuid in objectCacheSerialized) {
if (objectCacheSerialized[uuid].classname === 'Project') {
delete objectCacheSerialized[uuid];
}
- } // Remove some extra data that we don't actually want to save
- // Clear selection:
-
+ }
+ // Remove some extra data that we don't actually want to save
+ // Clear selection:
for (var uuid in objectCacheSerialized) {
var object = objectCacheSerialized[uuid];
-
if (object.classname === 'Selection') {
object.selectedObjects = [];
}
- } // Set focus to root
-
-
+ }
+ // Set focus to root
for (var uuid in objectCacheSerialized) {
var object = objectCacheSerialized[uuid];
-
if (projectSerialized.children.indexOf(uuid) !== -1 && object.classname === 'Clip') {
projectSerialized.focus = uuid;
}
- } // Reset all playhead positions
-
-
+ }
+ // Reset all playhead positions
for (var uuid in objectCacheSerialized) {
var object = objectCacheSerialized[uuid];
-
if (object.classname === 'Timeline') {
object.playheadPosition = 1;
}
- } // Add project json to root directory of zip file
-
+ }
+ // Add project json to root directory of zip file
var projectData = {
project: projectSerialized,
objects: objectCacheSerialized
@@ -48406,9 +48231,8 @@ Wick.WickFile = class {
}
}).then(callback);
}
- /* Make any small backwards compatibility fixes needed */
-
+ /* Make any small backwards compatibility fixes needed */
static _prepareProject(project) {
// 1.16+ projects don't allow gaps between frames.
Wick.ObjectCache.getAllObjects().filter(object => {
@@ -48420,7 +48244,6 @@ Wick.WickFile = class {
timeline.fillGapsMethod = oldFrameGapFillMethod;
});
}
-
};
/*
* Utility class to convert Pre 1.0.9a projects into the most recent format
@@ -48443,25 +48266,21 @@ Wick.WickFile.Alpha = class {
objects: newProjectObjects
};
}
-
static flattenWickObject(objectJSON, parentJSON, objects) {
objectJSON.children = [];
if (parentJSON) parentJSON.children.push(objectJSON.uuid);
objects[objectJSON.uuid] = objectJSON;
-
if (objectJSON.root) {
objectJSON.focus = objectJSON.root.uuid;
Wick.WickFile.Alpha.flattenWickObject(objectJSON.root, objectJSON, objects);
delete objectJSON.root;
}
-
if (objectJSON.assets) {
objectJSON.assets.forEach(asset => {
Wick.WickFile.Alpha.flattenWickObject(asset, objectJSON, objects);
});
delete objectJSON.assets;
}
-
if (objectJSON.selection) {
objectJSON.selection.widgetRotation = 0;
objectJSON.selection.pivotPoint = {
@@ -48471,7 +48290,6 @@ Wick.WickFile.Alpha = class {
Wick.WickFile.Alpha.flattenWickObject(objectJSON.selection, objectJSON, objects);
delete objectJSON.selection;
}
-
if (objectJSON.transform) {
objectJSON.transformation = {
x: objectJSON.transform.x,
@@ -48483,53 +48301,45 @@ Wick.WickFile.Alpha = class {
};
delete objectJSON.transform;
}
-
if (objectJSON.timeline) {
Wick.WickFile.Alpha.flattenWickObject(objectJSON.timeline, objectJSON, objects);
delete objectJSON.timeline;
}
-
if (objectJSON.layers) {
objectJSON.layers.forEach(layer => {
Wick.WickFile.Alpha.flattenWickObject(layer, objectJSON, objects);
});
delete objectJSON.layers;
}
-
if (objectJSON.frames) {
objectJSON.frames.forEach(frame => {
Wick.WickFile.Alpha.flattenWickObject(frame, objectJSON, objects);
});
delete objectJSON.frames;
}
-
if (objectJSON.clips) {
objectJSON.clips.forEach(clip => {
Wick.WickFile.Alpha.flattenWickObject(clip, objectJSON, objects);
});
delete objectJSON.clips;
}
-
if (objectJSON.paths) {
objectJSON.paths.forEach(path => {
Wick.WickFile.Alpha.flattenWickObject(path, objectJSON, objects);
});
delete objectJSON.paths;
}
-
if (objectJSON.tweens) {
objectJSON.tweens.forEach(tween => {
Wick.WickFile.Alpha.flattenWickObject(tween, objectJSON, objects);
});
delete objectJSON.tweens;
}
-
if (objectJSON.pathJSON) {
objectJSON.json = objectJSON.pathJSON;
delete objectJSON.pathJSON;
}
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -48564,23 +48374,19 @@ Wick.WickObjectFile = class {
if (typeof wickObjectFile === 'string') {
wickObjectFile = Wick.ExportUtils.dataURItoBlob(wickObjectFile);
}
-
var fr = new FileReader();
-
fr.onload = () => {
var data = JSON.parse(fr.result);
callback(data);
};
-
fr.readAsText(wickObjectFile);
}
+
/**
* Create a wick file from the project.
* @param {Wick.Project} clip - the clip to create a wickobject file from
* @param {string} format - Can be 'blob' or 'dataurl'.
*/
-
-
static toWickObjectFile(clip, format, callback) {
if (!format) format = 'blob';
var data = clip.export();
@@ -48588,22 +48394,18 @@ Wick.WickObjectFile = class {
var blob = new Blob([json], {
type: "application/json"
});
-
if (format === 'blob') {
callback(blob);
} else if (format === 'dataurl') {
var fr = new FileReader();
-
fr.onload = function (e) {
callback(e.target.result);
};
-
fr.readAsDataURL(blob);
} else {
console.error('toWickObjectFile: invalid format: ' + format);
}
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -48643,7 +48445,6 @@ Wick.HTMLExport = class {
});
}, 'base64');
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -48677,18 +48478,15 @@ Wick.HTMLPreview = class {
Wick.HTMLExport.bundleProject(project, html => {
var windowFeatures = "height=" + project.height + ",width=" + project.width;
var popupWindow = window.open('', '_blank', windowFeatures);
-
if (popupWindow) {
popupWindow.document.title = project.name;
popupWindow.document.open();
popupWindow.document.write(html);
popupWindow.document.close();
}
-
callback(popupWindow);
});
}
-
};
/*
* Copyright 2019 WICKLETS LLC
@@ -48722,15 +48520,13 @@ Wick.SVGFile = class {
if (typeof svgFile === 'string') {
svgFile = Wick.ExportUtils.dataURItoBlob(svgFile);
}
-
var fr = new FileReader();
-
fr.onload = function () {
callback(fr.result);
};
-
fr.readAsText(svgFile);
}
+
/**
* Create a wick file from the project.
* @param {Wick.Timeline} timeline - the clip to create a wickobject file from
@@ -48738,8 +48534,6 @@ Wick.SVGFile = class {
* @param {function(blob)} callback - function to call when done
* @returns {Blob}
*/
-
-
static toSVGFile(timeline, onError, callback) {
var svgString = timeline.exportSVG(onError);
var blob = new Blob([svgString], {
@@ -48748,7 +48542,6 @@ Wick.SVGFile = class {
callback(blob);
return blob;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -48785,10 +48578,10 @@ Wick.ImageSequence = class {
onFinish
} = args;
var zip = new JSZip();
-
let buildZip = files => {
let index = 0;
files.forEach(file => {
+ // console.log(file);
var blob = Wick.ExportUtils.dataURItoBlob(file.src);
let paddedNum = (index + '').padStart(12, '0');
zip.file('frame' + paddedNum + '.png', blob);
@@ -48796,13 +48589,12 @@ Wick.ImageSequence = class {
});
zip.generateAsync({
type: 'blob',
- compression: "DEFLATE",
+ compression: 'DEFLATE',
compressionOptions: {
level: 9
}
}).then(onFinish);
};
-
project.generateImageSequence({
width: args.width,
height: args.height,
@@ -48810,7 +48602,62 @@ Wick.ImageSequence = class {
onProgress: onProgress
});
}
+};
+/*
+ * Copyright 2020 WICKLETS LLC
+ *
+ * This file is part of Wick Engine.
+ *
+ * Wick Engine is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Wick Engine is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Wick Engine. If not, see .
+ */
+
+/**
+ * Utility class for generating an image file.
+ */
+Wick.ImageFile = class {
+ /**
+ * Create a png sequence from a project.
+ * @param {Wick.Project} project - the project to create a png sequence from
+ * @param {function} callback - Function called when the file is created. Contains the file as a parameter.
+ **/
+ static toPNGFile(args) {
+ let {
+ project,
+ onProgress,
+ onFinish
+ } = args;
+
+ // console.log('ImageFile.toPNGFile', args);
+
+ // var zip = new JSZip();
+ let buildImage = image => {
+ // console.log('ImageFile.toPNGFile image', image);
+
+ var blob = Wick.ExportUtils.dataURItoBlob(image.src);
+ onFinish(blob);
+ };
+
+ // console.log('ImageFile.toPNGFile', project);
+
+ project.generateImageFile({
+ width: args.width,
+ height: args.height,
+ onFinish: buildImage,
+ onProgress: onProgress
+ });
+ }
};
/*
* Copyright 2020 WICKLETS LLC
@@ -48842,7 +48689,6 @@ Wick.ZIPExport = class {
});
});
}
-
static _downloadDependenciesFiles(done) {
var list = [];
var urls = ["index.html", "preloadjs.min.js", "wickengine.js"];
@@ -48859,7 +48705,6 @@ Wick.ZIPExport = class {
done(results);
});
}
-
static _bundleFilesIntoZip(wickFile, dependenciesFiles, done) {
var zip = new JSZip();
dependenciesFiles.forEach(file => {
@@ -48874,7 +48719,6 @@ Wick.ZIPExport = class {
}
}).then(done);
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -48912,7 +48756,6 @@ Wick.Base = class {
Wick._originals[this.classname] = {};
Wick._originals[this.classname] = new Wick[this.classname]();
}
-
if (!args) args = {};
this._uuid = args.uuid || uuidv4();
this._identifier = args.identifier || null;
@@ -48924,8 +48767,9 @@ Wick.Base = class {
this._classname = this.classname;
this._children = [];
this._childrenData = null;
- this._parent = null; // If this is a project, use this object, otherwise use the passed in project if provided.
+ this._parent = null;
+ // If this is a project, use this object, otherwise use the passed in project if provided.
this._project = this.classname === 'Project' ? this : args.project ? args.project : null;
this.needsAutosave = true;
this._cachedSerializeData = null;
@@ -48933,71 +48777,59 @@ Wick.Base = class {
Wick.ObjectCache.addObject(this);
}
+
/**
* @param {object} data - Serialized data to use to create a new object.
*/
-
-
static fromData(data, project) {
if (!data.classname) {
console.warn('Wick.Base.fromData(): data was missing, did you mean to deserialize something else?');
}
-
if (!Wick[data.classname]) {
console.warn('Tried to deserialize an object with no Wick class: ' + data.classname);
}
-
var object = new Wick[data.classname]({
uuid: data.uuid,
project: project
});
object.deserialize(data);
-
if (data.classname === 'Project') {
object.initialize();
}
-
return object;
}
+
/**
* Converts this Wick Base object into a plain javascript object contianing raw data (no references).
* @return {object} Plain JavaScript object representing this Wick Base object.
*/
-
-
serialize(args) {
// TEMPORARY: Force the cache to never be accessed.
// This is because the cache was causing issues in the tests, and the
// performance boost that came with the cache was not signifigant enough
// to be worth fixing the bugs over...
this.needsAutosave = true;
-
if (this.needsAutosave || !this._cachedSerializeData) {
// If the cache is outdated or does not exist, reserialize and cache.
var data = this._serialize(args);
-
this._cacheSerializeData(data);
-
return data;
} else {
// Otherwise, just read from the cache
return this._cachedSerializeData;
}
}
+
/**
* Parses serialized data representing Base Objects which have been serialized using the serialize function of their class.
* @param {object} data Serialized data that was returned by a Base Object's serialize function.
*/
-
-
deserialize(data) {
this._deserialize(data);
-
this._cacheSerializeData(data);
}
- /* The internal serialize method that actually creates the data. Every class that inherits from Base must have one of these. */
-
+ /* The internal serialize method that actually creates the data. Every class that inherits from Base must have one of these. */
_serialize(args) {
var data = {};
data.classname = this.classname;
@@ -49009,63 +48841,63 @@ Wick.Base = class {
});
return data;
}
- /* The internal deserialize method that actually reads the data. Every class that inherits from Base must have one of these. */
-
+ /* The internal deserialize method that actually reads the data. Every class that inherits from Base must have one of these. */
_deserialize(data) {
this._uuid = data.uuid;
this._identifier = data.identifier;
this._name = data.name;
this._children = [];
- this._childrenData = data.children; // Clear any custom attributes set by scripts
+ this._childrenData = data.children;
+ // Clear any custom attributes set by scripts
var compareObj = Wick._originals[this.classname];
-
for (var name in this) {
if (compareObj[name] === undefined) {
delete this[name];
}
}
}
-
_cacheSerializeData(data) {
this._cachedSerializeData = data;
this.needsAutosave = false;
}
+
/**
* Returns a copy of a Wick Base object.
* @return {Wick.Base} The object resulting from the copy
*/
-
-
copy() {
var data = this.serialize();
data.uuid = uuidv4();
var copy = Wick.Base.fromData(data);
- copy._childrenData = null; // Copy children
+ copy._childrenData = null;
+ // Copy children
this.getChildren().forEach(child => {
copy.addChild(child.copy());
});
return copy;
}
+
/**
* Returns an object containing serialied data of this object, as well as all of its children.
* Use this to copy entire Wick.Base objects between projects, and to export individual Clips as files.
* @returns {object} The exported data.
*/
-
-
export() {
var copy = this.copy();
- copy._project = this.project; // the main object
+ copy._project = this.project;
- var object = copy.serialize(); // children
+ // the main object
+ var object = copy.serialize();
+ // children
var children = copy.getChildrenRecursive().map(child => {
return child.serialize();
- }); // assets
+ });
+ // assets
var assets = [];
copy.getChildrenRecursive().concat(copy).forEach(child => {
child._project = copy._project;
@@ -49081,41 +48913,40 @@ Wick.Base = class {
assets: assets
};
}
+
/**
* Import data created using Wick.Base.export().
* @param {object} exportData - an object created from Wick.Base.export().
*/
-
-
static import(exportData, project) {
if (!exportData) console.error('Wick.Base.import(): exportData is required');
if (!exportData.object) console.error('Wick.Base.import(): exportData is missing data');
- if (!exportData.children) console.error('Wick.Base.import(): exportData is missing data'); // Import assets first in case the objects need them!
+ if (!exportData.children) console.error('Wick.Base.import(): exportData is missing data');
+ // Import assets first in case the objects need them!
exportData.assets.forEach(assetData => {
// Don't import assets if they exist in the project already
// (Assets only get reimported when objects are pasted between projects)
if (project.getAssetByUUID(assetData.uuid)) {
return;
}
-
var asset = Wick.Base.fromData(assetData, project);
project.addAsset(asset);
});
- var object = Wick.Base.fromData(exportData.object, project); // Import children as well
+ var object = Wick.Base.fromData(exportData.object, project);
+ // Import children as well
exportData.children.forEach(childData => {
// Only need to call deserialize here, we just want the object to get added to ObjectCache
var child = Wick.Base.fromData(childData, project);
});
return object;
}
+
/**
* Marks the object as possibly changed, so that next time autosave happens, this object is written to the save.
* @type {boolean}
*/
-
-
set needsAutosave(needsAutosave) {
if (needsAutosave) {
Wick.ObjectCache.markObjectToBeAutosaved(this);
@@ -49123,167 +48954,149 @@ Wick.Base = class {
Wick.ObjectCache.clearObjectToBeAutosaved(this);
}
}
-
get needsAutosave() {
return Wick.ObjectCache.objectNeedsAutosave(this);
}
+
/**
* Signals if an object is removed from the project while playing.
* This is a temprary variable.
* @type {boolean}
*/
-
-
get removed() {
return typeof this._removed === 'undefined' ? false : this._removed;
}
-
set removed(bool) {
this._removed = bool;
}
+
/**
* Returns the classname of a Wick Base object.
* @type {string}
*/
-
-
get classname() {
return 'Base';
}
+
/**
* A marker if this object is temporary. Meaning it
* should be garbage collected after a play.
*/
-
-
get temporary() {
return this._temporary;
}
+
/**
* The uuid of a Wick Base object.
* @type {string}
*/
-
-
get uuid() {
return this._uuid;
}
+
/**
* Changes an object's uuid. This function should not be used consistently, as it creates an entire copy of the object
* in the object cache. Avoid using this if possile.
*/
-
-
set uuid(uuid) {
this._uuid = uuid;
Wick.ObjectCache.addObject(this);
}
+
/**
* The name of the object that is used to access the object through scripts. Must be a valid JS variable name.
* @type {string}
*/
-
-
get identifier() {
return this._identifier;
}
-
set identifier(identifier) {
// Treat empty string identifier as null
if (identifier === '' || identifier === null) {
this._identifier = null;
return;
- } // Make sure the identifier doesn't squash any attributes of the window
-
+ }
- if (this._identifierNameExistsInWindowContext(identifier)) return; // Make sure the identifier will not be squashed by Wick API functions
+ // Make sure the identifier doesn't squash any attributes of the window
+ if (this._identifierNameExistsInWindowContext(identifier)) return;
- if (this._identiferNameIsPartOfWickAPI(identifier)) return; // Make sure the identifier is a valid js variable name
+ // Make sure the identifier will not be squashed by Wick API functions
+ if (this._identiferNameIsPartOfWickAPI(identifier)) return;
+ // Make sure the identifier is a valid js variable name
if (!isVarName(identifier)) {
this.project && this.project.errorOccured('Identifier must be a valid variable name.');
return;
- } // Make sure the identifier is not a reserved word in js
-
+ }
- if (reserved.check(identifier)) return; // Ensure no objects with duplicate identifiers can exist
+ // Make sure the identifier is not a reserved word in js
+ if (reserved.check(identifier)) return;
+ // Ensure no objects with duplicate identifiers can exist
this._identifier = this._getUniqueIdentifier(identifier);
}
+
/**
* The name of the object.
* @type {string}
*/
-
-
get name() {
return this._name;
}
-
set name(name) {
if (typeof name !== 'string') return;
if (name === '') this._name = null;
this._name = name;
}
+
/**
* The Wick.View object that is used for rendering this object on the canvas.
*/
-
-
get view() {
return this._view;
}
-
set view(view) {
if (view) view.model = this;
this._view = view;
}
+
/**
* The object that is used for rendering this object in the timeline GUI.
*/
-
-
get guiElement() {
return this._guiElement;
}
-
set guiElement(guiElement) {
if (guiElement) guiElement.model = this;
this._guiElement = guiElement;
}
+
/**
* Returns a single child of this object with a given classname.
* @param {string} classname - the classname to use
*/
-
-
getChild(classname) {
return this.getChildren(classname)[0];
}
+
/**
* Gets all children with a given classname(s).
* @param {Array|string} classname - (optional) A string, or list of strings, of classnames.
*/
-
-
getChildren(classname) {
// Lazily generate children list from serialized data
if (this._childrenData) {
this._childrenData.forEach(uuid => {
this.addChild(Wick.ObjectCache.getObjectByUUID(uuid));
});
-
this._childrenData = null;
}
-
if (classname instanceof Array) {
let classNames = new Set(classname);
var children = [];
-
if (this._children !== undefined) {
children = this._children.filter(child => classNames.has(child.classname));
}
-
return children;
} else if (classname === undefined) {
// Retrieve all children if no classname was given
@@ -49291,16 +49104,14 @@ Wick.Base = class {
} else {
// Retrieve children by classname
var children = this._children.filter(child => child.classname === classname);
-
return children || [];
}
}
+
/**
* Get an array of all children of this object, and the children of those children, recursively.
* @type {Wick.Base[]}
*/
-
-
getChildrenRecursive(level, original) {
var children = this.getChildren();
this.getChildren().forEach(child => {
@@ -49308,57 +49119,51 @@ Wick.Base = class {
});
return children;
}
+
/**
* The parent of this object.
* @type {Wick.Base}
*/
-
-
get parent() {
return this._parent;
}
+
/**
* The parent Clip of this object.
* @type {Wick.Clip}
*/
-
-
get parentClip() {
return this._getParentByClassName('Clip');
}
+
/**
* The parent Layer of this object.
* @type {Wick.Layer}
*/
-
-
get parentLayer() {
return this._getParentByClassName('Layer');
}
+
/**
* The parent Frame of this object.
* @type {Wick.Frame}
*/
-
-
get parentFrame() {
return this._getParentByClassName('Frame');
}
+
/**
* The parent Timeline of this object.
* @type {Wick.Timeline}
*/
-
-
get parentTimeline() {
return this._getParentByClassName('Timeline');
}
+
/**
* The project that this object belongs to. Can be null if the object is not in a project.
* @type {Wick.Project}
*/
-
-
get project() {
if (this._project) {
return this._project;
@@ -49368,35 +49173,30 @@ Wick.Base = class {
return null;
}
}
+
/**
* Check if an object is selected or not.
* @type {boolean}
*/
-
-
get isSelected() {
if (!this.project) return false;
return this.project.selection.isObjectSelected(this);
}
+
/**
* Add a child to this object.
* @param {Wick.Base} child - the child to add.
*/
-
-
addChild(child) {
var classname = child.classname;
-
if (!this._children) {
this._children = [];
}
-
child._parent = this;
-
child._setProject(this.project);
-
this._children.push(child);
}
+
/**
* Insert a child into this at specified index.
*
@@ -49411,93 +49211,71 @@ Wick.Base = class {
* @param {number} index - where to add the child
* @returns {boolean} - true if an item before index was moved
*/
-
-
insertChild(child, index) {
var classname = child.classname;
-
if (child._parent === this) {
let result = 0;
-
let old_index = this._children.indexOf(child);
-
if (old_index < index) {
index--;
result = 1;
}
-
this._children.splice(index, 0, this._children.splice(old_index, 1)[0]);
-
return result;
}
-
if (child._parent) {
child._parent.removeChild(child);
}
-
if (!this._children) {
this._children = [];
}
-
child._parent = this;
-
child._setProject(this.project);
-
this._children.splice(index, 0, child);
-
return 0;
}
+
/**
* Remove a child from this object.
* @param {Wick.Base} child - the child to remove.
*/
-
-
removeChild(child) {
if (!this._children) {
return;
}
-
child._parent = null;
child._project = null;
this._children = this._children.filter(seekChild => {
return seekChild !== child;
});
}
+
/**
* Assets attached to this object.
* @returns {Wick.Base[]}
*/
-
-
getLinkedAssets() {
// Implemented by Wick.Frame and Wick.Clip
return [];
}
-
_generateView() {
var viewClass = Wick.View[this.classname];
-
if (viewClass) {
return new viewClass(this);
} else {
return null;
}
}
-
_generateGUIElement() {
var guiElementClass = Wick.GUIElement[this.classname];
-
if (guiElementClass && guiElementClass !== Wick.Button) {
return new guiElementClass(this);
} else {
return null;
}
}
-
_getParentByClassName(classname) {
if (!this.parent) return null;
-
if (this.parent instanceof Wick[classname]) {
return this.parent;
} else {
@@ -49505,7 +49283,6 @@ Wick.Base = class {
return this.parent._getParentByClassName(classname);
}
}
-
_setProject(project) {
this._project = project;
this.getChildren().forEach(child => {
@@ -49514,7 +49291,6 @@ Wick.Base = class {
}
});
}
-
_getUniqueIdentifier(identifier) {
if (!this.parent) return identifier;
var otherIdentifiers = this.parent.getChildren(['Clip', 'Frame', 'Button']).filter(child => {
@@ -49522,14 +49298,12 @@ Wick.Base = class {
}).map(child => {
return child.identifier;
});
-
if (otherIdentifiers.indexOf(identifier) === -1) {
return identifier;
} else {
return this._getUniqueIdentifier(identifier + '_copy');
}
}
-
_identifierNameExistsInWindowContext(identifier) {
if (window[identifier]) {
return true;
@@ -49537,17 +49311,14 @@ Wick.Base = class {
return false;
}
}
-
_identiferNameIsPartOfWickAPI(identifier) {
var globalAPI = new GlobalAPI(this);
-
if (globalAPI[identifier]) {
return true;
} else {
return false;
}
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -49584,66 +49355,56 @@ Wick.Layer = class extends Wick.Base {
this.hidden = args.hidden === undefined ? false : args.hidden;
this.name = args.name || null;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.locked = this.locked;
data.hidden = this.hidden;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.locked = data.locked;
this.hidden = data.hidden;
}
-
get classname() {
return 'Layer';
}
+
/**
* The frames belonging to this layer.
* @type {Wick.Frame[]}
*/
-
-
get frames() {
return this.getChildren('Frame');
}
+
/**
* The order of the Layer in the timeline.
* @type {number}
*/
-
-
get index() {
return this.parent && this.parent.layers.indexOf(this);
}
+
/**
* Set this layer to be the active layer in its timeline.
*/
-
-
activate() {
this.parent.activeLayerIndex = this.index;
}
+
/**
* True if this layer is the active layer in its timeline.
* @type {boolean}
*/
-
-
get isActive() {
return this.parent && this === this.parent.activeLayer;
}
+
/**
* The length of the layer in frames.
* @type {number}
*/
-
-
get length() {
var end = 0;
this.frames.forEach(function (frame) {
@@ -49653,165 +49414,153 @@ Wick.Layer = class extends Wick.Base {
});
return end;
}
+
/**
* The active frame on the layer.
* @type {Wick.Frame}
*/
-
-
get activeFrame() {
if (!this.parent) return null;
return this.getFrameAtPlayheadPosition(this.parent.playheadPosition);
}
+
/**
* Moves this layer to a different position, inserting it before/after other layers if needed.
* @param {number} index - the new position to move the layer to.
*/
-
-
move(index) {
this.parentTimeline.moveLayer(this, index);
}
+
/**
* Remove this layer from its timeline.
*/
-
-
remove() {
this.parentTimeline.removeLayer(this);
}
+
/**
* Adds a frame to the layer.
* @param {Wick.Frame} frame - The frame to add to the Layer.
*/
-
-
addFrame(frame) {
this.addChild(frame);
this.resolveOverlap([frame]);
this.resolveGaps([frame]);
}
+
/**
* Adds a tween to the active frame of this layer (if one exists).
* @param {Wick.Tween} tween - the tween to add
*/
-
-
addTween(tween) {
this.activeFrame && this.activeFrame.addChild(tween);
}
+
/**
* Adds a frame to the layer. If there is an existing frame where the new frame is
* inserted, then the existing frame will be cut, and the new frame will fill the
* gap created by that cut.
* @param {number} playheadPosition - Where to add the blank frame.
*/
-
-
insertBlankFrame(playheadPosition) {
if (!playheadPosition) {
throw new Error('insertBlankFrame: playheadPosition is required');
}
-
var frame = new Wick.Frame({
start: playheadPosition
});
- this.addChild(frame); // If there is is overlap with an existing frame
+ this.addChild(frame);
+ // If there is is overlap with an existing frame
var existingFrame = this.getFrameAtPlayheadPosition(playheadPosition);
-
if (existingFrame) {
// Make sure the new frame fills the empty space
frame.end = existingFrame.end;
}
-
this.resolveOverlap([frame]);
this.resolveGaps([frame]);
return frame;
}
+
/**
* Removes a frame from the Layer.
* @param {Wick.Frame} frame Frame to remove.
*/
-
-
removeFrame(frame) {
this.removeChild(frame);
this.resolveGaps();
}
+
/**
* Gets the frame at a specific playhead position.
* @param {number} playheadPosition - Playhead position to search for frame at.
* @return {Wick.Frame} The frame at the given playheadPosition.
*/
-
-
getFrameAtPlayheadPosition(playheadPosition) {
return this.frames.find(frame => {
return frame.inPosition(playheadPosition);
}) || null;
}
+
/**
* Gets all frames in the layer that are between the two given playhead positions.
* @param {number} playheadPositionStart - The start of the range to search
* @param {number} playheadPositionEnd - The end of the range to search
* @return {Wick.Frame[]} The frames in the given range.
*/
-
-
getFramesInRange(playheadPositionStart, playheadPositionEnd) {
return this.frames.filter(frame => {
return frame.inRange(playheadPositionStart, playheadPositionEnd);
});
}
+
/**
* Gets all frames in the layer that are contained within the two given playhead positions.
* @param {number} playheadPositionStart - The start of the range to search
* @param {number} playheadPositionEnd - The end of the range to search
* @return {Wick.Frame[]} The frames contained in the given range.
*/
-
-
getFramesContainedWithin(playheadPositionStart, playheadPositionEnd) {
return this.frames.filter(frame => {
return frame.containedWithin(playheadPositionStart, playheadPositionEnd);
});
}
+
/**
* Prevents frames from overlapping each other by removing pieces of frames that are touching.
* @param {Wick.Frame[]} newOrModifiedFrames - the frames that should take precedence when determining which frames should get "eaten".
*/
-
-
resolveOverlap(newOrModifiedFrames) {
- newOrModifiedFrames = newOrModifiedFrames || []; // Ensure that frames never go beyond the beginning of the timeline
+ newOrModifiedFrames = newOrModifiedFrames || [];
+ // Ensure that frames never go beyond the beginning of the timeline
newOrModifiedFrames.forEach(frame => {
if (frame.start <= 1) {
frame.start = 1;
}
});
-
var isEdible = existingFrame => {
return newOrModifiedFrames.indexOf(existingFrame) === -1;
};
-
newOrModifiedFrames.forEach(frame => {
// "Full eat"
// The frame completely eats the other frame.
var containedFrames = this.getFramesContainedWithin(frame.start, frame.end);
containedFrames.filter(isEdible).forEach(existingFrame => {
existingFrame.remove();
- }); // "Right eat"
- // The frame takes a chunk out of the right side of another frame.
+ });
+ // "Right eat"
+ // The frame takes a chunk out of the right side of another frame.
this.frames.filter(isEdible).forEach(existingFrame => {
if (existingFrame.inPosition(frame.start) && existingFrame.start !== frame.start) {
existingFrame.end = frame.start - 1;
}
- }); // "Left eat"
- // The frame takes a chunk out of the left side of another frame.
+ });
+ // "Left eat"
+ // The frame takes a chunk out of the left side of another frame.
this.frames.filter(isEdible).forEach(existingFrame => {
if (existingFrame.inPosition(frame.end) && existingFrame.end !== frame.end) {
existingFrame.start = frame.end + 1;
@@ -49819,11 +49568,10 @@ Wick.Layer = class extends Wick.Base {
});
});
}
+
/**
* Prevents gaps between frames by extending frames to fill empty space between themselves.
*/
-
-
resolveGaps(newOrModifiedFrames) {
if (this.parentTimeline && this.parentTimeline.waitToFillFrameGaps) return;
newOrModifiedFrames = newOrModifiedFrames || [];
@@ -49833,7 +49581,6 @@ Wick.Layer = class extends Wick.Base {
// Method 1: Use the frame on the left (if there is one) to fill the gap
if (fillGapsMethod === 'auto_extend') {
var frameOnLeft = this.getFrameAtPlayheadPosition(gap.start - 1);
-
if (!frameOnLeft || newOrModifiedFrames.indexOf(frameOnLeft) !== -1 || gap.start === 1) {
// If there is no frame on the left, create a blank one
var empty = new Wick.Frame({
@@ -49845,9 +49592,9 @@ Wick.Layer = class extends Wick.Base {
// Otherwise, extend the frame to the left to fill the gap
frameOnLeft.end = gap.end;
}
- } // Method 2: Always create empty frames to fill gaps
-
+ }
+ // Method 2: Always create empty frames to fill gaps
if (fillGapsMethod === 'blank_frames') {
var empty = new Wick.Frame({
start: gap.start,
@@ -49857,35 +49604,32 @@ Wick.Layer = class extends Wick.Base {
}
});
}
+
/**
* Generate a list of positions where there is empty space between frames.
* @returns {Object[]} An array of objects with start/end positions describing gaps.
*/
-
-
findGaps() {
var gaps = [];
var currentGap = null;
-
for (var i = 1; i <= this.length; i++) {
- var frame = this.getFrameAtPlayheadPosition(i); // Found the start of a gap
+ var frame = this.getFrameAtPlayheadPosition(i);
+ // Found the start of a gap
if (!frame && !currentGap) {
currentGap = {};
currentGap.start = i;
- } // Found the end of a gap
-
+ }
+ // Found the end of a gap
if (frame && currentGap) {
currentGap.end = i - 1;
gaps.push(currentGap);
currentGap = null;
}
}
-
return gaps;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -49918,8 +49662,13 @@ Wick.Project = class extends Wick.Base {
* @param {number} framerate - Project framerate in frames-per-second. Default 12.
* @param {Color} backgroundColor - Project background color in hex. Default #ffffff.
*/
- constructor(args) {
- if (!args) args = {};
+ constructor(paramArgs) {
+ let args = {};
+ if (paramArgs) {
+ args = {
+ ...paramArgs
+ };
+ }
super(args);
this._name = args.name || 'My Project';
this._width = args.width || 720;
@@ -49964,7 +49713,6 @@ Wick.Project = class extends Wick.Base {
this._hideCursor = false;
this._muted = false;
this._publishedMode = false; // Review the publishedMode setter for rules.
-
this._showClipBorders = true;
this._userErrorCallback = null;
this._tools = {
@@ -49984,14 +49732,11 @@ Wick.Project = class extends Wick.Base {
text: new Wick.Tools.Text(),
zoom: new Wick.Tools.Zoom()
};
-
for (var toolName in this._tools) {
this._tools[toolName].project = this;
}
-
this.activeTool = 'cursor';
this._toolSettings = new Wick.ToolSettings();
-
this._toolSettings.onSettingsChanged((name, value) => {
if (name === 'fillColor') {
this.selection.fillColor = value.rgba;
@@ -49999,56 +49744,49 @@ Wick.Project = class extends Wick.Base {
this.selection.strokeColor = value.rgba;
}
});
-
this._playing = false;
this._scriptSchedule = [];
this._error = null;
this.history.project = this;
this.history.pushState(Wick.History.StateType.ONLY_VISIBLE_OBJECTS);
}
+
/**
* Prepares the project to be used in an editor.
*/
-
-
prepareProjectForEditor() {
this.project.resetCache();
this.project.recenter();
this.project.view.prerender();
this.project.view.render();
}
+
/**
* Used to initialize the state of elements within the project. Should only be called after
* deserialization of project and all objects within the project.
*/
-
-
initialize() {
// Fixing all clip positions... This should be done in an internal method when the project is done loading...
this.activeFrame && this.activeFrame.clips.forEach(clip => {
clip.applySingleFramePosition();
});
}
+
/**
* Resets the cache and removes all unlinked items from the project.
*/
-
-
resetCache() {
Wick.ObjectCache.removeUnusedObjects(this);
}
+
/**
* TODO: Remove all elements created by this project.
*/
-
-
destroy() {
this.guiElement.removeAllEventListeners();
}
-
_deserialize(data) {
super._deserialize(data);
-
this.name = data.name;
this.width = data.width;
this.height = data.height;
@@ -50058,15 +49796,14 @@ Wick.Project = class extends Wick.Base {
this._hideCursor = false;
this._muted = false;
this._renderBlackBars = true;
- this._hitTestOptions = this.getDefaultHitTestOptions(); // reset rotation, but not pan/zoom.
- // not resetting pan/zoom is convenient when preview playing.
+ this._hitTestOptions = this.getDefaultHitTestOptions();
+ // reset rotation, but not pan/zoom.
+ // not resetting pan/zoom is convenient when preview playing.
this.rotation = 0;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.name = this.name;
data.width = this.width;
data.height = this.height;
@@ -50075,12 +49812,12 @@ Wick.Project = class extends Wick.Base {
data.onionSkinEnabled = this.onionSkinEnabled;
data.onionSkinSeekForwards = this.onionSkinSeekForwards;
data.onionSkinSeekBackwards = this.onionSkinSeekBackwards;
- data.focus = this.focus.uuid; // Save some metadata which will eventually end up in the wick file
+ data.focus = this.focus.uuid;
+ // Save some metadata which will eventually end up in the wick file
data.metadata = Wick.WickFile.generateMetaData();
return data;
}
-
getDefaultHitTestOptions() {
return {
mode: 'RECTANGLE',
@@ -50089,301 +49826,270 @@ Wick.Project = class extends Wick.Base {
intersections: false
};
}
-
get classname() {
return 'Project';
}
+
/**
* Assign a function to be called when a user error happens (not script
* errors - errors such as drawing tool errors, invalid selection props, etc)
* @param {Function} fn - the function to call when errors happen
*/
-
-
onError(fn) {
this._userErrorCallback = fn;
}
+
/**
* Called when an error occurs to forward to the onError function
* @param {String} message - the message to display for the error
*/
-
-
errorOccured(message) {
- if (this._userErrorCallback) this._userErrorCallback(message);
-
+ if (this._userErrorCallback) {
+ this._userErrorCallback(message);
+ }
this._internalErrorMessages.push(message);
}
+
/**
* The width of the project.
* @type {number}
*/
-
-
get width() {
return this._width;
}
-
set width(width) {
- if (typeof width !== 'number') return;
- if (width < 1) width = 1;
- if (width > 200000) width = 200000;
- this._width = width;
+ let newWidth = width;
+ if (typeof newWidth !== 'number') {
+ return;
+ }
+ if (newWidth < 1) {
+ newWidth = 1;
+ }
+ if (newWidth > 200000) {
+ newWidth = 200000;
+ }
+ this._width = newWidth;
}
+
/**
* The height of the project.
* @type {number}
*/
-
-
get height() {
return this._height;
}
-
set height(height) {
if (typeof height !== 'number') return;
if (height < 1) height = 1;
if (height > 200000) height = 200000;
this._height = height;
}
+
/**
* The framerate of the project.
* @type {number}
*/
-
-
get framerate() {
return this._framerate;
}
-
set framerate(framerate) {
if (typeof framerate !== 'number') return;
if (framerate < 1) framerate = 1;
if (framerate > 9999) framerate = 9999;
this._framerate = framerate;
}
+
/**
* The background color of the project.
* @type {string}
*/
-
-
get backgroundColor() {
return this._backgroundColor;
}
-
set backgroundColor(backgroundColor) {
this._backgroundColor = backgroundColor;
}
-
get hitTestOptions() {
return this._hitTestOptions;
}
-
set hitTestOptions(options) {
if (options) {
if (options.mode === 'CIRCLE' || options.mode === 'RECTANGLE' || options.mode === 'CONVEX') {
this._hitTestOptions.mode = options.mode;
}
-
if (typeof options.offset === 'boolean') {
this._hitTestOptions.offset = options.offset;
}
-
if (typeof options.overlap === 'boolean') {
this._hitTestOptions.overlap = options.overlap;
}
-
if (typeof options.intersections === 'boolean') {
this._hitTestOptions.intersections = options.intersections;
}
}
}
+
/**
* The timeline of the active clip.
* @type {Wick.Timeline}
*/
-
-
get activeTimeline() {
return this.focus.timeline;
}
+
/**
* The active layer of the active timeline.
* @type {Wick.Layer}
*/
-
-
get activeLayer() {
return this.activeTimeline.activeLayer;
}
+
/**
* The active frame of the active layer.
* @type {Wick.Frame}
*/
-
-
get activeFrame() {
return this.activeLayer.activeFrame;
}
+
/**
* The active frames of the active timeline.
* @type {Wick.Frame[]}
*/
-
-
get activeFrames() {
return this.focus.timeline.activeFrames;
}
+
/**
* All frames in this project.
* @type {Wick.Frame[]}
*/
-
-
getAllFrames() {
return this.root.timeline.getAllFrames(true);
}
+
/**
* The project selection.
* @type {Wick.Selection}
*/
-
-
get selection() {
return this.getChild('Selection');
}
-
set selection(selection) {
if (this.selection) {
this.removeChild(this.selection);
}
-
this.addChild(selection);
}
+
/**
* An instance of the Wick.History utility class for undo/redo functionality.
* @type {Wick.History}
*/
-
-
get history() {
return this._history;
}
-
set history(history) {
this._history = history;
}
+
/**
* Value used to determine the zoom of the canvas.
*/
-
-
get zoom() {
return this._zoom;
}
-
set zoom(z) {
const max = this.view.calculateFitZoom() * 10;
const min = .10;
this._zoom = Math.max(min, Math.min(max, z));
}
+
/**
* Undo the last action.
* @returns {boolean} true if there was something to undo, false otherwise.
*/
-
-
undo() {
// Undo discards in-progress brush strokes.
if (this._tools.brush.isInProgress()) {
this._tools.brush.discard();
-
return true;
}
-
this.selection.clear();
var success = this.project.history.popState();
return success;
}
+
/**
* Redo the last action that was undone.
* @returns {boolean} true if there was something to redo, false otherwise.
*/
-
-
redo() {
this.selection.clear();
var success = this.project.history.recoverState();
return success;
}
+
/**
* The assets belonging to the project.
* @type {Wick.Asset[]}
*/
-
-
get assets() {
return this.getChildren(['ImageAsset', 'SoundAsset', 'ClipAsset', 'FontAsset', 'SVGAsset']);
}
+
/**
* Adds an asset to the project.
* @param {Wick.Asset} asset - The asset to add to the project.
*/
-
-
addAsset(asset) {
if (this.assets.indexOf(asset) === -1) {
this.addChild(asset);
}
}
+
/**
* Removes an asset from the project. Also removes all instances of that asset from the project.
* @param {Wick.Asset} asset - The asset to remove from the project.
*/
-
-
removeAsset(asset) {
asset.removeAllInstances();
this.removeChild(asset);
}
+
/**
* Retrieve an asset from the project by its UUID.
* @param {string} uuid - The UUID of the asset to get.
* @return {Wick.Asset} The asset
*/
-
-
getAssetByUUID(uuid) {
var asset = this.getAssets().find(asset => {
return asset.uuid === uuid;
});
-
if (asset) {
return asset;
} else {
console.warn('Wick.Project.getAssetByUUID: No asset found with uuid ' + uuid);
}
}
+
/**
* Retrieve an asset from the project by its name.
* @param {string} name - The name of the asset to get.
* @return {Wick.Asset} The asset
*/
-
-
getAssetByName(name) {
return this.getAssets().find(asset => {
return asset.name === name;
});
}
+
/**
* The assets belonging to the project.
* @param {string} type - Optional, filter assets by type ("Sound"/"Image"/"Clip"/"Button")
* @returns {Wick.Asset[]} The assets in the project
*/
-
-
getAssets(type) {
if (!type) {
return this.assets;
@@ -50393,68 +50099,62 @@ Wick.Project = class extends Wick.Base {
});
}
}
+
/**
* A list of all "fontFamily" in the asset library.
* @returns {string[]}
*/
-
-
getFonts() {
return this.getAssets('Font').map(asset => {
return asset.fontFamily;
});
}
+
/**
* Check if a FontAsset with a given fontFamily exists in the project.
* @param {string} fontFamily - The font to check for
* @returns {boolean}
*/
-
-
hasFont(fontFamily) {
return this.getFonts().find(seekFontFamily => {
return seekFontFamily === fontFamily;
}) !== undefined;
}
+
/**
* The root clip.
* @type {Wick.Clip}
*/
-
-
get root() {
return this.getChild('Clip');
}
-
set root(root) {
if (this.root) {
this.removeChild(this.root);
}
-
this.addChild(root);
}
+
/**
* The currently focused clip.
* @type {Wick.Clip}
*/
-
-
get focus() {
return this._focus && Wick.ObjectCache.getObjectByUUID(this._focus);
}
-
set focus(focus) {
var focusChanged = this.focus !== null && this.focus !== focus;
this._focus = focus.uuid;
-
if (focusChanged) {
- this.selection.clear(); // Reset timelines of subclips of the newly focused clip
+ this.selection.clear();
+ // Reset timelines of subclips of the newly focused clip
focus.timeline.clips.forEach(subclip => {
subclip.timeline.playheadPosition = 1;
subclip.applySingleFramePosition(); // Make sure to visualize single frame clips properly.
- }); // Reset pan and zoom and clear selection on focus change
+ });
+ // Reset pan and zoom and clear selection on focus change
this.resetZoomAndPan();
} else {
// Make sure the single frame
@@ -50463,16 +50163,14 @@ Wick.Project = class extends Wick.Base {
});
}
}
+
/**
* The position of the mouse
* @type {object}
*/
-
-
get mousePosition() {
return this._mousePosition;
}
-
set mousePosition(mousePosition) {
this._lastMousePosition = {
x: this.mousePosition.x,
@@ -50480,12 +50178,11 @@ Wick.Project = class extends Wick.Base {
};
this._mousePosition = mousePosition;
}
+
/**
* The amount the mouse has moved in the last tick
* @type {object}
*/
-
-
get mouseMove() {
let moveX = this.mousePosition.x - this._lastMousePosition.x;
let moveY = this.mousePosition.y - this._lastMousePosition.y;
@@ -50494,93 +50191,82 @@ Wick.Project = class extends Wick.Base {
y: moveY
};
}
+
/**
* Determine if the mouse is down.
* @type {boolean}
*/
-
-
get isMouseDown() {
return this._isMouseDown;
}
-
set isMouseDown(isMouseDown) {
this._isMouseDown = isMouseDown;
}
+
/**
* The keys that are currenty held down.
* @type {string[]}
*/
-
-
get keysDown() {
return this._keysDown;
}
-
set keysDown(keysDown) {
this._keysDown = keysDown;
}
+
/**
* The keys were just pressed (i.e., are currently held down, but were not last tick).
* @type {string[]}
*/
-
-
get keysJustPressed() {
// keys that are in _keysDown, but not in _keysLastDown
return this._keysDown.filter(key => {
return this._keysLastDown.indexOf(key) === -1;
});
}
+
/**
* The keys that were just released (i.e. were down last tick back are no longer down.)
* @return {string[]}
*/
-
-
get keysJustReleased() {
return this._keysLastDown.filter(key => {
return this._keysDown.indexOf(key) === -1;
});
}
+
/**
* Check if a key is being pressed.
* @param {string} key - The name of the key to check
*/
-
-
isKeyDown(key) {
return this.keysDown.indexOf(key) !== -1;
}
+
/**
* Check if a key was just pressed.
* @param {string} key - The name of the key to check
*/
-
-
isKeyJustPressed(key) {
return this.keysJustPressed.indexOf(key) !== -1;
}
+
/**
* The key to be used in the global 'key' variable in the scripting API. Update currentKey before you run any key script.
* @type {string[]}
*/
-
-
get currentKey() {
return this._currentKey;
}
-
set currentKey(currentKey) {
this._currentKey = currentKey;
}
+
/**
* Creates an asset from a File object and adds that asset to the project.
* @param {File} file - File object to be read and converted into an asset.
* @param {function} callback Function with the created Wick Asset. Can be passed undefined on improper file input.
*/
-
-
importFile(file, callback) {
let imageTypes = Wick.ImageAsset.getValidMIMETypes();
let soundTypes = Wick.SoundAsset.getValidMIMETypes();
@@ -50591,24 +50277,20 @@ Wick.Project = class extends Wick.Base {
let soundExtensions = Wick.SoundAsset.getValidExtensions();
let fontExtensions = Wick.FontAsset.getValidExtensions();
let clipExtensions = Wick.ClipAsset.getValidExtensions();
- let svgExtensions = Wick.SVGAsset.getValidExtensions(); // Fix missing mimetype for wickobj files
+ let svgExtensions = Wick.SVGAsset.getValidExtensions();
+ // Fix missing mimetype for wickobj files
var type = file.type;
-
if (file.type === '' && file.name.endsWith('.wickobj')) {
type = 'application/json';
}
-
- var extension = "";
-
+ var extension = '';
if (file.name) {
extension = file.name.split('.').pop();
} else if (file.file && typeof file.file === 'string') {
extension = file.file.split('.').pop();
}
-
let asset = undefined;
-
if (imageTypes.indexOf(type) !== -1 || imageExtensions.indexOf(extension) !== -1) {
asset = new Wick.ImageAsset();
} else if (soundTypes.indexOf(type) !== -1 || soundExtensions.indexOf(extension) !== -1) {
@@ -50620,7 +50302,6 @@ Wick.Project = class extends Wick.Base {
} else if (svgTypes.indexOf(type) !== -1 || svgExtensions.indexOf(extension) !== -1) {
asset = new Wick.SVGAsset();
}
-
if (asset === undefined) {
console.warn('importFile(): Could not import file ' + file.name + ', filetype: "' + file.type + '" is not supported.');
console.warn('Supported File Types Are:', {
@@ -50640,9 +50321,7 @@ Wick.Project = class extends Wick.Base {
callback(null);
return;
}
-
let reader = new FileReader();
-
reader.onload = () => {
let dataURL = reader.result;
asset.src = dataURL;
@@ -50653,35 +50332,33 @@ Wick.Project = class extends Wick.Base {
callback(asset);
});
};
-
reader.readAsDataURL(file);
}
+
/**
* True if onion skinning is on. False otherwise.
*/
-
-
get onionSkinEnabled() {
return this._onionSkinEnabled;
}
-
set onionSkinEnabled(bool) {
- if (typeof bool !== "boolean") return; // Get all onion skinned frames, if we're turning off onion skinning.
+ if (typeof bool !== 'boolean') return;
+ // Get all onion skinned frames, if we're turning off onion skinning.
let onionSkinnedFrames = [];
if (!bool) onionSkinnedFrames = this.getAllOnionSkinnedFrames();
- this._onionSkinEnabled = bool; // Rerender any onion skinned frames.
+ this._onionSkinEnabled = bool;
+ // Rerender any onion skinned frames.
onionSkinnedFrames.forEach(frame => {
frame.view.render();
});
}
+
/**
* Returns all frames that should currently be onion skinned.
* @returns {Wick.Frame[]} Array of Wick frames that sould be onion skinned.
*/
-
-
getAllOnionSkinnedFrames() {
let onionSkinnedFrames = [];
this.activeTimeline.layers.forEach(layer => {
@@ -50692,11 +50369,10 @@ Wick.Project = class extends Wick.Base {
});
return onionSkinnedFrames;
}
+
/**
* Deletes all objects in the selection.
*/
-
-
deleteSelectedObjects() {
var objects = this.selection.getSelectedObjects();
this.selection.clear();
@@ -50710,12 +50386,11 @@ Wick.Project = class extends Wick.Base {
});
this.activeTimeline.resolveFrameGaps([]);
}
+
/**
* Perform a boolean operation on all selected paths.
* @param {string} booleanOpName - The name of the boolean op function to use. See Wick.Path.booleanOp.
*/
-
-
doBooleanOperationOnSelection(booleanOpName) {
var paths = this.selection.getSelectedObjects('Path');
this.selection.clear();
@@ -50725,21 +50400,18 @@ Wick.Project = class extends Wick.Base {
if (paths.indexOf(path) === paths.length - 1 && booleanOpName === 'subtract') {
return;
}
-
path.remove();
});
this.activeFrame.addPath(booleanOpResult);
this.selection.select(booleanOpResult);
}
+
/**
* Copy the contents of the selection to the clipboard.
* @returns {boolean} True if there was something to copy, false otherwise
*/
-
-
copySelectionToClipboard() {
var objects = this.selection.getSelectedObjects();
-
if (objects.length === 0) {
return false;
} else {
@@ -50747,12 +50419,11 @@ Wick.Project = class extends Wick.Base {
return true;
}
}
+
/**
* Copy the contents of the selection to the clipboard, and delete what was copied.
* @returns {boolean} True if there was something to cut, false otherwise
*/
-
-
cutSelectionToClipboard() {
if (this.copySelectionToClipboard()) {
this.deleteSelectedObjects();
@@ -50761,21 +50432,19 @@ Wick.Project = class extends Wick.Base {
return false;
}
}
+
/**
* Paste the contents of the clipboard into the project.
* @returns {boolean} True if there was something to paste in the clipboard, false otherwise.
*/
-
-
pasteClipboardContents() {
return this.clipboard.pasteObjectsFromClipboard(this);
}
+
/**
* Copy and paste the current selection.
* @returns {boolean} True if there was something to duplicate, false otherwise
*/
-
-
duplicateSelection() {
if (!this.copySelectionToClipboard()) {
return false;
@@ -50783,35 +50452,29 @@ Wick.Project = class extends Wick.Base {
return this.pasteClipboardContents();
}
}
+
/**
* Move the current selection above, below, or inside target.
* @param {object} target - The target object (to become parent of selection)
* @param {number} index - index to insert at
* @returns {boolean} - true if project did change
*/
-
-
moveSelection(target, index) {
// Indices give us a way to order the selection from top to bottom
let get_indices = obj => {
var indices = [];
-
while (obj.parent !== null) {
let parent = obj.parent;
-
if (parent.classname === 'Frame') {
indices.unshift(parent.getChildren().length - 1 - parent.getChildren().indexOf(obj));
} else {
indices.unshift(parent.getChildren().indexOf(obj));
}
-
obj = parent;
}
-
return indices;
- }; // Assumes i1, i2 same length, ordering same as outliner
-
-
+ };
+ // Assumes i1, i2 same length, ordering same as outliner
let compare_indices = (i1, i2) => {
for (let i = 0; i < i1.length; i++) {
if (i1[i] < i2[i]) {
@@ -50820,67 +50483,56 @@ Wick.Project = class extends Wick.Base {
return -1;
}
}
-
return 0;
};
-
let selection = this.selection.getSelectedObjects();
-
if (selection.length === 0) {
return false;
}
-
let selection_indices = selection.map(get_indices);
let l = selection_indices[0].length;
-
for (let i = 0; i < selection_indices.length; i++) {
if (selection_indices[i].length !== l) {
// Must all have the same depth
return false;
}
}
-
let zip = selection_indices.map((o, i) => {
return [o, selection[i]];
});
zip.sort(([i1], [i2]) => compare_indices(i1, i2));
-
if (target.classname === 'Frame') {
// Render order is reversed for children of frames
zip.reverse();
}
-
for (let i = 0; i < zip.length; i++) {
let [, obj] = zip[i];
index -= target.insertChild(obj, index) ? 1 : 0;
}
-
return true;
}
+
/**
* Cut the currently selected frames.
*/
-
-
cutSelectedFrames() {
this.selection.getSelectedObjects('Frame').forEach(frame => {
frame.cut();
});
}
+
/**
* Inserts a blank frame into the timeline at the position of the playhead.
* If the playhead is over an existing frame, that frame will be cut in half,
* and a blank frame will be added to fill the empty space created by the cut.
*/
-
-
insertBlankFrame() {
var playheadPosition = this.activeTimeline.playheadPosition;
- var newFrames = []; // Insert new frames
+ var newFrames = [];
+ // Insert new frames
if (this.selection.numObjects > 0) {
// Insert frames on all frames that are both active and selected
-
/*this.activeTimeline.activeFrames.filter(frame => {
return frame.isSelected;
}).forEach(frame => {
@@ -50892,21 +50544,19 @@ Wick.Project = class extends Wick.Base {
} else {
// Insert one frame on the active layer
newFrames.push(this.activeLayer.insertBlankFrame(playheadPosition));
- } // Select the newly added frames
-
+ }
+ // Select the newly added frames
this.selection.clear();
this.selection.selectMultipleObjects(newFrames);
}
+
/**
* A tween can be created if frames are selected or if there is a frame under the playhead on the active layer.
*/
-
-
get canCreateTween() {
// Frames are selected, a tween can be created
var selectedFrames = this.selection.getSelectedObjects('Frame');
-
if (selectedFrames.length > 0) {
// Make sure you can only create tweens on contentful frames
if (selectedFrames.find(frame => {
@@ -50916,26 +50566,22 @@ Wick.Project = class extends Wick.Base {
} else {
return true;
}
- } // There is a frame under the playhead on the active layer, a tween can be created
-
+ }
+ // There is a frame under the playhead on the active layer, a tween can be created
var activeFrame = this.activeLayer.activeFrame;
-
if (activeFrame) {
// ...but only if that frame is contentful
return activeFrame.contentful;
}
-
return false;
}
+
/**
* Create a new tween on all selected frames OR on the active frame of the active layer.
*/
-
-
createTween() {
var selectedFrames = this.selection.getSelectedObjects('Frame');
-
if (selectedFrames.length > 0) {
// Create a tween on all selected frames
this.selection.getSelectedObjects('Frame').forEach(frame => {
@@ -50946,23 +50592,20 @@ Wick.Project = class extends Wick.Base {
this.activeLayer.activeFrame.createTween();
}
}
+
/**
* Tries to create a tween if there is an empty space between tweens.
*/
-
-
tryToAutoCreateTween() {
var frame = this.activeFrame;
-
if (frame.tweens.length > 0 && !frame.getTweenAtPosition(frame.getRelativePlayheadPosition())) {
frame.createTween();
}
}
+
/**
* Move the right edge of all frames right one frame.
*/
-
-
extendFrames(frames) {
frames.forEach(frame => {
frame.end++;
@@ -50970,21 +50613,19 @@ Wick.Project = class extends Wick.Base {
this.activeTimeline.resolveFrameOverlap(frames);
this.activeTimeline.resolveFrameGaps(frames);
}
+
/**
* Move the right edge of all frames right one frame, and push other frames away.
*/
-
-
extendFramesAndPushOtherFrames(frames) {
frames.forEach(frame => {
frame.extendAndPushOtherFrames();
});
}
+
/**
* Move the right edge of all frames left one frame.
*/
-
-
shrinkFrames(frames) {
frames.forEach(frame => {
if (frame.length === 1) return;
@@ -50993,21 +50634,19 @@ Wick.Project = class extends Wick.Base {
this.activeTimeline.resolveFrameOverlap(frames);
this.activeTimeline.resolveFrameGaps(frames);
}
+
/**
* Move the right edge of all frames left one frame, and pull other frames along.
*/
-
-
shrinkFramesAndPullOtherFrames(frames) {
frames.forEach(frame => {
frame.shrinkAndPullOtherFrames();
});
}
+
/**
* Shift all selected frames over one frame to the right
*/
-
-
moveSelectedFramesRight() {
var frames = this.selection.getSelectedObjects('Frame');
frames.forEach(frame => {
@@ -51017,11 +50656,10 @@ Wick.Project = class extends Wick.Base {
this.activeTimeline.resolveFrameOverlap(frames);
this.activeTimeline.resolveFrameGaps();
}
+
/**
* Shift all selected frames over one frame to the left
*/
-
-
moveSelectedFramesLeft() {
var frames = this.selection.getSelectedObjects('Frame');
frames.forEach(frame => {
@@ -51031,11 +50669,10 @@ Wick.Project = class extends Wick.Base {
this.activeTimeline.resolveFrameOverlap(frames);
this.activeTimeline.resolveFrameGaps();
}
+
/**
* Selects all objects that are visible on the canvas (excluding locked layers and onion skinned objects)
*/
-
-
selectAll() {
let objectsToAdd = [];
this.selection.clear();
@@ -51051,6 +50688,7 @@ Wick.Project = class extends Wick.Base {
});
this.selection.selectMultipleObjects(objectsToAdd);
}
+
/**
* Adds an image path to the active frame using a given asset as its image src.
* @param {Wick.Asset} asset - the asset to use for the image src
@@ -51058,8 +50696,6 @@ Wick.Project = class extends Wick.Base {
* @param {number} y - the y position to create the image path at
* @param {function} callback - the function to call after the path is created.
*/
-
-
createImagePathFromAsset(asset, x, y, callback) {
let playheadPosition = this.focus.timeline.playheadPosition;
if (!this.activeFrame) this.activeLayer.insertBlankFrame(playheadPosition);
@@ -51070,6 +50706,7 @@ Wick.Project = class extends Wick.Base {
callback(path);
});
}
+
/**
* Adds an instance of a clip asset to the active frame.
* @param {Wick.Asset} asset - the asset to create the clip instance from
@@ -51077,8 +50714,6 @@ Wick.Project = class extends Wick.Base {
* @param {number} y - the y position to create the image path at
* @param {function} callback - the function to call after the path is created.
*/
-
-
createClipInstanceFromAsset(asset, x, y, callback) {
let playheadPosition = this.focus.timeline.playheadPosition;
if (!this.activeFrame) this.activeLayer.insertBlankFrame(playheadPosition);
@@ -51089,6 +50724,7 @@ Wick.Project = class extends Wick.Base {
callback(clip);
}, this);
}
+
/**
* Adds an instance of a clip asset to the active frame.
* @param {Wick.Asset} asset - the asset to create the SVG file instance from
@@ -51096,40 +50732,32 @@ Wick.Project = class extends Wick.Base {
* @param {number} y - the y position to import the SVG file at
* @param {function} callback - the function to call after the path is created.
*/
-
-
createSVGInstanceFromAsset(asset, x, y, callback) {
let playheadPosition = this.focus.timeline.playheadPosition;
if (!this.activeFrame) this.activeLayer.insertBlankFrame(playheadPosition);
asset.createInstance(svg => {
this.addObject(svg);
svg.x = x;
- svg.y = y; //this.addObject(svg);
-
+ svg.y = y;
+ //this.addObject(svg);
callback(svg);
});
}
+
/**
* Creates a symbol from the objects currently selected.
* @param {string} identifier - the identifier to give the new symbol
* @param {string} type - "Clip" or "Button"
*/
-
-
createClipFromSelection(args) {
if (!args) {
args = {};
}
-
- ;
-
if (args.type !== 'Clip' && args.type !== 'Button') {
console.error('createClipFromSelection: invalid type: ' + args.type);
return;
}
-
let clip;
-
if (args.type === 'Button') {
clip = new Wick[args.type]({
project: this,
@@ -51150,19 +50778,19 @@ Wick.Project = class extends Wick.Base {
})
});
clip.addObjects(this.selection.getSelectedObjects('Canvas'));
- } // Add the clip to the frame prior to adding objects.
-
+ }
- this.activeFrame.addClip(clip); // TODO add to asset library
+ // Add the clip to the frame prior to adding objects.
+ this.activeFrame.addClip(clip);
+ // TODO add to asset library
this.selection.clear();
this.selection.select(clip);
}
+
/**
* Breaks selected clips into their children clips and paths.
*/
-
-
breakApartSelection() {
var leftovers = [];
var clips = this.selection.getSelectedObjects('Clip');
@@ -51172,44 +50800,38 @@ Wick.Project = class extends Wick.Base {
});
this.selection.selectMultipleObjects(leftovers);
}
+
/**
* Sets the project focus to the timeline of the selected clip.
* @returns {boolean} True if selected clip is focused, false otherwise.
*/
-
-
focusTimelineOfSelectedClip() {
if (this.selection.getSelectedObject() instanceof Wick.Clip) {
this.focus = this.selection.getSelectedObject();
return true;
}
-
return false;
}
+
/**
* Sets the project focus to the parent timeline of the currently focused clip.
* @returns {boolean} True if parent clip is focused, false otherwise.
*/
-
-
focusTimelineOfParentClip() {
if (!this.focus.isRoot) {
this.focus = this.focus.parentClip;
return true;
}
-
return false;
}
+
/**
* Plays the sound in the asset library with the given name.
* @param {string} assetName - Name of the sound asset to play
* @param {Object} options - options for the sound. See Wick.SoundAsset.play
*/
-
-
playSound(assetName, options) {
var asset = this.getAssetByName(assetName);
-
if (!asset) {
console.warn('playSound(): No asset with name: "' + assetName + '"');
} else if (!(asset instanceof Wick.SoundAsset)) {
@@ -51218,29 +50840,25 @@ Wick.Project = class extends Wick.Base {
return this.playSoundFromAsset(asset, options);
}
}
+
/**
* Generates information for a single sound that is being played.
* @param {Wick.Asset} asset - Asset to be played.
* @param {Object} options - Options including start (ms), end (ms), offset (ms), src (sound source), filetype (string).
*/
-
-
generateSoundInfo(asset, options) {
if (!asset) return {};
if (!options) options = {};
let playheadPosition = this.focus.timeline.playheadPosition;
let soundStartMS = 1000 / this.framerate * (playheadPosition - 1); // Adjust by one to account for sounds on frame 1 starting at 0ms.
-
let soundEndMS = 0;
let seekMS = options.seekMS || 0;
-
if (options.frame) {
let soundLengthInFrames = options.frame.end - (options.frame.start - 1);
soundEndMS = soundStartMS + 1000 / this.framerate * soundLengthInFrames;
} else {
soundEndMS = soundStartMS + asset.duration * 1000;
}
-
let soundInfo = {
playheadPosition: playheadPosition,
start: soundStartMS,
@@ -51251,31 +50869,28 @@ Wick.Project = class extends Wick.Base {
name: asset.name,
volume: options.volume || 1,
playedFrom: options.playedFrom || undefined // uuid of object that played the sound.
-
};
+
return soundInfo;
}
+
/**
* Plays a sound from a presented asset.
* @param {Wick.SoundAsset} asset - Name of the sound asset to play.
*/
-
-
playSoundFromAsset(asset, options) {
let soundInfo = this.generateSoundInfo(asset, options);
this.soundsPlayed.push(soundInfo);
return asset.play(options);
}
+
/**
* Stops sound(s) currently playing.
* @param {string} assetName - The name of the SoundAsset to stop.
* @param {number} id - (optional) The ID of the sound to stop. Returned by playSound. If an ID is not given, all instances of the given sound asset will be stopped.
*/
-
-
stopSound(id) {
var asset = this.getAssetByName(assetName);
-
if (!asset) {
console.warn('stopSound(): No asset with name: "' + assetName + '"');
} else if (!(asset instanceof Wick.SoundAsset)) {
@@ -51284,128 +50899,113 @@ Wick.Project = class extends Wick.Base {
return asset.stop(id);
}
}
+
/**
* Stops all sounds playing from frames and sounds played using playSound().
*/
-
-
stopAllSounds() {
// Stop all sounds started with Wick.Project.playSound();
this.getAssets('Sound').forEach(soundAsset => {
soundAsset.stop();
- }); // Stop all sounds on frames
+ });
+ // Stop all sounds on frames
this.getAllFrames().forEach(frame => {
frame.stopSound();
});
}
+
/**
* Disable all sounds from playing
*/
-
-
mute() {
this._muted = true;
}
+
/**
* Enable all sounds to play
*/
-
-
unmute() {
this._muted = false;
}
+
/**
* Is the project currently muted?
* @type {boolean}
*/
-
-
get muted() {
return this._muted;
}
+
/**
* Should the project render black bars around the canvas area?
* (These only show up if the size of the window/element that the project
* is inside is a different size than the project dimensions).
* @type {boolean}
*/
-
-
get renderBlackBars() {
return this._renderBlackBars;
}
-
set renderBlackBars(renderBlackBars) {
this._renderBlackBars = renderBlackBars;
}
+
/**
* In "Published Mode", all layers will be rendered even if they are set to be hidden.
* This is enabled during GIF/Video export, and enabled when the project is run standalone.
* @type {boolean}
*/
-
-
get publishedMode() {
return this._publishedMode;
}
-
set publishedMode(publishedMode) {
let validModes = [false, "interactive", "imageSequence", "audioSequence"];
-
if (validModes.indexOf(publishedMode) === -1) {
throw new Error("Published Mode: " + publishedMode + " is invalid. Must be one of type: " + validModes);
}
-
this._publishedMode = publishedMode;
}
+
/**
* Returns true if the project is published, false otherwise.
*/
-
-
get isPublished() {
return this.publishedMode !== false;
}
+
/**
* Toggle whether or not to render borders around clips.
* @type {boolean}
*/
-
-
get showClipBorders() {
return this._showClipBorders;
}
-
set showClipBorders(showClipBorders) {
this._showClipBorders = showClipBorders;
}
+
/**
* The current error, if one was thrown, during the last tick.
* @type {Object}
*/
-
-
get error() {
return this._error;
}
-
set error(error) {
if (this._error && error) {
return;
- } else if (error && !this._error) {// console.error(error);
+ } else if (error && !this._error) {
+ // console.error(error);
}
-
this._error = error;
}
+
/**
* Schedules a script to be run at the end of the current tick.
* @param {string} uuid - the UUID of the object running the script.
* @param {string} name - the name of the script to run, see Tickable.possibleScripts.
* @param {Object} parameters - An object of key,value pairs to send as parameters to the script which runs.
*/
-
-
scheduleScript(uuid, name, parameters) {
this._scriptSchedule.push({
uuid: uuid,
@@ -51413,11 +51013,10 @@ Wick.Project = class extends Wick.Base {
parameters: parameters
});
}
+
/**
* Run scripts in schedule, in order based on Tickable.possibleScripts.
*/
-
-
runScheduledScripts() {
Wick.Tickable.possibleScripts.forEach(scriptOrderName => {
this._scriptSchedule.forEach(scheduledScript => {
@@ -51425,26 +51024,27 @@ Wick.Project = class extends Wick.Base {
uuid,
name,
parameters
- } = scheduledScript; // Make sure we only run the script based on the current iteration through possibleScripts
+ } = scheduledScript;
+ // Make sure we only run the script based on the current iteration through possibleScripts
if (name !== scriptOrderName) {
return;
- } // Run the script on the corresponding object!
-
+ }
+ // Run the script on the corresponding object!
Wick.ObjectCache.getObjectByUUID(uuid).runScript(name, parameters);
});
});
}
+
/**
* Checks if the project is currently playing.
* @type {boolean}
*/
-
-
get playing() {
return this._playing;
}
+
/**
* Start playing the project.
* Arguments: onError: Called when a script error occurs during a tick.
@@ -51452,8 +51052,6 @@ Wick.Project = class extends Wick.Base {
* onAfterTick: Called after every tick
* @param {object} args - Optional arguments
*/
-
-
play(args) {
if (!args) args = {};
if (!args.onError) args.onError = () => {};
@@ -51462,77 +51060,80 @@ Wick.Project = class extends Wick.Base {
window._scriptOnErrorCallback = args.onError;
this._playing = true;
this.view.paper.view.autoUpdate = false;
-
if (this._tickIntervalID) {
this.stop();
}
-
this.error = null;
this.history.saveSnapshot('state-before-play');
- this.selection.clear(); // Start tick loop
+ this.selection.clear();
+ // Start tick loop
this._tickIntervalID = setInterval(() => {
args.onBeforeTick();
- this.tools.interact.determineMouseTargets(); // console.time('tick');
+ this.tools.interact.determineMouseTargets();
+ // console.time('tick');
+ var error = this.tick();
+ // console.timeEnd('tick');
- var error = this.tick(); // console.timeEnd('tick');
// console.time('update');
-
- this.view.paper.view.update(); // console.timeEnd('update');
+ this.view.paper.view.update();
+ // console.timeEnd('update');
if (error) {
this.stop();
return;
- } // console.time('afterTick');
-
+ }
- args.onAfterTick(); // console.timeEnd('afterTick');
+ // console.time('afterTick');
+ args.onAfterTick();
+ // console.timeEnd('afterTick');
}, 1000 / this.framerate);
}
+
/**
* Ticks the project.
* @returns {object} An object containing information about an error, if one occured while running scripts. Null otherwise.
*/
-
-
tick() {
- this.root._identifier = 'Project'; // Process input
+ this.root._identifier = 'Project';
+ // Process input
this._mousePosition = this.tools.interact.mousePosition;
this._isMouseDown = this.tools.interact.mouseIsDown;
this._keysDown = this.tools.interact.keysDown;
this._currentKey = this.tools.interact.lastKeyDown;
- this._mouseTargets = this.tools.interact.mouseTargets; // Reset scripts before ticking
+ this._mouseTargets = this.tools.interact.mouseTargets;
- this._scriptSchedule = []; // Tick the focused clip
+ // Reset scripts before ticking
+ this._scriptSchedule = [];
+ // Tick the focused clip
this.focus._attachChildClipReferences();
-
this.focus.tick();
- this.runScheduledScripts(); // Save the current keysDown
+ this.runScheduledScripts();
+ // Save the current keysDown
this._lastMousePosition = {
x: this._mousePosition.x,
y: this._mousePosition.y
};
this._keysLastDown = [].concat(this._keysDown);
this.view.render();
-
if (this._error) {
return this._error;
} else {
return null;
}
}
+
/**
* Stop playing the project.
*/
-
-
stop() {
this._playing = false;
- this.view.paper.view.autoUpdate = true; // Run unload scripts on all objects
+ this.view.paper.view.autoUpdate = true;
+ // Run unload scripts on all objects
this.getAllFrames().forEach(frame => {
frame.clips.forEach(clip => {
clip.scheduleScript('unload');
@@ -51541,45 +51142,46 @@ Wick.Project = class extends Wick.Base {
this.runScheduledScripts();
this.stopAllSounds();
clearInterval(this._tickIntervalID);
- this._tickIntervalID = null; // Loading the snapshot to restore project state also moves the playhead back to where it was originally.
- // We actually don't want this, preview play should actually move the playhead after it's stopped.
+ this._tickIntervalID = null;
- var currentPlayhead = this.focus.timeline.playheadPosition; // Load the state of the project before it was played
+ // Loading the snapshot to restore project state also moves the playhead back to where it was originally.
+ // We actually don't want this, preview play should actually move the playhead after it's stopped.
+ var currentPlayhead = this.focus.timeline.playheadPosition;
- this.history.loadSnapshot('state-before-play'); // Wick.ObjectCache.removeUnusedObjects(this);
+ // Load the state of the project before it was played
+ this.history.loadSnapshot('state-before-play');
+ // Wick.ObjectCache.removeUnusedObjects(this);
if (this.error) {
// An error occured.
var errorObjUUID = this._error.uuid;
- var errorObj = Wick.ObjectCache.getObjectByUUID(errorObjUUID); // Focus the parent of the object that caused the error so that we can select the error-causer.
+ var errorObj = Wick.ObjectCache.getObjectByUUID(errorObjUUID);
- this.focus = errorObj.parentClip; // Select the object that caused the error
+ // Focus the parent of the object that caused the error so that we can select the error-causer.
+ this.focus = errorObj.parentClip;
+ // Select the object that caused the error
this.selection.clear();
this.selection.select(errorObj);
window._scriptOnErrorCallback && window._scriptOnErrorCallback(this.error);
} else {
this.focus.timeline.playheadPosition = currentPlayhead;
}
-
this.resetCache();
delete window._scriptOnErrorCallback;
}
+
/**
* Inject the project into an element on a webpage and start playing the project.
* @param {Element} element - the element to inject the project into
*/
-
-
inject(element) {
this.view.canvasContainer = element;
this.view.fitMode = 'fill';
this.view.canvasBGColor = this.backgroundColor.hex;
-
window.onresize = function () {
project.view.resize();
};
-
this.view.resize();
this.view.prerender();
this.focus = this.root;
@@ -51595,11 +51197,10 @@ Wick.Project = class extends Wick.Base {
}
});
}
+
/**
* Sets zoom and pan such that the canvas fits in the window, with some padding.
*/
-
-
recenter() {
this.pan = {
x: 0,
@@ -51609,11 +51210,10 @@ Wick.Project = class extends Wick.Base {
this.zoom = this.view.calculateFitZoom();
this.zoom *= paddingResize;
}
+
/**
* Resets zoom and pan (zoom resets to 1.0, pan resets to (0,0)).
*/
-
-
resetZoomAndPan() {
this.pan = {
x: 0,
@@ -51621,99 +51221,86 @@ Wick.Project = class extends Wick.Base {
};
this.zoom = 1;
}
+
/**
* Zooms the canvas in.
*/
-
-
zoomIn() {
this.zoom *= 1.25;
}
+
/**
* Zooms the canvas out.
*/
-
-
zoomOut() {
this.zoom *= 0.8;
}
+
/**
* Resets all tools in the project.
*/
-
-
resetTools() {
for (let toolName of Object.keys(this.tools)) {
let tool = this.tools[toolName];
tool.reset();
}
}
+
/**
* All tools belonging to the project.
* @type {Array}
*/
-
-
get tools() {
return this._tools;
}
+
/**
* The tool settings for the project's tools.
* @type {Wick.ToolSettings}
*/
-
-
get toolSettings() {
return this._toolSettings;
}
+
/**
* The currently activated tool.
* @type {Wick.Tool}
*/
-
-
get activeTool() {
return this._activeTool;
}
-
set activeTool(activeTool) {
var newTool;
-
if (typeof activeTool === 'string') {
var tool = this.tools[activeTool];
-
if (!tool) {
console.error('set activeTool: invalid tool: ' + activeTool);
}
-
newTool = tool;
} else {
newTool = activeTool;
- } // Clear selection if we changed between drawing tools
-
+ }
+ // Clear selection if we changed between drawing tools
if (newTool.name !== 'pan' && newTool.name !== 'eyedropper' && newTool.name !== 'cursor') {
this.selection.clear();
}
-
this._activeTool = newTool;
}
+
/**
* Returns an object associated with this project, by uuid.
* @param {string} uuid
*/
-
-
getObjectByUUID(uuid) {
return Wick.ObjectCache.getObjectByUUID(uuid);
}
+
/**
* Adds an object to the project.
* @param {Wick.Base} object
* @return {boolean} returns true if the obejct was added successfully, false otherwise.
*/
-
-
addObject(object) {
if (object instanceof Wick.Path) {
this.activeFrame.addPath(object);
@@ -51730,9 +51317,120 @@ Wick.Project = class extends Wick.Base {
} else {
return false;
}
-
return true;
}
+
+ /**
+ * Create a sequence of images from every frame in the project.
+ * @param {object} args - Options for generating the image sequence
+ * @param {string} imageType - MIMEtype to use for rendered image. Defaults to 'image/png'.
+ * @param {function} onProgress - Function to call for image loaded, useful for progress bars?
+ * @param {function} onFinish - Function to call when the image is loaded.
+ */
+ generateImageFile(args) {
+ let options = {};
+ if (args) {
+ options = {
+ ...args
+ };
+ }
+ if (!options.imageType) {
+ options.imageType = 'image/png';
+ }
+ if (!options.onProgress) {
+ options.onProgress = () => {};
+ }
+ if (!options.onFinish) {
+ options.onFinish = () => {};
+ }
+ if (!options.width) {
+ options.width = this.width;
+ }
+ if (!options.height) {
+ options.height = this.height;
+ }
+
+ // console.log('generateImageFile', options);
+
+ var renderCopy = this;
+ console.log('renderCopy/project', renderCopy);
+ renderCopy.renderBlackBars = false; // Turn off black bars (removes black lines)
+
+ var oldBackgroundColor = renderCopy._backgroundColor;
+ renderCopy._backgroundColor = new Wick.Color('#00000000');
+ var oldCanvasContainer = this.view.canvasContainer;
+ this.history.saveSnapshot('before-gif-render');
+ this.mute();
+ this.selection.clear();
+ // this.publishedMode = 'imageSequence';
+ // this.tick();
+
+ // Put the project canvas inside a div that's the same size as the project
+ // so the frames render at the correct resolution.
+ let container = window.document.createElement('div');
+ container.style.width = options.width / window.devicePixelRatio + 'px';
+ container.style.height = options.height / window.devicePixelRatio + 'px';
+ window.document.body.appendChild(container);
+ renderCopy.view.canvasContainer = container;
+ renderCopy.view.resize();
+ let oldZoom = renderCopy.zoom;
+
+ // Calculate the zoom needed to fit the project into the requested container width/height
+ var zoom = 1;
+ if (options.height < options.width) {
+ zoom = options.height / this.height;
+ } else {
+ zoom = options.width / this.width;
+ }
+
+ // Set the initial state of the project.
+ renderCopy.focus = renderCopy.root;
+ // renderCopy.focus.timeline.playheadPosition = 1;
+ renderCopy.onionSkinEnabled = false;
+ renderCopy.zoom = zoom / window.devicePixelRatio;
+ renderCopy.pan = {
+ x: 0,
+ y: 0
+ };
+
+ // renderCopy.tick();
+
+ // We need full control over when paper.js renders,
+ // if we leave autoUpdate on, it's possible to lose frames if paper.js doesnt automatically
+ // render as fast as we are generating the images.
+ // (See paper.js docs for info about autoUpdate)
+ renderCopy.view.paper.view.autoUpdate = false;
+
+ // var frameImages = [];
+ // var numMaxFrameImages = renderCopy.focus.timeline.length;
+
+ this.resetSoundsPlayed();
+
+ // Do the image render
+ var image = new Image();
+ image.onload = () => {
+ // console.log('Image onload', image);
+ options.onProgress(1, 1);
+
+ // reset autoUpdate back to normal
+ renderCopy.view.paper.view.autoUpdate = true;
+ this.view.canvasContainer = oldCanvasContainer;
+ this.view.resize();
+ this.history.loadSnapshot('before-gif-render');
+ // this.publishedMode = false;
+ this.view.render();
+ renderCopy._backgroundColor = oldBackgroundColor;
+ renderCopy.zoom = oldZoom;
+ window.document.body.removeChild(container);
+ options.onFinish(image);
+ };
+
+ // console.log('Image src render()', image);
+ renderCopy.view.render();
+ renderCopy.view.paper.view.update();
+ image.src = renderCopy.view.canvas.toDataURL(options.imageType);
+ }
+
/**
* Create a sequence of images from every frame in the project.
* @param {object} args - Options for generating the image sequence
@@ -51740,8 +51438,6 @@ Wick.Project = class extends Wick.Base {
* @param {function} onProgress - Function to call for each image loaded, useful for progress bars
* @param {function} onFinish - Function to call when the images are all loaded.
*/
-
-
generateImageSequence(args) {
if (!args) args = {};
if (!args.imageType) args.imageType = 'image/png';
@@ -51756,25 +51452,26 @@ Wick.Project = class extends Wick.Base {
this.history.saveSnapshot('before-gif-render');
this.mute();
this.selection.clear();
- this.publishedMode = "imageSequence"; // this.tick();
- // Put the project canvas inside a div that's the same size as the project so the frames render at the correct resolution.
+ this.publishedMode = "imageSequence";
+ // this.tick();
+ // Put the project canvas inside a div that's the same size as the project so the frames render at the correct resolution.
let container = window.document.createElement('div');
container.style.width = args.width / window.devicePixelRatio + 'px';
container.style.height = args.height / window.devicePixelRatio + 'px';
window.document.body.appendChild(container);
renderCopy.view.canvasContainer = container;
- renderCopy.view.resize(); // Calculate the zoom needed to fit the project into the requested container width/height
+ renderCopy.view.resize();
+ // Calculate the zoom needed to fit the project into the requested container width/height
var zoom = 1;
-
if (args.height < args.width) {
zoom = args.height / this.height;
} else {
zoom = args.width / this.width;
- } // Set the initial state of the project.
-
+ }
+ // Set the initial state of the project.
renderCopy.focus = renderCopy.root;
renderCopy.focus.timeline.playheadPosition = 1;
renderCopy.onionSkinEnabled = false;
@@ -51782,22 +51479,21 @@ Wick.Project = class extends Wick.Base {
renderCopy.pan = {
x: 0,
y: 0
- }; // renderCopy.tick();
+ };
+
+ // renderCopy.tick();
+
// We need full control over when paper.js renders, if we leave autoUpdate on, it's possible to lose frames if paper.js doesnt automatically render as fast as we are generating the images.
// (See paper.js docs for info about autoUpdate)
-
renderCopy.view.paper.view.autoUpdate = false;
var frameImages = [];
var numMaxFrameImages = renderCopy.focus.timeline.length;
-
var renderFrame = () => {
var frameImage = new Image();
-
frameImage.onload = () => {
frameImages.push(frameImage);
var currentPos = renderCopy.focus.timeline.playheadPosition;
args.onProgress(currentPos, numMaxFrameImages);
-
if (currentPos >= numMaxFrameImages) {
// reset autoUpdate back to normal
renderCopy.view.paper.view.autoUpdate = true;
@@ -51815,24 +51511,20 @@ Wick.Project = class extends Wick.Base {
renderFrame();
}
};
-
renderCopy.view.render();
renderCopy.view.paper.view.update();
frameImage.src = renderCopy.view.canvas.toDataURL(args.imageType);
};
-
this.resetSoundsPlayed();
renderFrame();
}
-
resetSoundsPlayed() {
this.soundsPlayed = [];
}
+
/**
* Play the project through to generate an audio track.
*/
-
-
generateAudioSequence(args) {
if (!args) args = {};
if (!args.onProgress) args.onProgress = (frame, maxFrames) => {};
@@ -51842,25 +51534,27 @@ Wick.Project = class extends Wick.Base {
this.history.saveSnapshot('before-audio-render');
this.mute();
this.selection.clear();
- this.publishedMode = "audioSequence"; // Put the project canvas inside a div that's the same size as the project so the frames render at the correct resolution.
+ this.publishedMode = "audioSequence";
+ // Put the project canvas inside a div that's the same size as the project so the frames render at the correct resolution.
let container = window.document.createElement('div');
container.style.width = args.width / window.devicePixelRatio + 'px';
container.style.height = args.height / window.devicePixelRatio + 'px';
window.document.body.appendChild(container);
renderCopy.view.canvasContainer = container;
- renderCopy.view.resize(); // Set the initial state of the project.
+ renderCopy.view.resize();
+ // Set the initial state of the project.
renderCopy.focus = renderCopy.root;
- renderCopy.focus.timeline.playheadPosition = 1; // renderCopy.tick(); // This is commented out to not miss frame 1.
+ renderCopy.focus.timeline.playheadPosition = 1;
+
+ // renderCopy.tick(); // This is commented out to not miss frame 1.
renderCopy.view.paper.view.autoUpdate = false;
var numMaxFrameImages = renderCopy.focus.timeline.length;
-
var renderFrame = () => {
var currentPos = renderCopy.focus.timeline.playheadPosition;
args.onProgress(currentPos, numMaxFrameImages);
-
if (currentPos >= numMaxFrameImages) {
// reset autoUpdate back to normal
renderCopy.view.paper.view.autoUpdate = true;
@@ -51878,10 +51572,10 @@ Wick.Project = class extends Wick.Base {
renderFrame();
}
};
-
this.resetSoundsPlayed();
renderFrame();
}
+
/**
* Create an object containing info on all sounds in the project.
* Format:
@@ -51891,8 +51585,6 @@ Wick.Project = class extends Wick.Base {
* src: The source of the sound as a dataURL.
* filetype: The file type of the sound asset.
*/
-
-
getAudioInfo() {
return this.root.timeline.frames.filter(frame => {
return frame.sound !== null;
@@ -51906,13 +51598,12 @@ Wick.Project = class extends Wick.Base {
};
});
}
+
/**
* Generate an audiobuffer containing all the project's sounds merged together.
* @param {object} args - takes soundInfo (list of soundInfo to use for audioGeneration).
* @param {Function} callback - callback used to recieve the final audiobuffer.
*/
-
-
generateAudioTrack(args, callback) {
var audioTrack = new Wick.AudioTrack(this);
audioTrack.toAudioBuffer({
@@ -51921,65 +51612,57 @@ Wick.Project = class extends Wick.Base {
onProgress: args.onProgress
});
}
+
/**
* Check if an object is a mouse target (if the mouse is currently hovered over the object)
* @param {Wick.Tickable} object - the object to check if it is a mouse target
*/
-
-
objectIsMouseTarget(object) {
return this._mouseTargets.indexOf(object) !== -1;
}
+
/**
* Whether or not to hide the cursor while project is playing.
* @type {boolean}
*/
-
-
get hideCursor() {
return this._hideCursor;
}
-
set hideCursor(hideCursor) {
this._hideCursor = hideCursor;
}
+
/**
* Returns true if there is currently an active frame to draw onto.
* @type {boolean}
*/
-
-
get canDraw() {
return !this.activeLayer.locked && !this.activeLayer.hidden;
}
+
/**
* Loads all Assets in the project's asset library. This must be called after opening a project.
* @param {function} callback - Called when all assets are done loading.
*/
-
-
loadAssets(callback) {
if (this.assets.length === 0) {
callback();
return;
}
-
var loadedAssetCount = 0;
this.assets.forEach(asset => {
asset.load(() => {
loadedAssetCount++;
-
if (loadedAssetCount === this.assets.length) {
callback();
}
});
});
}
+
/**
* Remove assets from the project that are never used.
*/
-
-
cleanupUnusedAssets() {
this.assets.forEach(asset => {
if (!asset.hasInstances()) {
@@ -51987,7 +51670,6 @@ Wick.Project = class extends Wick.Base {
}
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -52015,11 +51697,10 @@ Wick.Selection = class extends Wick.Base {
static get LOCATION_NAMES() {
return ['Canvas', 'Timeline', 'AssetLibrary'];
}
+
/**
* Create a Wick Selection.
*/
-
-
constructor(args) {
if (!args) args = {};
super(args);
@@ -52034,10 +51715,8 @@ Wick.Selection = class extends Wick.Base {
this.SELECTABLE_OBJECT_TYPES = ['Path', 'Clip', 'Frame', 'Tween', 'Layer', 'Asset', 'Button', 'ClipAsset', 'FileAsset', 'FontAsset', 'GIFAsset', 'ImageAsset', 'SoundAsset', 'SVGAsset'];
this.SELECTABLE_OBJECT_TYPES_SET = new Set(this.SELECTABLE_OBJECT_TYPES);
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.selectedObjects = Array.from(this._selectedObjectsUUIDs);
data.widgetRotation = this._widgetRotation;
data.pivotPoint = {
@@ -52048,10 +51727,8 @@ Wick.Selection = class extends Wick.Base {
data.originalHeight = this._originalHeight;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this._selectedObjectsUUIDs = data.selectedObjects || [];
this._widgetRotation = data.widgetRotation;
this._pivotPoint = {
@@ -52061,79 +51738,73 @@ Wick.Selection = class extends Wick.Base {
this._originalWidth = data.originalWidth;
this._originalHeight = data.originalHeight;
}
-
get classname() {
return 'Selection';
}
+
/**
* The names of all attributes of the selection that can be changed.
* @type {string[]}
*/
-
-
get allAttributeNames() {
return ["strokeWidth", "fillColor", "strokeColor", "name", "filename", "fontSize", "fontFamily", "fontWeight", "fontStyle", "src", "frameLength", "x", "y", "originX", "originY", "width", "height", "rotation", "opacity", "sound", "soundVolume", "soundStart", "identifier", "easingType", "fullRotations", "scaleX", "scaleY", "animationType", "singleFrameNumber", "isSynced"];
}
+
/**
* Returns true if an object is selectable.
* @param {object} object object to check if selectable
* @returns {boolean} true if selectable, false otherwise.
*/
-
-
isSelectable(object) {
return this.SELECTABLE_OBJECT_TYPES_SET.has(object.classname);
}
+
/**
* Add a wick object to the selection. If selecting multiple objects, you should use
* selection.selectMultipleObjects.
* @param {Wick.Base} object - The object to select.
*/
-
-
select(object) {
// Only allow specific objects to be selectable.
if (!this.isSelectable(object)) {
console.warn("Tried to select a " + object.classname + " object. This type is not selectable");
return;
- } // Don't do anything if the object is already selected
-
+ }
+ // Don't do anything if the object is already selected
if (this.isObjectSelected(object)) {
return;
- } // Activate the cursor tool when selection changes
-
+ }
+ // Activate the cursor tool when selection changes
if (this._locationOf(object) === 'Canvas') {
this.project.activeTool = this.project.tools.cursor;
object.parentLayer && object.parentLayer.activate();
- } // Only allow selection of objects of in the same location
-
+ }
+ // Only allow selection of objects of in the same location
if (this._locationOf(object) !== this.location) {
this.clear();
- } // Add the object to the selection!
-
-
- this._selectedObjectsUUIDs.push(object.uuid); // Select in between frames (for shift+click selecting frames)
+ }
+ // Add the object to the selection!
+ this._selectedObjectsUUIDs.push(object.uuid);
+ // Select in between frames (for shift+click selecting frames)
if (object instanceof Wick.Frame) {
this._selectInBetweenFrames(object);
}
+ this._resetPositioningValues();
- this._resetPositioningValues(); // Make sure the view gets updated the next time its needed...
-
-
+ // Make sure the view gets updated the next time its needed...
this.view.dirty = true;
}
+
/**
* Select multiple objects. Must be selectable objects. Significantly faster than selecting multiple elements
* with a select() independently.
* @param {object[]} objects
*/
-
-
selectMultipleObjects(objects) {
let UUIDsToAdd = [];
objects.forEach(obj => {
@@ -52143,82 +51814,69 @@ Wick.Selection = class extends Wick.Base {
if (this.location !== this._locationOf(obj)) {
this.clear();
}
-
UUIDsToAdd.push(obj.uuid);
}
});
UUIDsToAdd.forEach(uuid => {
this._selectedObjectsUUIDs.push(uuid);
});
-
this._resetPositioningValues();
-
this.view.dirty = true;
}
+
/**
* Remove a wick object from the selection.
* @param {Wick.Base} object - The object to deselect.
*/
-
-
deselect(object) {
this._selectedObjectsUUIDs = this._selectedObjectsUUIDs.filter(uuid => {
return uuid !== object.uuid;
});
+ this._resetPositioningValues();
- this._resetPositioningValues(); // Make sure the view gets updated the next time its needed...
-
-
+ // Make sure the view gets updated the next time its needed...
this.view.dirty = true;
}
+
/**
* Remove multiple objects from the selection. Does nothing if an object is not selected.
* @param {object[]} objects objects to remove from the selection.
*/
-
-
deselectMultipleObjects(objects) {
objects = objects.filter(obj => obj);
let uuids = objects.map(obj => obj.uuid);
uuids = new Set(uuids);
this._selectedObjectsUUIDs = this._selectedObjectsUUIDs.filter(uuid => !uuids.has(uuid));
-
this._resetPositioningValues();
-
this.view.dirty = true;
}
+
/**
* Remove all objects from the selection with an optional filter.
* @param {string} filter - A location or a type (see SELECTABLE_OBJECT_TYPES and LOCATION_NAMES)
*/
-
-
clear(filter) {
if (filter === undefined) {
this._selectedObjectsUUIDs = [];
-
this._resetPositioningValues();
-
this.view.dirty = true;
} else {
this.deselectMultipleObjects(this.project.selection.getSelectedObjects(filter));
}
}
+
/**
* Checks if a given object is selected.
* @param {Wick.Base} object - The object to check selection of.
*/
-
-
isObjectSelected(object) {
return this._selectedObjectsUUIDs.indexOf(object.uuid) !== -1;
}
+
/**
* Get the first object in the selection if there is a single object in the selection.
* @return {Wick.Base} The first object in the selection.
*/
-
-
getSelectedObject() {
if (this.numObjects === 1) {
return this.getSelectedObjects()[0];
@@ -52226,21 +51884,18 @@ Wick.Selection = class extends Wick.Base {
return null;
}
}
+
/**
* Get the objects in the selection with an optional filter.
* @param {string} filter - A location or a type (see SELECTABLE_OBJECT_TYPES and LOCATION_NAMES)
* @return {Wick.Base[]} The selected objects.
*/
-
-
getSelectedObjects(filter) {
var objects = this._selectedObjectsUUIDs.map(uuid => {
return Wick.ObjectCache.getObjectByUUID(uuid);
});
-
if (Wick.Selection.LOCATION_NAMES.indexOf(filter) !== -1) {
var location = filter;
-
if (this.location !== location) {
return [];
} else {
@@ -52252,37 +51907,33 @@ Wick.Selection = class extends Wick.Base {
return object instanceof Wick[classname];
});
}
-
return objects;
}
+
/**
* Get the UUIDs of the objects in the selection with an optional filter.
* @param {string} filter - A location or a type (see SELECTABLE_OBJECT_TYPES and LOCATION_NAMES)
* @return {string[]} The UUIDs of the selected objects.
*/
-
-
getSelectedObjectUUIDs(filter) {
return this.getSelectedObjects(filter).map(object => {
return object.uuid;
});
}
+
/**
* The location of the objects in the selection. (see LOCATION_NAMES)
* @type {string}
*/
-
-
get location() {
if (this.numObjects === 0) return null;
return this._locationOf(this.getSelectedObjects()[0]);
}
+
/**
* The types of the objects in the selection. (see SELECTABLE_OBJECT_TYPES)
* @type {string[]}
*/
-
-
get types() {
var types = this.getSelectedObjects().map(object => {
return object.classname;
@@ -52290,19 +51941,16 @@ Wick.Selection = class extends Wick.Base {
var uniqueTypes = [...new Set(types)];
return uniqueTypes;
}
+
/**
* A single string describing the contents of the selection.
* @type {string}
*/
-
-
get selectionType() {
let selection = this;
-
if (selection.location === 'Canvas') {
if (selection.numObjects === 1) {
var selectedObject = selection.getSelectedObject();
-
if (selectedObject instanceof window.Wick.Path) {
return selectedObject.pathType;
} else if (selectedObject instanceof window.Wick.Button) {
@@ -52353,47 +52001,41 @@ Wick.Selection = class extends Wick.Base {
return 'unknown';
}
}
+
/**
* The number of objects in the selection.
* @type {number}
*/
-
-
get numObjects() {
return this._selectedObjectsUUIDs.length;
}
+
/**
* The rotation of the selection (used for canvas selections)
* @type {number}
*/
-
-
get widgetRotation() {
return this._widgetRotation;
}
-
set widgetRotation(widgetRotation) {
this._widgetRotation = widgetRotation;
}
+
/**
* The point that transformations to the selection will be based around.
* @type {object}
*/
-
-
get pivotPoint() {
return this._pivotPoint;
}
-
set pivotPoint(pivotPoint) {
this._pivotPoint = pivotPoint;
}
+
/**
* The animation type of a clip.
* @type {string}
*/
-
-
get animationType() {
if (this.getSelectedObject() && this.selectionType === 'clip') {
return this.getSelectedObject().animationType;
@@ -52401,7 +52043,6 @@ Wick.Selection = class extends Wick.Base {
return null;
}
}
-
set animationType(newType) {
if (this.getSelectedObject()) {
this.getSelectedObject().animationType = newType;
@@ -52409,11 +52050,10 @@ Wick.Selection = class extends Wick.Base {
console.error("Cannot set the animation type of multiple objects...");
}
}
+
/**
* If a clip is set to singleFrame, this number will be used to determine that frame.
*/
-
-
get singleFrameNumber() {
if (this.getSelectedObject() && this.selectionType === 'clip') {
return this.getSelectedObject().singleFrameNumber;
@@ -52421,7 +52061,6 @@ Wick.Selection = class extends Wick.Base {
return null;
}
}
-
set singleFrameNumber(frame) {
if (this.getSelectedObject()) {
this.getSelectedObject().singleFrameNumber = frame;
@@ -52429,40 +52068,35 @@ Wick.Selection = class extends Wick.Base {
console.error("Cannot set singleFrameNumber of multiple objects...");
}
}
+
/**
* The position of the selection.
* @type {number}
*/
-
-
get x() {
return this.view.x;
}
-
set x(x) {
this.view.x = x;
this.project.tryToAutoCreateTween();
}
+
/**
* The position of the selection.
* @type {number}
*/
-
-
get y() {
return this.view.y;
}
-
set y(y) {
this.view.y = y;
this.project.tryToAutoCreateTween();
}
+
/**
* The origin position the selection.
* @type {number}
*/
-
-
get originX() {
// If there's only 1 object selected, the origin is that object's position.
if (this.getSelectedObject() && (this.selectionType === "clip" || this.selectionType === "button")) {
@@ -52471,7 +52105,6 @@ Wick.Selection = class extends Wick.Base {
return this.x + this.width / 2;
}
}
-
set originX(x) {
if (this.getSelectedObject() && (this.selectionType === "clip" || this.selectionType === "button")) {
this.getSelectedObject().x = x;
@@ -52483,12 +52116,11 @@ Wick.Selection = class extends Wick.Base {
this.x = x - this.width / 2;
}
}
+
/**
* The origin position the selection.
* @type {number}
*/
-
-
get originY() {
// If there's only 1 object selected, the origin is that object's position.
if (this.getSelectedObject() && (this.selectionType === "clip" || this.selectionType === "button")) {
@@ -52497,7 +52129,6 @@ Wick.Selection = class extends Wick.Base {
return this.y + this.height / 2;
}
}
-
set originY(y) {
if (this.getSelectedObject() && (this.selectionType === "clip" || this.selectionType === "button")) {
this.getSelectedObject().y = y;
@@ -52509,80 +52140,69 @@ Wick.Selection = class extends Wick.Base {
this.y = y - this.height / 2;
}
}
+
/**
* The width of the selection.
* @type {number}
*/
-
-
get width() {
return this.view.width;
}
-
set width(width) {
this.project.tryToAutoCreateTween();
this.view.width = width;
}
+
/**
* The height of the selection.
* @type {number}
*/
-
-
get height() {
return this.view.height;
}
-
set height(height) {
this.project.tryToAutoCreateTween();
this.view.height = height;
}
+
/**
* The rotation of the selection.
* @type {number}
*/
-
-
get rotation() {
return this.view.rotation;
}
-
set rotation(rotation) {
this.project.tryToAutoCreateTween();
this.view.rotation = rotation;
}
+
/**
* It is the original width of the selection at creation.
* @type {number}
*/
-
-
get originalWidth() {
return this._originalWidth;
}
-
set originalWidth(originalWidth) {
this._originalWidth = originalWidth;
}
+
/**
* It is the original height of the selection at creation.
* @type {number}
*/
-
-
get originalHeight() {
return this._originalHeight;
}
-
set originalHeight(originalHeight) {
this._originalHeight = originalHeight;
}
+
/**
* The scale of the selection on the X axis.
* @type {number}
*/
-
-
get scaleX() {
// Clips store their scale state internally
if (this.selectionType === "clip" || this.selectionType === "button") {
@@ -52592,7 +52212,6 @@ Wick.Selection = class extends Wick.Base {
return this.width / this.originalWidth;
}
}
-
set scaleX(scaleX) {
// Clips store their scale state internally
if (this.selectionType === "clip" || this.selectionType === "button") {
@@ -52601,12 +52220,11 @@ Wick.Selection = class extends Wick.Base {
this.width = this.originalWidth * scaleX;
}
}
+
/**
* The scale of the selection on the Y axis.
* @type {number}
*/
-
-
get scaleY() {
// Clips store their scale state internally
if (this.selectionType === "clip" || this.selectionType === "button") {
@@ -52615,7 +52233,6 @@ Wick.Selection = class extends Wick.Base {
return this.height / this.originalHeight;
}
}
-
set scaleY(scaleY) {
// Clips store their scale state internally
if (this.selectionType === "clip" || this.selectionType === "button") {
@@ -52624,11 +52241,10 @@ Wick.Selection = class extends Wick.Base {
this.height = this.originalHeight * scaleY;
}
}
+
/**
* Determines if a clip is synced to the timeline.
*/
-
-
get isSynced() {
// Clips store can be synced to the animation timeline
if (this.selectionType === "clip") {
@@ -52637,354 +52253,300 @@ Wick.Selection = class extends Wick.Base {
return false;
}
}
-
set isSynced(syncBool) {
if (!typeof syncBool === "boolean") return;
-
if (this.selectionType === "clip") {
this.getSelectedObject().isSynced = syncBool;
}
}
+
/**
* Flips the selected obejcts horizontally.
*/
-
-
flipHorizontally() {
this.project.tryToAutoCreateTween();
this.view.flipHorizontally();
}
+
/**
* Flips the selected obejcts vertically.
*/
-
-
flipVertically() {
this.project.tryToAutoCreateTween();
this.view.flipVertically();
}
+
/**
* Sends the selected objects to the back.
*/
-
-
sendToBack() {
this.view.sendToBack();
}
+
/**
* Brings the selected objects to the front.
*/
-
-
bringToFront() {
this.view.bringToFront();
}
+
/**
* Moves the selected objects forwards.
*/
-
-
moveForwards() {
this.view.moveForwards();
}
+
/**
* Moves the selected objects backwards.
*/
-
-
moveBackwards() {
this.view.moveBackwards();
}
+
/**
* The identifier of the selected object.
* @type {string}
*/
-
-
get identifier() {
return this._getSingleAttribute('identifier');
}
-
set identifier(identifier) {
this._setSingleAttribute('identifier', identifier);
}
+
/**
* The name of the selected object.
* @type {string}
*/
-
-
get name() {
return this._getSingleAttribute('name');
}
-
set name(name) {
this._setSingleAttribute('name', name);
}
+
/**
* The fill color of the selected object.
* @type {paper.Color}
*/
-
-
get fillColor() {
return this._getSingleAttribute('fillColor');
}
-
set fillColor(fillColor) {
this._setSingleAttribute('fillColor', fillColor);
}
+
/**
* The stroke color of the selected object.
* @type {paper.Color}
*/
-
-
get strokeColor() {
return this._getSingleAttribute('strokeColor');
}
-
set strokeColor(strokeColor) {
this._setSingleAttribute('strokeColor', strokeColor);
}
+
/**
* The stroke width of the selected object.
* @type {number}
*/
-
-
get strokeWidth() {
return this._getSingleAttribute('strokeWidth');
}
-
set strokeWidth(strokeWidth) {
this._setSingleAttribute('strokeWidth', strokeWidth);
}
+
/**
* The font family of the selected object.
* @type {string}
*/
-
-
get fontFamily() {
return this._getSingleAttribute('fontFamily');
}
-
set fontFamily(fontFamily) {
this._setSingleAttribute('fontFamily', fontFamily);
}
+
/**
* The font size of the selected object.
* @type {number}
*/
-
-
get fontSize() {
return this._getSingleAttribute('fontSize');
}
-
set fontSize(fontSize) {
this._setSingleAttribute('fontSize', fontSize);
}
+
/**
* The font weight of the selected object.
* @type {number}
*/
-
-
get fontWeight() {
return this._getSingleAttribute('fontWeight');
}
-
set fontWeight(fontWeight) {
this._setSingleAttribute('fontWeight', fontWeight);
}
+
/**
* The font style of the selected object. ('italic' or 'oblique')
* @type {string}
*/
-
-
get fontStyle() {
return this._getSingleAttribute('fontStyle');
}
-
set fontStyle(fontStyle) {
this._setSingleAttribute('fontStyle', fontStyle);
}
+
/**
* The opacity of the selected object.
* @type {number}
*/
-
-
get opacity() {
return this._getSingleAttribute('opacity');
}
-
set opacity(opacity) {
this.project.tryToAutoCreateTween();
-
this._setSingleAttribute('opacity', opacity);
}
+
/**
* The sound attached to the selected frame.
* @type {Wick.SoundAsset}
*/
-
-
get sound() {
return this._getSingleAttribute('sound');
}
-
set sound(sound) {
this._setSingleAttribute('sound', sound);
}
+
/**
* The length of the selected frame.
* @type {number}
*/
-
-
get frameLength() {
return this._getSingleAttribute('length');
}
-
set frameLength(frameLength) {
this._setSingleAttribute('length', frameLength);
-
var layer = this.project.activeLayer;
layer.resolveOverlap(this.getSelectedObjects());
layer.resolveGaps();
}
+
/**
* The volume of the sound attached to the selected frame.
* @type {number}
*/
-
-
get soundVolume() {
return this._getSingleAttribute('soundVolume');
}
-
set soundVolume(soundVolume) {
this._setSingleAttribute('soundVolume', soundVolume);
}
+
/**
* The starting position of the sound on the frame in ms.
* @type {number}
*/
-
-
get soundStart() {
return this._getSingleAttribute('soundStart');
}
-
set soundStart(soundStart) {
this._setSingleAttribute('soundStart', soundStart);
}
+
/**
* The easing type of a selected tween. See Wick.Tween.VALID_EASING_TYPES.
* @type {string}
*/
-
-
get easingType() {
return this._getSingleAttribute('easingType');
}
-
set easingType(easingType) {
return this._setSingleAttribute('easingType', easingType);
}
+
/**
* The amount of rotations to perform during a tween. Positive value = clockwise rotation.
* @type {Number}
*/
-
-
get fullRotations() {
return this._getSingleAttribute('fullRotations');
}
-
set fullRotations(fullRotations) {
return this._setSingleAttribute('fullRotations', fullRotations);
}
+
/**
* The filename of the selected asset. Read only.
* @type {string}
*/
-
-
get filename() {
return this._getSingleAttribute('filename');
}
+
/**
* True if the selection is scriptable. Read only.
* @type {boolean}
*/
-
-
get isScriptable() {
return this.numObjects === 1 && this.getSelectedObjects()[0].isScriptable;
}
+
/**
* The source (dataURL) of the selected ImageAsset or SoundAsset. Read only.
* @type {string}
*/
-
-
get src() {
return this.numObjects === 1 && this.getSelectedObjects()[0].src;
}
+
/**
* Get a list of only the farthest right frames on each layer.
* @returns {Wick.Frame[]}
*/
-
-
getRightmostFrames() {
var selectedFrames = this.getSelectedObjects('Frame');
var rightmostFrames = {};
selectedFrames.forEach(frame => {
var layerid = frame.parentLayer.uuid;
-
if (!rightmostFrames[layerid] || frame.end > rightmostFrames[layerid].end) {
rightmostFrames[layerid] = frame;
}
});
var result = [];
-
for (var id in rightmostFrames) {
result.push(rightmostFrames[id]);
}
-
return result;
}
+
/**
* Get a list of only the farthest left frames on each layer.
* @returns {Wick.Frame[]}
*/
-
-
getLeftmostFrames() {
var selectedFrames = this.getSelectedObjects('Frame');
var leftmostFrames = {};
selectedFrames.forEach(frame => {
var layerid = frame.parentLayer.uuid;
-
if (!leftmostFrames[layerid] || frame.start < leftmostFrames[layerid].end) {
leftmostFrames[layerid] = frame;
}
});
var result = [];
-
for (var id in leftmostFrames) {
result.push(leftmostFrames[id]);
}
-
return result;
}
-
_locationOf(object) {
if (object instanceof Wick.Frame || object instanceof Wick.Tween || object instanceof Wick.Layer) {
return 'Timeline';
@@ -52994,12 +52556,10 @@ Wick.Selection = class extends Wick.Base {
return 'Canvas';
}
}
- /* Helper function: Calculate the selection x,y */
-
+ /* Helper function: Calculate the selection x,y */
_resetPositioningValues() {
var selectedObject = this.getSelectedObject();
-
if (selectedObject instanceof Wick.Clip) {
// Single clip selected: Use that Clip's transformation for the pivot point and rotation
this._widgetRotation = selectedObject.transformation.rotation;
@@ -53010,70 +52570,64 @@ Wick.Selection = class extends Wick.Base {
} else {
// Path selected or multiple objects selected: Reset rotation and use center for pivot point
this._widgetRotation = 0;
-
var boundsCenter = this.view._getSelectedObjectsBounds().center;
-
this._pivotPoint = {
x: boundsCenter.x,
y: boundsCenter.y
- }; // Always pull original size values.
+ };
+ // Always pull original size values.
this._originalWidth = this.view._getSelectedObjectsBounds().width;
this._originalHeight = this.view._getSelectedObjectsBounds().height;
}
}
- /* helper function for getting a single value from multiple selected objects */
-
+ /* helper function for getting a single value from multiple selected objects */
_getSingleAttribute(attributeName) {
if (this.numObjects === 0) return null;
return this.getSelectedObjects()[0][attributeName];
}
- /* helper function for updating the same attribute on all items in the selection */
-
+ /* helper function for updating the same attribute on all items in the selection */
_setSingleAttribute(attributeName, value) {
this.getSelectedObjects().forEach(selectedObject => {
selectedObject[attributeName] = value;
});
}
- /*helper function for shift+selecting frames*/
-
+ /*helper function for shift+selecting frames*/
_selectInBetweenFrames(selectedFrame) {
var frameBounds = {
playheadStart: null,
playheadEnd: null
- }; // Calculate bounding box of all selected frames
+ };
+ // Calculate bounding box of all selected frames
var selectedFrames = this.getSelectedObjects('Frame');
selectedFrames.filter(frame => {
return frame.parentLayer === selectedFrame.parentLayer;
}).forEach(frame => {
var start = frame.start;
var end = frame.end;
-
if (!frameBounds.playheadStart || !frameBounds.playheadEnd) {
frameBounds.playheadStart = start;
frameBounds.playheadEnd = end;
}
-
if (start < frameBounds.playheadStart) {
frameBounds.playheadStart = start;
}
-
if (end > frameBounds.playheadEnd) {
frameBounds.playheadEnd = end;
}
- }); // Select all frames inside bounding box
+ });
+ // Select all frames inside bounding box
this.project.activeTimeline.getAllFrames().filter(frame => {
return !frame.isSelected && frame.parentLayer === selectedFrame.parentLayer && frame.inRange(frameBounds.playheadStart, frameBounds.playheadEnd);
}).forEach(frame => {
this._selectedObjectsUUIDs.push(frame.uuid);
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -53109,146 +52663,126 @@ Wick.Timeline = class extends Wick.Base {
this._fillGapsMethod = "auto_extend";
this._frameForced = false;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.playheadPosition = this._playheadPosition;
data.activeLayerIndex = this._activeLayerIndex;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this._playheadPosition = data.playheadPosition;
this._activeLayerIndex = data.activeLayerIndex;
this._playing = true;
}
-
get classname() {
return 'Timeline';
}
+
/**
* The layers that belong to this timeline.
* @type {Wick.Layer}
*/
-
-
get layers() {
return this.getChildren('Layer');
}
+
/**
* The position of the playhead. Determines which frames are visible.
* @type {number}
*/
-
-
get playheadPosition() {
return this._playheadPosition;
}
-
set playheadPosition(playheadPosition) {
// Automatically clear selection when any playhead in the project moves
if (this.project && this._playheadPosition !== playheadPosition && this.parentClip.isFocus) {
this.project.selection.clear('Canvas');
this.project.resetTools();
}
-
this._playheadPosition = playheadPosition;
-
if (this._playheadPosition < 1) {
this._playheadPosition = 1;
- } // Automatically apply tween transforms on child frames when playhead moves
-
+ }
+ // Automatically apply tween transforms on child frames when playhead moves
this.activeFrames.forEach(frame => {
frame.applyTweenTransforms();
frame.updateClipTimelinesForAnimationType();
});
}
+
/**
* Forces timeline to move to the next frame.
* @param {number} frame
*/
-
-
forceFrame(frame) {
this.playheadPosition = frame;
this._frameForced = true;
this.makeTimelineInBounds();
}
+
/**
* Returns true if the frame was forced previously.
*/
-
-
get frameForced() {
return this._frameForced;
}
+
/**
* The index of the active layer. Determines which frame to draw onto.
* @type {number}
*/
-
-
get activeLayerIndex() {
return this._activeLayerIndex;
}
-
set activeLayerIndex(activeLayerIndex) {
this._activeLayerIndex = activeLayerIndex;
}
+
/**
* The total length of the timeline.
* @type {number}
*/
-
-
get length() {
var length = 0;
this.layers.forEach(function (layer) {
var layerLength = layer.length;
-
if (layerLength > length) {
length = layerLength;
}
});
return length;
}
+
/**
* The active layer.
* @type {Wick.Layer}
*/
-
-
get activeLayer() {
return this.layers[this.activeLayerIndex];
}
+
/**
* The active frames, determined by the playhead position.
* @type {Wick.Frame[]}
*/
-
-
get activeFrames() {
var frames = [];
this.layers.forEach(layer => {
var layerFrame = layer.activeFrame;
-
if (layerFrame) {
frames.push(layerFrame);
}
});
return frames;
}
+
/*
* exports the project as an SVG file
* @onError {function(message)}
* @returns {string} - the SVG for the current view in string form (maybe this should be base64 or a blob or something)
*/
-
-
exportSVG(onError) {
var svgOutput = paper.project.exportSVG({
asString: true,
@@ -53256,24 +52790,21 @@ Wick.Timeline = class extends Wick.Base {
embedImages: true
});
return svgOutput;
- } //this.project.paper.
+ }
+ //this.project.paper.
//paperGroup = new paper.Group
-
/**
* The active frame, determined by the playhead position.
* @type {Wick.Frame}
*/
-
-
get activeFrame() {
return this.activeLayer && this.activeLayer.activeFrame;
}
+
/**
* All frames inside the timeline.
* @type {Wick.Frame[]}
*/
-
-
get frames() {
var frames = [];
this.layers.forEach(layer => {
@@ -53283,12 +52814,11 @@ Wick.Timeline = class extends Wick.Base {
});
return frames;
}
+
/**
* All clips inside the timeline.
* @type {Wick.Clip[]}
*/
-
-
get clips() {
var clips = [];
this.frames.forEach(frame => {
@@ -53296,41 +52826,36 @@ Wick.Timeline = class extends Wick.Base {
});
return clips;
}
+
/**
* Finds the frame with a given name.
* @type {Wick.Frame|null}
*/
-
-
getFrameByName(name) {
return this.frames.find(frame => {
return frame.name === name;
}) || null;
}
+
/**
* Add a frame to one of the layers on this timeline. If there is no layer where the frame wants to go, the frame will not be added.
* @param {Wick.Frame} frame - the frame to add
*/
-
-
addFrame(frame) {
if (frame.originalLayerIndex >= this.layers.length) return;
-
if (frame.originalLayerIndex === -1) {
this.activeLayer.addFrame(frame);
} else {
this.layers[frame.originalLayerIndex].addFrame(frame);
}
}
+
/**
* Adds a layer to the timeline.
* @param {Wick.Layer} layer - The layer to add.
*/
-
-
addLayer(layer) {
this.addChild(layer);
-
if (!layer.name) {
if (this.layers.length > 1) {
layer.name = "Layer " + this.layers.length;
@@ -53339,60 +52864,54 @@ Wick.Timeline = class extends Wick.Base {
}
}
}
+
/**
* Adds a tween to a frame on this timeline.
* @param {Wick.Tween} tween - the tween to add.
*/
-
-
addTween(tween) {
if (tween.originalLayerIndex >= this.layers.length) return;
-
if (tween.originalLayerIndex === -1) {
this.activeLayer.addTween(tween);
} else {
this.layers[tween.originalLayerIndex].addTween(tween);
}
}
+
/**
* Remmoves a layer from the timeline.
* @param {Wick.Layer} layer - The layer to remove.
*/
-
-
removeLayer(layer) {
// You can't remove the last layer.
if (this.layers.length <= 1) {
return;
- } // Activate the layer below the removed layer if we removed the active layer.
-
+ }
+ // Activate the layer below the removed layer if we removed the active layer.
if (this.activeLayerIndex === this.layers.length - 1) {
this.activeLayerIndex--;
}
-
this.removeChild(layer);
}
+
/**
* Moves a layer to a different position, inserting it before/after other layers if needed.
* @param {Wick.Layer} layer - The layer to add.
* @param {number} index - the new position to move the layer to.
*/
-
-
moveLayer(layer, index) {
var layers = this.getChildren('Layer');
layers.splice(layers.indexOf(layer), 1);
layers.splice(index, 0, layer);
this._children = layers;
}
+
/**
* Gets the frames at the given playhead position.
* @param {number} playheadPosition - the playhead position to search.
* @returns {Wick.Frame[]} The frames at the playhead position.
*/
-
-
getFramesAtPlayheadPosition(playheadPosition) {
var frames = [];
this.layers.forEach(layer => {
@@ -53401,17 +52920,15 @@ Wick.Timeline = class extends Wick.Base {
});
return frames;
}
+
/**
* Get all frames in this timeline.
* @param {boolean} recursive - If set to true, will also include the children of all child timelines.
*/
-
-
getAllFrames(recursive) {
var allFrames = [];
this.layers.forEach(layer => {
allFrames = allFrames.concat(layer.frames);
-
if (recursive) {
layer.frames.forEach(frame => {
frame.clips.forEach(clip => {
@@ -53422,6 +52939,7 @@ Wick.Timeline = class extends Wick.Base {
});
return allFrames;
}
+
/**
* Gets all frames in the layer that are between the two given playhead positions and layer indices.
* @param {number} playheadPositionStart - The start of the horizontal range to search
@@ -53430,8 +52948,6 @@ Wick.Timeline = class extends Wick.Base {
* @param {number} layerIndexEnd - The end of the vertical range to search
* @return {Wick.Frame[]} The frames in the given range.
*/
-
-
getFramesInRange(playheadPositionStart, playheadPositionEnd, layerIndexStart, layerIndexEnd) {
var framesInRange = [];
this.layers.filter(layer => {
@@ -53441,11 +52957,10 @@ Wick.Timeline = class extends Wick.Base {
});
return framesInRange;
}
+
/**
* Advances the timeline one frame forwards. Loops back to beginning if the end is reached.
*/
-
-
advance() {
if (this._playing) {
this.playheadPosition++;
@@ -53453,93 +52968,80 @@ Wick.Timeline = class extends Wick.Base {
this.makeTimelineInBounds();
}
}
+
/**
* Ensures playhead position is in bounds.
*/
-
-
makeTimelineInBounds() {
if (this.playheadPosition > this.length) {
this.playheadPosition = 1;
}
}
+
/**
* Makes the timeline advance automatically during ticks.
*/
-
-
play() {
this._playing = true;
}
+
/**
* Stops the timeline from advancing during ticks.
*/
-
-
stop() {
this._playing = false;
}
+
/**
* Stops the timeline and moves to a given frame number or name.
* @param {string|number} frame - A playhead position or name of a frame to move to.
*/
-
-
gotoAndStop(frame) {
this.stop();
this.gotoFrame(frame);
}
+
/**
* Plays the timeline and moves to a given frame number or name.
* @param {string|number} frame - A playhead position or name of a frame to move to.
*/
-
-
gotoAndPlay(frame) {
this.play();
this.gotoFrame(frame);
}
+
/**
* Moves the timeline forward one frame. Loops back to 1 if gotoNextFrame moves the playhead past the past frame.
*/
-
-
gotoNextFrame() {
// Loop back to beginning if gotoNextFrame goes past the last frame
var nextFramePlayheadPosition = this.playheadPosition + 1;
-
if (nextFramePlayheadPosition > this.length) {
nextFramePlayheadPosition = 1;
}
-
this.gotoFrame(nextFramePlayheadPosition);
}
+
/**
* Moves the timeline backwards one frame. Loops to the last frame if gotoPrevFrame moves the playhead before the first frame.
*/
-
-
gotoPrevFrame() {
var prevFramePlayheadPosition = this.playheadPosition - 1;
-
if (prevFramePlayheadPosition <= 0) {
prevFramePlayheadPosition = this.length;
}
-
this.gotoFrame(prevFramePlayheadPosition);
}
+
/**
* Moves the playhead to a given frame number or name.
* @param {string|number} frame - A playhead position or name of a frame to move to.
*/
-
-
gotoFrame(frame) {
if (typeof frame === 'string') {
var namedFrame = this.frames.find(seekframe => {
return seekframe.identifier === frame && !seekframe.onScreen;
});
-
if (namedFrame) {
this.forceFrame(namedFrame.start);
}
@@ -53549,16 +53051,14 @@ Wick.Timeline = class extends Wick.Base {
throw new Error('gotoFrame: Invalid argument: ' + frame);
}
}
+
/**
* The method to use to fill gaps in-beteen frames. Options: "blank_frames" or "auto_extend" (see Wick.Layer.resolveGaps)
* @type {string}
*/
-
-
get fillGapsMethod() {
return this._fillGapsMethod;
}
-
set fillGapsMethod(fillGapsMethod) {
if (fillGapsMethod === 'blank_frames' || fillGapsMethod === 'auto_extend') {
this._fillGapsMethod = fillGapsMethod;
@@ -53567,29 +53067,26 @@ Wick.Timeline = class extends Wick.Base {
console.warn('Valid fillGapsMethod: "blank_frames", "auto_extend"');
}
}
+
/**
* Check if frame gap fixing should be deferred until later. Read only.
* @type {boolean}
*/
-
-
get waitToFillFrameGaps() {
return this._waitToFillFrameGaps;
}
+
/**
* Disables frame gap filling until resolveFrameGaps is called again.
*/
-
-
deferFrameGapResolve() {
this._waitToFillFrameGaps = true;
}
+
/**
* Fill in all gaps between frames in all layers in this timeline.
* @param {Wick.Frame[]} newOrModifiedFrames - The frames that should not be affected by the gap fill by being extended or shrunk.
*/
-
-
resolveFrameGaps(newOrModifiedFrames) {
if (!newOrModifiedFrames) newOrModifiedFrames = [];
this._waitToFillFrameGaps = false;
@@ -53599,12 +53096,11 @@ Wick.Timeline = class extends Wick.Base {
}));
});
}
+
/**
* Prevents frames from overlapping each other by removing pieces of frames that are touching.
* @param {Wick.Frame[]} newOrModifiedFrames - the frames that should take precedence when determining which frames should get "eaten".
*/
-
-
resolveFrameOverlap(frames) {
this.layers.forEach(layer => {
layer.resolveOverlap(frames.filter(frame => {
@@ -53612,7 +53108,6 @@ Wick.Timeline = class extends Wick.Base {
}));
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -53640,7 +53135,6 @@ Wick.Tween = class extends Wick.Base {
static get VALID_EASING_TYPES() {
return ['none', 'in', 'out', 'in-out'];
}
-
static _calculateTimeValue(tweenA, tweenB, playheadPosition) {
var tweenAPlayhead = tweenA.playheadPosition;
var tweenBPlayhead = tweenB.playheadPosition;
@@ -53648,14 +53142,13 @@ Wick.Tween = class extends Wick.Base {
var t = (playheadPosition - tweenAPlayhead) / dist;
return t;
}
+
/**
* Create a tween
* @param {number} playheadPosition - the playhead position relative to the frame that the tween belongs to
* @param {Wick.Transform} transformation - the transformation this tween will apply to child objects
* @param {number} fullRotations - the number of rotations to add to the tween's transformation
*/
-
-
constructor(args) {
if (!args) args = {};
super(args);
@@ -53665,31 +53158,28 @@ Wick.Tween = class extends Wick.Base {
this.easingType = args.easingType || 'none';
this._originalLayerIndex = -1;
}
+
/**
* Create a tween by interpolating two existing tweens.
* @param {Wick.Tween} tweenA - The first tween
* @param {Wick.Tween} tweenB - The second tween
* @param {Number} playheadPosition - The point between the two tweens to use to interpolate
*/
-
-
static interpolate(tweenA, tweenB, playheadPosition) {
- var interpTween = new Wick.Tween(); // Calculate value (0.0-1.0) to pass to tweening function
-
- var t = Wick.Tween._calculateTimeValue(tweenA, tweenB, playheadPosition); // Interpolate every transformation attribute using the t value
+ var interpTween = new Wick.Tween();
+ // Calculate value (0.0-1.0) to pass to tweening function
+ var t = Wick.Tween._calculateTimeValue(tweenA, tweenB, playheadPosition);
+ // Interpolate every transformation attribute using the t value
["x", "y", "scaleX", "scaleY", "rotation", "opacity"].forEach(propName => {
var tweenFn = tweenA._getTweenFunction();
-
var tt = tweenFn(t);
var valA = tweenA.transformation[propName];
var valB = tweenB.transformation[propName];
-
if (propName === 'rotation') {
// Constrain rotation values to range of -180 to 180
// (Disabled for now - a bug in paper.js clamps these for us)
-
/*while(valA < -180) valA += 360;
while(valB < -180) valB += 360;
while(valA > 180) valA -= 360;
@@ -53697,20 +53187,16 @@ Wick.Tween = class extends Wick.Base {
// Convert full rotations to 360 degree amounts
valB += tweenA.fullRotations * 360;
}
-
interpTween.transformation[propName] = lerp(valA, valB, tt);
});
interpTween.playheadPosition = playheadPosition;
return interpTween;
}
-
get classname() {
return 'Tween';
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.playheadPosition = this.playheadPosition;
data.transformation = this._transformation.values;
data.fullRotations = this.fullRotations;
@@ -53718,122 +53204,107 @@ Wick.Tween = class extends Wick.Base {
data.originalLayerIndex = this.layerIndex !== -1 ? this.layerIndex : this._originalLayerIndex;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.playheadPosition = data.playheadPosition;
this._transformation = new Wick.Transformation(data.transformation);
this.fullRotations = data.fullRotations;
this.easingType = data.easingType;
this._originalLayerIndex = data.originalLayerIndex;
}
+
/**
* The playhead position of the tween.
* @type {number}
*/
-
-
get playheadPosition() {
return this._playheadPosition;
}
-
set playheadPosition(playheadPosition) {
this._playheadPosition = playheadPosition;
}
+
/**
* The transformation representing the position, rotation and other elements of the tween.
* @type {object}
*/
-
-
get transformation() {
return this._transformation;
}
-
set transformation(transformation) {
this._transformation = transformation;
}
+
/**
* The type of interpolation to use for easing.
* @type {string}
*/
-
-
get easingType() {
return this._easingType;
}
-
set easingType(easingType) {
if (Wick.Tween.VALID_EASING_TYPES.indexOf(easingType) === -1) {
console.warn('Invalid easingType. Valid easingTypes: ');
console.warn(Wick.Tween.VALID_EASING_TYPES);
return;
}
-
this._easingType = easingType;
}
+
/**
* Remove this tween from its parent frame.
*/
-
-
remove() {
this.parent.removeTween(this);
}
+
/**
* Set the transformation of a clip to this tween's transformation.
* @param {Wick.Clip} clip - the clip to apply the tween transforms to.
*/
-
-
applyTransformsToClip(clip) {
clip.transformation = this.transformation.copy();
}
+
/**
* The tween that comes after this tween in the parent frame.
* @returns {Wick.Tween}
*/
-
-
getNextTween() {
if (!this.parentFrame) return null;
var frontTween = this.parentFrame.seekTweenInFront(this.playheadPosition + 1);
return frontTween;
}
+
/**
* Prevents tweens from existing outside of the frame's length. Call this after changing the length of the parent frame.
*/
-
-
restrictToFrameSize() {
- var playheadPosition = this.playheadPosition; // Remove tween if playheadPosition is out of bounds
+ var playheadPosition = this.playheadPosition;
+ // Remove tween if playheadPosition is out of bounds
if (playheadPosition < 1 || playheadPosition > this.parentFrame.length) {
this.remove();
}
}
+
/**
* The index of the parent layer of this tween.
* @type {number}
*/
-
-
get layerIndex() {
return this.parentLayer ? this.parentLayer.index : -1;
}
+
/**
* The index of the layer that this tween last belonged to. Used when copying and pasting tweens.
* @type {number}
*/
-
-
get originalLayerIndex() {
return this._originalLayerIndex;
}
- /* retrieve Tween.js easing functions by name */
-
+ /* retrieve Tween.js easing functions by name */
_getTweenFunction() {
return {
'none': TWEEN.Easing.Linear.None,
@@ -53842,7 +53313,6 @@ Wick.Tween = class extends Wick.Base {
'in-out': TWEEN.Easing.Quadratic.InOut
}[this.easingType];
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -53879,7 +53349,6 @@ Wick.Path = class extends Wick.Base {
this._fontWeight = 400;
this._isPlaceholder = args.isPlaceholder;
this._originalStyle = null;
-
if (args.path) {
this.json = args.path.exportJSON({
asString: false
@@ -53893,20 +53362,17 @@ Wick.Path = class extends Wick.Base {
asString: false
});
}
-
this.needReimport = true;
}
+
/**
* Create a path containing an image from an ImageAsset.
* @param {Wick.ImageAsset} asset - The asset from which the image src will be loaded from
* @param {Function} callback - A function that will be called when the image is done loading.
*/
-
-
static createImagePath(asset, callback) {
var img = new Image();
img.src = asset.src;
-
img.onload = () => {
var raster = new paper.Raster(img);
raster.remove();
@@ -53917,12 +53383,11 @@ Wick.Path = class extends Wick.Base {
callback(path);
};
}
+
/**
* Create a path (synchronously) containing an image from an ImageAsset.
* @param {Wick.ImageAsset} asset - The asset from which the image src will be loaded from
*/
-
-
static createImagePathSync(asset) {
var raster = new paper.Raster(asset.src);
raster.remove();
@@ -53932,17 +53397,15 @@ Wick.Path = class extends Wick.Base {
});
return path;
}
-
get classname() {
return 'Path';
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.json = this.json;
- delete data.json[1].data; // optimization: replace dataurls with asset uuids
+ delete data.json[1].data;
+ // optimization: replace dataurls with asset uuids
if (data.json[0] === 'Raster' && data.json[1].source.startsWith('data:')) {
if (!this.project) {
console.warn('Could not replace raster image source with asset UUID, path does not belong to a project.');
@@ -53954,35 +53417,30 @@ Wick.Path = class extends Wick.Base {
});
}
}
-
data.fontStyle = this._fontStyle;
data.fontWeight = this._fontWeight;
data.isPlaceholder = this._isPlaceholder;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.json = data.json;
this._fontStyle = data.fontStyle || 'normal';
this._fontWeight = data.fontWeight || 400;
this._isPlaceholder = data.isPlaceholder;
}
+
/**
* Determines if this Path is visible in the project.
*/
-
-
get onScreen() {
return this.parent.onScreen;
}
+
/**
* The type of path that this path is. Can be 'path', 'text', or 'image'
* @returns {string}
*/
-
-
get pathType() {
if (this.view.item instanceof paper.TextItem) {
return 'text';
@@ -53992,27 +53450,24 @@ Wick.Path = class extends Wick.Base {
return 'path';
}
}
+
/**
* Path data exported from paper.js using exportJSON({asString:false}).
* @type {object}
*/
-
-
get json() {
return this._json;
}
-
set json(json) {
this._json = json;
this.needReimport = true;
this.view.render();
}
+
/**
* The bounding box of the path.
* @type {object}
*/
-
-
get bounds() {
var paperBounds = this.view.item.bounds;
return {
@@ -54024,291 +53479,252 @@ Wick.Path = class extends Wick.Base {
height: paperBounds.height
};
}
+
/**
* The position of the path.
* @type {number}
*/
-
-
get x() {
return this.view.item.position.x;
}
-
set x(x) {
this.view.item.position.x = x;
this.updateJSON();
}
+
/**
* The position of the path.
* @type {number}
*/
-
-
get y() {
return this.view.item.position.y;
}
-
set y(y) {
this.view.item.position.y = y;
this.updateJSON();
}
+
/**
* The fill color of the path.
* @type {paper.Color}
*/
-
-
get fillColor() {
return this.view.item.fillColor || new paper.Color();
}
-
set fillColor(fillColor) {
this.view.item.fillColor = fillColor;
this.updateJSON();
}
+
/**
* The stroke color of the path.
* @type {paper.Color}
*/
-
-
get strokeColor() {
return this.view.item.strokeColor || new paper.Color();
}
-
set strokeColor(strokeColor) {
this.view.item.strokeColor = strokeColor;
this.updateJSON();
}
+
/**
* The stroke width of the path.
* @type {number}
*/
-
-
get strokeWidth() {
return this.view.item.strokeWidth;
}
-
set strokeWidth(strokeWidth) {
this.view.item.strokeWidth = strokeWidth;
this.updateJSON();
}
+
/**
* The opacity of the path.
* @type {number}
*/
-
-
get opacity() {
if (this.view.item.opacity === undefined || this.view.item.opacity === null) {
return 1.0;
}
-
return this.view.item.opacity;
}
-
set opacity(opacity) {
this.view.item.opacity = opacity;
this.updateJSON();
}
+
/**
* The font family of the path.
* @type {string}
*/
-
-
get fontFamily() {
return this.view.item.fontFamily;
}
-
set fontFamily(fontFamily) {
this.view.item.fontFamily = fontFamily;
this.fontWeight = 400;
this.fontStyle = 'normal';
this.updateJSON();
}
+
/**
* The font size of the path.
* @type {number}
*/
-
-
get fontSize() {
return this.view.item.fontSize;
}
-
set fontSize(fontSize) {
this.view.item.fontSize = fontSize;
this.view.item.leading = fontSize * 1.2;
this.updateJSON();
}
+
/**
* The font weight of the path.
* @type {number}
*/
-
-
get fontWeight() {
return this._fontWeight;
}
-
set fontWeight(fontWeight) {
if (typeof fontWeight === 'string') {
console.error('fontWeight must be a number.');
return;
}
-
this._fontWeight = fontWeight;
this.updateJSON();
}
+
/**
* The font style of the path ('italic' or 'oblique').
* @type {string}
*/
-
-
get fontStyle() {
return this._fontStyle;
}
-
set fontStyle(fontStyle) {
this._fontStyle = fontStyle;
this.updateJSON();
}
+
/**
* The original style of the path (used to recover the path's style if it was changed by a custom onion skin style)
* @type {object}
*/
-
-
get originalStyle() {
return this._originalStyle;
}
-
set originalStyle(originalStyle) {
this._originalStyle = originalStyle;
}
+
/**
* The content of the text.
* @type {string}
*/
-
-
get textContent() {
return this.view.item.content;
}
-
set textContent(textContent) {
this.view.item.content = textContent;
}
+
/**
* Update the JSON of the path based on the path on the view.
*/
-
-
updateJSON() {
this.json = this.view.exportJSON();
}
+
/**
* API function to change the textContent of dynamic text paths.
*/
-
-
setText(newTextContent) {
this.textContent = newTextContent;
}
+
/**
* Check if this path is a dynamic text object.
* @type {boolean}
*/
-
-
get isDynamicText() {
return this.pathType === 'text' && this.identifier !== null;
}
+
/**
* The image asset that this path uses, if this path is a Raster path.
* @returns {Wick.Asset[]}
*/
//should this also return the SVGAsset if the path is loaded from an SVGAsset
-
-
getLinkedAssets() {
var linkedAssets = [];
var data = this.serialize(); // just need the asset uuid...
-
if (data.json[0] === 'Raster') {
var uuid = data.json[1].source.split(':')[1];
linkedAssets.push(this.project.getAssetByUUID(uuid));
}
-
return linkedAssets;
}
+
/**
* Removes this path from its parent frame.
*/
-
-
remove() {
this.parentFrame.removePath(this);
}
+
/**
* Creates a new path using boolean unite on multiple paths. The resulting path will use the fillColor, strokeWidth, and strokeColor of the first path in the array.
* @param {Wick.Path[]} paths - an array containing the paths to process.
* @returns {Wick.Path} The path resulting from the boolean unite.
*/
-
-
static unite(paths) {
return Wick.Path.booleanOp(paths, 'unite');
}
+
/**
* Creates a new path using boolean subtration on multiple paths. The resulting path will use the fillColor, strokeWidth, and strokeColor of the first path in the array.
* @param {Wick.Path[]} paths - an array containing the paths to process.
* @returns {Wick.Path} The path resulting from the boolean subtraction.
*/
-
-
static subtract(paths) {
return Wick.Path.booleanOp(paths, 'subtract');
}
+
/**
* Creates a new path using boolean intersection on multiple paths. The resulting path will use the fillColor, strokeWidth, and strokeColor of the first path in the array.
* @param {Wick.Path[]} paths - an array containing the paths to process.
* @returns {Wick.Path} The path resulting from the boolean intersection.
*/
-
-
static intersect(paths) {
return Wick.Path.booleanOp(paths, 'intersect');
}
+
/**
* Perform a paper.js boolean operation on a list of paths.
* @param {Wick.Path[]} paths - a list of paths to perform the boolean operation on.
* @param {string} booleanOpName - the name of the boolean operation to perform. Currently supports "unite", "subtract", and "intersect"
*/
-
-
static booleanOp(paths, booleanOpName) {
if (!booleanOpName) {
console.error('Wick.Path.booleanOp: booleanOpName is required');
}
-
if (booleanOpName !== 'unite' && booleanOpName !== 'subtract' && booleanOpName !== 'intersect') {
console.error('Wick.Path.booleanOp: unsupported booleanOpName: ' + booleanOpName);
}
-
if (!paths || paths.length === 0) {
console.error('Wick.Path.booleanOp: a non-empty list of paths is required');
- } // Single path? Nothing to do.
-
+ }
+ // Single path? Nothing to do.
if (paths.length === 1) {
return paths[0];
- } // Get paper.js path objects
-
+ }
+ // Get paper.js path objects
paths = paths.map(path => {
return path.view.item;
});
@@ -54327,21 +53743,18 @@ Wick.Path = class extends Wick.Base {
});
return resultWickPath;
}
+
/**
* Converts a stroke into fill. Only works with paths that have a strokeWidth and strokeColor, and have no fillColor. Does nothing otherwise.
* @returns {Wick.Path} A flattened version of this path. Can be null if the path cannot be flattened.
*/
-
-
flatten() {
if (this.fillColor || !this.strokeColor || !this.strokeWidth) {
return null;
}
-
if (!(this instanceof paper.Path)) {
return null;
}
-
var flatPath = new Wick.Path({
json: this.view.item.flatten().exportJSON({
asString: false
@@ -54350,20 +53763,17 @@ Wick.Path = class extends Wick.Base {
flatPath.fillColor = this.strokeColor;
return flatPath;
}
+
/**
* Is this path used as a placeholder for preventing empty clips?
* @type {bool}
*/
-
-
set isPlaceholder(isPlaceholder) {
this._isPlaceholder = isPlaceholder;
}
-
get isPlaceholder() {
return this._isPlaceholder;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -54383,6 +53793,7 @@ Wick.Path = class extends Wick.Base {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Asset = class extends Wick.Base {
/**
* Creates a new Wick Asset.
@@ -54393,46 +53804,40 @@ Wick.Asset = class extends Wick.Base {
super(args);
this.name = args.name;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.name = this.name;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.name = data.name;
}
+
/**
* A list of all objects using this asset.
*/
-
-
- getInstances() {// Implemented by subclasses
+ getInstances() {
+ // Implemented by subclasses
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
- hasInstances() {// Implemented by sublasses
+ hasInstances() {
+ // Implemented by sublasses
}
+
/**
* Remove all instances of this asset from the project. (Implemented by ClipAsset, ImageAsset, and SoundAsset)
*/
-
-
- removeAllInstances() {// Implemented by sublasses
+ removeAllInstances() {
+ // Implemented by sublasses
}
-
get classname() {
return 'Asset';
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -54452,6 +53857,7 @@ Wick.Asset = class extends Wick.Base {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.FileAsset = class extends Wick.Asset {
/**
* Returns all valid MIME types for files which can be converted to Wick Assets.
@@ -54466,13 +53872,12 @@ Wick.FileAsset = class extends Wick.Asset {
let gifTypes = Wick.GIFAsset.getValidMIMETypes();
return imageTypes.concat(soundTypes).concat(fontTypes).concat(clipTypes).concat(svgTypes).concat(gifTypes);
}
+
/**
* Returns all valid extensions types for files which can be attempted to be
* converted to Wick Assets.
* @return {string[]} Array of strings representing extensions.
*/
-
-
static getValidExtensions() {
let imageExtensions = Wick.ImageAsset.getValidExtensions();
let soundExtensions = Wick.SoundAsset.getValidExtensions();
@@ -54482,13 +53887,12 @@ Wick.FileAsset = class extends Wick.Asset {
let gifExtensions = Wick.GIFAsset.getValidExtensions();
return imageExtensions.concat(soundExtensions).concat(fontExtensions).concat(clipExtensions).concat(svgExtensions).concat(gifExtensions);
}
+
/**
* Create a new FileAsset.
* @param {string} filename - the filename of the file being used as this asset's source.
* @param {string} src - a base64 string containing the source for this asset.
*/
-
-
constructor(args) {
if (!args) args = {};
args.name = args.filename;
@@ -54498,48 +53902,38 @@ Wick.FileAsset = class extends Wick.Asset {
this.filename = args.filename;
this.src = args.src;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.filename = this.filename;
data.MIMEType = this.MIMEType;
data.fileExtension = this.fileExtension;
-
if (args && args.includeOriginalSource) {
data.originalSource = this.src;
}
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.filename = data.filename;
this.MIMEType = data.MIMEType;
this.fileExtension = data.fileExtension;
-
if (data.originalSource) {
this.src = data.originalSource;
}
}
-
get classname() {
return 'FileAsset';
}
+
/**
* The source of the data of the asset, in base64. Returns null if the file is not found.
* @type {string}
*/
-
-
get src() {
let file = Wick.FileCache.getFile(this.uuid);
if (file) return file.src;
return null;
}
-
set src(src) {
if (src) {
Wick.FileCache.addFile(src, this.uuid);
@@ -54547,36 +53941,30 @@ Wick.FileAsset = class extends Wick.Asset {
this.MIMEType = this._MIMETypeOfString(src);
}
}
+
/**
* Loads data about the file into the asset.
*/
-
-
load(callback) {
callback();
}
+
/**
* Copies the FileAsset and also copies the src in FileCache.
* @return {Wick.FileAsset}
*/
-
-
copy() {
var copy = super.copy();
copy.src = this.src;
return copy;
}
-
_MIMETypeOfString(string) {
return string.split(':')[1].split(',')[0].split(';')[0];
}
-
_fileExtensionOfString(string) {
var MIMEType = this._MIMETypeOfString(string);
-
return MIMEType && MIMEType.split('/')[1];
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -54596,6 +53984,7 @@ Wick.FileAsset = class extends Wick.Asset {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.FontAsset = class extends Wick.FileAsset {
/**
* Valid MIME types for font assets.
@@ -54604,63 +53993,53 @@ Wick.FontAsset = class extends Wick.FileAsset {
static getValidMIMETypes() {
return ['font/ttf', 'application/x-font-ttf', 'application/x-font-truetype'];
}
+
/**
* Valid extensions for font assets.
* @returns {string[]} Array of strings representing extensions.
*/
-
-
static getValidExtensions() {
return ['.ttf'];
}
+
/**
* The default font to use if a font couldn't load, or if a FontAsset was deleted
* @type {string}
*/
-
-
static get MISSING_FONT_DEFAULT() {
return 'Helvetica, Arial, sans-serif';
}
+
/**
* Create a new FontAsset.
* @param {object} args - Asset constructor args. see constructor for Wick.Asset
*/
-
-
constructor(args) {
super(args);
}
-
_serialize(args) {
var data = super._serialize(args);
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
}
-
get classname() {
return 'FontAsset';
}
+
/**
* Loads the font into the window.
* @param {function} callback - function to call when the font is done being loaded.
*/
-
-
load(callback) {
var fontDataArraybuffer = Base64ArrayBuffer.decode(this.src.split(',')[1]);
var fontFamily = this.fontFamily;
-
if (!fontFamily) {
console.error('FontAsset: Could not get fontFamily from filename.');
} else if (fontFamily === "") {
console.error('FontAsset: fontfamily not found. Showing as "".');
}
-
var font = new FontFace(fontFamily, fontDataArraybuffer);
font.load().then(loaded_face => {
document.fonts.add(loaded_face);
@@ -54671,12 +54050,11 @@ Wick.FontAsset = class extends Wick.FileAsset {
callback(); // Make the callback so that the page doesn't freeze.
});
}
+
/**
* A list of Wick Paths that use this font as their fontFamily.
* @returns {Wick.Path[]}
*/
-
-
getInstances() {
var paths = [];
this.project.getAllFrames().forEach(frame => {
@@ -54688,35 +54066,31 @@ Wick.FontAsset = class extends Wick.FileAsset {
});
return paths;
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
hasInstances() {
return this.getInstances().length > 0;
}
+
/**
* Finds all PointText paths using this font as their fontFamily and replaces that font with a default font.
*/
-
-
removeAllInstances() {
this.getInstances().forEach(path => {
path.fontFamily = Wick.FontAsset.MISSING_FONT_DEFAULT;
});
}
+
/**
* The name of the font that this FontAsset represents.
* @type {string}
*/
-
-
get fontFamily() {
return this.filename.split('.')[0];
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -54736,6 +54110,7 @@ Wick.FontAsset = class extends Wick.FileAsset {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.ImageAsset = class extends Wick.FileAsset {
/**
* Valid MIME types for image assets.
@@ -54746,48 +54121,40 @@ Wick.ImageAsset = class extends Wick.FileAsset {
let pngTypes = ['image/png'];
return jpgTypes.concat(pngTypes);
}
+
/**
* Valid extensions for image assets.
* @returns {string[]} Array of strings representing extensions.
*/
-
-
static getValidExtensions() {
return ['.jpeg', '.jpg', '.png'];
}
+
/**
* Create a new ImageAsset.
* @param {object} args - Asset constructor args. see constructor for Wick.Asset
*/
-
-
constructor(args) {
super(args);
this.gifAssetUUID = null;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.gifAssetUUID = this.gifAssetUUID;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.gifAssetUUID = data.gifAssetUUID;
}
-
get classname() {
return 'ImageAsset';
}
+
/**
* A list of Wick Paths that use this image as their image source.
* @returns {Wick.Path[]}
*/
-
-
getInstances() {
var paths = [];
this.project.getAllFrames().forEach(frame => {
@@ -54799,69 +54166,61 @@ Wick.ImageAsset = class extends Wick.FileAsset {
});
return paths;
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
hasInstances() {
return this.getInstances().length > 0;
}
+
/**
* Removes all paths using this asset as their image source from the project.
* @returns {boolean}
*/
-
-
removeAllInstances() {
this.getInstances().forEach(path => {
path.remove();
});
}
+
/**
* Load data in the asset
* @param {function} callback - function to call when the data is done being loaded.
*/
-
-
load(callback) {
// Try to get paper.js to cache the image src.
var img = new Image();
img.src = this.src;
-
img.onload = () => {
var raster = new paper.Raster(img);
raster.remove();
callback();
};
-
img.onerror = () => {
this.project.errorOccured("Error loading image " + this.filename + ". Check that this is loaded properly.");
callback();
};
}
+
/**
* Creates a new Wick Path that uses this asset's image data as it's image source.
* @param {function} callback - called when the path is done loading.
*/
-
-
createInstance(callback) {
Wick.Path.createImagePath(this, path => {
callback(path);
});
}
+
/**
* Is this image asset part of a GIF? (if this is set to true, this asset won't appear in the asset library GUI)
* @type {boolean}
*/
-
-
get isGifImage() {
return this.gifAssetUUID;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -54881,6 +54240,7 @@ Wick.ImageAsset = class extends Wick.FileAsset {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.ClipAsset = class extends Wick.FileAsset {
/**
* Returns all valid MIME types for files which can be converted to ClipAssets.
@@ -54889,29 +54249,26 @@ Wick.ClipAsset = class extends Wick.FileAsset {
static getValidMIMETypes() {
return ['application/json', 'application/octet-stream'];
}
+
/**
* Returns all valid extensions types for files which can be attempted to be
* converted to ClipAssets.
* @return {string[]} Array of strings representing extensions.
*/
-
-
static getValidExtensions() {
return ['.wickobj'];
}
+
/**
* Creates a ClipAsset from the data of a given Clip.
* @param {Wick.Clip} - the clip to use as a source
* @param {function} callback -
*/
-
-
static fromClip(clip, project, callback) {
project.addObject(clip);
Wick.WickObjectFile.toWickObjectFile(clip, 'blob', file => {
// Convert blob to dataURL
var a = new FileReader();
-
a.onload = e => {
// Create ClipAsset
var clipAsset = new Wick.ClipAsset({
@@ -54921,39 +54278,32 @@ Wick.ClipAsset = class extends Wick.FileAsset {
clip.remove();
callback(clipAsset);
};
-
a.readAsDataURL(file);
});
}
+
/**
* Create a new ClipAsset.
* @param {object} args
*/
-
-
constructor(args) {
super(args);
}
-
_serialize(args) {
var data = super._serialize(args);
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
}
-
get classname() {
return 'ClipAsset';
}
+
/**
* A list of Wick Clips that use this ClipAsset as their source.
* @returns {Wick.Clip[]}
*/
-
-
getInstances() {
var clips = [];
this.project.getAllFrames().forEach(frame => {
@@ -54965,68 +54315,61 @@ Wick.ClipAsset = class extends Wick.FileAsset {
});
return clips;
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
hasInstances() {
return this.getInstances().length > 0;
}
+
/**
* Removes all Clips using this asset as their source from the project.
* @returns {boolean}
*/
-
-
removeAllInstances() {
this.getInstances().forEach(instance => {
instance.remove();
- }); // Also remove any ImageAssets that are part of this clip, and are GIF frames
+ });
+ // Also remove any ImageAssets that are part of this clip, and are GIF frames
this.project.getAllFrames().forEach(frame => {
frame.paths.forEach(path => {
var images = path.getLinkedAssets();
-
if (images.length > 0 && images[0].gifAssetUUID === this.uuid) {
images[0].remove();
}
});
});
}
+
/**
* Load data in the asset
* @param {function} callback - function to call when the data is done being loaded.
*/
-
-
load(callback) {
// We don't need to do anything here, the data for ClipAssets is just json
callback();
}
+
/**
* Creates a new Wick Clip that uses this asset's data.
* @param {function} callback - called when the Clip is done loading.
*/
-
-
createInstance(callback, project) {
if (!callback) {
console.warn("Cannot create clip instance without callback.");
}
-
if (!project) {
console.warn("Cannot create clip instance without project reference.");
}
-
Wick.WickObjectFile.fromWickObjectFile(this.src, data => {
var clip = Wick.Base.import(data, project).copy();
clip.assetSourceUUID = this.uuid;
callback(clip);
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -55046,6 +54389,7 @@ Wick.ClipAsset = class extends Wick.FileAsset {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.GIFAsset = class extends Wick.ClipAsset {
/**
* Returns all valid MIME types for files which can be converted to GIFAssets.
@@ -55054,28 +54398,25 @@ Wick.GIFAsset = class extends Wick.ClipAsset {
static getValidMIMETypes() {
return ['image/gif'];
}
+
/**
* Returns all valid extensions types for files which can be attempted to be
* converted to GIFAssets.
* @return {string[]} Array of strings representing extensions.
*/
-
-
static getValidExtensions() {
return ['.gif'];
}
+
/**
* Create a new GIFAsset from a series of images.
* @param {Wick.ImageAsset} images - The ImageAssets, in order of where they will appear in the timeline, which are used to create a ClipAsset
* @param {function} callback - Fuction to be called when the asset is done being created
*/
-
-
static fromImages(images, project, callback) {
var clip = new Wick.Clip();
clip.activeFrame.remove();
var imagesCreatedCount = 0;
-
var processNextImage = () => {
images[imagesCreatedCount].createInstance(imagePath => {
// Create a frame for every image
@@ -55083,10 +54424,10 @@ Wick.GIFAsset = class extends Wick.ClipAsset {
start: imagesCreatedCount + 1
});
frame.addPath(imagePath);
- clip.activeLayer.addFrame(frame); // Check if all images have been created
+ clip.activeLayer.addFrame(frame);
+ // Check if all images have been created
imagesCreatedCount++;
-
if (imagesCreatedCount === images.length) {
Wick.ClipAsset.fromClip(clip, project, clipAsset => {
// Attach a reference to the resulting clip to all images
@@ -55101,72 +54442,61 @@ Wick.GIFAsset = class extends Wick.ClipAsset {
}
});
};
-
processNextImage();
}
+
/**
* Create a new GIFAsset.
* @param {object} args - Asset args, see Wick.Asset constructor
*/
-
-
constructor(args) {
super(args);
}
-
_serialize(args) {
var data = super._serialize(args);
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
}
-
get classname() {
return 'GIFAsset';
}
+
/**
* A list of objects that use this asset as their source.
* @returns {Wick.Clip[]}
*/
-
-
getInstances() {
// Inherited from ClipAsset
return super.getInstances();
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
hasInstances() {
// Inherited from ClipAsset
return super.hasInstances();
}
+
/**
* Removes all objects using this asset as their source from the project.
* @returns {boolean}
*/
-
-
removeAllInstances() {
// Inherited from ClipAsset
super.removeAllInstances();
}
+
/**
* Load data in the asset
*/
-
-
load(callback) {
// We don't need to do anything here, the data for ClipAssets/GIFAssets is just json
callback();
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -55186,6 +54516,7 @@ Wick.GIFAsset = class extends Wick.ClipAsset {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.SoundAsset = class extends Wick.FileAsset {
/**
* Returns valid MIME types for a Sound Asset.
@@ -55197,39 +54528,34 @@ Wick.SoundAsset = class extends Wick.FileAsset {
let wavTypes = ['audio/wave', 'audio/wav', 'audio/x-wav', 'audio/x-pn-wav'];
return mp3Types.concat(oggTypes).concat(wavTypes);
}
+
/**
* Returns valid extensions for a sound asset.
* @returns {string[]} Array of strings representing valid
*/
-
-
static getValidExtensions() {
return ['.mp3', '.ogg', '.wav'];
}
+
/**
* Creates a new SoundAsset.
* @param {object} args - Asset constructor args. see constructor for Wick.Asset
*/
-
-
constructor(args) {
super(args);
this._waveform = null;
}
-
_serialize(args) {
var data = super._serialize(args);
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
}
-
get classname() {
return 'SoundAsset';
}
+
/**
* Plays this asset's sound.
* @param {number} seekMS - the amount of time in milliseconds into the sound the sound should start at.
@@ -55237,61 +54563,51 @@ Wick.SoundAsset = class extends Wick.FileAsset {
* @param {boolean} loop - if set to true, the sound will loop
* @return {number} The id of the sound instance that was played.
*/
-
-
play(options) {
if (!options) options = {};
if (options.seekMS === undefined) options.seekMS = 0;
if (options.volume === undefined) options.volume = 1.0;
- if (options.loop === undefined) options.loop = false; // don't do anything if the project is muted...
+ if (options.loop === undefined) options.loop = false;
+ // don't do anything if the project is muted...
if (this.project.muted) {
return;
}
-
var id = this._howl.play();
-
this._howl.seek(options.seekMS / 1000, id);
-
this._howl.volume(options.volume, id);
-
this._howl.loop(options.loop, id);
-
return id;
}
+
/**
* Stops this asset's sound.
* @param {number} id - (optional) the ID of the instance to stop. If ID is not given, every instance of this sound will stop.
*/
-
-
stop(id) {
// Howl instance was never created, sound has never played yet, so do nothing
if (!this._howl) {
return;
}
-
if (id === undefined) {
this._howl.stop();
} else {
this._howl.stop(id);
}
}
+
/**
* The length of the sound in seconds
* @type {number}
*/
-
-
get duration() {
return this._howl.duration();
}
+
/**
* A list of frames that use this sound.
* @returns {Wick.Frame[]}
*/
-
-
getInstances() {
var frames = [];
this.project.getAllFrames().forEach(frame => {
@@ -55301,31 +54617,28 @@ Wick.SoundAsset = class extends Wick.FileAsset {
});
return frames;
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
hasInstances() {
return this.getInstances().length > 0;
}
+
/**
* Remove the sound from any frames in the project that use this asset as their sound.
*/
-
-
removeAllInstances() {
this.getInstances().forEach(frame => {
frame.removeSound();
});
}
+
/**
* Loads data about the sound into the asset.
* @param {function} callback - function to call when the data is done being loaded.
*/
-
-
load(callback) {
this._generateWaveform(() => {
this._waitForHowlLoad(() => {
@@ -55333,16 +54646,14 @@ Wick.SoundAsset = class extends Wick.FileAsset {
});
});
}
+
/**
* Image of the waveform of this sound.
* @type {Image}
*/
-
-
get waveform() {
return this._waveform;
}
-
get _howl() {
// Lazily create howler instance
if (!this._howlInstance) {
@@ -55353,10 +54664,8 @@ Wick.SoundAsset = class extends Wick.FileAsset {
src: [srcFixed]
});
}
-
return this._howlInstance;
}
-
_waitForHowlLoad(callback) {
if (this._howl.state() === 'loaded') {
callback();
@@ -55366,29 +54675,24 @@ Wick.SoundAsset = class extends Wick.FileAsset {
});
}
}
-
_generateWaveform(callback) {
if (this._waveform) {
callback();
return;
}
-
var soundSrc = this.src;
if (!soundSrc) console.log("error", this, soundSrc);
var scwf = new SCWF();
scwf.generate(soundSrc, {
onComplete: (png, pixels) => {
this._waveform = new Image();
-
this._waveform.onload = () => {
callback();
};
-
this._waveform.src = png;
}
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -55408,6 +54712,7 @@ Wick.SoundAsset = class extends Wick.FileAsset {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.SVGAsset = class extends Wick.FileAsset {
/**
* Returns all valid MIME types for files which can be converted to SVGAssets.
@@ -55416,82 +54721,72 @@ Wick.SVGAsset = class extends Wick.FileAsset {
static getValidMIMETypes() {
return ['image/svg+xml'];
}
+
/**
* Returns all valid extensions types for files which can be attempted to be
* converted to SVGAssets.
* @return {string[]} Array of strings representing extensions.
*/
-
-
static getValidExtensions() {
return ['.svg'];
}
+
/**
* Create a new SVGAsset.
* @param {object} args
*/
-
-
constructor(args) {
super(args);
}
-
_serialize(args) {
var data = super._serialize(args);
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
}
-
get classname() {
return 'SVGAsset';
}
+
/**
* A list of Wick Paths, Clips and Layers that use this SVGAsset as their image source.
* I think this should return Assets not Paths
* @returns {Wick.Path[]}
*/
-
-
getInstances() {
return []; // TODO
}
+
/**
* Check if there are any objects in the project that use this asset.
* @returns {boolean}
*/
-
-
hasInstances() {
return false;
}
+
/**
* Removes all Items using this asset as their source from the project.
* @returns {boolean}
*/
-
-
- removeAllInstances() {// TODO
+ removeAllInstances() {
+ // TODO
}
+
/**
* Load data in the asset
*/
-
-
load(callback) {
// We don't need to do anything here, the data for SVGAssets is just SVG
callback();
}
+
/**
* Walks through the items tree creating the apprptiate wick object for each node*
* @param {paper.Item} item - called when the Path is done loading.
* @returns {Wick.Base}
*/
-
-
static walkItems(item) {
// create paths for all the path items, this also needs to be done for the following item.className=:
// 'Group', 'Layer', 'Path', 'CompoundPath', 'Shape', 'Raster', 'SymbolItem', 'PointText'
@@ -55505,16 +54800,15 @@ Wick.SVGAsset = class extends Wick.FileAsset {
var frame = new Wick.Frame();
wickItem.addFrame(frame);
var groupChildren = Array.from(item.children); //prevent any side effects
-
groupChildren.forEach(childItem => {
var wickChildItem = Wick.SVGAsset.walkItems(childItem).copy();
-
if (wickChildItem instanceof Wick.Clip) {
frame.addClip(wickChildItem);
} else if (wickChildItem instanceof Wick.Path) {
frame.addPath(wickChildItem);
} else if (wickChildItem instanceof Wick.Layer) {
- frame.addLayer(wickChildItem); //console.error("SVG Import: Error importing, nested layers.ignoring."); // Insert text
+ frame.addLayer(wickChildItem);
+ //console.error("SVG Import: Error importing, nested layers.ignoring."); // Insert text
} else {
console.error("SVG Import: Unknown item type.".concat(wickChildItem.classname)); // Insert text
}
@@ -55524,12 +54818,10 @@ Wick.SVGAsset = class extends Wick.FileAsset {
var wickObjects = [];
var layers = [];
var groupChildren = Array.from(item.children); //prevent any side effects
-
groupChildren.forEach(childItem => {
- var clipActiveLayer = wickItem.activeLayer; ///This should be clips and paths not layers
-
+ var clipActiveLayer = wickItem.activeLayer;
+ ///This should be clips and paths not layers
var walkItem = Wick.SVGAsset.walkItems(childItem).copy();
-
if (walkItem instanceof Wick.Layer) {
//console.error("SVG Import: Clip has a child that is a layer, this should never happen. ignoring."); // Insert text
layers.push(walkItem);
@@ -55540,9 +54832,7 @@ Wick.SVGAsset = class extends Wick.FileAsset {
});
wickItem.addObjects(wickObjects); //add the items to the project
// add layers after onjects so the objexts don't get bound to the new layer
-
var layersCopy = Array.from(layers); //prevent any side effects
-
layersCopy.forEach(layer => {
wickItem.timeline.addLayer(layer);
});
@@ -55556,7 +54846,6 @@ Wick.SVGAsset = class extends Wick.FileAsset {
json: item.exportJSON()
});
}
-
return wickItem;
}
/**
@@ -55568,11 +54857,8 @@ Wick.SVGAsset = class extends Wick.FileAsset {
* Walks through the items tree converting shapes into paths. This should be possible to do in the walkitems routine
* @param {Paper.Item} item - called when the Path is done loading.
*/
-
-
static _breakAppartShapesRecursively(item) {
item.applyMatrix = true;
-
if (item instanceof paper.Group || item instanceof paper.Layer) {
var children = Array.from(item.children);
children.forEach(childItem => {
@@ -55580,19 +54866,19 @@ Wick.SVGAsset = class extends Wick.FileAsset {
});
} else if (item instanceof paper.Shape) {
//This should have been done automatically by the import options, spo shouldn't be needed
- var path = item.toPath(); //item.parent.addChild(path);
+ var path = item.toPath();
+ //item.parent.addChild(path);
//path.insertAbove(item);
//item.remove();
-
item.replaceWith(path);
}
}
+
/**
* Creates a new Wick SVG that uses this asset's data.
* @param {function} callback - called when the SVG is done loading.
*/
-
createInstance(callback) {
// needs to take a base64 encoded string.
//we need a viewSVG and an SVG object that extends base by the looks of things.
@@ -55626,16 +54912,12 @@ Wick.SVGAsset = class extends Wick.FileAsset {
expandShapes: true,
insert: false
});
-
Wick.SVGAsset._breakAppartShapesRecursively(item);
-
var wickItem = Wick.SVGAsset.walkItems(item).copy();
callback(wickItem);
};
-
Wick.SVGFile.fromSVGFile(this.src, importSVG);
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -55666,20 +54948,18 @@ Wick.Tickable = class extends Wick.Base {
static get LOG_ERRORS() {
return false;
}
+
/**
* Returns a list of all possible events for this object.
* @return {string[]} Array of all possible scripts.
*/
-
-
static get possibleScripts() {
return ['default', 'mouseenter', 'mousedown', 'mousepressed', 'mousereleased', 'mouseleave', 'mousehover', 'mousedrag', 'mouseclick', 'keypressed', 'keyreleased', 'keydown', 'load', 'update', 'unload'];
}
+
/**
* Create a new tickable object.
*/
-
-
constructor(args) {
if (!args) args = {};
super(args);
@@ -55694,10 +54974,8 @@ Wick.Tickable = class extends Wick.Base {
this._onEventFns = {};
this._cachedScripts = {};
}
-
_deserialize(data) {
super._deserialize(data);
-
this._onscreen = false;
this._onscreenLastTick = false;
this._mouseState = 'out';
@@ -55707,139 +54985,119 @@ Wick.Tickable = class extends Wick.Base {
this._onEventFns = {};
this._cachedScripts = {};
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.scripts = JSON.parse(JSON.stringify(this._scripts));
data.cursor = this.cursor;
return data;
}
-
get classname() {
return 'Tickable';
}
+
/**
* The scripts on this object.
* @type {object[]}
*/
-
-
get scripts() {
return this._scripts;
}
+
/**
* Checks if this object has a non-empty script.
* @type {boolean}
*/
-
-
get hasContentfulScripts() {
var hasContentfulScripts = false;
-
for (var script of this.scripts) {
if (this.scriptIsContentful(script.name)) {
hasContentfulScripts = true;
}
}
-
return hasContentfulScripts;
}
+
/**
* Check if this object is currently visible in the project, based on its parent.
* @type {boolean}
*/
-
-
get onScreen() {
if (!this.parent) return false;
return this.parent.onScreen;
}
+
/**
* Add a function to be called when an event happens.
* @param {string} name - The name of the event to attach the function to.
* @param {function} fn - The function to call when the given event happens.
*/
-
-
onEvent(name, fn) {
if (Wick.Tickable.possibleScripts.indexOf(name) === -1) {
console.warn("onEvent: " + name + " is not a valid event name.");
return;
}
-
this.addEventFn(name, fn);
}
+
/**
* Attach a function to a given event.
* @param {string} name - the name of the event to attach a function to.
* @param {function} fn - the function to attach
*/
-
-
addEventFn(name, fn) {
this.getEventFns(name).push(fn);
}
+
/**
* Gets all functions attached to an event with a given name.
* @param {string} - The name of the event
*/
-
-
getEventFns(name) {
if (!this._onEventFns[name]) {
this._onEventFns[name] = [];
}
-
return this._onEventFns[name];
}
+
/**
* Check if an object can have scripts attached to it. Helpful when iterating through a lot of different wick objects that may or may not be tickables. Always returns true.
* @type {boolean}
*/
-
-
get isScriptable() {
return true;
}
+
/**
* Add a new script to an object.
* @param {string} name - The name of the event that will trigger the script. See Wick.Tickable.possibleScripts
* @param {string} src - The source code of the new script.
*/
-
-
addScript(name, src) {
if (Wick.Tickable.possibleScripts.indexOf(name) === -1) console.error(name + ' is not a valid script!');
-
if (this.hasScript(name)) {
this.updateScript(name, src);
return;
}
-
this._scripts.push({
name: name,
src: ''
- }); // Sort scripts by where they appear in the possibleScripts list
-
+ });
+ // Sort scripts by where they appear in the possibleScripts list
var possibleScripts = Wick.Tickable.possibleScripts;
-
this._scripts.sort((a, b) => {
return possibleScripts.indexOf(a.name) - possibleScripts.indexOf(b.name);
});
-
if (src) {
this.updateScript(name, src);
}
}
+
/**
* Get the script of this object that is triggered when the given event name happens.
* @param {string} name - The name of the event. See Wick.Tickable.possibleScripts
* @returns {object} the script with the given name. Can be null if the object doesn't have that script.
*/
-
-
getScript(name) {
if (Wick.Tickable.possibleScripts.indexOf(name) === -1) {
console.error(name + ' is not a valid script!');
@@ -55849,7 +55107,6 @@ Wick.Tickable = class extends Wick.Base {
let script = this._scripts.find(script => {
return script.name === name;
});
-
if (!script) {
// Create the script if it doesn't exist.
script = {
@@ -55857,167 +55114,145 @@ Wick.Tickable = class extends Wick.Base {
src: ""
};
return script;
- } // If the script is missing, add an empty.
-
+ }
+ // If the script is missing, add an empty.
if (!script.src) {
script.src = "";
}
-
return script;
}
}
+
/**
* Returns a list of script names which are not currently in use for this object.
* @return {string[]} Available script names.
*/
-
-
getAvailableScripts() {
return Wick.Tickable.possibleScripts.filter(script => !this.hasScript(script));
}
+
/**
* Check if the object has a script with the given event name.
* @param {string} name - The name of the event. See Wick.Tickable.possibleScripts
* @returns {boolean} True if the script with the given name exists
*/
-
-
hasScript(name) {
let script = this.scripts.find(script => script.name === name);
-
if (script) {
return true;
}
-
return false;
}
+
/**
* Check if the object has a non-empty script with a given name.
* @param {string} name - The name of the event. See Wick.Tickable.possibleScripts
* @returns {boolean} True if the script with the given name has code
*/
-
-
scriptIsContentful(name) {
if (!this.hasScript(name)) {
return false;
}
-
var script = this.getScript(name);
-
if (script && script.src.trim() !== '') {
return true;
}
-
return false;
}
+
/**
* Changes the source of the script with the given event name.
* @param {string} name - The name of the event that will trigger the script. See Wick.Tickable.possibleScripts
* @param {string} src - The source code of the script.
*/
-
-
updateScript(name, src) {
if (!src) src = ""; // Reset script if it is not defined.
-
this.getScript(name).src = src;
delete this._cachedScripts[name];
}
+
/**
* Remove the script that corresponds to a given event name.
* @param {string} name - The name of the event. See Wick.Tickable.possibleScripts
*/
-
-
removeScript(name) {
this._scripts = this._scripts.filter(script => {
return script.name !== name;
});
}
+
/**
* Schedule a script to run at the end of the tick.
* @param {string} name - The name of the script to run. See Tickable.possibleScripts
* @param {Object} parameters - An object consisting of key,value pairs which correspond to parameters to pass to the script.
*/
-
-
scheduleScript(name, parameters) {
if (!this.project) return;
this.project.scheduleScript(this.uuid, name, parameters);
}
+
/**
* Run the script with the corresponding event name. Will not run the script if the object is marked as removed.
* @param {string} name - The name of the event. See Wick.Tickable.possibleScripts
* @param {Object} parameters - An object containing key,value pairs of parameters to send to the script.
* @returns {object} object containing error info if an error happened. Returns null if there was no error (script ran successfully)
*/
-
-
runScript(name, parameters) {
if (this.removed || !this.onScreen) {
return;
}
-
if (!Wick.Tickable.possibleScripts.indexOf(name) === -1) {
console.error(name + ' is not a valid script!');
- } // Don't run scripts if this object is the focus
+ }
+ // Don't run scripts if this object is the focus
// (this makes it so preview play will always play, even if the parent Clip of the timeline has a stop script)
-
-
if (this.project && this.project.focus === this) {
return null;
- } // Run functions attached using onEvent
-
+ }
+ // Run functions attached using onEvent
var eventFnError = null;
this.getEventFns(name).forEach(eventFn => {
if (eventFnError) return;
eventFnError = this._runFunction(eventFn, name, parameters);
});
-
if (eventFnError) {
this.project.error = eventFnError;
return;
- } // Run function inside tab
-
+ }
+ // Run function inside tab
if (this.scriptIsContentful(name)) {
var script = this.getScript(name);
-
var fn = this._cachedScripts[name] || this._evalScript(name, script.src);
-
if (!(fn instanceof Function)) {
return fn; // error
}
this._cachedScripts[name] = fn;
-
var error = this._runFunction(fn, name, parameters);
-
if (error && this.project) {
this.project.error = error;
return;
}
}
}
+
/**
* The tick routine to be called when the object ticks.
* @returns {object} - An object with information about the result from ticking. Null if no errors occured, and the script ran successfully.
*/
-
-
tick() {
// Update named child references
- this._attachChildClipReferences(); // Update onScreen flags.
-
+ this._attachChildClipReferences();
+ // Update onScreen flags.
this._onscreenLastTick = this._onscreen;
- this._onscreen = this.onScreen; // Update mouse states.
+ this._onscreen = this.onScreen;
+ // Update mouse states.
this._lastMouseState = this._mouseState;
-
if (this.project && this.project.objectIsMouseTarget(this)) {
if (this.project.isMouseDown) {
this._mouseState = 'down';
@@ -56026,9 +55261,9 @@ Wick.Tickable = class extends Wick.Base {
}
} else {
this._mouseState = 'out';
- } // Call tick event function that corresponds to state.
-
+ }
+ // Call tick event function that corresponds to state.
if (!this._onscreen && !this._onscreenLastTick) {
this._onInactive();
} else if (this._onscreen && !this._onscreenLastTick) {
@@ -56039,77 +55274,77 @@ Wick.Tickable = class extends Wick.Base {
this._onDeactivated();
}
}
-
- _onInactive() {// Do nothing.
+ _onInactive() {
+ // Do nothing.
}
-
_onActivated() {
this.runScript('default'); // Run the script immediately.
-
this.scheduleScript('load');
}
-
_onActive() {
this.scheduleScript('update');
var current = this._mouseState;
- var last = this._lastMouseState; // Mouse enter
+ var last = this._lastMouseState;
+ // Mouse enter
if (last === 'out' && current !== 'out') {
this.scheduleScript('mouseenter');
- } // Mouse down
-
+ }
+ // Mouse down
if (current === 'down') {
this.scheduleScript('mousedown');
- } // Mouse pressed
-
+ }
+ // Mouse pressed
if (last === 'over' && current === 'down') {
this._isClickTarget = true;
this.scheduleScript('mousepressed');
- } // Mouse click
-
+ }
+ // Mouse click
if (last === 'down' && current === 'over' && this._isClickTarget) {
this.scheduleScript('mouseclick');
- } // Mouse released
-
+ }
+ // Mouse released
if (last === 'down' && current === 'over') {
this._isClickTarget = false;
this.scheduleScript('mousereleased');
- } // Mouse leave
-
+ }
+ // Mouse leave
if (last !== 'out' && current === 'out') {
this.scheduleScript('mouseleave');
- } // Mouse hover
-
+ }
+ // Mouse hover
if (current === 'over') {
this.scheduleScript('mousehover');
- } // Mouse drag
-
+ }
+ // Mouse drag
if (last === 'down' && current === 'down') {
this.scheduleScript('mousedrag');
- } // Key down
-
+ }
+ // Key down
this.project.keysDown.forEach(key => {
this.project.currentKey = key;
this.scheduleScript('keydown', {
key: key
});
- }); // Key press
+ });
+ // Key press
this.project.keysJustPressed.forEach(key => {
this.project.currentKey = key;
this.scheduleScript('keypressed', {
key: key
});
- }); // Key released
+ });
+ // Key released
this.project.keysJustReleased.forEach(key => {
this.project.currentKey = key;
this.scheduleScript('keyreleased', {
@@ -56117,23 +55352,22 @@ Wick.Tickable = class extends Wick.Base {
});
});
}
-
_onDeactivated() {
this._isClickTarget = false;
this.scheduleScript('unload');
}
-
_evalScript(name, src) {
- var fn = null; // Check for syntax/parsing errors
+ var fn = null;
+ // Check for syntax/parsing errors
try {
esprima.parseScript(src);
} catch (e) {
this.project.error = this._generateEsprimaErrorInfo(e, name);
return;
- } // Attempt to create valid function...
-
+ }
+ // Attempt to create valid function...
try {
fn = new Function([], src);
} catch (e) {
@@ -56142,20 +55376,19 @@ Wick.Tickable = class extends Wick.Base {
this.project.error = this._generateErrorInfo(e, name);
return;
}
-
return fn;
}
+
/**
* _runFunction runs an event function while passing in necessary global and local parameters.
* @param {string} fn - Function to run.
* @param {string} name - Name of the event function being run (i.e. keyDown)
* @param {Object} parameters - An object of key,value pairs to be passed as parameters to the function.
*/
-
-
_runFunction(fn, name, parameters) {
- var error = null; // Attach API methods
+ var error = null;
+ // Attach API methods
var globalAPI = new GlobalAPI(this);
var otherObjects = this.parentClip ? this.parentClip.activeNamedChildren : [];
var apiMembers = globalAPI.apiMembers.concat(otherObjects.map(otherObject => {
@@ -56163,8 +55396,9 @@ Wick.Tickable = class extends Wick.Base {
name: otherObject.identifier,
fn: otherObject
};
- })); // Add in parameters, if necessary.
+ }));
+ // Add in parameters, if necessary.
if (parameters) {
Object.keys(parameters).forEach(parameter => {
apiMembers.push({
@@ -56173,50 +55407,50 @@ Wick.Tickable = class extends Wick.Base {
});
});
}
-
apiMembers.forEach(apiMember => {
window[apiMember.name] = apiMember.fn;
- }); // These are currently hacked in here for performance reasons...
+ });
+ // These are currently hacked in here for performance reasons...
var project = this.project;
var root = project && project.root;
window.project = root;
-
if (project) {
window.project.resolution = {
x: project.width,
y: project.height
};
window.project.framerate = project.framerate;
- window.project.backgroundColor = project.backgroundColor; //window.project.hitTestOptions = project.hitTestOptions;
+ window.project.backgroundColor = project.backgroundColor;
+ //window.project.hitTestOptions = project.hitTestOptions;
}
window.root = root;
window.parent = this.parentClip;
- window.parentObject = this.parentObject; // Run the function
+ window.parentObject = this.parentObject;
+ // Run the function
var thisScope = this instanceof Wick.Frame ? this.parentClip : this;
-
try {
fn.bind(thisScope)();
} catch (e) {
// Catch runtime errors
console.error(e);
error = this._generateErrorInfo(e, name);
- } // These are currently hacked in here for performance reasons...
-
+ }
+ // These are currently hacked in here for performance reasons...
delete window.project;
delete window.root;
delete window.parent;
- delete window.parentObject; // Detatch API methods
+ delete window.parentObject;
+ // Detatch API methods
apiMembers.forEach(apiMember => {
delete window[apiMember.name];
});
return error;
}
-
_generateErrorInfo(error, name) {
if (Wick.Tickable.LOG_ERRORS) console.log(error);
return {
@@ -56226,7 +55460,6 @@ Wick.Tickable = class extends Wick.Base {
uuid: this.isClone ? this.sourceClipUUID : this.uuid
};
}
-
_generateEsprimaErrorInfo(error, name) {
if (Wick.Tickable.LOG_ERRORS) console.log(error);
return {
@@ -56236,7 +55469,6 @@ Wick.Tickable = class extends Wick.Base {
uuid: this.uuid
};
}
-
_generateLineNumberFromStackTrace(trace) {
var lineNumber = null;
trace.split('\n').forEach(line => {
@@ -56244,7 +55476,6 @@ Wick.Tickable = class extends Wick.Base {
var split = line.split(':');
var lineString = split[split.length - 2];
var lineInt = parseInt(lineString);
-
if (!isNaN(lineInt)) {
lineNumber = lineInt - 2;
lineNumber = lineInt;
@@ -56253,10 +55484,9 @@ Wick.Tickable = class extends Wick.Base {
});
return lineNumber;
}
-
- _attachChildClipReferences() {// Implemented by Wick.Clip and Wick.Frame.
+ _attachChildClipReferences() {
+ // Implemented by Wick.Clip and Wick.Frame.
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -56298,10 +55528,8 @@ Wick.Frame = class extends Wick.Tickable {
this._soundStart = 0;
this._originalLayerIndex = -1;
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.start = this.start;
data.end = this.end;
data.sound = this._soundAssetUUID;
@@ -56311,10 +55539,8 @@ Wick.Frame = class extends Wick.Tickable {
data.originalLayerIndex = this.layerIndex !== -1 ? this.layerIndex : this._originalLayerIndex;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.start = data.start;
this.end = data.end;
this._soundAssetUUID = data.sound;
@@ -56323,129 +55549,112 @@ Wick.Frame = class extends Wick.Tickable {
this._soundStart = data.soundStart === undefined ? 0 : data.soundStart;
this._originalLayerIndex = data.originalLayerIndex;
}
-
get classname() {
return 'Frame';
}
+
/**
* The length of the frame.
* @type {number}
*/
-
-
get length() {
return this.end - this.start + 1;
}
-
set length(length) {
length = Math.max(1, length);
var diff = length - this.length;
this.end += diff;
}
+
/**
* The midpoint of the frame.
* @type {number}
*/
-
-
get midpoint() {
return this.start + (this.end - this.start) / 2;
}
+
/**
* Is true if the frame is currently visible.
* @type {boolean}
*/
-
-
get onScreen() {
if (!this.parent) return true;
return this.inPosition(this.parentTimeline.playheadPosition) && this.parentClip.onScreen;
}
+
/**
* The sound attached to the frame.
* @type {Wick.SoundAsset}
*/
-
-
get sound() {
var uuid = this._soundAssetUUID;
return uuid ? this.project.getAssetByUUID(uuid) : null;
}
-
set sound(soundAsset) {
if (!soundAsset) {
this.removeSound();
return;
}
-
this._soundAssetUUID = soundAsset.uuid;
}
+
/**
* The volume of the sound attached to the frame.
* @type {number}
*/
-
-
get soundVolume() {
return this._soundVolume;
}
-
set soundVolume(soundVolume) {
this._soundVolume = soundVolume;
}
+
/**
* Whether or not the sound loops.
* @type {boolean}
*/
-
-
get soundLoop() {
return this._soundLoop;
}
-
set soundLoop(soundLoop) {
this._soundLoop = soundLoop;
}
+
/**
* True if this frame should currently be onion skinned.
*/
-
-
get onionSkinned() {
if (!this.project || !this.project.onionSkinEnabled) {
return false;
- } // Don't onion skin if we're in the playhead's position.
-
+ }
+ // Don't onion skin if we're in the playhead's position.
var playheadPosition = this.project.focus.timeline.playheadPosition;
-
if (this.inPosition(playheadPosition)) {
return false;
- } // Determine if we're in onion skinning range.
-
+ }
+ // Determine if we're in onion skinning range.
var onionSkinSeekBackwards = this.project.onionSkinSeekBackwards;
var onionSkinSeekForwards = this.project.onionSkinSeekForwards;
return this.inRange(playheadPosition - onionSkinSeekBackwards, playheadPosition + onionSkinSeekForwards);
}
+
/**
* Removes the sound attached to this frame.
*/
-
-
removeSound() {
this._soundAssetUUID = null;
}
+
/**
* Plays the sound attached to this frame.
*/
-
-
playSound() {
if (!this.sound) {
return;
}
-
var options = {
seekMS: this.playheadSoundOffsetMS + this.soundStart,
volume: this.soundVolume,
@@ -56454,75 +55663,67 @@ Wick.Frame = class extends Wick.Tickable {
};
this._soundID = this.project.playSoundFromAsset(this.sound, options);
}
+
/**
* Stops the sound attached to this frame.
*/
-
-
stopSound() {
if (this.sound) {
this.sound.stop(this._soundID);
this._soundID = null;
}
}
+
/**
* Check if the sound on this frame is playing.
* @returns {boolean} true if the sound is playing
*/
-
-
isSoundPlaying() {
return this._soundID !== null;
}
+
/**
* The amount of time, in milliseconds, that the frame's sound should play before stopping.
* @type {number}
*/
-
-
get playheadSoundOffsetMS() {
var offsetFrames = this.parentTimeline.playheadPosition - this.start;
var offsetMS = 1000 / this.project.framerate * offsetFrames;
return offsetMS;
}
+
/**
* The amount of time the sound playing should be offset, in milliseconds. If this is 0,
* the sound plays normally. A negative value means the sound should start at a later point
* in the track. THIS DOES NOT DETERMINE WHEN A SOUND PLAYS.
* @type {number}
*/
-
-
get soundStart() {
return this._soundStart;
}
-
set soundStart(val) {
this._soundStart = val;
}
+
/**
* When should the sound start, in milliseconds.
* @type {number}
*/
-
-
get soundStartMS() {
return 1000 / this.project.framerate * (this.start - 1);
}
+
/**
* When should the sound end, in milliseconds.
* @type {number}
*/
-
-
get soundEndMS() {
return 1000 / this.project.framerate * this.end;
}
+
/**
* Returns the frame's start position in relation to the root timeline.
*/
-
-
get projectFrameStart() {
if (this.parentClip.isRoot) {
return this.start;
@@ -56531,50 +55732,45 @@ Wick.Frame = class extends Wick.Tickable {
return val;
}
}
+
/**
* The paths on the frame.
* @type {Wick.Path[]}
*/
-
-
get paths() {
return this.getChildren('Path');
}
+
/**
* The paths that are text and have identifiers, for dynamic text.
* @type {Wick.Path[]}
*/
-
-
get dynamicTextPaths() {
return this.paths.filter(path => {
return path.isDynamicText;
});
}
+
/**
* The clips on the frame.
* @type {Wick.Clip[]}
*/
-
-
get clips() {
return this.getChildren(['Clip', 'Button']);
}
+
/**
* The drawable objectson the frame.
* @type {Wick.Base[]}
*/
-
-
get drawable() {
return this.getChildren(['Clip', 'Button', 'Path']);
}
+
/**
* The tweens on this frame.
* @type {Wick.Tween[]}
*/
-
-
get tweens() {
// Ensure no tweens are outside of this frame's length.
var tweens = this.getChildren('Tween');
@@ -56583,182 +55779,161 @@ Wick.Frame = class extends Wick.Tickable {
});
return this.getChildren('Tween');
}
+
/**
* True if there are clips or paths on the frame.
* @type {boolean}
*/
-
-
get contentful() {
return this.paths.filter(path => {
return !path.view.item.data._isPlaceholder;
}).length > 0 || this.clips.length > 0;
}
+
/**
* The index of the parent layer.
* @type {number}
*/
-
-
get layerIndex() {
return this.parentLayer ? this.parentLayer.index : -1;
}
+
/**
* The index of the layer that this frame last belonged to. Used when copying and pasting frames.
* @type {number}
*/
-
-
get originalLayerIndex() {
return this._originalLayerIndex;
}
+
/**
* Removes this frame from its parent layer.
*/
-
-
remove() {
this.parent.removeFrame(this);
}
+
/**
* True if the playhead is on this frame.
* @param {number} playheadPosition - the position of the playhead.
* @return {boolean}
*/
-
-
inPosition(playheadPosition) {
return this.start <= playheadPosition && this.end >= playheadPosition;
}
+
/**
* True if the frame exists within the given range.
* @param {number} start - the start of the range to check.
* @param {number} end - the end of the range to check.
* @return {boolean}
*/
-
-
inRange(start, end) {
return this.inPosition(start) || this.inPosition(end) || this.start >= start && this.start <= end || this.end >= start && this.end <= end;
}
+
/**
* True if the frame is contained fully within a given range.
* @param {number} start - the start of the range to check.
* @param {number} end - the end of the range to check.
* @return {boolean}
*/
-
-
containedWithin(start, end) {
return this.start >= start && this.end <= end;
}
+
/**
* The number of frames that this frame is from a given playhead position.
* @param {number} playheadPosition
*/
-
-
distanceFrom(playheadPosition) {
// playhead position is inside frame, distance is zero.
if (this.start <= playheadPosition && this.end >= playheadPosition) {
return 0;
- } // otherwise, find the distance from the nearest end
-
+ }
+ // otherwise, find the distance from the nearest end
if (this.start >= playheadPosition) {
return this.start - playheadPosition;
} else if (this.end <= playheadPosition) {
return playheadPosition - this.end;
}
}
+
/**
* Add a clip to the frame.
* @param {Wick.Clip} clip - the clip to add.
*/
-
-
addClip(clip) {
if (clip.parent) {
clip.remove();
}
+ this.addChild(clip);
- this.addChild(clip); // Pre-render the clip's frames
+ // Pre-render the clip's frames
// (this fixes an issue where clips created from ClipAssets would be "missing" frames)
-
clip.timeline.getAllFrames(true).forEach(frame => {
frame.view.render();
});
}
+
/**
* Remove a clip from the frame.
* @param {Wick.Clip} clip - the clip to remove.
*/
-
-
removeClip(clip) {
this.removeChild(clip);
}
+
/**
* Add a path to the frame.
* @param {Wick.Path} path - the path to add.
*/
-
-
addPath(path) {
if (path.parent) {
path.remove();
}
-
this.addChild(path);
}
+
/**
* Remove a path from the frame.
* @param {Wick.Path} path - the path to remove.
*/
-
-
removePath(path) {
this.removeChild(path);
}
+
/**
* Add a tween to the frame.
* @param {Wick.Tween} tween - the tween to add.
*/
-
-
addTween(tween) {
// New tweens eat existing tweens.
var otherTween = this.getTweenAtPosition(tween.playheadPosition);
-
if (otherTween) {
otherTween.remove();
}
-
this.addChild(tween);
tween.restrictToFrameSize();
}
+
/**
* Automatically creates a tween at the current playhead position. Converts all objects into one clip if needed.
*/
-
-
createTween() {
// Don't make a tween if one already exits
var playheadPosition = this.getRelativePlayheadPosition();
-
if (this.getTweenAtPosition(playheadPosition)) {
return;
- } // If more than one object exists on the frame, or if there is only one path, create a clip from those objects
-
+ }
+ // If more than one object exists on the frame, or if there is only one path, create a clip from those objects
var clips = this.clips;
var paths = this.paths;
-
if (clips.length === 0 && paths.length === 1 || clips.length + paths.length > 1) {
var allDrawables = paths.concat(clips);
-
var center = this.project.selection.view._getObjectsBounds(allDrawables).center;
-
var clip = new Wick.Clip({
transformation: new Wick.Transformation({
x: center.x,
@@ -56767,74 +55942,66 @@ Wick.Frame = class extends Wick.Tickable {
});
this.addClip(clip);
clip.addObjects(allDrawables);
- } // Create the tween (if there's not already a tween at the current playhead position)
-
+ }
+ // Create the tween (if there's not already a tween at the current playhead position)
var clip = this.clips[0];
this.addTween(new Wick.Tween({
playheadPosition: playheadPosition,
transformation: clip ? clip.transformation.copy() : new Wick.Transformation()
}));
}
+
/**
* Remove a tween from the frame.
* @param {Wick.Tween} tween - the tween to remove.
*/
-
-
removeTween(tween) {
this.removeChild(tween);
}
+
/**
* Remove all tweens from this frame.
*/
-
-
removeAllTweens(tween) {
this.tweens.forEach(tween => {
tween.remove();
});
}
+
/**
* Get the tween at the given playhead position. Returns null if there is no tween.
* @param {number} playheadPosition - the playhead position to look for tweens at.
* @returns {Wick.Tween || null} the tween at the given playhead position.
*/
-
-
getTweenAtPosition(playheadPosition) {
return this.tweens.find(tween => {
return tween.playheadPosition === playheadPosition;
}) || null;
}
+
/**
* Returns the tween at the current playhead position, if one exists on the frame. Null otherwise.
* @returns {Wick.Tween || null}
*/
-
-
getTweenAtCurrentPlayheadPosition() {
let playheadPosition = this.getRelativePlayheadPosition();
return this.getTweenAtPosition(playheadPosition);
}
+
/**
* The tween being used to transform the objects on the frame.
* @returns {Wick.Tween || null} tween - the active tween. Null if there is no active tween.
*/
-
-
getActiveTween() {
if (!this.parentTimeline) return null;
var playheadPosition = this.getRelativePlayheadPosition();
var tween = this.getTweenAtPosition(playheadPosition);
-
if (tween) {
return tween;
}
-
var seekBackwardsTween = this.seekTweenBehind(playheadPosition);
var seekForwardsTween = this.seekTweenInFront(playheadPosition);
-
if (seekBackwardsTween && seekForwardsTween) {
return Wick.Tween.interpolate(seekBackwardsTween, seekForwardsTween, playheadPosition);
} else if (seekForwardsTween) {
@@ -56845,84 +56012,80 @@ Wick.Frame = class extends Wick.Tickable {
return null;
}
}
+
/**
* Applies the transformation of current tween to the objects on the frame.
*/
-
-
applyTweenTransforms() {
var tween = this.getActiveTween();
-
if (tween) {
this.clips.forEach(clip => {
tween.applyTransformsToClip(clip);
});
}
}
+
/**
* Applies single frame positions to timelines if necessary.
*/
-
-
applyClipSingleFramePositions() {
this.clips.forEach(clip => {
clip.applySingleFramePosition();
});
}
+
/**
* Update all clip timelines for their animation type.
*/
-
-
updateClipTimelinesForAnimationType() {
this.clips.forEach(clip => {
clip.updateTimelineForAnimationType();
});
}
+
/**
* The asset of the sound attached to this frame, if one exists
* @returns {Wick.Asset[]}
*/
-
-
getLinkedAssets() {
var linkedAssets = [];
-
if (this.sound) {
linkedAssets.push(this.sound);
}
-
return linkedAssets;
}
+
/**
* Cut this frame in half using the parent timeline's playhead position.
*/
-
-
cut() {
// Can't cut a frame that doesn't beolong to a timeline + layer
- if (!this.parentTimeline) return; // Can't cut a frame with length 1
+ if (!this.parentTimeline) return;
- if (this.length === 1) return; // Can't cut a frame that isn't under the playhead
+ // Can't cut a frame with length 1
+ if (this.length === 1) return;
+ // Can't cut a frame that isn't under the playhead
var playheadPosition = this.parentTimeline.playheadPosition;
- if (!this.inPosition(playheadPosition)) return; // Create right half (leftover) frame
+ if (!this.inPosition(playheadPosition)) return;
+ // Create right half (leftover) frame
var rightHalf = this.copy();
rightHalf.identifier = null;
rightHalf.removeSound();
rightHalf.removeAllTweens();
- rightHalf.start = playheadPosition = playheadPosition; // Cut this frame shorter
+ rightHalf.start = playheadPosition = playheadPosition;
- this.end = playheadPosition - 1; // Add right frame
+ // Cut this frame shorter
+ this.end = playheadPosition - 1;
+ // Add right frame
this.parentLayer.addFrame(rightHalf);
}
+
/**
* Extend this frame by one and push all frames right of this frame to the right.
*/
-
-
extendAndPushOtherFrames() {
this.parentLayer.getFramesInRange(this.end + 1, Infinity).forEach(frame => {
frame.start += 1;
@@ -56930,11 +56093,10 @@ Wick.Frame = class extends Wick.Tickable {
});
this.end += 1;
}
+
/**
* Shrink this frame by one and pull all frames left of this frame to the left.
*/
-
-
shrinkAndPullOtherFrames() {
if (this.length === 1) return;
this.parentLayer.getFramesInRange(this.end + 1, Infinity).forEach(frame => {
@@ -56943,107 +56105,84 @@ Wick.Frame = class extends Wick.Tickable {
});
this.end -= 1;
}
+
/**
* Import SVG data into this frame. SVGs containing mulitple paths will be split into multiple Wick Paths.
* @param {string} svg - the SVG data to parse and import.
*/
-
/*
importSVG (svg) {
this.view.importSVG(svg);
}
*/
-
/**
* Get the position of this frame in relation to the parent timeline's playhead position.
* @returns {number}
*/
-
-
getRelativePlayheadPosition() {
return this.parentTimeline.playheadPosition - this.start + 1;
}
+
/**
* Find the first tween on this frame that exists behind the given playhead position.
* @returns {Wick.Tween}
*/
-
-
seekTweenBehind(playheadPosition) {
var seekBackwardsPosition = playheadPosition;
var seekBackwardsTween = null;
-
while (seekBackwardsPosition > 0) {
seekBackwardsTween = this.getTweenAtPosition(seekBackwardsPosition);
seekBackwardsPosition--;
if (seekBackwardsTween) break;
}
-
return seekBackwardsTween;
}
+
/**
* Find the first tween on this frame that exists past the given playhead position.
* @returns {Wick.Tween}
*/
-
-
seekTweenInFront(playheadPosition) {
var seekForwardsPosition = playheadPosition;
var seekForwardsTween = null;
-
while (seekForwardsPosition <= this.end) {
seekForwardsTween = this.getTweenAtPosition(seekForwardsPosition);
seekForwardsPosition++;
if (seekForwardsTween) break;
}
-
return seekForwardsTween;
}
-
_onInactive() {
super._onInactive();
-
this._tickChildren();
}
-
_onActivated() {
super._onActivated();
-
this.playSound();
-
this._tickChildren();
}
-
_onActive() {
super._onActive();
-
this._tickChildren();
}
-
_onDeactivated() {
super._onDeactivated();
-
this.stopSound();
-
this._tickChildren();
}
-
_tickChildren() {
this.clips.forEach(clip => {
clip.tick();
});
}
-
_attachChildClipReferences() {
this.clips.forEach(clip => {
if (clip.identifier) {
this[clip.identifier] = clip;
-
clip._attachChildClipReferences();
}
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -57079,14 +56218,13 @@ Wick.Clip = class extends Wick.Tickable {
'playOnce': 'Play Once'
};
}
+
/**
* Create a new clip.
* @param {string} identifier - The identifier of the new clip.
* @param {Wick.Path|Wick.Clip[]} objects - Optional. A list of objects to add to the clip.
* @param {Wick.Transformation} transformation - Optional. The initial transformation of the clip.
*/
-
-
constructor(args) {
if (!args) args = {};
super(args);
@@ -57094,9 +56232,7 @@ Wick.Clip = class extends Wick.Tickable {
this.timeline.addLayer(new Wick.Layer());
this.timeline.activeLayer.addFrame(new Wick.Frame());
this._animationType = 'loop'; // Can be one of loop, oneFrame, single
-
this._singleFrameNumber = 1; // Default to 1, this value is only used if the animation type is single
-
this._playedOnce = false;
this._isSynced = false;
this._transformation = args.transformation || new Wick.Transformation();
@@ -57104,18 +56240,15 @@ Wick.Clip = class extends Wick.Tickable {
this._isClone = false;
this._sourceClipUUID = null;
this._assetSourceUUID = null;
- /* If objects are passed in, add them to the clip and reposition them */
+ /* If objects are passed in, add them to the clip and reposition them */
if (args.objects) {
this.addObjects(args.objects);
}
-
this._clones = [];
}
-
_serialize(args) {
var data = super._serialize(args);
-
data.transformation = this.transformation.values;
data.timeline = this._timeline;
data.animationType = this._animationType;
@@ -57124,10 +56257,8 @@ Wick.Clip = class extends Wick.Tickable {
data.isSynced = this._isSynced;
return data;
}
-
_deserialize(data) {
super._deserialize(data);
-
this.transformation = new Wick.Transformation(data.transformation);
this._timeline = data.timeline;
this._animationType = data.animationType || 'loop';
@@ -57137,16 +56268,14 @@ Wick.Clip = class extends Wick.Tickable {
this._playedOnce = false;
this._clones = [];
}
-
get classname() {
return 'Clip';
}
+
/**
* Determines whether or not the clip is visible in the project.
* @type {boolean}
*/
-
-
get onScreen() {
if (this.isRoot) {
return true;
@@ -57154,116 +56283,100 @@ Wick.Clip = class extends Wick.Tickable {
return this.parentFrame.onScreen;
}
}
+
/**
* Determines whether or not the clip is the root clip in the project.
* @type {boolean}
*/
-
-
get isRoot() {
return this.project && this === this.project.root;
}
+
/**
* True if the clip should sync to the timeline's position.
* @type {boolean}
*/
-
-
get isSynced() {
let isSingle = this.animationType === 'single';
return this._isSynced && !isSingle && !this.isRoot;
}
-
set isSynced(bool) {
if (!(typeof bool === 'boolean')) {
return;
}
-
this._isSynced = bool;
-
if (bool) {
this.applySyncPosition();
} else {
this.timeline.playheadPosition = 1;
}
}
+
/**
* Determines whether or not the clip is the currently focused clip in the project.
* @type {boolean}
*/
-
-
get isFocus() {
return this.project && this === this.project.focus;
}
+
/**
* Check if a Clip is a clone of another object.
* @type {boolean}
*/
-
-
get isClone() {
return this._isClone;
}
+
/**
* The uuid of the clip that this clip was cloned from.
* @type {string}
*/
-
-
get sourceClipUUID() {
return this._sourceClipUUID;
}
+
/**
* Returns the source clip of this clip if this clip is a clone. Null otherwise.
*
*/
-
-
get sourceClip() {
if (!this.sourceClipUUID) return null;
return this.project.getObjectByUUID(this.sourceClipUUID);
}
+
/**
* The uuid of the ClipAsset that this clip was created from.
* @type {string}
*/
-
-
get assetSourceUUID() {
return this._assetSourceUUID;
}
-
set assetSourceUUID(assetSourceUUID) {
this._assetSourceUUID = assetSourceUUID;
}
+
/**
* The timeline of the clip.
* @type {Wick.Timeline}
*/
-
-
get timeline() {
return this.getChild('Timeline');
}
-
set timeline(timeline) {
if (this.timeline) {
this.removeChild(this.timeline);
}
-
this.addChild(timeline);
}
+
/**
* The animation type of the clip. Must be of a type represented within animationTypes;
* @type {string}
*/
-
-
get animationType() {
return this._animationType;
}
-
set animationType(animationType) {
// Default to loop if an invalid animation type is passed in.
if (!Wick.Clip.animationTypes[animationType]) {
@@ -57274,12 +56387,11 @@ Wick.Clip = class extends Wick.Tickable {
this.resetTimelinePosition();
}
}
+
/**
* The frame to display when animation type is set to singleFrame.
* @type {number}
*/
-
-
get singleFrameNumber() {
if (this.animationType !== 'single') {
return null;
@@ -57287,7 +56399,6 @@ Wick.Clip = class extends Wick.Tickable {
return this._singleFrameNumber;
}
}
-
set singleFrameNumber(frame) {
// Constrain to be within the length of the clip.
if (frame < 1) {
@@ -57295,101 +56406,95 @@ Wick.Clip = class extends Wick.Tickable {
} else if (frame > this.timeline.length) {
frame = this.timeline.length;
}
-
this._singleFrameNumber = frame;
this.applySingleFramePosition();
}
+
/**
* The frame to display when the clip is synced
* @type {number}
*/
-
-
get syncFrame() {
- let timelineOffset = this.parentClip.timeline.playheadPosition - this.parentFrame.start; // Show the last frame if we're past it on a playOnce Clip.
+ let timelineOffset = this.parentClip.timeline.playheadPosition - this.parentFrame.start;
+ // Show the last frame if we're past it on a playOnce Clip.
if (this.animationType === 'playOnce' && timelineOffset >= this.timeline.length) {
return this.timeline.length;
- } // Otherwise, show the correct frame.
-
+ }
+ // Otherwise, show the correct frame.
return timelineOffset % this.timeline.length + 1;
}
+
/**
* Returns true if the clip has been played through fully once.
* @type {boolean}
*/
-
-
get playedOnce() {
return this._playedOnce;
}
-
set playedOnce(bool) {
return this._playedOnce = bool;
}
+
/**
* The active layer of the clip's timeline.
* @type {Wick.Layer}
*/
-
-
get activeLayer() {
return this.timeline.activeLayer;
}
+
/**
* The active frame of the clip's timeline.
* @type {Wick.Frame}
*/
-
-
get activeFrame() {
return this.activeLayer.activeFrame;
}
+
/**
* An array containing every clip and frame that is a child of this clip and has an identifier.
* @type {Wick.Base[]}
*/
-
-
get namedChildren() {
var namedChildren = [];
this.timeline.frames.forEach(frame => {
// Objects that can be accessed by their identifiers:
+
// Frames
if (frame.identifier) {
namedChildren.push(frame);
- } // Clips
-
+ }
+ // Clips
frame.clips.forEach(clip => {
if (clip.identifier) {
namedChildren.push(clip);
}
- }); // Dynamic text paths
+ });
+ // Dynamic text paths
frame.dynamicTextPaths.forEach(path => {
namedChildren.push(path);
});
});
return namedChildren;
}
+
/**
* An array containing every clip and frame that is a child of this clip and has an identifier, and also is visible on screen.
* @type {Wick.Base[]}
*/
-
-
get activeNamedChildren() {
return this.namedChildren.filter(child => {
return child.onScreen;
});
}
+
/**
* Resets the clip's timeline position.
*/
-
-
resetTimelinePosition() {
if (this.animationType === 'single') {
this.applySingleFramePosition();
@@ -57397,74 +56502,69 @@ Wick.Clip = class extends Wick.Tickable {
this.timeline.playheadPosition = 1; // Reset timeline position if we are not on single frame.
}
}
+
/**
* Updates the frame's single frame positions if necessary. Only works if the clip's animationType is 'single'.
*/
-
-
applySingleFramePosition() {
if (this.animationType === 'single') {
// Ensure that the single frame we've chosen is reflected no matter what.
this.timeline.playheadPosition = this.singleFrameNumber;
}
}
+
/**
* Updates the clip's playhead position if the Clip is in sync mode
*/
-
-
applySyncPosition() {
if (this.isSynced) {
this.timeline.playheadPosition = this.syncFrame;
}
}
+
/**
* Updates the timeline of the clip based on the animation type of the clip.
*/
-
-
updateTimelineForAnimationType() {
if (this.animationType === 'single') {
this.applySingleFramePosition();
}
-
if (this.isSynced) {
this.applySyncPosition();
}
}
+
/**
* Remove a clone from the clones array by uuid.
* @param {string} uuid
*/
-
-
removeClone(uuid) {
if (this.isClone) return;
this._clones = this.clones.filter(obj => obj.uuid !== uuid);
}
+
/**
* Remove this clip from its parent frame.
*/
-
-
remove() {
// Don't attempt to remove if the object has already been removed.
// (This is caused by calling remove() multiple times on one object inside a script.)
if (!this.parent || this._willBeRemoved) return;
- this._willBeRemoved = true; // Force unload to run now, before object is removed;
+ this._willBeRemoved = true;
- this.runScript('unload'); // Remove from the clones array.
+ // Force unload to run now, before object is removed;
+ this.runScript('unload');
+ // Remove from the clones array.
this.sourceClip && this.sourceClip.removeClone(this.uuid);
this.parent.removeClip(this);
this.removed = true;
}
+
/**
* Remove this clip and add all of its paths and clips to its parent frame.
* @returns {Wick.Base[]} the objects that were inside the clip.
*/
-
-
breakApart() {
var leftovers = [];
this.timeline.activeFrames.forEach(frame => {
@@ -57484,12 +56584,11 @@ Wick.Clip = class extends Wick.Tickable {
this.remove();
return leftovers;
}
+
/**
* Add paths and clips to this clip.
* @param {Wick.Base[]} objects - the paths and clips to add to the clip
*/
-
-
addObjects(objects) {
// Reposition objects such that their origin point is equal to this Clip's position
objects.forEach(object => {
@@ -57504,119 +56603,107 @@ Wick.Clip = class extends Wick.Tickable {
}
});
}
+
/**
* Stops a clip's timeline on that clip's current playhead position.
*/
-
-
stop() {
this.timeline.stop();
}
+
/**
* Plays a clip's timeline from that clip's current playhead position.
*/
-
-
play() {
this.timeline.play();
}
+
/**
* Moves a clip's playhead to a specific position and stops that clip's timeline on that position.
* @param {number|string} frame - number or string representing the frame to move the playhead to.
*/
-
-
gotoAndStop(frame) {
this.timeline.gotoAndStop(frame);
this.applySingleFramePosition();
}
+
/**
* Moves a clip's playhead to a specific position and plays that clip's timeline from that position.
* @param {number|string} frame - number or string representing the frame to move the playhead to.
*/
-
-
gotoAndPlay(frame) {
this.timeline.gotoAndPlay(frame);
this.applySingleFramePosition();
}
+
/**
* Move the playhead of the clips timeline forward one frame. Does nothing if the clip is on its last frame.
*/
-
-
gotoNextFrame() {
this.timeline.gotoNextFrame();
this.applySingleFramePosition();
}
+
/**
* Move the playhead of the clips timeline backwards one frame. Does nothing if the clip is on its first frame.
*/
-
-
gotoPrevFrame() {
this.timeline.gotoPrevFrame();
this.applySingleFramePosition();
}
+
/**
* Returns the name of the frame which is currently active. If multiple frames are active, returns the name of the first active frame.
* @returns {string} Active Frame name. If the active frame does not have an identifier, returns empty string.
*/
-
-
get currentFrameName() {
let frames = this.timeline.activeFrames;
let name = '';
frames.forEach(frame => {
if (name) return;
-
if (frame.identifier) {
name = frame.identifier;
}
});
return name;
}
+
/**
* @deprecated
* Returns the current playhead position. This is a legacy function, you should use clip.playheadPosition instead.
* @returns {number} Playhead Position.
*/
-
-
get currentFrameNumber() {
return this.timeline.playheadPosition;
}
+
/**
* The current transformation of the clip.
* @type {Wick.Transformation}
*/
-
-
get transformation() {
return this._transformation;
}
-
set transformation(transformation) {
- this._transformation = transformation; // When the transformation changes, update the current tween, if one exists
+ this._transformation = transformation;
+ // When the transformation changes, update the current tween, if one exists
if (this.parentFrame) {
// This tween must only ever be the tween over the current playhead position.
// Altering the active tween will overwrite tweens when moving between frames.
var tween = this.parentFrame.getTweenAtCurrentPlayheadPosition();
-
if (tween) {
tween.transformation = this._transformation.copy();
}
}
}
+
/**
* Perform circular hit test with other clip.
* @param {Wick.Clip} other - the clip to hit test with
* @param {object} options - Hit test options
* @returns {object} Hit information
*/
-
-
circleHits(other, options) {
let bounds1 = this.absoluteBounds;
let bounds2 = other.absoluteBounds;
@@ -57625,28 +56712,25 @@ Wick.Clip = class extends Wick.Tickable {
let distance = Math.sqrt((c1.x - c2.x) * (c1.x - c2.x) + (c1.y - c2.y) * (c1.y - c2.y));
let r1 = options.radius ? options.radius : this.radius;
let r2 = other.radius; //should add option for other radius?
-
- let overlap = r1 + r2 - distance; // TODO: Maybe add a case for overlap === 0?
-
+ let overlap = r1 + r2 - distance;
+ // TODO: Maybe add a case for overlap === 0?
if (overlap > 0) {
let x = c1.x - c2.x;
let y = c1.y - c2.y;
let magnitude = Math.sqrt(x * x + y * y);
x = x / magnitude;
- y = y / magnitude; // is now a normalized vector from c2 to c1
+ y = y / magnitude;
+ // is now a normalized vector from c2 to c1
let result = {};
-
if (options.overlap) {
result.overlapX = overlap * x;
result.overlapY = overlap * y;
}
-
if (options.offset) {
result.offsetX = overlap * x;
result.offsetY = overlap * y;
}
-
if (options.intersections) {
if (r2 - distance > r1 || r1 - distance > r2 || distance === 0) {
result.intersections = [];
@@ -57665,27 +56749,24 @@ Wick.Clip = class extends Wick.Tickable {
}];
}
}
-
return result;
}
-
return null;
}
+
/**
* Perform rectangular hit test with other clip.
* @param {Wick.Clip} other - the clip to hit test with
* @param {object} options - Hit test options
* @returns {object} Hit information
*/
-
-
rectangleHits(other, options) {
let bounds1 = this.absoluteBounds;
- let bounds2 = other.absoluteBounds; // TODO: write intersects so we don't rely on paper Rectangle objects
+ let bounds2 = other.absoluteBounds;
+ // TODO: write intersects so we don't rely on paper Rectangle objects
if (bounds1.intersects(bounds2)) {
let result = {};
-
if (options.overlap) {
// Find the direction along which we have to travel the least distance to no longer overlap
let left = bounds2.left - bounds1.right;
@@ -57694,28 +56775,25 @@ Wick.Clip = class extends Wick.Tickable {
let down = bounds2.bottom - bounds1.top;
let overlapX = Math.abs(left) < Math.abs(right) ? left : right;
let overlapY = Math.abs(up) < Math.abs(down) ? up : down;
-
if (Math.abs(overlapX) < Math.abs(overlapY)) {
overlapY = 0;
} else {
overlapX = 0;
}
-
result.overlapX = overlapX;
result.overlapY = overlapY;
}
-
if (options.offset) {
// Find how far along the center to center vector we must travel to no longer overlap
let vectorX = bounds1.center.x - bounds2.center.x;
let vectorY = bounds1.center.y - bounds2.center.y;
let magnitude = Math.sqrt(vectorX * vectorX + vectorY * vectorY);
vectorX /= magnitude;
- vectorY /= magnitude; // Choose p1, p2, based on quadrant of center to center vector
+ vectorY /= magnitude;
+ // Choose p1, p2, based on quadrant of center to center vector
let p1 = vectorX > 0 ? vectorY > 0 ? bounds1.topLeft : bounds1.bottomLeft : vectorY > 0 ? bounds1.topRight : bounds1.bottomRight;
let p2 = vectorX > 0 ? vectorY > 0 ? bounds2.bottomRight : bounds2.topRight : vectorY > 0 ? bounds2.bottomLeft : bounds2.topLeft;
-
if (Math.abs(p2.x - p1.x) < Math.abs((p2.y - p1.y) * vectorX / vectorY)) {
result.offsetX = p2.x - p1.x;
result.offsetY = result.offsetX * vectorY / vectorX;
@@ -57724,27 +56802,25 @@ Wick.Clip = class extends Wick.Tickable {
result.offsetX = result.offsetY * vectorX / vectorY;
}
}
-
if (options.intersections) {
result.intersections = [];
let ps1 = [bounds1.topLeft, bounds1.topRight, bounds1.bottomRight, bounds1.bottomLeft];
let ps2 = [bounds2.topLeft, bounds2.topRight, bounds2.bottomRight, bounds2.bottomLeft];
-
for (let i = 0; i < 4; i++) {
for (let j = (i + 1) % 2; j < 4; j += 2) {
// iterate over the perpendicular lines
let a = ps1[i];
let b = ps1[(i + 1) % 4];
let c = ps2[j];
- let d = ps2[(j + 1) % 4]; // Perpendicular lines will intersect, we'll use parametric line intersection
+ let d = ps2[(j + 1) % 4];
+
+ // Perpendicular lines will intersect, we'll use parametric line intersection
// = a + (b - a)t1
// = c + (d - c)t2
//a + (b - a)t1 = c + (d - c)t2
//t1(b - a) = (c + (d - c)t2 - a)
//(a - c)/(d - c) = t2
-
let t1, t2;
-
if (a.x === b.x) {
t2 = (a.x - c.x) / (d.x - c.x);
t1 = (c.y + (d.y - c.y) * t2 - a.y) / (b.y - a.y);
@@ -57753,7 +56829,6 @@ Wick.Clip = class extends Wick.Tickable {
t2 = (a.y - c.y) / (d.y - c.y);
t1 = (c.x + (d.x - c.x) * t2 - a.x) / (b.x - a.x);
}
-
if (0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1) {
result.intersections.push({
x: a.x + (b.x - a.x) * t1,
@@ -57763,39 +56838,37 @@ Wick.Clip = class extends Wick.Tickable {
}
}
}
-
return result;
} else {
return null;
}
- } // Return whether triangle p1 p2 p3 is clockwise (in screen space,
- // means counterclockwise in a normal space with y axis pointed up)
-
+ }
+ // Return whether triangle p1 p2 p3 is clockwise (in screen space,
+ // means counterclockwise in a normal space with y axis pointed up)
cw(x1, y1, x2, y2, x3, y3) {
const cw = (y3 - y1) * (x2 - x1) - (y2 - y1) * (x3 - x1);
return cw >= 0; // colinear ?
}
+
/**
* Perform convex hull hit test with other clip.
* @param {Wick.Clip} other - the clip to hit test with
* @param {object} options - Hit test options
* @returns {object} Hit information
*/
-
-
convexHits(other, options) {
// Efficient check first
let bounds1 = this.absoluteBounds;
- let bounds2 = other.absoluteBounds; // TODO: write intersects so we don't rely on paper Rectangle objects
-
+ let bounds2 = other.absoluteBounds;
+ // TODO: write intersects so we don't rely on paper Rectangle objects
if (!bounds1.intersects(bounds2)) {
return null;
}
-
let c1 = bounds1.center;
- let c2 = bounds2.center; // clockwise arrays of points in format [[x1, y1], [x2, y2], ...]
+ let c2 = bounds2.center;
+ // clockwise arrays of points in format [[x1, y1], [x2, y2], ...]
let hull1 = this.convexHull;
let hull2 = other.convexHull;
let finished1 = false;
@@ -57803,15 +56876,17 @@ Wick.Clip = class extends Wick.Tickable {
let i1 = hull1.length - 1;
let i2 = hull2.length - 1;
let intersections = [];
- let n = 0; // Algorithm from https://www.bowdoin.edu/~ltoma/teaching/cs3250-CompGeom/spring17/Lectures/cg-convexintersection.pdf
-
+ let n = 0;
+ // Algorithm from https://www.bowdoin.edu/~ltoma/teaching/cs3250-CompGeom/spring17/Lectures/cg-convexintersection.pdf
while ((!finished1 || !finished2) && n <= 2 * (hull1.length + hull2.length)) {
- n++; // line segments A is ab, B is cd
-
+ n++;
+ // line segments A is ab, B is cd
let a = hull1[i1],
- b = hull1[((i1 - 1) % hull1.length + hull1.length) % hull1.length],
- c = hull2[i2],
- d = hull2[((i2 - 1) % hull2.length + hull2.length) % hull2.length]; //Use parametric line intersection
+ b = hull1[((i1 - 1) % hull1.length + hull1.length) % hull1.length],
+ c = hull2[i2],
+ d = hull2[((i2 - 1) % hull2.length + hull2.length) % hull2.length];
+
+ //Use parametric line intersection
// = a + (b - a)t1
// = c + (d - c)t2
//a + (b - a)t1 = c + (d - c)t2
@@ -57819,24 +56894,19 @@ Wick.Clip = class extends Wick.Tickable {
//a.y + (b.y - a.y) * (c.x + (d.x - c.x)t2 - a.x) / (b.x - a.x) = c.y + (d.y - c.y)t2
//t2((b.y - a.y)(d.x - c.x)/(b.x - a.x) - (d.y - c.y)) = c.y - a.y - (b.y - a.y)*(c.x - a.x)/(b.x - a.x)
//t2 = (c.y - a.y - (b.y - a.y)*(c.x - a.x)/(b.x - a.x)) / ((b.y - a.y)(d.x - c.x)/(b.x - a.x) - (d.y - c.y))
-
let t2 = (c[1] - a[1] - (b[1] - a[1]) * (c[0] - a[0]) / (b[0] - a[0])) / ((b[1] - a[1]) * (d[0] - c[0]) / (b[0] - a[0]) - d[1] + c[1]);
let t1 = (c[0] + (d[0] - c[0]) * t2 - a[0]) / (b[0] - a[0]);
-
if (0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1) {
intersections.push({
x: a[0] + (b[0] - a[0]) * t1,
y: a[1] + (b[1] - a[1]) * t1
});
}
-
let APointingToB = t1 > 1;
let BPointingToA = t2 > 1;
-
if (BPointingToA && !APointingToB) {
// Advance B
i2 -= 1;
-
if (i2 < 0) {
finished2 = true;
i2 += hull2.length;
@@ -57844,7 +56914,6 @@ Wick.Clip = class extends Wick.Tickable {
} else if (APointingToB && !BPointingToA) {
// Advance A
i1 -= 1;
-
if (i1 < 0) {
finished1 = true;
i1 += hull1.length;
@@ -57854,7 +56923,6 @@ Wick.Clip = class extends Wick.Tickable {
if (this.cw(a[0], a[1], b[0], b[1], d[0], d[1])) {
// Advance B
i2 -= 1;
-
if (i2 < 0) {
finished2 = true;
i2 += hull2.length;
@@ -57862,21 +56930,18 @@ Wick.Clip = class extends Wick.Tickable {
} else {
// Advance A
i1 -= 1;
-
if (i1 < 0) {
finished1 = true;
i1 += hull1.length;
}
}
}
- } // Ok, we have all the intersections now
-
-
+ }
+ // Ok, we have all the intersections now
let avgIntersection = {
x: 0,
y: 0
};
-
if (intersections.length === 0) {
avgIntersection.x = bounds1.width < bounds2.width ? c1.x : c2.x;
avgIntersection.y = bounds1.width < bounds2.width ? c1.y : c2.y;
@@ -57885,25 +56950,21 @@ Wick.Clip = class extends Wick.Tickable {
avgIntersection.x += intersections[i].x;
avgIntersection.y += intersections[i].y;
}
-
avgIntersection.x /= intersections.length;
avgIntersection.y /= intersections.length;
}
-
let result = {};
-
if (options.intersections) {
result.intersections = intersections;
}
-
if (options.offset) {
// Calculate offset by taking the center of mass of the intersection, call it P,
// get the radius from P on this convex hull in the direction
// from this center to that center,
// Then, the offset is a vector in the direction from that center to this center
// with magnitude of that radius
- let targetTheta = Math.atan2(c2.y - c1.y, c2.x - c1.x); //from c1 to c2
+ let targetTheta = Math.atan2(c2.y - c1.y, c2.x - c1.x); //from c1 to c2
let r = this.radiusAtPointInDirection(hull1, avgIntersection, targetTheta);
targetTheta = (targetTheta + Math.PI) % (2 * Math.PI);
r += this.radiusAtPointInDirection(hull2, avgIntersection, targetTheta);
@@ -57915,27 +56976,23 @@ Wick.Clip = class extends Wick.Tickable {
result.offsetX = directionX;
result.offsetY = directionY;
}
-
if (options.overlap) {
//same as offset except instead of center to center,
//we will move perpendicular to the best fit line
//of the intersection points
- let directionX, directionY;
+ let directionX, directionY;
if (intersections.length < 2) {
directionX = c2.x - c1.x;
directionY = c2.y - c1.y;
} else {
let max_d = 0;
-
for (let i = 1; i < intersections.length; i++) {
let d = (intersections[i].y - intersections[0].y) * (intersections[i].y - intersections[0].y) + (intersections[i].x - intersections[0].x) * (intersections[i].x - intersections[0].x);
-
if (d > max_d) {
max_d = d;
directionX = -(intersections[i].y - intersections[0].y);
directionY = intersections[i].x - intersections[0].x;
-
if (directionX * (c1.x - avgIntersection.x) + directionY * (c1.y - avgIntersection.y) > 0) {
directionX = -directionX;
directionY = -directionY;
@@ -57943,7 +57000,6 @@ Wick.Clip = class extends Wick.Tickable {
}
}
}
-
let targetTheta = Math.atan2(directionY, directionX);
let r = this.radiusAtPointInDirection(hull1, avgIntersection, targetTheta);
targetTheta = (targetTheta + Math.PI) % (2 * Math.PI);
@@ -57951,22 +57007,20 @@ Wick.Clip = class extends Wick.Tickable {
let r2 = this.radiusAtPointInDirection(hull1, avgIntersection, targetTheta);
targetTheta = (targetTheta + Math.PI) % (2 * Math.PI);
r2 += this.radiusAtPointInDirection(hull2, avgIntersection, targetTheta);
-
if (r2 < r) {
r = r2;
directionX *= -1;
directionY *= -1;
}
-
let mag = Math.sqrt(directionX * directionX + directionY * directionY);
directionX *= -r / mag;
directionY *= -r / mag;
result.overlapX = directionX;
result.overlapY = directionY;
}
-
return result;
}
+
/**
* Casts a ray from p in the direction targetTheta and intersects it with the hull ch,
* returns the distance from p to the surface of ch.
@@ -57975,26 +57029,22 @@ Wick.Clip = class extends Wick.Tickable {
* @param {number} targetTheta - the direction of the ray
* @returns {number} the distance to the surface of the convex hull from the point in the direction theta
*/
-
-
radiusAtPointInDirection(ch, p, targetTheta) {
let minThetaDiff = Infinity;
let index;
-
for (let i = 0; i < ch.length; i++) {
let theta = Math.atan2(ch[i][1] - p.y, ch[i][0] - p.x);
let thetaDiff = ((targetTheta - theta) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI); //positive mod
-
if (thetaDiff < minThetaDiff) {
minThetaDiff = thetaDiff;
index = i;
}
}
-
let a = ch[index];
let b = ch[(index + 1) % ch.length];
let c = [p.x, p.y];
- let d = [p.x + 100 * Math.cos(targetTheta), p.y + 100 * Math.sin(targetTheta)]; //Use parametric line intersection
+ let d = [p.x + 100 * Math.cos(targetTheta), p.y + 100 * Math.sin(targetTheta)];
+ //Use parametric line intersection
// = a + (b - a)t1
// = c + (d - c)t2
//a + (b - a)t1 = c + (d - c)t2
@@ -58002,46 +57052,39 @@ Wick.Clip = class extends Wick.Tickable {
//a.y + (b.y - a.y) * (c.x + (d.x - c.x)t2 - a.x) / (b.x - a.x) = c.y + (d.y - c.y)t2
//t2((b.y - a.y)(d.x - c.x)/(b.x - a.x) - (d.y - c.y)) = c.y - a.y - (b.y - a.y)*(c.x - a.x)/(b.x - a.x)
//t2 = (c.y - a.y - (b.y - a.y)*(c.x - a.x)/(b.x - a.x)) / ((b.y - a.y)(d.x - c.x)/(b.x - a.x) - (d.y - c.y))
-
let t2 = (c[1] - a[1] - (b[1] - a[1]) * (c[0] - a[0]) / (b[0] - a[0])) / ((b[1] - a[1]) * (d[0] - c[0]) / (b[0] - a[0]) - d[1] + c[1]);
let t1 = (c[0] + (d[0] - c[0]) * t2 - a[0]) / (b[0] - a[0]);
return Math.hypot(a[0] + (b[0] - a[0]) * t1 - p.x, a[1] + (b[1] - a[1]) * t1 - p.y);
}
+
/**
* Perform hit test with other clip.
* @param {Wick.Clip} other - the clip to hit test with
* @param {object} options - Hit test options
* @returns {object} Hit information
*/
-
-
hits(other, options) {
// Get hit options
- let finalOptions = { ...this.project.hitTestOptions
+ let finalOptions = {
+ ...this.project.hitTestOptions
};
-
if (options) {
if (options.mode === 'CIRCLE' || options.mode === 'RECTANGLE' || options.mode === 'CONVEX') {
finalOptions.mode = options.mode;
}
-
if (typeof options.offset === "boolean") {
finalOptions.offset = options.offset;
}
-
if (typeof options.overlap === "boolean") {
finalOptions.overlap = options.overlap;
}
-
if (typeof options.intersections === "boolean") {
finalOptions.intersections = options.intersections;
}
-
if (options.radius) {
finalOptions.radius = options.radius;
}
}
-
if (finalOptions.mode === 'CIRCLE') {
return this.circleHits(other, finalOptions);
} else if (finalOptions.mode === 'CONVEX') {
@@ -58050,43 +57093,39 @@ Wick.Clip = class extends Wick.Tickable {
return this.rectangleHits(other, finalOptions);
}
}
+
/**
* Returns true if this clip collides with another clip.
* @param {Wick.Clip} other - The other clip to check collision with.
* @returns {boolean} True if this clip collides the other clip.
*/
-
-
hitTest(other) {
// TODO: write intersects so we don't rely on paper Rectangle objects
return this.absoluteBounds.intersects(other.absoluteBounds);
}
+
/**
* The bounding box of the clip.
* @type {object}
*/
-
-
get bounds() {
// TODO: Refactor so that getting bounds does not rely on the view
return this.view.bounds;
}
-
get absoluteBounds() {
// TODO: Refactor so that getting bounds does not rely on the view
return this.view.absoluteBounds;
}
-
get points() {
// TODO: Refactor so that does not rely on the view
return this.view.points;
}
-
get radius() {
// Use length of half diagonal of bounding box
let b = this.absoluteBounds;
- return Math.sqrt(b.width * b.width + b.height * b.height) / 2 / Math.sqrt(2); // Alternative: use largest distance from center to a point on the object
+ return Math.sqrt(b.width * b.width + b.height * b.height) / 2 / Math.sqrt(2);
+ // Alternative: use largest distance from center to a point on the object
/*
let center = this.absoluteBounds.center;
let points = this.points;
@@ -58099,16 +57138,16 @@ Wick.Clip = class extends Wick.Tickable {
}
return Math.sqrt(max_r);
*/
- } // Gives clockwise in screen space, which is ccw in regular axes
-
+ }
+ // Gives clockwise in screen space, which is ccw in regular axes
get convexHull() {
- let points = this.points; // Infinity gets us the convex hull
+ let points = this.points;
+ // Infinity gets us the convex hull
let ch = hull(points, Infinity);
let removedDuplicates = [];
let epsilon = 0.01;
-
for (let i = 0; i < ch.length; i++) {
if (removedDuplicates.length > 0) {
if ((Math.abs(ch[i][0] - removedDuplicates[removedDuplicates.length - 1][0]) > epsilon || Math.abs(ch[i][1] - removedDuplicates[removedDuplicates.length - 1][1]) > epsilon) && (Math.abs(ch[i][0] - removedDuplicates[0][0]) > epsilon || Math.abs(ch[i][1] - removedDuplicates[0][1]) > epsilon)) {
@@ -58118,159 +57157,134 @@ Wick.Clip = class extends Wick.Tickable {
removedDuplicates.push(ch[i]);
}
}
-
return removedDuplicates;
}
+
/**
* The X position of the clip.
* @type {number}
*/
-
-
get x() {
return this.transformation.x;
}
-
set x(x) {
this.transformation.x = x;
}
+
/**
* The Y position of the clip.
* @type {number}
*/
-
-
get y() {
return this.transformation.y;
}
-
set y(y) {
this.transformation.y = y;
}
+
/**
* The X scale of the clip.
* @type {number}
*/
-
-
get scaleX() {
return this.transformation.scaleX;
}
-
set scaleX(scaleX) {
if (scaleX === 0) scaleX = 0.001; // Protects against NaN issues
-
this.transformation.scaleX = scaleX;
}
+
/**
* The Y scale of the clip.
* @type {number}
*/
-
-
get scaleY() {
return this.transformation.scaleY;
}
-
set scaleY(scaleY) {
if (scaleY === 0) scaleY = 0.001; // Protects against NaN issues
-
this.transformation.scaleY = scaleY;
}
+
/**
* The width of the clip.
* @type {number}
*/
-
-
get width() {
return this.isRoot ? this.project.width : this.bounds.width * this.scaleX;
}
-
set width(width) {
this.scaleX = width / this.width * this.scaleX;
}
+
/**
* The height of the clip.
* @type {number}
*/
-
-
get height() {
return this.isRoot ? this.project.height : this.bounds.height * this.scaleY;
}
-
set height(height) {
this.scaleY = height / this.height * this.scaleY;
}
+
/**
* The rotation of the clip.
* @type {number}
*/
-
-
get rotation() {
return this.transformation.rotation;
}
-
set rotation(rotation) {
this.transformation.rotation = rotation;
}
+
/**
* The opacity of the clip.
* @type {number}
*/
-
-
get opacity() {
return this.transformation.opacity;
}
-
set opacity(opacity) {
opacity = Math.min(1, opacity);
opacity = Math.max(0, opacity);
this.transformation.opacity = opacity;
}
+
/**
* Copy this clip, and add the copy to the same frame as the original clip.
* @returns {Wick.Clip} the result of the clone.
*/
-
-
clone() {
var clone = this.copy();
clone.identifier = null;
this.parentFrame.addClip(clone);
-
this._clones.push(clone);
-
clone._isClone = true;
clone._sourceClipUUID = this.uuid;
return clone;
}
+
/**
* An array containing all objects that were created by calling clone() on this Clip.
* @type {Wick.Clip[]}
*/
-
-
get clones() {
return this._clones;
}
+
/**
* This is a stopgap to prevent users from using setText with a Clip.
*/
-
-
setText() {
throw new Error('setText() can only be used with text objects.');
}
+
/**
* The list of parents, grandparents, grand-grandparents...etc of the clip.
* @returns {Wick.Clip[]} Array of all parents
*/
-
-
get lineage() {
if (this.isRoot) {
return [this];
@@ -58278,50 +57292,50 @@ Wick.Clip = class extends Wick.Tickable {
return [this].concat(this.parentClip.lineage);
}
}
+
/**
* Add a placeholder path to this clip to ensure the Clip is always selectable when rendered.
*/
-
-
ensureActiveFrameIsContentful() {
// Ensure layer exists
var firstLayerExists = this.timeline.activeLayer;
-
if (!firstLayerExists) {
this.timeline.addLayer(new Wick.Layer());
- } // Ensure active frame exists
-
+ }
+ // Ensure active frame exists
var playheadPosition = this.timeline.playheadPosition;
var activeFrameExists = this.timeline.getFramesAtPlayheadPosition(playheadPosition).length > 0;
-
if (!activeFrameExists) {
this.timeline.activeLayer.addFrame(new Wick.Frame({
start: playheadPosition
}));
- } // Clear placeholders
-
+ }
+ // Clear placeholders
var frame = this.timeline.getFramesAtPlayheadPosition(playheadPosition)[0];
frame.paths.forEach(path => {
if (!path.isPlaceholder) return;
path.remove();
- }); // Check if active frame is contentful
+ });
+ // Check if active frame is contentful
var firstFramesAreContentful = false;
this.timeline.getFramesAtPlayheadPosition(playheadPosition).forEach(frame => {
if (frame.contentful) {
firstFramesAreContentful = true;
}
- }); // Ensure active frame is contentful
+ });
+ // Ensure active frame is contentful
if (!firstFramesAreContentful) {
// Clear placeholders
var frame = this.timeline.getFramesAtPlayheadPosition(playheadPosition)[0];
frame.paths.forEach(path => {
path.remove();
- }); // Generate crosshair
+ });
+ // Generate crosshair
var size = Wick.View.Clip.PLACEHOLDER_SIZE;
var line1 = new paper.Path.Line({
from: [0, -size],
@@ -58345,27 +57359,20 @@ Wick.Clip = class extends Wick.Tickable {
}));
}
}
-
_onInactive() {
super._onInactive();
-
this._tickChildren();
}
-
_onActivated() {
super._onActivated();
-
this._tickChildren();
-
if (this.animationType === 'playOnce') {
this.playedOnce = false;
this.timeline.playheadPosition = 1;
}
}
-
_onActive() {
super._onActive();
-
if (this.animationType === 'loop') {
this.timeline.advance();
} else if (this.animationType === 'single') {
@@ -58379,20 +57386,15 @@ Wick.Clip = class extends Wick.Tickable {
}
}
}
-
if (this.isSynced) {
this.timeline.playheadPosition = this.syncFrame;
}
-
this._tickChildren();
}
-
_onDeactivated() {
super._onDeactivated();
-
this._tickChildren();
}
-
_tickChildren() {
var childError = null;
this.timeline.frames.forEach(frame => {
@@ -58401,23 +57403,21 @@ Wick.Clip = class extends Wick.Tickable {
});
return childError;
}
-
_attachChildClipReferences() {
this.timeline.activeFrames.forEach(frame => {
frame.clips.forEach(clip => {
if (clip.identifier) {
this[clip.identifier] = clip;
-
clip._attachChildClipReferences();
}
- }); // Dynamic text paths can be accessed by their identifiers.
+ });
+ // Dynamic text paths can be accessed by their identifiers.
frame.dynamicTextPaths.forEach(path => {
this[path.identifier] = path;
});
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -58465,38 +57465,29 @@ Wick.Button = class extends Wick.Clip {
this.removeScript('default');
this.addScript('mouseclick', '');
}
-
_serialize(args) {
var data = super._serialize(args);
-
return data;
}
-
_deserialize(data) {
super._deserialize(data);
}
-
get classname() {
return 'Button';
}
-
_onInactive() {
return super._onInactive();
}
-
_onActivated() {
var error = super._onActivated();
-
this.timeline.stop();
this.timeline.playheadPosition = 1;
return error;
}
-
_onActive() {
this.timeline.gotoFrame(1);
var frame2Exists = this.timeline.getFramesAtPlayheadPosition(2).length > 0;
var frame3Exists = this.timeline.getFramesAtPlayheadPosition(3).length > 0;
-
if (this._mouseState === 'over') {
if (frame2Exists) {
this.timeline.gotoFrame(2);
@@ -58508,17 +57499,13 @@ Wick.Button = class extends Wick.Clip {
this.timeline.gotoFrame(2);
}
}
-
var error = super._onActive();
-
if (error) return error;
return null;
}
-
_onDeactivated() {
super._onDeactivated();
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -58538,205 +57525,183 @@ Wick.Button = class extends Wick.Clip {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tool = class {
static get DOUBLE_CLICK_TIME() {
return 300;
}
-
static get DOUBLE_CLICK_MAX_DISTANCE() {
return 20;
}
+
/**
* Creates a new Wick Tool.
*/
-
-
constructor() {
- this.paperTool = new this.paper.Tool(); // Attach onActivate event
+ this.paperTool = new this.paper.Tool();
+ // Attach onActivate event
this.paperTool.onActivate = e => {
this.onActivate(e);
- }; // Attach onDeactivate event
-
+ };
+ // Attach onDeactivate event
this.paperTool.onDeactivate = e => {
this.onDeactivate(e);
- }; // Attach mouse move event
-
+ };
+ // Attach mouse move event
this.paperTool.onMouseMove = e => {
this.onMouseMove(e);
- }; // Attach mouse down + double click event
-
+ };
+ // Attach mouse down + double click event
this.paperTool.onMouseDown = e => {
if (this.doubleClickEnabled && this._lastMousedownTimestamp !== null && e.timeStamp - this._lastMousedownTimestamp < Wick.Tool.DOUBLE_CLICK_TIME && e.point.subtract(this._lastMousedownPoint).length < Wick.Tool.DOUBLE_CLICK_MAX_DISTANCE) {
this.onDoubleClick(e);
} else {
this.onMouseDown(e);
}
-
this._lastMousedownTimestamp = e.timeStamp;
this._lastMousedownPoint = e.point;
- }; // Attach key events
-
+ };
+ // Attach key events
this.paperTool.onKeyDown = e => {
this.onKeyDown(e);
};
-
this.paperTool.onKeyUp = e => {
this.onKeyUp(e);
- }; // Attach mouse move event
-
+ };
+ // Attach mouse move event
this.paperTool.onMouseDrag = e => {
this.onMouseDrag(e);
- }; // Attach mouse up event
-
+ };
+ // Attach mouse up event
this.paperTool.onMouseUp = e => {
this.onMouseUp(e);
};
-
this._eventCallbacks = {};
this._lastMousedownTimestamp = null;
}
+
/**
* The paper.js scope to use.
*/
-
-
get paper() {
return Wick.View.paperScope;
}
+
/**
* The CSS cursor to display for this tool.
*/
-
-
get cursor() {
console.warn("Warning: Tool is missing a cursor!");
}
+
/**
* Called when the tool is activated
*/
-
-
onActivate(e) {}
+
/**
* Called when the tool is deactivated (another tool is activated)
*/
-
-
onDeactivate(e) {}
+
/**
* Called when the mouse moves and the tool is active.
*/
-
-
onMouseMove(e) {
this.setCursor(this.cursor);
}
+
/**
* Called when the mouse clicks the paper.js canvas and this is the active tool.
*/
-
-
onMouseDown(e) {}
+
/**
* Called when the mouse is dragged on the paper.js canvas and this is the active tool.
*/
-
-
onMouseDrag(e) {}
+
/**
* Called when the mouse is clicked on the paper.js canvas and this is the active tool.
*/
-
-
onMouseUp(e) {}
+
/**
* Called when the mouse double clicks on the paper.js canvas and this is the active tool.
*/
-
-
onDoubleClick(e) {}
+
/**
* Called when a key is pressed and this is the active tool.
*/
-
-
onKeyDown(e) {}
+
/**
* Called when a key is released and this is the active tool.
*/
-
-
onKeyUp(e) {}
+
/**
* Should reset the state of the tool.
*/
-
-
reset() {}
+
/**
* Activates this tool in paper.js.
*/
-
-
activate() {
this.paperTool.activate();
}
+
/**
* Sets the cursor of the paper.js canvas that the tool belongs to.
* @param {string} cursor - a CSS cursor style
*/
-
-
setCursor(cursor) {
this.paper.view._element.style.cursor = cursor;
}
+
/**
* Attach a function to get called when an event happens.
* @param {string} eventName - the name of the event
* @param {function} fn - the function to call when the event is fired
*/
-
-
on(eventName, fn) {
this._eventCallbacks[eventName] = fn;
}
+
/**
* Call the functions attached to a given event.
* @param {string} eventName - the name of the event to fire
* @param {object} e - (optional) an object to attach some data to, if needed
* @param {string} actionName - Name of the action committed.
*/
-
-
fireEvent({
eventName,
e,
actionName
}) {
if (!e) e = {};
-
if (!e.layers) {
e.layers = [this.paper.project.activeLayer];
}
-
var fn = this._eventCallbacks[eventName];
fn && fn(e, actionName);
}
+
/**
*
* @param {paper.Color} color - the color of the cursor
* @param {number} size - the width of the cursor image to generate
* @param {boolean} transparent - if set to true, color is ignored
*/
-
-
createDynamicCursor(color, size, transparent) {
var radius = size / 2;
var canvas = document.createElement("canvas");
@@ -58749,7 +57714,6 @@ Wick.Tool = class {
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.strokeStyle = transparent ? 'black' : invert(color);
context.stroke();
-
if (transparent) {
context.beginPath();
context.arc(centerX, centerY, radius - 1, 0, 2 * Math.PI, false);
@@ -58761,59 +57725,50 @@ Wick.Tool = class {
context.fillStyle = color;
context.fill();
}
-
return 'url(' + canvas.toDataURL() + ') ' + (radius + 1) + ' ' + (radius + 1) + ',default';
}
+
/**
* Get a tool setting from the project. See Wick.ToolSettings for all options
* @param {string} name - the name of the setting to get
*/
-
-
getSetting(name) {
return this.project.toolSettings.getSetting(name);
}
+
/**
* Does this tool have a double click action? (override this in classes that extend Wick.Tool)
* @type {boolean}
*/
-
-
get doubleClickEnabled() {
return true;
}
+
/**
* Adds a paper.Path to the active frame's paper.Layer.
* @param {paper.Path} path - the path to add
* @param {Wick.Frame} frame - (optional) the frame to add the path to.
*/
-
-
addPathToProject(path, frame) {
// Avoid adding empty paths
if (!path) {
return;
}
-
if (path instanceof paper.Path && path.segments.length === 0) {
return;
}
-
if (path instanceof paper.CompoundPath && path.children.length === 0) {
return;
}
-
if (!this.project.activeFrame) {
// Automatically add a frame is there isn't one
this.project.insertBlankFrame();
this.project.view.render();
}
-
if (!path) {
console.error("Warning: addPathToProject: path is null/undefined");
return;
}
-
if (frame && frame !== this.project.activeFrame) {
/* If the path must be added to a frame other than the active frame,
* convert the paper.js path into a Wick path and add it to the given frame. */
@@ -58830,7 +57785,6 @@ Wick.Tool = class {
this.paper.project.activeLayer.addChild(path);
}
}
-
};
Wick.Tools = {};
/*
@@ -58851,19 +57805,18 @@ Wick.Tools = {};
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Brush = class extends Wick.Tool {
static get CROQUIS_WAIT_AMT_MS() {
return 100;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
* Creates the brush tool.
*/
-
-
constructor() {
super();
this.name = 'brush';
@@ -58878,25 +57831,24 @@ Wick.Tools.Brush = class extends Wick.Tool {
this.lastPressure = null;
this.errorOccured = false;
this._isInProgress = false;
- this._croquisStartTimeout = null; // These are used to crop the final path image.
+ this._croquisStartTimeout = null;
+ // These are used to crop the final path image.
this.strokeBounds = new paper.Rectangle();
this._lastMousePoint = new paper.Point(0, 0);
- this._lastMousePressure = 1; // The frame that the brush started the current stroke on.
+ this._lastMousePressure = 1;
+ // The frame that the brush started the current stroke on.
this._currentDrawingFrame = null;
}
-
- get cursor() {// the brush cursor is done in a custom way using _regenCursor().
+ get cursor() {
+ // the brush cursor is done in a custom way using _regenCursor().
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {
if (this._isInProgress) this.finishStrokeEarly();
-
if (!this.croquis) {
this.croquis = new Croquis();
this.croquis.setCanvasSize(500, 500);
@@ -58916,96 +57868,77 @@ Wick.Tools.Brush = class extends Wick.Tool {
this.croquisDOMElement.style.display = 'block';
this.croquisDOMElement.style.pointerEvents = 'none';
}
-
this._isInProgress = false;
this._lastMousePoint = new paper.Point(0, 0);
this._lastMousePressure = 1;
}
-
onDeactivate(e) {
// This prevents croquis from leaving stuck brush strokes on the screen.
this.finishStrokeEarly();
}
-
onMouseMove(e) {
super.onMouseMove(e);
-
this._updateCanvasAttributes();
-
this._regenCursor();
}
-
onMouseDown(e) {
if (this._isInProgress) this.discard();
this._currentDrawingFrame = this.project.activeFrame;
clearTimeout(this._croquisStartTimeout);
this._isInProgress = true;
+ this._updateCanvasAttributes();
- this._updateCanvasAttributes(); // Update croquis params
-
-
+ // Update croquis params
this.croquisBrush.setSize(this._getRealBrushSize());
this.croquisBrush.setColor(this.getSetting('fillColor').hex);
this.croquisBrush.setSpacing(this.BRUSH_POINT_SPACING);
this.croquis.setToolStabilizeLevel(this.BRUSH_STABILIZER_LEVEL);
this.croquis.setToolStabilizeWeight(this.getSetting('brushStabilizerWeight') / 100.0 + 0.3);
- this.croquis.setToolStabilizeInterval(1); // Forward mouse event to croquis canvas
+ this.croquis.setToolStabilizeInterval(1);
+ // Forward mouse event to croquis canvas
var point = this._croquisToPaperPoint(e.point);
-
this._updateStrokeBounds(point);
-
try {
this._updateLastMouseState(point, this.pressure);
-
this.croquis.down(point.x, point.y, this.pressure);
} catch (e) {
this.handleBrushError(e);
return;
}
}
-
onMouseDrag(e) {
- if (!this._isInProgress) return; // Forward mouse event to croquis canvas
+ if (!this._isInProgress) return;
+ // Forward mouse event to croquis canvas
var point = this._croquisToPaperPoint(e.point);
-
this._updateStrokeBounds(point);
-
try {
this._updateLastMouseState(point, this.pressure);
-
this.croquis.move(point.x, point.y, this.pressure);
} catch (e) {
this.handleBrushError(e);
return;
}
-
this.lastPressure = this.pressure;
}
-
onMouseUp(e) {
if (!this._isInProgress) return;
this._isInProgress = false;
-
var point = this._croquisToPaperPoint(e.point);
-
this._calculateStrokeBounds(point);
-
try {
this.croquis.up(point.x, point.y, this.lastPressure);
} catch (e) {
this.handleBrushError(e);
return;
}
-
this._potraceCroquisCanvas(point);
}
+
/**
* The current amount of pressure applied to the paper js canvas this tool belongs to.
*/
-
-
get pressure() {
if (this.getSetting('pressureEnabled')) {
var pressure = this.paper.view.pressure;
@@ -59014,176 +57947,161 @@ Wick.Tools.Brush = class extends Wick.Tool {
return 1;
}
}
+
/**
* Croquis throws a lot of errrors. This is a helpful function to handle those errors gracefully.
*/
-
-
handleBrushError(e) {
this._isInProgress = false;
this.croquis.clearLayer();
-
if (!this.errorOccured) {
console.error("Brush error");
console.error(e);
}
-
this.errorOccured = true;
}
+
/**
* Is the brush currently making a stroke?
* @type {boolean}
*/
-
-
isInProgress() {
return this._isInProgress;
}
+
/**
* Discard the current brush stroke.
*/
-
-
discard() {
if (!this._isInProgress) return;
- this._isInProgress = false; // "Give up" on the current stroke by forcing a mouseup
+ this._isInProgress = false;
- this.croquis.up(this._lastMousePoint.x, this._lastMousePoint.y, this._lastMousePressure); // Clear the current croquis canvas
+ // "Give up" on the current stroke by forcing a mouseup
+ this.croquis.up(this._lastMousePoint.x, this._lastMousePoint.y, this._lastMousePressure);
+ // Clear the current croquis canvas
setTimeout(() => {
this.croquis.clearLayer();
}, 10);
}
+
/**
* Force the current stroke to be finished, and add the stroke to the project.
*/
-
-
finishStrokeEarly() {
if (!this._isInProgress) return;
- this._isInProgress = false; // Hide the croquis canvas so that the current stroke is never seen on the new frame.
+ this._isInProgress = false;
- this.croquisDOMElement.style.opacity = 0; // "Give up" on the current stroke by forcing a mouseup
+ // Hide the croquis canvas so that the current stroke is never seen on the new frame.
+ this.croquisDOMElement.style.opacity = 0;
- this.croquis.up(this._lastMousePoint.x, this._lastMousePoint.y, this._lastMousePressure); // Add path to project
+ // "Give up" on the current stroke by forcing a mouseup
+ this.croquis.up(this._lastMousePoint.x, this._lastMousePoint.y, this._lastMousePressure);
+ // Add path to project
this._calculateStrokeBounds(this._lastMousePoint);
-
this._potraceCroquisCanvas(this._lastMousePoint);
}
- /* Generate a new circle cursor based on the brush size. */
-
+ /* Generate a new circle cursor based on the brush size. */
_regenCursor() {
var size = this._getRealBrushSize();
-
var color = this.getSetting('fillColor').hex;
this.cachedCursor = this.createDynamicCursor(color, size, this.getSetting('pressureEnabled'));
this.setCursor(this.cachedCursor);
}
- /* Get the actual pixel size of the brush to send to Croquis. */
-
+ /* Get the actual pixel size of the brush to send to Croquis. */
_getRealBrushSize() {
var size = this.getSetting('brushSize') + 1;
-
if (!this.getSetting('relativeBrushSize')) {
size *= this.paper.view.zoom;
}
-
return size;
}
- /* Update Croquis and the div containing croquis to reflect all current options. */
-
+ /* Update Croquis and the div containing croquis to reflect all current options. */
_updateCanvasAttributes() {
if (!this.paper.view._element.parentElement) {
return;
- } // Update croquis element and pressure options
-
+ }
+ // Update croquis element and pressure options
if (!this.paper.view._element.parentElement.contains(this.croquisDOMElement)) {
this.paper.view.enablePressure();
-
this.paper.view._element.parentElement.appendChild(this.croquisDOMElement);
- } // Update croquis element canvas size
-
+ }
+ // Update croquis element canvas size
if (this.croquis.getCanvasWidth() !== this.paper.view._element.width || this.croquis.getCanvasHeight() !== this.paper.view._element.height) {
this.croquis.setCanvasSize(this.paper.view._element.width, this.paper.view._element.height);
- } // Fake brush opacity in croquis by changing the opacity of the croquis canvas
-
+ }
+ // Fake brush opacity in croquis by changing the opacity of the croquis canvas
this.croquisDOMElement.style.opacity = this.getSetting('fillColor').a;
}
- /* Convert a point in Croquis' canvas space to paper.js's canvas space. */
-
+ /* Convert a point in Croquis' canvas space to paper.js's canvas space. */
_croquisToPaperPoint(croquisPoint) {
var paperPoint = this.paper.view.projectToView(croquisPoint.x, croquisPoint.y);
return paperPoint;
}
- /* Used for calculating the crop amount for potrace. */
-
+ /* Used for calculating the crop amount for potrace. */
_resetStrokeBounds(point) {
this.strokeBounds = new paper.Rectangle(point.x, point.y, 1, 1);
}
- /* Used for calculating the crop amount for potrace. */
-
+ /* Used for calculating the crop amount for potrace. */
_updateStrokeBounds(point) {
this.strokeBounds = this.strokeBounds.include(point);
}
- /* Used for saving information on the mouse (croquis does not save this.) */
-
+ /* Used for saving information on the mouse (croquis does not save this.) */
_updateLastMouseState(point, pressure) {
this._lastMousePoint = new paper.Point(point.x, point.y);
this._lastMousePressure = this.pressure;
}
-
_calculateStrokeBounds(point) {
// Forward mouse event to croquis canvas
- this._updateStrokeBounds(point); // This prevents cropping out edges of the brush stroke
-
-
+ this._updateStrokeBounds(point);
+ // This prevents cropping out edges of the brush stroke
this.strokeBounds = this.strokeBounds.expand(this._getRealBrushSize());
}
- /* Create a paper.js path by potracing the croquis canvas, and add the resulting path to the project. */
-
+ /* Create a paper.js path by potracing the croquis canvas, and add the resulting path to the project. */
_potraceCroquisCanvas(point) {
this.errorOccured = false;
- var strokeBounds = this.strokeBounds.clone(); // Attempting to draw with a transparent fill color. Throw an error.
+ var strokeBounds = this.strokeBounds.clone();
+ // Attempting to draw with a transparent fill color. Throw an error.
if (this.getSetting('fillColor').a === 0) {
this.handleBrushError('transparentColor');
this.project.errorOccured("Fill Color is Transparent!");
return;
- } // Give croquis just a little bit to get the canvas ready...
-
+ }
+ // Give croquis just a little bit to get the canvas ready...
this._croquisStartTimeout = setTimeout(() => {
// Retrieve Croquis canvas
var canvas = this.paper.view._element.parentElement.getElementsByClassName('croquis-layer-canvas')[1];
-
if (!canvas) {
console.warn("Croquis canvas was not found in the canvas container. Something very bad has happened.");
this.handleBrushError('misingCroquisCanvas');
return;
- } // Rip image data out of Croquis.js canvas
- // (and crop out empty space using strokeBounds - this massively speeds up potrace)
-
+ }
+ // Rip image data out of Croquis.js canvas
+ // (and crop out empty space using strokeBounds - this massively speeds up potrace)
var croppedCanvas = document.createElement("canvas");
var croppedCanvasCtx = croppedCanvas.getContext("2d");
croppedCanvas.width = strokeBounds.width;
croppedCanvas.height = strokeBounds.height;
if (strokeBounds.x < 0) strokeBounds.x = 0;
if (strokeBounds.y < 0) strokeBounds.y = 0;
- croppedCanvasCtx.drawImage(canvas, strokeBounds.x, strokeBounds.y, strokeBounds.width, strokeBounds.height, 0, 0, croppedCanvas.width, croppedCanvas.height); // Run potrace and add the resulting path to the project
+ croppedCanvasCtx.drawImage(canvas, strokeBounds.x, strokeBounds.y, strokeBounds.width, strokeBounds.height, 0, 0, croppedCanvas.width, croppedCanvas.height);
+ // Run potrace and add the resulting path to the project
var svg = potrace.fromImage(croppedCanvas).toSVG(1 / this.POTRACE_RESOLUTION / this.paper.view.zoom);
var potracePath = this.paper.project.importSVG(svg);
potracePath.fillColor = this.getSetting('fillColor').rgba;
@@ -59195,22 +58113,23 @@ Wick.Tools.Brush = class extends Wick.Tool {
potracePath.closed = true;
potracePath.children[0].closed = true;
potracePath.children[0].applyMatrix = true;
- var result = potracePath.children[0]; // Do special brush mode action
+ var result = potracePath.children[0];
+ // Do special brush mode action
var brushMode = this.getSetting('brushMode');
-
if (this._currentDrawingFrame && this._currentDrawingFrame.view) {
// Don't apply brush mode if there is no frame to draw on
// (the frame is added during addPathToProject)
result = this._applyBrushMode(brushMode, result, this._currentDrawingFrame.view.objectsLayer);
- } // Done! Add the path to the project
-
-
- this.addPathToProject(result, this._currentDrawingFrame); // We're done potracing using the current croquis canvas, reset the stroke bounds
+ }
- this._resetStrokeBounds(point); // Clear croquis canvas
+ // Done! Add the path to the project
+ this.addPathToProject(result, this._currentDrawingFrame);
+ // We're done potracing using the current croquis canvas, reset the stroke bounds
+ this._resetStrokeBounds(point);
+ // Clear croquis canvas
this.croquis.clearLayer();
this.fireEvent({
eventName: 'canvasModified',
@@ -59218,18 +58137,15 @@ Wick.Tools.Brush = class extends Wick.Tool {
});
}, Wick.Tools.Brush.CROQUIS_WAIT_AMT_MS);
}
-
_applyBrushMode(mode, path, layer) {
if (!mode) {
console.warn('_applyBrushMode: Invalid brush mode: ' + mode);
console.warn('Valid brush modes are "inside" and "outside".');
return;
}
-
if (mode === 'none') {
return path;
}
-
var booleanOpName = {
'inside': 'intersect',
'outside': 'subtract'
@@ -59237,26 +58153,22 @@ Wick.Tools.Brush = class extends Wick.Tool {
var mask = null;
layer.children.forEach(otherPath => {
if (otherPath === mask) return;
-
if (mask) {
var newMask = mask.unite(otherPath);
-
- if (newMask.children && newMask.children.length === 0 || newMask.segments && newMask.segments.length === 0) {// Ignore boolean ops that result in empty paths
+ if (newMask.children && newMask.children.length === 0 || newMask.segments && newMask.segments.length === 0) {
+ // Ignore boolean ops that result in empty paths
} else {
mask = newMask;
}
-
newMask.remove();
} else {
mask = otherPath;
}
});
-
if (!mask) {
// Nothing to mask with
return path;
}
-
var result = path.clone({
insert: false
});
@@ -59264,7 +58176,6 @@ Wick.Tools.Brush = class extends Wick.Tool {
result.remove();
return result;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -59284,6 +58195,7 @@ Wick.Tools.Brush = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Cursor = class extends Wick.Tool {
/**
* Creates a cursor tool.
@@ -59311,42 +58223,38 @@ Wick.Tools.Cursor = class extends Wick.Tool {
this.selectedItems = [];
this.currentCursorIcon = '';
}
+
/**
* Generate the current cursor.
* @type {string}
*/
-
-
get cursor() {
return 'url("' + this.currentCursorIcon + '") 32 32, auto';
}
-
onActivate(e) {
this.selectedItems = [];
}
-
onDeactivate(e) {}
-
onMouseMove(e) {
- super.onMouseMove(e); // Find the thing that is currently under the cursor.
+ super.onMouseMove(e);
- this.hitResult = this._updateHitResult(e); // Update the image being used for the cursor
+ // Find the thing that is currently under the cursor.
+ this.hitResult = this._updateHitResult(e);
+ // Update the image being used for the cursor
this._setCursor(this._getCursor());
}
-
onMouseDown(e) {
super.onMouseDown(e);
if (!e.modifiers) e.modifiers = {};
this.hitResult = this._updateHitResult(e);
-
- if (this.hitResult.item && this.hitResult.item.data.isSelectionBoxGUI) {// Clicked the selection box GUI, do nothing
+ if (this.hitResult.item && this.hitResult.item.data.isSelectionBoxGUI) {
+ // Clicked the selection box GUI, do nothing
} else if (this.hitResult.item && this._isItemSelected(this.hitResult.item)) {
// We clicked something that was already selected.
// Shift click: Deselect that item
if (e.modifiers.shift) {
this._deselectItem(this.hitResult.item);
-
this.fireEvent({
eventName: 'canvasModified',
actionName: 'cursorDeselect'
@@ -59356,11 +58264,9 @@ Wick.Tools.Cursor = class extends Wick.Tool {
if (!e.modifiers.shift) {
// Shift click? Keep everything else selected.
this._clearSelection();
- } // Clicked an item: select that item
-
-
+ }
+ // Clicked an item: select that item
this._selectItem(this.hitResult.item);
-
this.fireEvent({
eventName: 'canvasModified',
actionName: 'cursorSelect'
@@ -59370,20 +58276,16 @@ Wick.Tools.Cursor = class extends Wick.Tool {
// (don't clear the selection if shift is held, though)
if (this._selection.numObjects > 0 && !e.modifiers.shift) {
this._clearSelection();
-
this.fireEvent({
eventName: 'canvasModified',
actionName: 'cursorClearSelect'
});
}
-
this.selectionBox.start(e.point);
}
}
-
onDoubleClick(e) {
var selectedObject = this._selection.getSelectedObject();
-
if (selectedObject && selectedObject instanceof Wick.Clip) {
// Double clicked a Clip, set the focus to that Clip.
if (this.project.focusTimelineOfSelectedClip()) {
@@ -59392,7 +58294,8 @@ Wick.Tools.Cursor = class extends Wick.Tool {
actionName: 'cursorFocusTimelineSelected'
});
}
- } else if (selectedObject && selectedObject instanceof Wick.Path && selectedObject.view.item instanceof paper.PointText) {// Double clicked text, switch to text tool and edit the text item.
+ } else if (selectedObject && selectedObject instanceof Wick.Path && selectedObject.view.item instanceof paper.PointText) {
+ // Double clicked text, switch to text tool and edit the text item.
// TODO
} else if (!selectedObject) {
// Double clicked the canvas, leave the current focus.
@@ -59404,17 +58307,14 @@ Wick.Tools.Cursor = class extends Wick.Tool {
}
}
}
-
onMouseDrag(e) {
if (!e.modifiers) e.modifiers = {};
this.__isDragging = true;
-
if (this.hitResult.item && this.hitResult.item.data.isSelectionBoxGUI) {
// Update selection drag
if (!this._widget.currentTransformation) {
this._widget.startTransformation(this.hitResult.item);
}
-
this._widget.updateTransformation(this.hitResult.item, e);
} else if (this.selectionBox.active) {
// Selection box is being used, update it with a new point
@@ -59424,32 +58324,26 @@ Wick.Tools.Cursor = class extends Wick.Tool {
if (!this._widget.currentTransformation) {
this._widget.startTransformation(this.hitResult.item);
}
-
this._widget.updateTransformation(this.hitResult.item, e);
} else {
this.__isDragging = false;
}
}
-
onMouseUp(e) {
if (!e.modifiers) e.modifiers = {};
-
if (this.selectionBox.active) {
// Finish selection box and select objects touching box (or inside box, if alt is held)
this.selectionBox.mode = e.modifiers.alt ? 'contains' : 'intersects';
this.selectionBox.end(e.point);
-
if (!e.modifiers.shift) {
this._selection.clear();
}
-
let selectables = this.selectionBox.items.filter(item => {
return item.data.wickUUID;
});
+ this._selectItems(selectables);
- this._selectItems(selectables); // Only modify the canvas if you actually selected something.
-
-
+ // Only modify the canvas if you actually selected something.
if (this.selectionBox.items.length > 0) {
this.fireEvent({
eventName: 'canvasModified',
@@ -59460,9 +58354,7 @@ Wick.Tools.Cursor = class extends Wick.Tool {
if (this.__isDragging) {
this.__isDragging = false;
this.project.tryToAutoCreateTween();
-
this._widget.finishTransformation();
-
this.fireEvent({
eventName: 'canvasModified',
actionName: 'cursorDrag'
@@ -59470,7 +58362,6 @@ Wick.Tools.Cursor = class extends Wick.Tool {
}
}
}
-
_updateHitResult(e) {
var newHitResult = this.paper.project.hitTest(e.point, {
fill: true,
@@ -59483,44 +58374,39 @@ Wick.Tools.Cursor = class extends Wick.Tool {
}
});
if (!newHitResult) newHitResult = new this.paper.HitResult();
-
if (newHitResult.item && !newHitResult.item.data.isSelectionBoxGUI) {
// You can't select children of compound paths, you can only select the whole thing.
if (newHitResult.item.parent.className === 'CompoundPath') {
newHitResult.item = newHitResult.item.parent;
- } // You can't select individual children in a group, you can only select the whole thing.
-
+ }
+ // You can't select individual children in a group, you can only select the whole thing.
if (newHitResult.item.parent.parent) {
newHitResult.type = 'fill';
-
while (newHitResult.item.parent.parent) {
newHitResult.item = newHitResult.item.parent;
}
- } // this.paper.js has two names for strokes+curves, we don't need that extra info
-
+ }
+ // this.paper.js has two names for strokes+curves, we don't need that extra info
if (newHitResult.type === 'stroke') {
newHitResult.type = 'curve';
- } // Mousing over rasters acts the same as mousing over fills.
-
+ }
+ // Mousing over rasters acts the same as mousing over fills.
if (newHitResult.type === 'pixel') {
newHitResult.type = 'fill';
}
+ ;
- ; // Disable curve and segment selection. (this was moved to the PathCursor)
-
+ // Disable curve and segment selection. (this was moved to the PathCursor)
if (newHitResult.type === 'segment' || newHitResult.type === 'curve') {
newHitResult.type = 'fill';
}
-
;
}
-
return newHitResult;
}
-
_getCursor() {
if (!this.hitResult.item) {
return this.CURSOR_DEFAULT;
@@ -59528,9 +58414,13 @@ Wick.Tools.Cursor = class extends Wick.Tool {
// Don't show any custom cursor if the mouse is over the border, the border does nothing
if (this.hitResult.item.name === 'border') {
return this.CURSOR_DEFAULT;
- } // Calculate the angle in which the scale handle scales the selection.
+ }
+
+ // Calculate the angle in which the scale handle scales the selection.
// Use that angle to determine the cursor graphic to use.
+
// Here is a handy diagram showing the cursors that correspond to the angles:
+
// 315 0 45
// o-----o-----o
// | |
@@ -59541,7 +58431,6 @@ Wick.Tools.Cursor = class extends Wick.Tool {
// o-----o-----o
// 225 180 135
-
var baseAngle = {
topCenter: 0,
topRight: 45,
@@ -59552,17 +58441,17 @@ Wick.Tools.Cursor = class extends Wick.Tool {
leftCenter: 270,
topLeft: 315
}[this.hitResult.item.data.handleEdge];
- var angle = baseAngle + this._widget.rotation; // It makes angle math easier if we dont allow angles >360 or <0 degrees:
-
+ var angle = baseAngle + this._widget.rotation;
+ // It makes angle math easier if we dont allow angles >360 or <0 degrees:
if (angle < 0) angle += 360;
- if (angle > 360) angle -= 360; // Round the angle to the nearest 45 degree interval.
+ if (angle > 360) angle -= 360;
+ // Round the angle to the nearest 45 degree interval.
var angleRoundedToNearest45 = Math.round(angle / 45) * 45;
angleRoundedToNearest45 = Math.round(angleRoundedToNearest45); // just incase of float weirdness
-
angleRoundedToNearest45 = '' + angleRoundedToNearest45; // convert to string
- // Now we know which of eight directions the handle is pointing, so we choose the correct cursor
+ // Now we know which of eight directions the handle is pointing, so we choose the correct cursor
if (this.hitResult.item.data.handleType === 'scale') {
var cursorGraphicFromAngle = {
'0': this.CURSOR_SCALE_VERTICAL,
@@ -59596,66 +58485,50 @@ Wick.Tools.Cursor = class extends Wick.Tool {
}
}
}
-
_setCursor(cursor) {
this.currentCursorIcon = cursor;
}
-
get _selection() {
return this.project.selection;
}
-
get _widget() {
return this._selection.view.widget;
}
-
_clearSelection() {
this._selection.clear();
}
-
_selectItem(item) {
var object = this._wickObjectFromPaperItem(item);
-
this._selection.select(object);
}
+
/**
* Select multiple items simultaneously.
* @param {object[]} items paper items
*/
-
-
_selectItems(items) {
let objects = [];
items.forEach(item => {
objects.push(this._wickObjectFromPaperItem(item));
});
-
this._selection.selectMultipleObjects(objects);
}
-
_deselectItem(item) {
var object = this._wickObjectFromPaperItem(item);
-
this._selection.deselect(object);
}
-
_isItemSelected(item) {
var object = this._wickObjectFromPaperItem(item);
-
return object.isSelected;
}
-
_wickObjectFromPaperItem(item) {
var uuid = item.data.wickUUID;
-
if (!uuid) {
console.error('WARNING: _wickObjectFromPaperItem: item had no wick UUID. did you try to select something that wasnt created by a wick view? is the view up-to-date?');
console.log(item);
}
-
return Wick.ObjectCache.getObjectByUUID(uuid);
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -59675,6 +58548,7 @@ Wick.Tools.Cursor = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Ellipse = class extends Wick.Tool {
/**
* Creates an instance of the ellipse tool.
@@ -59686,49 +58560,42 @@ Wick.Tools.Ellipse = class extends Wick.Tool {
this.topLeft = null;
this.bottomRight = null;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
* A crosshair cursor.
* @type {string}
*/
-
-
get cursor() {
return 'crosshair';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {}
-
onDeactivate(e) {
if (this.path) {
this.path.remove();
this.path = null;
}
}
-
onMouseDown(e) {
this.topLeft = e.point;
this.bottomRight = e.point;
}
-
onMouseDrag(e) {
if (this.path) this.path.remove();
- this.bottomRight = e.point; // Lock width and height if shift is held down
+ this.bottomRight = e.point;
+ // Lock width and height if shift is held down
if (e.modifiers.shift) {
var d = this.bottomRight.subtract(this.topLeft);
var max = Math.max(Math.abs(d.x), Math.abs(d.y));
this.bottomRight.x = this.topLeft.x + max * (d.x < 0 ? -1 : 1);
this.bottomRight.y = this.topLeft.y + max * (d.y < 0 ? -1 : 1);
}
-
var bounds = new this.paper.Rectangle(new this.paper.Point(this.topLeft.x, this.topLeft.y), new this.paper.Point(this.bottomRight.x, this.bottomRight.y));
this.path = new this.paper.Path.Ellipse(bounds);
this.paper.project.activeLayer.addChild(this.path);
@@ -59737,7 +58604,6 @@ Wick.Tools.Ellipse = class extends Wick.Tool {
this.path.strokeWidth = this.getSetting('strokeWidth');
this.path.strokeCap = 'round';
}
-
onMouseUp(e) {
if (!this.path) return;
this.path.remove();
@@ -59748,7 +58614,6 @@ Wick.Tools.Ellipse = class extends Wick.Tool {
actionName: 'ellipse'
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -59768,6 +58633,7 @@ Wick.Tools.Ellipse = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Eraser = class extends Wick.Tool {
/**
*
@@ -59779,46 +58645,38 @@ Wick.Tools.Eraser = class extends Wick.Tool {
this.cursorSize = null;
this.cachedCursor = null;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return this.cachedCursor || 'crosshair';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {
this.cursorSize = null;
}
-
onDeactivate(e) {
if (this.path) {
this.path.remove();
this.path = null;
}
}
-
onMouseMove(e) {
// Don't render cursor after every mouse move, cache and only render when size changes
var cursorNeedsRegen = this.getSetting('eraserSize') !== this.cursorSize;
-
if (cursorNeedsRegen) {
this.cachedCursor = this.createDynamicCursor('#ffffff', this.getSetting('eraserSize') + 1);
this.cursorSize = this.getSetting('eraserSize');
this.setCursor(this.cachedCursor);
}
}
-
onMouseDown(e) {
if (!this.path) {
this.path = new this.paper.Path({
@@ -59826,20 +58684,18 @@ Wick.Tools.Eraser = class extends Wick.Tool {
strokeCap: 'round',
strokeWidth: (this.getSetting('eraserSize') + 1) / this.paper.view.zoom
});
- } // Add two points so we always at least have a dot.
-
+ }
+ // Add two points so we always at least have a dot.
this.path.add(e.point);
this.path.add(e.point);
}
-
onMouseDrag(e) {
if (e.point) {
this.path.add(e.point);
this.path.smooth();
}
}
-
onMouseUp(e) {
if (!this.path) return;
var potraceResolution = 0.7;
@@ -59856,7 +58712,6 @@ Wick.Tools.Eraser = class extends Wick.Tool {
resolution: potraceResolution * this.paper.view.zoom
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -59876,6 +58731,7 @@ Wick.Tools.Eraser = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Eyedropper = class extends Wick.Tool {
/**
*
@@ -59887,26 +58743,21 @@ Wick.Tools.Eyedropper = class extends Wick.Tool {
this.hoverColor = '#ffffff';
this.colorPreview = null;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'url(cursors/eyedropper.png) 32 32, auto';
}
-
onActivate(e) {}
-
onDeactivate(e) {
this._destroyColorPreview();
}
-
onMouseMove(e) {
super.onMouseMove(e);
var canvas = this.paper.view._element;
@@ -59917,13 +58768,10 @@ Wick.Tools.Eyedropper = class extends Wick.Tool {
var colorData = ctx.getImageData(pointPx.x, pointPx.y, 1, 1).data;
var colorCSS = 'rgb(' + colorData[0] + ',' + colorData[1] + ',' + colorData[2] + ')';
this.hoverColor = colorCSS;
-
this._createColorPreview(e.point);
}
-
onMouseDown(e) {
this._destroyColorPreview();
-
this.fireEvent({
eventName: 'eyedropperPickedColor',
e: {
@@ -59931,16 +58779,12 @@ Wick.Tools.Eyedropper = class extends Wick.Tool {
}
});
}
-
onMouseDrag(e) {}
-
onMouseUp(e) {
this._createColorPreview(e.point);
}
-
_createColorPreview(point) {
this._destroyColorPreview();
-
var offset = 10 / this.paper.view.zoom;
var center = point.add(new paper.Point(offset + 0.5, offset + 0.5));
var radius = 10 / paper.view.zoom;
@@ -59954,14 +58798,12 @@ Wick.Tools.Eyedropper = class extends Wick.Tool {
strokeWidth: 1.0 / this.paper.view.zoom
}));
}
-
_destroyColorPreview() {
if (this.colorPreview) {
this.colorPreview.remove();
this.colorPreview = null;
}
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -59981,6 +58823,7 @@ Wick.Tools.Eyedropper = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.FillBucket = class extends Wick.Tool {
/**
*
@@ -59989,28 +58832,22 @@ Wick.Tools.FillBucket = class extends Wick.Tool {
super();
this.name = 'fillbucket';
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'url(cursors/fillbucket.png) 32 32, auto';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {}
-
onDeactivate(e) {}
-
onMouseDown(e) {
setTimeout(() => {
this.setCursor('wait');
@@ -60027,19 +58864,16 @@ Wick.Tools.FillBucket = class extends Wick.Tool {
}),
onFinish: path => {
this.setCursor('default');
-
if (path) {
path.fillColor = this.getSetting('fillColor').rgba;
path.name = null;
this.addPathToProject();
-
if (e.item) {
path.insertAbove(e.item);
} else {
this.paper.project.activeLayer.addChild(path);
this.paper.OrderingUtils.sendToBack([path]);
}
-
this.fireEvent({
eventName: 'canvasModified',
actionName: 'fillbucket'
@@ -60053,11 +58887,8 @@ Wick.Tools.FillBucket = class extends Wick.Tool {
});
}, 50);
}
-
onMouseDrag(e) {}
-
onMouseUp(e) {}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60077,6 +58908,7 @@ Wick.Tools.FillBucket = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Interact = class extends Wick.Tool {
/**
* Creates an Interact tool.
@@ -60090,71 +58922,55 @@ Wick.Tools.Interact = class extends Wick.Tool {
this._mousePosition = new paper.Point(0, 0);
this._mouseTargets = [];
}
-
onActivate(e) {}
-
onDeactivate(e) {}
-
onMouseMove(e) {
this._mousePosition = e.point;
}
-
onMouseDrag(e) {
this._mousePosition = e.point;
}
-
onMouseDown(e) {
this._mousePosition = e.point;
this._mouseIsDown = true;
}
-
onMouseUp(e) {
this._mousePosition = e.point;
this._mouseIsDown = false;
}
-
onKeyDown(e) {
this._lastKeyDown = e.key;
-
if (this._keysDown.indexOf(e.key) === -1) {
this._keysDown.push(e.key);
}
}
-
onKeyUp(e) {
this._keysDown = this._keysDown.filter(key => {
return key !== e.key;
});
}
-
get mousePosition() {
return this._mousePosition;
}
-
get mouseIsDown() {
return this._mouseIsDown;
}
-
get keysDown() {
return this._keysDown;
}
-
get lastKeyDown() {
return this._lastKeyDown;
}
-
get mouseTargets() {
return this._mouseTargets;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
* Use the current position of the mouse to determine which object(s) are under the mouse
*/
-
-
determineMouseTargets() {
var targets = [];
var hitResult = this.paper.project.hitTest(this.mousePosition, {
@@ -60162,14 +58978,13 @@ Wick.Tools.Interact = class extends Wick.Tool {
stroke: true,
curves: true,
segments: true
- }); // Check for clips under the mouse.
+ });
+ // Check for clips under the mouse.
if (hitResult) {
var uuid = hitResult.item.data.wickUUID;
-
if (uuid) {
var path = Wick.ObjectCache.getObjectByUUID(uuid);
-
if (path && !path.parentClip.isRoot) {
var clip = path.parentClip;
var lineageWithoutRoot = clip.lineage;
@@ -60182,9 +58997,9 @@ Wick.Tools.Interact = class extends Wick.Tool {
targets = [this.project.activeFrame];
} else {
targets = [];
- } // Update cursor
-
+ }
+ // Update cursor
if (this.project.hideCursor) {
this.setCursor('none');
} else {
@@ -60193,10 +59008,8 @@ Wick.Tools.Interact = class extends Wick.Tool {
clip && this.setCursor(clip.cursor);
}
}
-
this._mouseTargets = targets;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60216,6 +59029,7 @@ Wick.Tools.Interact = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Line = class extends Wick.Tool {
/**
*
@@ -60229,36 +59043,29 @@ Wick.Tools.Line = class extends Wick.Tool {
this.startPoint;
this.endPoint;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'crosshair';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {
this.path.remove();
}
-
onDeactivate(e) {
this.path.remove();
}
-
onMouseDown(e) {
this.startPoint = e.point;
}
-
onMouseDrag(e) {
this.path.remove();
this.endPoint = e.point;
@@ -60267,7 +59074,6 @@ Wick.Tools.Line = class extends Wick.Tool {
this.path.strokeColor = this.getSetting('strokeColor').rgba;
this.path.strokeWidth = this.getSetting('strokeWidth');
}
-
onMouseUp(e) {
this.path.remove();
this.addPathToProject(this.path);
@@ -60276,7 +59082,6 @@ Wick.Tools.Line = class extends Wick.Tool {
actionName: 'line'
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60296,6 +59101,7 @@ Wick.Tools.Line = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.None = class extends Wick.Tool {
/**
* Creates a none tool.
@@ -60304,23 +59110,18 @@ Wick.Tools.None = class extends Wick.Tool {
super();
this.name = 'none';
}
+
/**
* The "no-sign" cursor.
* @type {string}
*/
-
-
get cursor() {
return 'not-allowed';
}
-
onActivate(e) {}
-
onDeactivate(e) {}
-
onMouseDown(e) {
var message = '';
-
if (!this.project.activeFrame) {
message = 'CLICK_NOT_ALLOWED_NO_FRAME';
} else if (this.project.activeLayer.locked) {
@@ -60330,14 +59131,10 @@ Wick.Tools.None = class extends Wick.Tool {
} else {
return;
}
-
this.project.errorOccured(message);
}
-
onMouseDrag(e) {}
-
onMouseUp(e) {}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60357,6 +59154,7 @@ Wick.Tools.None = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Pan = class extends Wick.Tool {
/**
*
@@ -60365,37 +59163,29 @@ Wick.Tools.Pan = class extends Wick.Tool {
super();
this.name = 'pan';
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'move';
}
-
onActivate(e) {}
-
onDeactivate(e) {}
-
onMouseDown(e) {}
-
onMouseDrag(e) {
var d = e.downPoint.subtract(e.point);
this.paper.view.center = this.paper.view.center.add(d);
}
-
onMouseUp(e) {
this.fireEvent({
eventName: 'canvasViewTransformed'
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60415,6 +59205,7 @@ Wick.Tools.Pan = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.PathCursor = class extends Wick.Tool {
constructor() {
super();
@@ -60438,31 +59229,29 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
this.detailedEditing = null;
this.currentCursorIcon = '';
}
-
get doubleClickEnabled() {
return true;
}
-
get cursor() {
return 'url("' + this.currentCursorIcon + '") 32 32, auto';
}
-
onActivate(e) {}
-
onDeactivate(e) {
this._leaveDetailedEditing();
}
-
onMouseMove(e) {
- super.onMouseMove(e); // Remove the hover preview, a new one will be generated if needed
-
- this.hoverPreview.remove(); // Find the thing that is currently under the cursor.
+ super.onMouseMove(e);
- this.hitResult = this._updateHitResult(e); // Update the image being used for the cursor
+ // Remove the hover preview, a new one will be generated if needed
+ this.hoverPreview.remove();
- this._setCursor(this._getCursor()); // Regen hover preview
+ // Find the thing that is currently under the cursor.
+ this.hitResult = this._updateHitResult(e);
+ // Update the image being used for the cursor
+ this._setCursor(this._getCursor());
+ // Regen hover preview
if (this.hitResult.type === 'segment' && !this.hitResult.item.data.isSelectionBoxGUI) {
// Hovering over a segment, draw a circle where the segment is
this.hoverPreview = new this.paper.Path.Circle(this.hitResult.segment.point, this.HOVER_PREVIEW_SEGMENT_RADIUS / this.paper.view.zoom);
@@ -60479,20 +59268,16 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
this.hoverPreview.segments[0].handleOut = this.hitResult.location.curve.handle1;
this.hoverPreview.segments[1].handleIn = this.hitResult.location.curve.handle2;
}
-
this.hoverPreview.data.wickType = 'gui';
}
-
onMouseDown(e) {
super.onMouseDown(e);
if (!e.modifiers) e.modifiers = {};
this.hitResult = this._updateHitResult(e);
-
if (this.detailedEditing !== null && !(this.hitResult.item || this.hitResult.type && this.hitResult.type.startsWith('handle'))) {
// Clicked neither on the currently edited path nor on a handle.
this._leaveDetailedEditing();
}
-
if (this.hitResult.item && this.hitResult.type === 'curve') {
// Clicked a curve, start dragging it
this.draggingCurve = this.hitResult.location.curve;
@@ -60502,10 +59287,8 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
}
}
}
-
onDoubleClick(e) {
this.hitResult = this._updateHitResult(e);
-
if (this.detailedEditing == null) {
// If detailed editing is off, turn it on for this path.
this.detailedEditing = this.hitResult.item;
@@ -60518,12 +59301,10 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
var location = this.hitResult.location;
var path = this.hitResult.item;
var addedPoint = path.insert(location.index + 1, e.point);
-
if (!e.modifiers.shift) {
addedPoint.smooth();
var handleInMag = Math.sqrt(addedPoint.handleIn.x * addedPoint.handleIn.x + addedPoint.handleIn.y + addedPoint.handleIn.y);
var handleOutMag = Math.sqrt(addedPoint.handleOut.x * addedPoint.handleOut.x + addedPoint.handleOut.y + addedPoint.handleOut.y);
-
if (handleInMag > handleOutMag) {
var avgMag = handleOutMag;
addedPoint.handleIn.x = -addedPoint.handleOut.x * 1.5;
@@ -60538,7 +59319,6 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
addedPoint.handleIn.y *= 1.5;
}
}
-
if (this.detailedEditing !== null) {
path.setFullySelected(true);
}
@@ -60547,7 +59327,6 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
var hiy = this.hitResult.segment.handleIn.y;
var hox = this.hitResult.segment.handleOut.x;
var hoy = this.hitResult.segment.handleOut.y;
-
if (hix === 0 && hiy === 0 && hix === 0 && hiy === 0) {
this.hitResult.segment.smooth();
} else {
@@ -60558,10 +59337,8 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
}
}
}
-
onMouseDrag(e) {
if (!e.modifiers) e.modifiers = {};
-
if (this.hitResult.item && this.hitResult.type === 'segment') {
// We're dragging an individual point, so move the point.
this.hitResult.segment.point = this.hitResult.segment.point.add(e.delta);
@@ -60572,30 +59349,26 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
var segment2 = this.draggingCurve.segment2;
var handleIn = segment1.handleOut;
var handleOut = segment2.handleIn;
-
if (handleIn.x === 0 && handleIn.y === 0) {
handleIn.x = (segment2.point.x - segment1.point.x) / 4;
handleIn.y = (segment2.point.y - segment1.point.y) / 4;
}
-
if (handleOut.x === 0 && handleOut.y === 0) {
handleOut.x = (segment1.point.x - segment2.point.x) / 4;
handleOut.y = (segment1.point.y - segment2.point.y) / 4;
}
-
handleIn.x += e.delta.x;
handleIn.y += e.delta.y;
handleOut.x += e.delta.x;
- handleOut.y += e.delta.y; // Update the hover preview to match the curve we just changed
+ handleOut.y += e.delta.y;
+ // Update the hover preview to match the curve we just changed
this.hoverPreview.segments[0].handleOut = this.draggingCurve.handle1;
this.hoverPreview.segments[1].handleIn = this.draggingCurve.handle2;
}
-
if (this.hitResult.type && this.hitResult.type.startsWith('handle')) {
var otherHandle;
var handle;
-
if (this.hitResult.type === 'handle-in') {
handle = this.hitResult.segment.handleIn;
otherHandle = this.hitResult.segment.handleOut;
@@ -60603,17 +59376,14 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
handle = this.hitResult.segment.handleOut;
otherHandle = this.hitResult.segment.handleIn;
}
-
handle.x += e.delta.x;
handle.y += e.delta.y;
-
if (!e.modifiers.shift) {
otherHandle.x -= e.delta.x;
otherHandle.y -= e.delta.y;
}
}
}
-
onMouseUp(e) {
if (this.hitResult.type === 'segment' || this.hitResult.type === 'curve') {
this.fireEvent({
@@ -60622,7 +59392,6 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
});
}
}
-
onKeyDown(e) {
if (this.detailedEditing !== null && e.key == "<") {
var wick = Wick.ObjectCache.getObjectByUUID(this._getWickUUID(this.detailedEditing));
@@ -60631,7 +59400,6 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
this.fireEvent('canvasModified');
}
}
-
_updateHitResult(e) {
var newHitResult = this.paper.project.hitTest(e.point, {
fill: true,
@@ -60645,48 +59413,42 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
}
});
if (!newHitResult) newHitResult = new this.paper.HitResult();
-
if (this.detailedEditing !== null) {
if (this._getWickUUID(newHitResult.item) !== this._getWickUUID(this.detailedEditing)) {
// Hits an item, but not the one currently in detail edit - handle as a click with no hit.
return new this.paper.HitResult();
}
-
if (newHitResult.item && newHitResult.type.startsWith('handle')) {
// If this a click on a handle, do not apply hit type prediction below.
return newHitResult;
}
}
-
if (newHitResult.item && !newHitResult.item.data.isSelectionBoxGUI) {
// You can't select children of compound paths, you can only select the whole thing.
if (newHitResult.item.parent.className === 'CompoundPath') {
newHitResult.item = newHitResult.item.parent;
- } // You can't select individual children in a group, you can only select the whole thing.
-
+ }
+ // You can't select individual children in a group, you can only select the whole thing.
if (newHitResult.item.parent.parent) {
newHitResult.type = 'fill';
-
while (newHitResult.item.parent.parent) {
newHitResult.item = newHitResult.item.parent;
}
- } // this.paper.js has two names for strokes+curves, we don't need that extra info
-
+ }
+ // this.paper.js has two names for strokes+curves, we don't need that extra info
if (newHitResult.type === 'stroke') {
newHitResult.type = 'curve';
- } // Mousing over rasters acts the same as mousing over fills.
-
+ }
+ // Mousing over rasters acts the same as mousing over fills.
if (newHitResult.type === 'pixel') {
newHitResult.type = 'fill';
}
}
-
return newHitResult;
}
-
_getCursor() {
if (!this.hitResult.item) {
return this.CURSOR_DEFAULT;
@@ -60696,11 +59458,9 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
return this.CURSOR_SEGMENT;
}
}
-
_setCursor(cursor) {
this.currentCursorIcon = cursor;
}
-
_leaveDetailedEditing() {
if (this.detailedEditing !== null) {
this.paper.project.deselectAll();
@@ -60713,7 +59473,6 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
this.fireEvent('canvasModified');
}
}
-
_getWickUUID(item) {
if (item) {
return item.data.wickUUID;
@@ -60721,7 +59480,6 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
return undefined;
}
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60741,46 +59499,39 @@ Wick.Tools.PathCursor = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Pencil = class extends Wick.Tool {
static get MIN_ADD_POINT_MOVEMENT() {
return 2;
}
+
/**
* Creates a pencil tool.
*/
-
-
constructor() {
super();
this.name = 'pencil';
this.path = null;
this._movement = new paper.Point();
}
-
get doubleClickEnabled() {
return false;
}
+
/**
* The pencil cursor.
* @type {string}
*/
-
-
get cursor() {
return 'url(cursors/pencil.png) 32 32, auto';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {}
-
onDeactivate(e) {}
-
onMouseDown(e) {
this._movement = new paper.Point();
-
if (!this.path) {
this.path = new this.paper.Path({
strokeColor: this.getSetting('strokeColor').rgba,
@@ -60788,21 +59539,17 @@ Wick.Tools.Pencil = class extends Wick.Tool {
strokeCap: 'round'
});
}
-
this.path.add(e.point);
}
-
onMouseDrag(e) {
if (!this.path) return;
this._movement = this._movement.add(e.delta);
-
if (this._movement.length > Wick.Tools.Pencil.MIN_ADD_POINT_MOVEMENT / this.paper.view.zoom) {
this._movement = new paper.Point();
this.path.add(e.point);
this.path.smooth();
}
}
-
onMouseUp(e) {
if (!this.path) return;
this.path.add(e.point);
@@ -60815,7 +59562,6 @@ Wick.Tools.Pencil = class extends Wick.Tool {
actionName: 'pencil'
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60835,6 +59581,7 @@ Wick.Tools.Pencil = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Rectangle = class extends Wick.Tool {
/**
*
@@ -60846,63 +59593,53 @@ Wick.Tools.Rectangle = class extends Wick.Tool {
this.topLeft = null;
this.bottomRight = null;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'crosshair';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {}
-
onDeactivate(e) {
if (this.path) {
this.path.remove();
this.path = null;
}
}
-
onMouseDown(e) {
this.topLeft = e.point;
this.bottomRight = e.point;
}
-
onMouseDrag(e) {
if (this.path) this.path.remove();
- this.bottomRight = e.point; // Lock width and height if shift is held down
+ this.bottomRight = e.point;
+ // Lock width and height if shift is held down
if (e.modifiers.shift) {
var d = this.bottomRight.subtract(this.topLeft);
var max = Math.max(Math.abs(d.x), Math.abs(d.y));
this.bottomRight.x = this.topLeft.x + max * (d.x < 0 ? -1 : 1);
this.bottomRight.y = this.topLeft.y + max * (d.y < 0 ? -1 : 1);
}
-
var bounds = new this.paper.Rectangle(new paper.Point(this.topLeft.x, this.topLeft.y), new paper.Point(this.bottomRight.x, this.bottomRight.y));
-
if (this.getSetting('cornerRadius') !== 0) {
this.path = new this.paper.Path.Rectangle(bounds, this.getSetting('cornerRadius'));
} else {
this.path = new this.paper.Path.Rectangle(bounds);
}
-
this.path.fillColor = this.getSetting('fillColor').rgba;
this.path.strokeColor = this.getSetting('strokeColor').rgba;
this.path.strokeWidth = this.getSetting('strokeWidth');
this.path.strokeCap = 'round';
}
-
onMouseUp(e) {
if (!this.path) return;
this.path.remove();
@@ -60913,7 +59650,6 @@ Wick.Tools.Rectangle = class extends Wick.Tool {
actionName: 'rectangle'
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -60933,6 +59669,7 @@ Wick.Tools.Rectangle = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Text = class extends Wick.Tool {
/**
*
@@ -60943,37 +59680,29 @@ Wick.Tools.Text = class extends Wick.Tool {
this.hoveredOverText = null;
this.editingText = null;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'text';
}
-
get isDrawingTool() {
return true;
}
-
onActivate(e) {}
-
onDeactivate(e) {
if (this.editingText) {
this.finishEditingText();
}
-
this.hoveredOverText = null;
}
-
onMouseMove(e) {
super.onMouseMove(e);
-
if (e.item && e.item.className === 'PointText' && !e.item.parent.parent) {
this.hoveredOverText = e.item;
this.setCursor('text');
@@ -60982,7 +59711,6 @@ Wick.Tools.Text = class extends Wick.Tool {
this.setCursor('url(cursors/text.png) 32 32, auto');
}
}
-
onMouseDown(e) {
if (this.editingText) {
this.finishEditingText();
@@ -61003,37 +59731,33 @@ Wick.Tools.Text = class extends Wick.Tool {
this.project.activeFrame.addPath(wickText);
this.project.view.render();
this.editingText = wickText.view.item;
- this.editingText.edit(this.project.view.paper); //this.fireEvent('canvasModified');
+ this.editingText.edit(this.project.view.paper);
+
+ //this.fireEvent('canvasModified');
}
}
onMouseDrag(e) {}
-
onMouseUp(e) {}
-
reset() {
this.finishEditingText();
}
+
/**
* Stop editing the current text and apply changes.
*/
-
-
finishEditingText() {
if (!this.editingText) return;
this.editingText.finishEditing();
-
if (this.editingText.content === '') {
this.editingText.remove();
}
-
this.editingText = null;
this.fireEvent({
eventName: 'canvasModified',
actionName: 'text'
});
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -61053,6 +59777,7 @@ Wick.Tools.Text = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
Wick.Tools.Zoom = class extends Wick.Tool {
/**
*
@@ -61065,33 +59790,26 @@ Wick.Tools.Zoom = class extends Wick.Tool {
this.MIN_ZOOMBOX_SIZE = 20;
this.zoomBox = null;
}
-
get doubleClickEnabled() {
return false;
}
+
/**
*
* @type {string}
*/
-
-
get cursor() {
return 'zoom-in';
}
-
onActivate(e) {}
-
onDeactivate(e) {
this.deleteZoomBox();
}
-
onMouseDown(e) {}
-
onMouseDrag(e) {
this.deleteZoomBox();
this.createZoomBox(e);
}
-
onMouseUp(e) {
if (this.zoomBox && this.zoomBoxIsValidSize()) {
var bounds = this.zoomBox.bounds;
@@ -61102,13 +59820,11 @@ Wick.Tools.Zoom = class extends Wick.Tool {
var zoomAmount = e.modifiers.alt ? this.ZOOM_OUT_AMOUNT : this.ZOOM_IN_AMOUNT;
this.paper.view.scale(zoomAmount, e.point);
}
-
this.deleteZoomBox();
this.fireEvent({
eventName: 'canvasViewTransformed'
});
}
-
createZoomBox(e) {
var bounds = new this.paper.Rectangle(e.downPoint, e.point);
bounds.x += 0.5;
@@ -61117,18 +59833,15 @@ Wick.Tools.Zoom = class extends Wick.Tool {
this.zoomBox.strokeColor = 'black';
this.zoomBox.strokeWidth = 1.0 / this.paper.view.zoom;
}
-
deleteZoomBox() {
if (this.zoomBox) {
this.zoomBox.remove();
this.zoomBox = null;
}
}
-
zoomBoxIsValidSize() {
return this.zoomBox.bounds.width > this.MIN_ZOOMBOX_SIZE && this.zoomBox.bounds.height > this.MIN_ZOOMBOX_SIZE;
}
-
};
/*
* Copyright 2020 WICKLETS LLC
@@ -61156,6 +59869,7 @@ Wick.Tools.Zoom = class extends Wick.Tool {
by zrispo (github.com/zrispo) (zach@wickeditor.com)
*/
+
(function () {
// Splits a CompoundPath with multiple CW children into individual pieces
function splitCompoundPath(compoundPath) {
@@ -61173,8 +59887,9 @@ Wick.Tools.Zoom = class extends Wick.Tool {
part.insertAbove(compoundPath);
parts.push(part);
}
- }); // Find hole ownership for each 'part'
+ });
+ // Find hole ownership for each 'part'
var resolvedHoles = [];
parts.forEach(function (part) {
var cmp;
@@ -61189,19 +59904,18 @@ Wick.Tools.Zoom = class extends Wick.Tool {
insert: false
}));
}
-
cmp.addChild(hole);
resolvedHoles.push(hole);
}
-
if (cmp) {
cmp.fillColor = compoundPath.fillColor;
cmp.insertAbove(part);
part.remove();
}
});
- }); // If any holes could not find a path to be a part of, turn them into their own paths
+ });
+ // If any holes could not find a path to be a part of, turn them into their own paths
holes.filter(hole => {
return resolvedHoles.indexOf(hole) === -1;
}).forEach(hole => {
@@ -61210,7 +59924,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
});
compoundPath.remove();
}
-
function eraseFill(path, eraserPath) {
if (path.closePath) path.closePath();
var res = path.subtract(eraserPath, {
@@ -61218,7 +59931,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
trace: true
});
res.fillColor = path.fillColor;
-
if (res.children) {
res.insertAbove(path);
res.data = {};
@@ -61229,19 +59941,15 @@ Wick.Tools.Zoom = class extends Wick.Tool {
res.data = {};
res.insertAbove(path);
}
-
path.remove();
}
-
path.remove();
}
-
function eraseStroke(path, eraserPath) {
var res = path.subtract(eraserPath, {
insert: false,
trace: false
});
-
if (res.children) {
// Since the path is only strokes, it's trivial to split it into individual paths
var children = [];
@@ -61258,10 +59966,8 @@ Wick.Tools.Zoom = class extends Wick.Tool {
res.remove();
if (res.segments.length > 0) res.insertAbove(path);
}
-
path.remove();
}
-
function splitPath(path) {
var fill = path.clone({
insert: false
@@ -61282,7 +59988,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
stroke: stroke
};
}
-
function eraseWithPath(eraserPath) {
var erasables = this.children.filter(path => {
return path instanceof paper.Path || path instanceof paper.CompoundPath;
@@ -61302,7 +60007,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
}
});
}
-
paper.Layer.inject({
erase: eraseWithPath
});
@@ -61334,6 +60038,7 @@ Wick.Tools.Zoom = class extends Wick.Tool {
Adapted from the FillBucket tool from old Wick
by zrispo (github.com/zrispo) (zach@wickeditor.com)
*/
+
(function () {
var VERBOSE = false;
var PREVIEW_IMAGE = false;
@@ -61348,12 +60053,10 @@ Wick.Tools.Zoom = class extends Wick.Tool {
var floodFillY;
var bgColor;
var gapFillAmount;
-
function previewImage(image) {
var win = window.open('', 'Title', 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=' + image.width + ', height=' + image.height + ', top=100, left=100');
win.document.body.innerHTML = '
';
}
-
function rasterizePaths(callback) {
var layerGroup = new paper.Group({
insert: false
@@ -61361,29 +60064,26 @@ Wick.Tools.Zoom = class extends Wick.Tool {
layers.reverse().forEach(layer => {
layer.children.forEach(function (child) {
if (child._class !== 'Path' && child._class !== 'CompoundPath') return;
-
for (var i = 0; i < N_RASTER_CLONE; i++) {
var clone = child.clone({
insert: false
- }); //experiment: bump out all strokes a bit by expanding their stroke widths
+ });
+ //experiment: bump out all strokes a bit by expanding their stroke widths
if (!clone.strokeColor && clone.fillColor) {
clone.strokeColor = clone.fillColor;
clone.strokeWidth = gapFillAmount / RASTER_BASE_RESOLUTION;
} else if (clone.strokeWidth) {
clone.strokeWidth += gapFillAmount / RASTER_BASE_RESOLUTION;
}
-
layerGroup.addChild(clone);
}
});
});
-
if (layerGroup.children.length === 0) {
onError('NO_PATHS');
return;
}
-
var rasterResolution = paper.view.resolution * RASTER_BASE_RESOLUTION / window.devicePixelRatio;
var layerPathsRaster = layerGroup.rasterize(rasterResolution, {
insert: false
@@ -61392,7 +60092,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
var rasterCtx = rasterCanvas.getContext('2d');
var layerPathsImageData = rasterCtx.getImageData(0, 0, layerPathsRaster.width, layerPathsRaster.height);
var layerPathsImageDataRaw = layerPathsImageData.data;
-
for (var i = 0; i < layerPathsImageDataRaw.length; i += 4) {
if (layerPathsImageDataRaw[i + 3] === 0) {
layerPathsImageDataRaw[i] = bgColor.red;
@@ -61401,7 +60100,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
layerPathsImageDataRaw[i + 3] = 255;
}
}
-
rasterCtx.putImageData(layerPathsImageData, 0, 0);
layerPathsImageData = rasterCtx.getImageData(0, 0, layerPathsRaster.width, layerPathsRaster.height);
var rasterPosition = layerPathsRaster.bounds.topLeft;
@@ -61412,19 +60110,16 @@ Wick.Tools.Zoom = class extends Wick.Tool {
var floodFillCanvas = document.createElement('canvas');
floodFillCanvas.width = layerPathsRaster.canvas.width;
floodFillCanvas.height = layerPathsRaster.canvas.height;
-
if (x < 0 || y < 0 || x >= floodFillCanvas.width || y >= floodFillCanvas.height) {
onError('OUT_OF_BOUNDS');
return;
}
-
var floodFillCtx = floodFillCanvas.getContext('2d');
floodFillCtx.putImageData(layerPathsImageData, 0, 0);
floodFillCtx.fillStyle = "rgba(123,124,125,255)";
floodFillCtx.fillFlood(x, y, FILL_TOLERANCE);
var floodFillImageData = floodFillCtx.getImageData(0, 0, floodFillCanvas.width, floodFillCanvas.height);
var imageDataRaw = floodFillImageData.data;
-
for (var i = 0; i < imageDataRaw.length; i += 4) {
if (imageDataRaw[i] === 123 && imageDataRaw[i + 1] === 124 && imageDataRaw[i + 2] === 125) {
imageDataRaw[i] = 0;
@@ -61438,16 +60133,14 @@ Wick.Tools.Zoom = class extends Wick.Tool {
imageDataRaw[i + 3] = 0;
}
}
-
floodFillCtx.putImageData(floodFillImageData, 0, 0);
var floodFillProcessedImage = new Image();
-
floodFillProcessedImage.onload = function () {
if (PREVIEW_IMAGE) previewImage(floodFillProcessedImage);
var svgString = potrace.fromImage(floodFillProcessedImage).toSVG(1);
var xmlString = svgString,
- parser = new DOMParser(),
- doc = parser.parseFromString(xmlString, "text/xml");
+ parser = new DOMParser(),
+ doc = parser.parseFromString(xmlString, "text/xml");
var resultHolePath = paper.project.importSVG(doc, {
insert: true
});
@@ -61461,7 +60154,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
var holeIsLeaky = false;
var w = floodFillProcessedImage.width;
var h = floodFillProcessedImage.height;
-
for (var x = 0; x < floodFillProcessedImage.width; x++) {
if (getPixelAt(x, 0, w, h, floodFillImageData.data).r === 0 && getPixelAt(x, 0, w, h, floodFillImageData.data).a === 255) {
holeIsLeaky = true;
@@ -61469,27 +60161,21 @@ Wick.Tools.Zoom = class extends Wick.Tool {
return;
}
}
-
expandHole(resultHolePath);
callback(resultHolePath);
};
-
floodFillProcessedImage.src = floodFillCanvas.toDataURL();
}
-
function expandHole(path) {
if (path instanceof paper.Group) {
path = path.children[0];
}
-
var children;
-
if (path instanceof paper.Path) {
children = [path];
} else if (path instanceof paper.CompoundPath) {
children = path.children;
}
-
children.forEach(function (hole) {
var normals = [];
hole.closePath();
@@ -61518,7 +60204,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
y: d.y
});
});
-
for (var i = 0; i < hole.segments.length; i++) {
var segment = hole.segments[i];
var normal = normals[i];
@@ -61526,9 +60211,9 @@ Wick.Tools.Zoom = class extends Wick.Tool {
segment.point.y += normal.y * EXPAND_AMT;
}
});
- } // http://www.felixeve.co.uk/how-to-rotate-a-point-around-an-origin-with-javascript/
-
+ }
+ // http://www.felixeve.co.uk/how-to-rotate-a-point-around-an-origin-with-javascript/
function rotate_point(pointX, pointY, originX, originY, angle) {
angle = angle * Math.PI / 180.0;
return {
@@ -61536,7 +60221,6 @@ Wick.Tools.Zoom = class extends Wick.Tool {
y: Math.sin(angle) * (pointX - originX) + Math.cos(angle) * (pointY - originY) + originY
};
}
-
function getPixelAt(x, y, width, height, imageData) {
if (x < 0 || y < 0 || x >= width || y >= height) return null;
var offset = (y * width + x) * 4;
@@ -61547,9 +60231,8 @@ Wick.Tools.Zoom = class extends Wick.Tool {
a: imageData[offset + 3]
};
}
- /* Add hole() method to paper */
-
+ /* Add hole() method to paper */
paper.PaperScope.inject({
hole: function (args) {
if (!args) console.error('paper.hole: args is required');
@@ -61587,6 +60270,7 @@ Wick.Tools.Zoom = class extends Wick.Tool {
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
class PaperJSOrderingUtils {
/**
* Moves the selected items forwards.
@@ -61600,11 +60284,10 @@ class PaperJSOrderingUtils {
});
});
}
+
/**
* Moves the selected items backwards.
*/
-
-
static moveBackwards(items) {
PaperJSOrderingUtils._sortItemsByLayer(items).forEach(layerItems => {
PaperJSOrderingUtils._sortItemsByZIndex(layerItems).forEach(item => {
@@ -61614,11 +60297,10 @@ class PaperJSOrderingUtils {
});
});
}
+
/**
* Brings the selected objects to the front.
*/
-
-
static bringToFront(items) {
PaperJSOrderingUtils._sortItemsByLayer(items).forEach(layerItems => {
PaperJSOrderingUtils._sortItemsByZIndex(layerItems).forEach(item => {
@@ -61626,11 +60308,10 @@ class PaperJSOrderingUtils {
});
});
}
+
/**
* Sends the selected objects to the back.
*/
-
-
static sendToBack(items) {
PaperJSOrderingUtils._sortItemsByLayer(items).forEach(layerItems => {
PaperJSOrderingUtils._sortItemsByZIndex(layerItems).reverse().forEach(item => {
@@ -61638,38 +60319,32 @@ class PaperJSOrderingUtils {
});
});
}
-
static _sortItemsByLayer(items) {
var layerLists = {};
items.forEach(item => {
// Create new list for the item's layer if it doesn't exist
var layerID = item.layer.id;
-
if (!layerLists[layerID]) {
layerLists[layerID] = [];
- } // Add this item to its corresponding layer list
-
+ }
+ // Add this item to its corresponding layer list
layerLists[layerID].push(item);
- }); // Convert id->array object to array of arrays
+ });
+ // Convert id->array object to array of arrays
var layerItemsArrays = [];
-
for (var layerID in layerLists) {
layerItemsArrays.push(layerLists[layerID]);
}
-
return layerItemsArrays;
}
-
static _sortItemsByZIndex(items) {
return items.sort(function (a, b) {
return a.index - b.index;
});
}
-
}
-
;
paper.PaperScope.inject({
OrderingUtils: PaperJSOrderingUtils
@@ -61692,6 +60367,7 @@ paper.PaperScope.inject({
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see .
*/
+
class SelectionWidget {
/**
* Creates a SelectionWidget
@@ -61704,145 +60380,124 @@ class SelectionWidget {
insert: false
});
}
+
/**
* The item containing the widget GUI
*/
-
-
get item() {
return this._item;
}
+
/**
* The layer to add the widget GUI item to.
*/
-
-
get layer() {
return this._layer;
}
-
set layer(layer) {
this._layer = layer;
}
+
/**
* The rotation of the selection box GUI.
*/
-
-
get boxRotation() {
return this._boxRotation;
}
-
set boxRotation(boxRotation) {
this._boxRotation = boxRotation;
}
+
/**
* The items currently inside the selection widget
*/
-
-
get itemsInSelection() {
return this._itemsInSelection;
}
+
/**
* The point to rotate/scale the widget around.
*/
-
-
get pivot() {
return this._pivot;
}
-
set pivot(pivot) {
this._pivot = pivot;
}
+
/**
* The position of the top left corner of the selection box.
*/
-
-
get position() {
return this._boundingBox.topLeft.rotate(this.rotation, this.pivot);
}
-
set position(position) {
var d = position.subtract(this.position);
this.translateSelection(d);
}
+
/**
* The width of the selection.
*/
-
-
get width() {
return this._boundingBox.width;
}
-
set width(width) {
var d = width / this.width;
if (d === 0) d = 0.001;
this.scaleSelection(new paper.Point(d, 1.0));
}
+
/**
* The height of the selection.
*/
-
-
get height() {
return this._boundingBox.height;
}
-
set height(height) {
var d = height / this.height;
this.scaleSelection(new paper.Point(1.0, d));
}
+
/**
* The rotation of the selection.
*/
-
-
get rotation() {
return this._boxRotation;
}
-
set rotation(rotation) {
var d = rotation - this.rotation;
this.rotateSelection(d);
}
+
/**
* Flip the selected items horizontally.
*/
-
-
flipHorizontally() {
this.scaleSelection(new paper.Point(-1.0, 1.0));
}
+
/**
* Flip the selected items vertically.
*/
-
-
flipVertically() {
this.scaleSelection(new paper.Point(1.0, -1.0));
}
+
/**
* The bounding box of the widget.
*/
-
-
get boundingBox() {
return this._boundingBox;
}
+
/**
* The current transformation being done to the selection widget.
* @type {string}
*/
-
-
get currentTransformation() {
return this._currentTransformation;
}
-
set currentTransformation(currentTransformation) {
if (['translate', 'scale', 'rotate'].indexOf(currentTransformation) === -1) {
console.error('Paper.SelectionWidget: Invalid transformation type: ' + currentTransformation);
@@ -61851,14 +60506,13 @@ class SelectionWidget {
this._currentTransformation = currentTransformation;
}
}
+
/**
* Build a new SelectionWidget GUI around some items.
* @param {number} boxRotation - the rotation of the selection GUI. Optional, defaults to 0
* @param {paper.Item[]} items - the items to build the GUI around
* @param {paper.Point} pivot - the pivot point that the selection rotates around. Defaults to (0,0)
*/
-
-
build(args) {
if (!args) args = {};
if (!args.boxRotation) args.boxRotation = 0;
@@ -61870,33 +60524,25 @@ class SelectionWidget {
this._boundingBox = this._calculateBoundingBox();
this.item.remove();
this.item.removeChildren();
-
if (this._ghost) {
this._ghost.remove();
}
-
if (this._pivotPointHandle) {
this._pivotPointHandle.remove();
}
-
if (this._itemsInSelection.length > 0) {
this._center = this._calculateBoundingBoxOfItems(this._itemsInSelection).center;
-
this._buildGUI();
-
this.layer.addChild(this.item);
}
}
+
/**
*
*/
-
-
startTransformation(item) {
this._ghost = this._buildGhost();
-
this._layer.addChild(this._ghost);
-
if (item.data.handleType === 'rotation') {
this.currentTransformation = 'rotate';
} else if (item.data.handleType === 'scale') {
@@ -61904,15 +60550,13 @@ class SelectionWidget {
} else {
this.currentTransformation = 'translate';
}
-
this._ghost.data.initialPosition = this._ghost.position;
this._ghost.data.scale = new paper.Point(1, 1);
}
+
/**
*
*/
-
-
updateTransformation(item, e) {
if (this.currentTransformation === 'translate') {
this._ghost.position = this._ghost.position.add(e.delta);
@@ -61923,28 +60567,24 @@ class SelectionWidget {
currentPoint = currentPoint.rotate(-this.boxRotation, this.pivot);
var pivotToLastPointVector = lastPoint.subtract(this.pivot);
var pivotToCurrentPointVector = currentPoint.subtract(this.pivot);
- var scaleAmt = pivotToCurrentPointVector.divide(pivotToLastPointVector); // Lock scaling in a direction if the side handles are being dragged.
+ var scaleAmt = pivotToCurrentPointVector.divide(pivotToLastPointVector);
+ // Lock scaling in a direction if the side handles are being dragged.
if (item.data.handleEdge === 'topCenter' || item.data.handleEdge === 'bottomCenter') {
scaleAmt.x = 1.0;
}
-
if (item.data.handleEdge === 'leftCenter' || item.data.handleEdge === 'rightCenter') {
scaleAmt.y = 1.0;
- } // Holding shift locks aspect ratio
-
+ }
+ // Holding shift locks aspect ratio
if (e.modifiers.shift) {
scaleAmt.y = scaleAmt.x;
}
-
this._ghost.data.scale = this._ghost.data.scale.multiply(scaleAmt);
this._ghost.matrix = new paper.Matrix();
-
this._ghost.rotate(-this.boxRotation);
-
this._ghost.scale(this._ghost.data.scale.x, this._ghost.data.scale.y, this.pivot);
-
this._ghost.rotate(this.boxRotation);
} else if (this.currentTransformation === 'rotate') {
var lastPoint = e.point.subtract(e.delta);
@@ -61954,51 +60594,41 @@ class SelectionWidget {
var pivotToLastPointAngle = pivotToLastPointVector.angle;
var pivotToCurrentPointAngle = pivotToCurrentPointVector.angle;
var rotation = pivotToCurrentPointAngle - pivotToLastPointAngle;
-
this._ghost.rotate(rotation, this.pivot);
-
this.boxRotation += rotation;
}
}
+
/**
*
*/
-
-
finishTransformation(item) {
if (!this._currentTransformation) return;
-
this._ghost.remove();
-
if (this.currentTransformation === 'translate') {
var d = this._ghost.position.subtract(this._ghost.data.initialPosition);
-
this.translateSelection(d);
} else if (this.currentTransformation === 'scale') {
this.scaleSelection(this._ghost.data.scale);
} else if (this.currentTransformation === 'rotate') {
this.rotateSelection(this._ghost.rotation);
}
-
this._currentTransformation = null;
}
+
/**
*
*/
-
-
translateSelection(delta) {
this._itemsInSelection.forEach(item => {
item.position = item.position.add(delta);
});
-
this.pivot = this.pivot.add(delta);
}
+
/**
*
*/
-
-
scaleSelection(scale) {
this._itemsInSelection.forEach(item => {
item.rotate(-this.boxRotation, this.pivot);
@@ -62006,24 +60636,20 @@ class SelectionWidget {
item.rotate(this.boxRotation, this.pivot);
});
}
+
/**
*
*/
-
-
rotateSelection(angle) {
this._itemsInSelection.forEach(item => {
item.rotate(angle, this.pivot);
});
}
-
_buildGUI() {
this.item.addChild(this._buildBorder());
-
if (this._itemsInSelection.length > 1) {
this.item.addChildren(this._buildItemOutlines());
}
-
let guiElements = [];
guiElements.push(this._buildRotationHotspot('topLeft'));
guiElements.push(this._buildRotationHotspot('topRight'));
@@ -62045,7 +60671,6 @@ class SelectionWidget {
child.data.isSelectionBoxGUI = true;
});
}
-
_buildBorder() {
var border = new paper.Path.Rectangle({
name: 'border',
@@ -62058,7 +60683,6 @@ class SelectionWidget {
border.data.isBorder = true;
return border;
}
-
_buildItemOutlines() {
return this._itemsInSelection.map(item => {
var clone = item.clone({
@@ -62071,13 +60695,12 @@ class SelectionWidget {
to: bounds.bottomRight,
strokeWidth: SelectionWidget.BOX_STROKE_WIDTH,
strokeColor: SelectionWidget.BOX_STROKE_COLOR
- }); //border.rotate(-this.boxRotation, this._center);
-
+ });
+ //border.rotate(-this.boxRotation, this._center);
border.remove();
return border;
});
}
-
_buildScalingHandle(edge) {
var handle = this._buildHandle({
name: edge,
@@ -62086,10 +60709,8 @@ class SelectionWidget {
fillColor: SelectionWidget.HANDLE_FILL_COLOR,
strokeColor: SelectionWidget.HANDLE_STROKE_COLOR
});
-
return handle;
}
-
_buildPivotPointHandle() {
var handle = this._buildHandle({
name: 'pivot',
@@ -62098,11 +60719,9 @@ class SelectionWidget {
fillColor: SelectionWidget.PIVOT_FILL_COLOR,
strokeColor: SelectionWidget.PIVOT_STROKE_COLOR
});
-
handle.locked = true;
return handle;
}
-
_buildHandle(args) {
if (!args) console.error('_createHandle: args is required');
if (!args.name) console.error('_createHandle: args.name is required');
@@ -62124,9 +60743,9 @@ class SelectionWidget {
circle.data.handleEdge = args.name;
return circle;
}
-
_buildRotationHotspot(cornerName) {
// Build the not-yet-rotated hotspot, which starts out like this:
+
// |
// +---+
// | |
@@ -62134,30 +60753,31 @@ class SelectionWidget {
// | |
// +------+
// |
+
var r = SelectionWidget.ROTATION_HOTSPOT_RADIUS / paper.view.zoom;
var hotspot = new paper.Path([new paper.Point(0, 0), new paper.Point(0, r), new paper.Point(r, r), new paper.Point(r, -r), new paper.Point(-r, -r), new paper.Point(-r, 0)]);
hotspot.fillColor = SelectionWidget.ROTATION_HOTSPOT_FILLCOLOR;
hotspot.position.x = this.boundingBox[cornerName].x;
- hotspot.position.y = this.boundingBox[cornerName].y; // Orient the rotation handles in the correct direction, even if the selection is flipped
+ hotspot.position.y = this.boundingBox[cornerName].y;
+ // Orient the rotation handles in the correct direction, even if the selection is flipped
hotspot.rotate({
'topRight': 0,
'bottomRight': 90,
'bottomLeft': 180,
'topLeft': 270
- }[cornerName]); // Some metadata.
+ }[cornerName]);
+ // Some metadata.
hotspot.data.handleType = 'rotation';
hotspot.data.handleEdge = cornerName;
return hotspot;
}
-
_buildGhost() {
var ghost = new paper.Group({
insert: false,
applyMatrix: false
});
-
this._itemsInSelection.forEach(item => {
var outline = item.clone();
outline.remove();
@@ -62172,7 +60792,6 @@ class SelectionWidget {
outline2.strokeWidth = SelectionWidget.GHOST_STROKE_WIDTH;
ghost.addChild(outline2);
});
-
var boundsOutline = new paper.Path.Rectangle({
from: this.boundingBox.topLeft,
to: this.boundingBox.bottomRight,
@@ -62186,24 +60805,19 @@ class SelectionWidget {
ghost.opacity = 0.5;
return ghost;
}
-
_calculateBoundingBox() {
if (this._itemsInSelection.length === 0) {
return new paper.Rectangle();
}
-
var center = this._calculateBoundingBoxOfItems(this._itemsInSelection).center;
-
var itemsForBoundsCalc = this._itemsInSelection.map(item => {
var clone = item.clone();
clone.rotate(-this.boxRotation, center);
clone.remove();
return clone;
});
-
return this._calculateBoundingBoxOfItems(itemsForBoundsCalc);
}
-
_calculateBoundingBoxOfItems(items) {
var bounds = null;
items.forEach(item => {
@@ -62211,9 +60825,7 @@ class SelectionWidget {
});
return bounds || new paper.Rectangle();
}
-
}
-
;
SelectionWidget.BOX_STROKE_WIDTH = 1;
SelectionWidget.BOX_STROKE_COLOR = 'rgba(100,150,255,1.0)';
@@ -62250,6 +60862,7 @@ paper.PaperScope.inject({
* You should have received a copy of the GNU General Public License
* along with Paper.js-drawing-tools. If not, see .
*/
+
paper.SelectionBox = class {
/*
*
@@ -62265,79 +60878,64 @@ paper.SelectionBox = class {
});
this._mode = 'intersects';
}
+
/*
*
*/
-
-
start(point) {
this._active = true;
this._start = point;
this._end = point;
-
this._rebuildBox();
}
+
/*
*
*/
-
-
drag(point) {
this._end = point;
-
this._rebuildBox();
}
+
/*
*
*/
-
-
end(point) {
this._end = point;
this._active = false;
-
this._rebuildBox();
-
this._box.remove();
-
this._items = this._itemsInBox(this._box);
}
+
/*
*
*/
-
-
get items() {
return this._items;
}
+
/*
*
*/
-
-
get active() {
return this._active;
}
+
/*
*
*/
-
-
get mode() {
return this._mode;
}
-
set mode(mode) {
if (mode !== 'contains' && mode !== 'intersects') {
throw new Error("SelectionBox.mode: invalid mode");
}
-
this._mode = mode;
}
-
_rebuildBox() {
this._box.remove();
-
this._box = new this.paper.Path.Rectangle({
from: this._start,
to: this._end,
@@ -62345,16 +60943,13 @@ paper.SelectionBox = class {
strokeColor: 'black'
});
}
-
_itemsInBox(box) {
var checkItems = [];
-
this._getSelectableLayers().forEach(layer => {
layer.children.forEach(child => {
checkItems.push(child);
});
});
-
var items = [];
checkItems.forEach(item => {
if (this.mode === 'contains') {
@@ -62369,7 +60964,6 @@ paper.SelectionBox = class {
});
return items;
}
-
_shapesIntersect(itemA, itemB) {
if (itemA instanceof this.paper.Group) {
var intersects = false;
@@ -62384,20 +60978,17 @@ paper.SelectionBox = class {
} else {
var shapesDoIntersect = itemB.intersects(itemA);
var boundsContain = itemB.bounds.contains(itemA.bounds);
-
if (shapesDoIntersect || boundsContain) {
return true;
}
}
}
-
_getSelectableLayers() {
var self = this;
return this.paper.project.layers.filter(layer => {
return !layer.locked;
});
}
-
};
paper.PaperScope.inject({
SelectionBox: paper.SelectionBox
@@ -62428,6 +61019,7 @@ paper.PaperScope.inject({
by zrispo (github.com/zrispo) (zach@wickeditor.com)
*/
+
paper.Path.inject({
potrace: function (args) {
var self = this;
@@ -62438,14 +61030,12 @@ paper.Path.inject({
var raster = this.rasterize(finalRasterResolution);
raster.remove();
var rasterDataURL = raster.toDataURL();
-
if (rasterDataURL === 'data:,') {
args.done(null);
- } // https://oov.github.io/potrace/
-
+ }
+ // https://oov.github.io/potrace/
var img = new Image();
-
img.onload = function () {
var svg = potrace.fromImage(img).toSVG(1 / args.resolution);
var potracePath = paper.project.importSVG(svg);
@@ -62456,7 +61046,6 @@ paper.Path.inject({
potracePath.children[0].closed = true;
args.done(potracePath.children[0]);
};
-
img.src = rasterDataURL;
}
});
@@ -62478,6 +61067,7 @@ paper.Path.inject({
* You should have received a copy of the GNU General Public License
* along with Paper.js-drawing-tools. If not, see .
*/
+
(function () {
var editElem = $('