diff --git a/src/core/PaperScope.js b/src/core/PaperScope.js
index c3798cf2..21e17c18 100644
--- a/src/core/PaperScope.js
+++ b/src/core/PaperScope.js
@@ -49,8 +49,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
// Whenever a PaperScope is created, it automatically becomes the active
// one.
paper = this;
- this.view = null;
- this.views = [];
this.project = null;
this.projects = [];
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
* @type View
*/
-
- /**
- * The list of view of the active project.
- * @name PaperScope#views
- * @type View[]
- */
+ getView: function() {
+ return this.project.view;
+ },
/**
* 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
// are automatically associated with it.
paper = this;
- this.project = new Project();
- // Create a view for the canvas.
- if (canvas)
- this.view = new View(canvas);
+ this.project = new Project(canvas);
},
clear: function() {
// Remove all projects, views and tools.
+ // This also removes the installed event handlers.
for (var i = this.projects.length - 1; i >= 0; i--)
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--)
this.tools[i].remove();
},
@@ -181,15 +171,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
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 */{
_scopes: {},
_id: 0,
@@ -205,16 +186,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
if (typeof id === 'object')
id = id.getAttribute('id');
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);
}
}
});
diff --git a/src/docs/global.js b/src/docs/global.js
index 7fc0290d..01020eb4 100644
--- a/src/docs/global.js
+++ b/src/docs/global.js
@@ -34,17 +34,11 @@
*/
/**
- * The active view of the active project.
+ * The reference to the active project's view.
* @name view
* @type View
*/
-/**
- * The list of view of the active project.
- * @name views
- * @type View[]
- */
-
/**
* The reference to the active tool.
* @name tool
diff --git a/src/project/Project.js b/src/project/Project.js
index adb20ae9..38d37802 100644
--- a/src/project/Project.js
+++ b/src/project/Project.js
@@ -44,10 +44,13 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
*
* When working with PaperScript, a project is automatically created for us
* 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() {
- // Activate straight away so paper.project is set, as required by
- // Layer and DoumentView constructors.
+ initialize: function(view) {
+ // Activate straight away by passing true to base(), so paper.project is
+ // set, as required by Layer and DoumentView constructors.
this.base(true);
this._currentStyle = new PathStyle();
this._selectedItems = {};
@@ -55,14 +58,16 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
this.layers = [];
this.symbols = [];
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:
// this._changes = [];
// this._changesById = {};
},
_needsRedraw: function() {
- if (this._scope)
- this._scope._needsRedraw();
+ if (this.view)
+ 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.
- *
- * @name Project#remove
- * @function
+ * Removes this project from the {@link PaperScope#projects} list, and also
+ * removes its view, if one was defined.
+ */
+ 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
*/
/**
diff --git a/src/ui/View.js b/src/ui/View.js
index c16cc394..7dcf9927 100644
--- a/src/ui/View.js
+++ b/src/ui/View.js
@@ -23,9 +23,7 @@
* center, both useful for constructing artwork that should appear centered on
* screen.
*/
-var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
- _list: 'views',
- _reference: 'view',
+var View = this.View = Base.extend(Callback, /** @lends View# */{
_events: {
onFrame: {
install: function() {
@@ -79,15 +77,18 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
},
/**
- * Creates a view object
- * @param {HTMLCanvasElement|String} canvas The canvas object that this
- * view should wrap, or the String id that represents it
+ * Creates a view object for a given project.
+ *
+ * @param {HTMLCanvasElement} canvas The canvas object that this view should
+ * wrap
*/
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
var size;
-
/*#*/ if (options.server) {
if (canvas && canvas instanceof Canvas) {
this._canvas = canvas;
@@ -104,11 +105,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
this._id = this._canvas.id;
if (this._id == null)
this._canvas.id = this._id = 'canvas-' + View._id++;
-/*#*/ } // options.server
-
-/*#*/ if (options.browser) {
- if (typeof canvas === 'string')
- canvas = document.getElementById(canvas);
+/*#*/ } else if (options.browser) {
if (canvas instanceof HTMLCanvasElement) {
this._canvas = canvas;
// 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');
if (this._id == null)
this._canvas.setAttribute('id', this._id = 'canvas-' + View._id++);
+ // Install event handlers
+ this._handlers = this._createHandlers();
+ DomEvent.add(this._canvas, this._handlers);
/*#*/ } // options.browser
-
+ // Keep track of views internally
+ View._views.push(this);
// Link this id to our view
- View._views[this._id] = this;
+ View._viewsById[this._id] = this;
this._viewSize = LinkedSize.create(this, 'setViewSize',
size.width, size.height);
this._context = this._canvas.getContext('2d');
this._matrix = new Matrix();
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
if (!View._focused)
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
- * point to it.
- *
- * @name View#activate
- * @function
- */
-
- /**
- * Removes thsi view from the {@link PaperScope#views} list and frees the
- * associated canvas.
+ * Removes this view from and frees the associated canvas.
*/
remove: function() {
- if (!this.base())
+ if (!this._project)
return false;
// Clear focus if removed view had it
if (View._focused == this)
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.
- DomEvent.remove(this._canvas, this._domEvents);
- this._canvas = this._domEvents = null;
+ DomEvent.remove(this._canvas, this._handlers);
+ this._canvas = this._project = this._handlers = null;
// Removing all onFrame handlers makes the _onFrameCallback handler stop
// automatically through its uninstall method.
this.detach('frame');
@@ -324,7 +312,8 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
setZoom: function(zoom) {
// 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;
},
@@ -367,14 +356,9 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
ctx.save();
this._matrix.applyToContext(ctx);
- // Just draw the active project for now
- this._scope.project.draw(ctx);
+ this._project.draw(ctx);
ctx.restore();
- if (this._redrawNeeded) {
- this._redrawNeeded = false;
- // Update _redrawNotified in PaperScope as soon as a view was drawn
- this._scope._redrawNotified = false;
- }
+ this._redrawNeeded = false;
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 frame event:
*
- * {@code event.count}: the number of times the frame event was fired.
- * {@code event.time}: the total amount of time passed since the first frame
- * event in seconds.
- * {@code event.delta}: the time passed in seconds since the last frame
- * event.
+ * {@code event.count}: the number of times the frame event was
+ * fired.
+ * {@code event.time}: the total amount of time passed since the
+ * first frame event in seconds.
+ * {@code event.delta}: the time passed in seconds since the last
+ * frame event.
*
* @example {@paperscript}
* // Creating an animation:
@@ -450,8 +435,19 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
*/
}, {
statics: {
- _views: {},
- _id: 0
+ _views: [],
+ _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() {
// Injection scope for special code on browser (mouse events)
@@ -469,16 +465,14 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
function updateFocus() {
if (!View._focused || !View._focused.isVisible()) {
- // Find the first visible view in all scopes
- PaperScope.each(function(scope) {
- for (var i = 0, l = scope.views.length; i < l; i++) {
- var view = scope.views[i];
- if (view.isVisible()) {
- View._focused = tempFocus = view;
- throw Base.stop;
- }
+ // Find the first visible view
+ for (var i = 0, l = View._views.length; i < l; i++) {
+ var view = View._views[i];
+ if (view && view.isVisible()) {
+ View._focused = tempFocus = view;
+ throw Base.stop;
}
- });
+ }
}
}
@@ -487,7 +481,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
if (!dragging) {
// See if we can get the view from the current event target, and
// handle the mouse move over it.
- view = View._views[DomEvent.getTarget(event).getAttribute('id')];
+ view = View._viewsById[DomEvent.getTarget(event).getAttribute('id')];
if (view) {
// Temporarily focus this view without making it sticky, so
// 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 (timer != null)
timer = clearInterval(timer);
- if (tool.onHandleEvent('mouseup', viewToProject(view, event), event)) {
+ if (tool.onHandleEvent('mouseup', viewToProject(view, event),
+ event)) {
view.draw(true);
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
// 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
- // by _createEvents below.
+ // by _createHandlers below.
DomEvent.add(document, {
mousemove: mousemove,
@@ -559,7 +554,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
});
return {
- _createEvents: function() {
+ _createHandlers: function() {
var view = this;
function mousedown(event) {
@@ -583,7 +578,6 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
},
statics: {
-
/**
* Loops through all scopes and their views and sets the focus on
* the first active one.