paper.js/src/core/PaperScope.js

200 lines
5.5 KiB
JavaScript

/*
* Paper.js
*
* This file is part of Paper.js, a JavaScript Vector Graphics Library,
* based on Scriptographer.org and designed to be largely API compatible.
* http://paperjs.org/
* http://scriptographer.org/
*
* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
* http://lehni.org/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
/**
* @name PaperScope
*
* @class The {@code PaperScope} class represents the scope associated with a
* Paper context. When working with PaperScript, these scopes are automatically
* created for us, and through clever scoping the properties and methods of the
* active scope seem to become part of the global scope.
*
* When working with normal JavaScript code, {@code PaperScope} objects need to
* be manually created and handled.
*
* Paper classes can only be accessed through {@code PaperScope} objects. Thus
* in PaperScript they are global, while in JavaScript, they are available on
* the global {@link paper} object. For JavaScript you can use
* {@link PaperScope#install(scope) } to install the Paper classes and objects
* on the global scope. Note that when working with more than one scope, this
* still works for classes, but not for objects like {@link PaperScope#project},
* since they are not updated in the injected scope if scopes are switched.
*
* The global {@link paper} object is simply a reference to the currently active
* {@code PaperScope}.
*/
var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
/**
* Creates a PaperScope object. If a canvas is provided, it also creates a
* an empty {@link Project} and a {@link View} for it, both linked to this
* scope.
*
* @name PaperScope#initialize
* @function
* @param {HTMLCanvasElement} canvas The canvas this scope should be
* associated with.
*/
initialize: function(canvas, script) {
// script is only used internally, when creating scopes for PaperScript.
// 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;
this.tools = [];
var obj = script || canvas;
this._id = obj && obj.getAttribute('id')
|| script && script.src
|| ('paperscope-' + (PaperScope._id++));
// Make sure the script tag also has this id now. If it already had an
// id, we're not changing it, since it's the first option we're
// trying to get an id from above.
if (script)
script.setAttribute('id', this._id);
PaperScope._scopes[this._id] = this;
if (canvas) {
// Create an empty project for the scope.
// Since the global paper variable points to this PaperScope, the
// created project and view are automatically associated with it.
this.project = new Project();
// Create a view for the canvas.
this.view = new View(canvas);
}
},
/**
* The version of Paper.js, as a float number.
*
* @type Number
*/
version: /*#=*/ options.version,
/**
* The currently active project.
* @name PaperScope#project
* @type Project
*/
/**
* The list of all open projects within the current Paper.js context.
* @name PaperScope#projects
* @type Project[]
*/
/**
* The active view of the active project.
* @name PaperScope#view
* @type View
*/
/**
* The list of view of the active project.
* @name PaperScope#views
* @type View[]
*/
/**
* The reference to the active tool.
* @name PaperScope#tool
* @type Tool
*/
/**
* The list of available tools.
* @name PaperScope#tools
* @type Tool[]
*/
evaluate: function(code) {
var res = PaperScript.evaluate(code, this);
View.updateFocus();
return res;
},
/**
* Injects the paper scope into any other given scope. Can be used for
* examle to inject the currently active PaperScope into the window's global
* scope, to emulate PaperScript-style globally accessible Paper classes and
* objects:
*
* @example
* paper.install(window);
*/
install: function(scope) {
// Use scope as side-car (= 'this' inside iterator), and have it
// returned at the end.
return Base.each(this, function(value, key) {
this[key] = value;
}, scope);
},
clear: function() {
// Remove all projects, views and tools.
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();
},
remove: function() {
this.clear();
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,
/**
* Retrieves a PaperScope object with the given id or associated with
* the passed canvas element.
*
* @param id
*/
get: function(id) {
// If a script tag is passed, get the id from it.
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);
}
}
});