From 719ae2315c1921d1a1c33ba16fa8222e89d96d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Sat, 12 Nov 2011 16:56:23 +0100 Subject: [PATCH] Remove global views list, link View to Project and allow projects to only have one view. --- src/core/PaperScope.js | 41 ++----------- src/docs/global.js | 8 +-- src/project/Project.js | 34 ++++++++--- src/ui/View.js | 128 ++++++++++++++++++++--------------------- 4 files changed, 93 insertions(+), 118 deletions(-) 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.