Remove global views list, link View to Project and allow projects to only have one view.

This commit is contained in:
Jürg Lehni 2011-11-12 16:56:23 +01:00
parent ea689faa43
commit 719ae2315c
4 changed files with 93 additions and 118 deletions

View file

@ -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);
} }
} }
}); });

View file

@ -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

View file

@ -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
*/ */
/** /**

View file

@ -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.