mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-22 07:19:57 -05:00
Remove global views list, link View to Project and allow projects to only have one view.
This commit is contained in:
parent
ea689faa43
commit
719ae2315c
4 changed files with 93 additions and 118 deletions
|
@ -49,8 +49,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
// Whenever a PaperScope is created, it automatically becomes the active
|
// Whenever a PaperScope is created, it automatically becomes the active
|
||||||
// one.
|
// one.
|
||||||
paper = this;
|
paper = this;
|
||||||
this.view = null;
|
|
||||||
this.views = [];
|
|
||||||
this.project = null;
|
this.project = null;
|
||||||
this.projects = [];
|
this.projects = [];
|
||||||
this.tool = null;
|
this.tool = null;
|
||||||
|
@ -87,16 +85,13 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The active view of the active project.
|
* The reference to the active project's view.
|
||||||
* @name PaperScope#view
|
* @name PaperScope#view
|
||||||
* @type View
|
* @type View
|
||||||
*/
|
*/
|
||||||
|
getView: function() {
|
||||||
/**
|
return this.project.view;
|
||||||
* The list of view of the active project.
|
},
|
||||||
* @name PaperScope#views
|
|
||||||
* @type View[]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reference to the active tool.
|
* The reference to the active tool.
|
||||||
|
@ -159,19 +154,14 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
// Make sure this is the active scope, so the created project and view
|
// Make sure this is the active scope, so the created project and view
|
||||||
// are automatically associated with it.
|
// are automatically associated with it.
|
||||||
paper = this;
|
paper = this;
|
||||||
this.project = new Project();
|
this.project = new Project(canvas);
|
||||||
// Create a view for the canvas.
|
|
||||||
if (canvas)
|
|
||||||
this.view = new View(canvas);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: function() {
|
clear: function() {
|
||||||
// Remove all projects, views and tools.
|
// Remove all projects, views and tools.
|
||||||
|
// This also removes the installed event handlers.
|
||||||
for (var i = this.projects.length - 1; i >= 0; i--)
|
for (var i = this.projects.length - 1; i >= 0; i--)
|
||||||
this.projects[i].remove();
|
this.projects[i].remove();
|
||||||
// This also removes the installed event handlers.
|
|
||||||
for (var i = this.views.length - 1; i >= 0; i--)
|
|
||||||
this.views[i].remove();
|
|
||||||
for (var i = this.tools.length - 1; i >= 0; i--)
|
for (var i = this.tools.length - 1; i >= 0; i--)
|
||||||
this.tools[i].remove();
|
this.tools[i].remove();
|
||||||
},
|
},
|
||||||
|
@ -181,15 +171,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
delete PaperScope._scopes[this._id];
|
delete PaperScope._scopes[this._id];
|
||||||
},
|
},
|
||||||
|
|
||||||
_needsRedraw: function() {
|
|
||||||
// Make sure we're not looping through the view list each time...
|
|
||||||
if (!this._redrawNotified) {
|
|
||||||
for (var i = this.views.length - 1; i >= 0; i--)
|
|
||||||
this.views[i]._redrawNeeded = true;
|
|
||||||
this._redrawNotified = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
statics: /** @lends PaperScope */{
|
statics: /** @lends PaperScope */{
|
||||||
_scopes: {},
|
_scopes: {},
|
||||||
_id: 0,
|
_id: 0,
|
||||||
|
@ -205,16 +186,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
if (typeof id === 'object')
|
if (typeof id === 'object')
|
||||||
id = id.getAttribute('id');
|
id = id.getAttribute('id');
|
||||||
return this._scopes[id] || null;
|
return this._scopes[id] || null;
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates over all active scopes and calls the passed iterator
|
|
||||||
* function for each of them.
|
|
||||||
*
|
|
||||||
* @param iter the iterator function.
|
|
||||||
*/
|
|
||||||
each: function(iter) {
|
|
||||||
Base.each(this._scopes, iter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -34,17 +34,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The active view of the active project.
|
* The reference to the active project's view.
|
||||||
* @name view
|
* @name view
|
||||||
* @type View
|
* @type View
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of view of the active project.
|
|
||||||
* @name views
|
|
||||||
* @type View[]
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reference to the active tool.
|
* The reference to the active tool.
|
||||||
* @name tool
|
* @name tool
|
||||||
|
|
|
@ -44,10 +44,13 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
*
|
*
|
||||||
* When working with PaperScript, a project is automatically created for us
|
* When working with PaperScript, a project is automatically created for us
|
||||||
* and the {@link PaperScope#project} variable points to it.
|
* and the {@link PaperScope#project} variable points to it.
|
||||||
|
*
|
||||||
|
* @param {View|HTMLCanvasElement} view Either a view object or an HTML
|
||||||
|
* Canvas element that should be wrapped in a newly created view.
|
||||||
*/
|
*/
|
||||||
initialize: function() {
|
initialize: function(view) {
|
||||||
// Activate straight away so paper.project is set, as required by
|
// Activate straight away by passing true to base(), so paper.project is
|
||||||
// Layer and DoumentView constructors.
|
// set, as required by Layer and DoumentView constructors.
|
||||||
this.base(true);
|
this.base(true);
|
||||||
this._currentStyle = new PathStyle();
|
this._currentStyle = new PathStyle();
|
||||||
this._selectedItems = {};
|
this._selectedItems = {};
|
||||||
|
@ -55,14 +58,16 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
this.layers = [];
|
this.layers = [];
|
||||||
this.symbols = [];
|
this.symbols = [];
|
||||||
this.activeLayer = new Layer();
|
this.activeLayer = new Layer();
|
||||||
|
if (view)
|
||||||
|
this.view = view instanceof View ? view : View.create(view);
|
||||||
// Change tracking, not in use for now. Activate once required:
|
// Change tracking, not in use for now. Activate once required:
|
||||||
// this._changes = [];
|
// this._changes = [];
|
||||||
// this._changesById = {};
|
// this._changesById = {};
|
||||||
},
|
},
|
||||||
|
|
||||||
_needsRedraw: function() {
|
_needsRedraw: function() {
|
||||||
if (this._scope)
|
if (this.view)
|
||||||
this._scope._needsRedraw();
|
this.view._redrawNeeded = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,10 +79,21 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes this project from the {@link PaperScope#projects} list.
|
* Removes this project from the {@link PaperScope#projects} list, and also
|
||||||
*
|
* removes its view, if one was defined.
|
||||||
* @name Project#remove
|
*/
|
||||||
* @function
|
remove: function() {
|
||||||
|
if (!this.base())
|
||||||
|
return false;
|
||||||
|
if (this.view)
|
||||||
|
this.view.remove();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reference to the project's view.
|
||||||
|
* @name Project#view
|
||||||
|
* @type View
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
120
src/ui/View.js
120
src/ui/View.js
|
@ -23,9 +23,7 @@
|
||||||
* center, both useful for constructing artwork that should appear centered on
|
* center, both useful for constructing artwork that should appear centered on
|
||||||
* screen.
|
* screen.
|
||||||
*/
|
*/
|
||||||
var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
var View = this.View = Base.extend(Callback, /** @lends View# */{
|
||||||
_list: 'views',
|
|
||||||
_reference: 'view',
|
|
||||||
_events: {
|
_events: {
|
||||||
onFrame: {
|
onFrame: {
|
||||||
install: function() {
|
install: function() {
|
||||||
|
@ -79,15 +77,18 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a view object
|
* Creates a view object for a given project.
|
||||||
* @param {HTMLCanvasElement|String} canvas The canvas object that this
|
*
|
||||||
* view should wrap, or the String id that represents it
|
* @param {HTMLCanvasElement} canvas The canvas object that this view should
|
||||||
|
* wrap
|
||||||
*/
|
*/
|
||||||
initialize: function(canvas) {
|
initialize: function(canvas) {
|
||||||
this.base();
|
// Store reference to the currently active global paper scope, and the
|
||||||
|
// active project, which will be represented by this view
|
||||||
|
this._scope = paper;
|
||||||
|
this._project = paper.project;
|
||||||
// Handle canvas argument
|
// Handle canvas argument
|
||||||
var size;
|
var size;
|
||||||
|
|
||||||
/*#*/ if (options.server) {
|
/*#*/ if (options.server) {
|
||||||
if (canvas && canvas instanceof Canvas) {
|
if (canvas && canvas instanceof Canvas) {
|
||||||
this._canvas = canvas;
|
this._canvas = canvas;
|
||||||
|
@ -104,11 +105,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
this._id = this._canvas.id;
|
this._id = this._canvas.id;
|
||||||
if (this._id == null)
|
if (this._id == null)
|
||||||
this._canvas.id = this._id = 'canvas-' + View._id++;
|
this._canvas.id = this._id = 'canvas-' + View._id++;
|
||||||
/*#*/ } // options.server
|
/*#*/ } else if (options.browser) {
|
||||||
|
|
||||||
/*#*/ if (options.browser) {
|
|
||||||
if (typeof canvas === 'string')
|
|
||||||
canvas = document.getElementById(canvas);
|
|
||||||
if (canvas instanceof HTMLCanvasElement) {
|
if (canvas instanceof HTMLCanvasElement) {
|
||||||
this._canvas = canvas;
|
this._canvas = canvas;
|
||||||
// If the canvas has the resize attribute, resize the it to fill the
|
// If the canvas has the resize attribute, resize the it to fill the
|
||||||
|
@ -163,51 +160,42 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
this._id = this._canvas.getAttribute('id');
|
this._id = this._canvas.getAttribute('id');
|
||||||
if (this._id == null)
|
if (this._id == null)
|
||||||
this._canvas.setAttribute('id', this._id = 'canvas-' + View._id++);
|
this._canvas.setAttribute('id', this._id = 'canvas-' + View._id++);
|
||||||
|
// Install event handlers
|
||||||
|
this._handlers = this._createHandlers();
|
||||||
|
DomEvent.add(this._canvas, this._handlers);
|
||||||
/*#*/ } // options.browser
|
/*#*/ } // options.browser
|
||||||
|
// Keep track of views internally
|
||||||
|
View._views.push(this);
|
||||||
// Link this id to our view
|
// Link this id to our view
|
||||||
View._views[this._id] = this;
|
View._viewsById[this._id] = this;
|
||||||
this._viewSize = LinkedSize.create(this, 'setViewSize',
|
this._viewSize = LinkedSize.create(this, 'setViewSize',
|
||||||
size.width, size.height);
|
size.width, size.height);
|
||||||
this._context = this._canvas.getContext('2d');
|
this._context = this._canvas.getContext('2d');
|
||||||
this._matrix = new Matrix();
|
this._matrix = new Matrix();
|
||||||
this._zoom = 1;
|
this._zoom = 1;
|
||||||
|
|
||||||
/*#*/ if (options.browser) {
|
|
||||||
this._domEvents = this._createEvents();
|
|
||||||
DomEvent.add(this._canvas, this._domEvents);
|
|
||||||
// Make sure the first view is focused for keyboard input straight away
|
// Make sure the first view is focused for keyboard input straight away
|
||||||
if (!View._focused)
|
if (!View._focused)
|
||||||
View._focused = this;
|
View._focused = this;
|
||||||
/*#*/ } // options.browser
|
|
||||||
|
|
||||||
// As soon as a new view is added we need to mark the redraw as not
|
|
||||||
// motified, so the next call loops through all the views again.
|
|
||||||
this._scope._redrawNotified = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes this view the active one, meaning {@link PaperScope#view} will
|
* Removes this view from and frees the associated canvas.
|
||||||
* point to it.
|
|
||||||
*
|
|
||||||
* @name View#activate
|
|
||||||
* @function
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes thsi view from the {@link PaperScope#views} list and frees the
|
|
||||||
* associated canvas.
|
|
||||||
*/
|
*/
|
||||||
remove: function() {
|
remove: function() {
|
||||||
if (!this.base())
|
if (!this._project)
|
||||||
return false;
|
return false;
|
||||||
// Clear focus if removed view had it
|
// Clear focus if removed view had it
|
||||||
if (View._focused == this)
|
if (View._focused == this)
|
||||||
View._focused = null;
|
View._focused = null;
|
||||||
delete View._views[this._id];
|
// Remove view from internal structures
|
||||||
|
View._views.splice(View._views.indexOf(this), 1);
|
||||||
|
delete View._viewsById[this._id];
|
||||||
|
// Unlink from project
|
||||||
|
if (this._project.view == this)
|
||||||
|
this._project.view = null;
|
||||||
// Uninstall event handlers again for this view.
|
// Uninstall event handlers again for this view.
|
||||||
DomEvent.remove(this._canvas, this._domEvents);
|
DomEvent.remove(this._canvas, this._handlers);
|
||||||
this._canvas = this._domEvents = null;
|
this._canvas = this._project = this._handlers = null;
|
||||||
// Removing all onFrame handlers makes the _onFrameCallback handler stop
|
// Removing all onFrame handlers makes the _onFrameCallback handler stop
|
||||||
// automatically through its uninstall method.
|
// automatically through its uninstall method.
|
||||||
this.detach('frame');
|
this.detach('frame');
|
||||||
|
@ -324,7 +312,8 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
|
|
||||||
setZoom: function(zoom) {
|
setZoom: function(zoom) {
|
||||||
// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
|
// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
|
||||||
this._transform(new Matrix().scale(zoom / this._zoom, this.getCenter()));
|
this._transform(new Matrix().scale(zoom / this._zoom,
|
||||||
|
this.getCenter()));
|
||||||
this._zoom = zoom;
|
this._zoom = zoom;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -367,14 +356,9 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
this._matrix.applyToContext(ctx);
|
this._matrix.applyToContext(ctx);
|
||||||
// Just draw the active project for now
|
this._project.draw(ctx);
|
||||||
this._scope.project.draw(ctx);
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
if (this._redrawNeeded) {
|
|
||||||
this._redrawNeeded = false;
|
this._redrawNeeded = false;
|
||||||
// Update _redrawNotified in PaperScope as soon as a view was drawn
|
|
||||||
this._scope._redrawNotified = false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -405,11 +389,12 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
* The function receives an event object which contains information about
|
* The function receives an event object which contains information about
|
||||||
* the frame event:
|
* the frame event:
|
||||||
*
|
*
|
||||||
* <b>{@code event.count}</b>: the number of times the frame event was fired.
|
* <b>{@code event.count}</b>: the number of times the frame event was
|
||||||
* <b>{@code event.time}</b>: the total amount of time passed since the first frame
|
* fired.
|
||||||
* event in seconds.
|
* <b>{@code event.time}</b>: the total amount of time passed since the
|
||||||
* <b>{@code event.delta}</b>: the time passed in seconds since the last frame
|
* first frame event in seconds.
|
||||||
* event.
|
* <b>{@code event.delta}</b>: the time passed in seconds since the last
|
||||||
|
* frame event.
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Creating an animation:
|
* // Creating an animation:
|
||||||
|
@ -450,8 +435,19 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
*/
|
*/
|
||||||
}, {
|
}, {
|
||||||
statics: {
|
statics: {
|
||||||
_views: {},
|
_views: [],
|
||||||
_id: 0
|
_viewsById: {},
|
||||||
|
_id: 0,
|
||||||
|
|
||||||
|
create: function(element) {
|
||||||
|
/*#*/ if (options.browser) {
|
||||||
|
if (typeof element === 'string')
|
||||||
|
element = document.getElementById(element);
|
||||||
|
/*#*/ } // options.browser
|
||||||
|
// Factory to provide the right View subclass for a given element.
|
||||||
|
// Produces only Canvas-Views for now:
|
||||||
|
return new View(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, new function() {
|
}, new function() {
|
||||||
// Injection scope for special code on browser (mouse events)
|
// Injection scope for special code on browser (mouse events)
|
||||||
|
@ -469,16 +465,14 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
|
|
||||||
function updateFocus() {
|
function updateFocus() {
|
||||||
if (!View._focused || !View._focused.isVisible()) {
|
if (!View._focused || !View._focused.isVisible()) {
|
||||||
// Find the first visible view in all scopes
|
// Find the first visible view
|
||||||
PaperScope.each(function(scope) {
|
for (var i = 0, l = View._views.length; i < l; i++) {
|
||||||
for (var i = 0, l = scope.views.length; i < l; i++) {
|
var view = View._views[i];
|
||||||
var view = scope.views[i];
|
if (view && view.isVisible()) {
|
||||||
if (view.isVisible()) {
|
|
||||||
View._focused = tempFocus = view;
|
View._focused = tempFocus = view;
|
||||||
throw Base.stop;
|
throw Base.stop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,7 +481,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
if (!dragging) {
|
if (!dragging) {
|
||||||
// See if we can get the view from the current event target, and
|
// See if we can get the view from the current event target, and
|
||||||
// handle the mouse move over it.
|
// handle the mouse move over it.
|
||||||
view = View._views[DomEvent.getTarget(event).getAttribute('id')];
|
view = View._viewsById[DomEvent.getTarget(event).getAttribute('id')];
|
||||||
if (view) {
|
if (view) {
|
||||||
// Temporarily focus this view without making it sticky, so
|
// Temporarily focus this view without making it sticky, so
|
||||||
// Key events are handled too during the mouse over
|
// Key events are handled too during the mouse over
|
||||||
|
@ -526,7 +520,8 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
if (tool) {
|
if (tool) {
|
||||||
if (timer != null)
|
if (timer != null)
|
||||||
timer = clearInterval(timer);
|
timer = clearInterval(timer);
|
||||||
if (tool.onHandleEvent('mouseup', viewToProject(view, event), event)) {
|
if (tool.onHandleEvent('mouseup', viewToProject(view, event),
|
||||||
|
event)) {
|
||||||
view.draw(true);
|
view.draw(true);
|
||||||
DomEvent.stop(event);
|
DomEvent.stop(event);
|
||||||
}
|
}
|
||||||
|
@ -543,7 +538,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
// mousemove and mouseup events need to be installed on document, not the
|
// mousemove and mouseup events need to be installed on document, not the
|
||||||
// view canvas, since we want to catch the end of drag events even outside
|
// view canvas, since we want to catch the end of drag events even outside
|
||||||
// our view. Only the mousedown events are installed on the view, as handled
|
// our view. Only the mousedown events are installed on the view, as handled
|
||||||
// by _createEvents below.
|
// by _createHandlers below.
|
||||||
|
|
||||||
DomEvent.add(document, {
|
DomEvent.add(document, {
|
||||||
mousemove: mousemove,
|
mousemove: mousemove,
|
||||||
|
@ -559,7 +554,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_createEvents: function() {
|
_createHandlers: function() {
|
||||||
var view = this;
|
var view = this;
|
||||||
|
|
||||||
function mousedown(event) {
|
function mousedown(event) {
|
||||||
|
@ -583,7 +578,6 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
statics: {
|
statics: {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loops through all scopes and their views and sets the focus on
|
* Loops through all scopes and their views and sets the focus on
|
||||||
* the first active one.
|
* the first active one.
|
||||||
|
|
Loading…
Reference in a new issue