mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-05 20:32:00 -05:00
Step one of transition to proper separation of view and document, regarding canvas drawing, mouse interaction, resizing, frame handling, etc. Work in progress.
This commit is contained in:
parent
0dc2241a9c
commit
f0e8c54008
3 changed files with 140 additions and 121 deletions
|
@ -17,87 +17,46 @@
|
|||
var Document = this.Document = Base.extend({
|
||||
beans: true,
|
||||
|
||||
// XXX: Add arguments to define pages, but do not pass canvas here
|
||||
initialize: function(canvas) {
|
||||
// Store reference to the currently active global paper scope:
|
||||
this._scope = paper;
|
||||
if (canvas && canvas instanceof HTMLCanvasElement) {
|
||||
this.canvas = canvas;
|
||||
if (canvas.attributes.resize) {
|
||||
// If the canvas has a fullscreen attribute,
|
||||
// resize the canvas to fill the window and resize it again
|
||||
// whenever the user resizes the window.
|
||||
// TODO: set the following styles on the body tag:
|
||||
// body {
|
||||
// background: black;
|
||||
// margin: 0;
|
||||
// overflow: hidden;
|
||||
// }
|
||||
this._size = DomElement.getWindowSize()
|
||||
.subtract(DomElement.getOffset(this.canvas));
|
||||
this.canvas.width = this._size.width;
|
||||
this.canvas.height = this._size.height;
|
||||
var that = this;
|
||||
var offset = DomElement.getOffset(this.canvas);
|
||||
DomEvent.add(window, {
|
||||
resize: function(event) {
|
||||
// Only get canvas offset if it's not invisible (size is
|
||||
// 0, 0), as otherwise the offset would be wrong.
|
||||
if (!DomElement.getSize(that.canvas).equals([0, 0]))
|
||||
offset = DomElement.getOffset(that.canvas);
|
||||
that.setSize(DomElement.getWindowSize().subtract(offset));
|
||||
that.redraw();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._size = Size.create(canvas.offsetWidth,
|
||||
canvas.offsetHeight);
|
||||
}
|
||||
} else {
|
||||
this._size = Size.read(arguments) || new Size(1024, 768);
|
||||
this.canvas = CanvasProvider.getCanvas(this._size);
|
||||
}
|
||||
// TODO: Currently we don't do anything with Document#bounds.
|
||||
// What does it mean to change the bounds of the document? (JP)
|
||||
this.bounds = Rectangle.create(0, 0, this._size.width,
|
||||
this._size.height);
|
||||
this.context = this.canvas.getContext('2d');
|
||||
// Push it onto this._scope.documents and set index:
|
||||
this._index = this._scope.documents.push(this) - 1;
|
||||
// Activate straight away so paper.document is set, as required by
|
||||
// Layer and DoumentView constructors.
|
||||
this.activate();
|
||||
this.layers = [];
|
||||
this.activeLayer = new Layer();
|
||||
this.setCurrentStyle(null);
|
||||
this.views = [];
|
||||
this.symbols = [];
|
||||
this.activeView = new DocumentView(this);
|
||||
this.views = [this.activeView];
|
||||
this.activeLayer = new Layer();
|
||||
this.activeView = canvas ? new DocumentView(canvas) : null;
|
||||
// XXX: Introduce pages and remove Document#bounds!
|
||||
var size = this.activeView && this.activeView._size
|
||||
|| new Size(1024, 768);
|
||||
this._bounds = Rectangle.create(0, 0, size.width, size.height);
|
||||
this._selectedItems = {};
|
||||
this._selectedItemCount = 0;
|
||||
// TODO: Test this on IE:
|
||||
if (this.canvas.attributes.stats) {
|
||||
this.stats = new Stats();
|
||||
// Align top-left to the canvas
|
||||
var element = this.stats.domElement,
|
||||
style = element.style,
|
||||
offset = DomElement.getOffset(this.canvas);
|
||||
style.position = 'absolute';
|
||||
style.left = offset.x + 'px';
|
||||
style.top = offset.y + 'px';
|
||||
document.body.appendChild(element);
|
||||
}
|
||||
this.setCurrentStyle(null);
|
||||
},
|
||||
|
||||
|
||||
getBounds: function() {
|
||||
// TODO: Consider LinkedRectangle once it is required.
|
||||
return this._bounds;
|
||||
},
|
||||
|
||||
setBounds: function(rect) {
|
||||
rect = Rectangle.read(arguments);
|
||||
this._bounds.set(rect.x, rect.y, rect.width, rect.height);
|
||||
},
|
||||
|
||||
getSize: function() {
|
||||
return this._size;
|
||||
return this._bounds.getSize();
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
size = Size.read(arguments);
|
||||
if (this.canvas) {
|
||||
this.canvas.width = size.width;
|
||||
this.canvas.height = size.height;
|
||||
}
|
||||
this._size = size;
|
||||
this.bounds.setSize(size);
|
||||
// TODO: Once _bounds is a LinkedRectangle, this will recurse
|
||||
this._bounds.setSize.apply(this._bounds, arguments);
|
||||
},
|
||||
|
||||
getCurrentStyle: function() {
|
||||
|
@ -170,39 +129,29 @@ var Document = this.Document = Base.extend({
|
|||
this._selectedItems[i].setSelected(false);
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
if (this.canvas) {
|
||||
if (this.stats)
|
||||
this.stats.update();
|
||||
var ctx = this.context;
|
||||
|
||||
// Initial tests conclude that clearing the canvas using clearRect
|
||||
// is always faster than setting canvas.width = canvas.width
|
||||
// http://jsperf.com/clearrect-vs-setting-width/7
|
||||
ctx.clearRect(0, 0, this.size.width + 1, this.size.height + 1);
|
||||
draw: function(ctx) {
|
||||
ctx.save();
|
||||
var param = { offset: new Point(0, 0) };
|
||||
for (var i = 0, l = this.layers.length; i < l; i++)
|
||||
Item.draw(this.layers[i], ctx, param);
|
||||
ctx.restore();
|
||||
|
||||
// Draw the selection of the selected items in the document:
|
||||
if (this._selectedItemCount > 0) {
|
||||
ctx.save();
|
||||
var param = { offset: new Point(0, 0) };
|
||||
for (var i = 0, l = this.layers.length; i < l; i++)
|
||||
Item.draw(this.layers[i], ctx, param);
|
||||
ctx.strokeWidth = 1;
|
||||
// TODO: use Layer#color
|
||||
ctx.strokeStyle = ctx.fillStyle = '#009dec';
|
||||
param = { selection: true };
|
||||
Base.each(this._selectedItems, function(item) {
|
||||
item.draw(ctx, param);
|
||||
});
|
||||
ctx.restore();
|
||||
|
||||
// Draw the selection of the selected items in the document:
|
||||
if (this._selectedItemCount > 0) {
|
||||
ctx.save();
|
||||
ctx.strokeWidth = 1;
|
||||
// TODO: use Layer#color
|
||||
ctx.strokeStyle = ctx.fillStyle = '#009dec';
|
||||
param = { selection: true };
|
||||
Base.each(this._selectedItems, function(item) {
|
||||
item.draw(ctx, param);
|
||||
});
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
redraw: function() {
|
||||
this.draw();
|
||||
for (var i = 0, l = this.views.length; i < l; i++)
|
||||
this.views[i].draw();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -17,24 +17,86 @@
|
|||
var DocumentView = this.DocumentView = Base.extend({
|
||||
beans: true,
|
||||
|
||||
initialize: function(document) {
|
||||
this.document = document;
|
||||
this._bounds = this.document.bounds.clone();
|
||||
// TODO: Add bounds parameter that defines position within canvas?
|
||||
// Find a good name for these bounds, since #bounds is already the artboard
|
||||
// bounds of the visible area.
|
||||
initialize: function(canvas) {
|
||||
// To go with the convention of never passing document to constructors,
|
||||
// in all items, associate the view with the currently active document.
|
||||
this._document = paper.document;
|
||||
// Push it onto document.views and set index:
|
||||
this._index = this._document.views.push(this) - 1;
|
||||
// Handle canvas argument
|
||||
if (canvas && canvas instanceof HTMLCanvasElement) {
|
||||
this._canvas = canvas;
|
||||
var offset = DomElement.getOffset(canvas);
|
||||
// If the canvas has the resize attribute, resize the it to fill the
|
||||
// window and resize it again whenever the user resizes the window.
|
||||
if (canvas.attributes.resize) {
|
||||
this._size = DomElement.getWindowSize().subtract(offset);
|
||||
canvas.width = this._size.width;
|
||||
canvas.height = this._size.height;
|
||||
var that = this;
|
||||
DomEvent.add(window, {
|
||||
resize: function(event) {
|
||||
// Only get canvas offset if it's not invisible (size is
|
||||
// 0, 0), as otherwise the offset would be wrong.
|
||||
if (!DomElement.getSize(canvas).equals([0, 0]))
|
||||
offset = DomElement.getOffset(canvas);
|
||||
that.setSize(DomElement.getWindowSize().subtract(offset));
|
||||
that.draw();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._size = Size.create(
|
||||
canvas.offsetWidth, canvas.offsetHeight);
|
||||
}
|
||||
// TODO: Test this on IE:
|
||||
if (canvas.attributes.stats) {
|
||||
this._stats = new Stats();
|
||||
// Align top-left to the canvas
|
||||
var element = this._stats.domElement,
|
||||
style = element.style;
|
||||
style.position = 'absolute';
|
||||
style.left = offset.x + 'px';
|
||||
style.top = offset.y + 'px';
|
||||
document.body.appendChild(element);
|
||||
}
|
||||
} else {
|
||||
// 2nd argument onwards could be view size, otherwise use default:
|
||||
this._size = Size.read(arguments, 1);
|
||||
if (this._size.isZero())
|
||||
this._size = new Size(1024, 768);
|
||||
this._canvas = CanvasProvider.getCanvas(this._size);
|
||||
}
|
||||
this._context = this._canvas.getContext('2d');
|
||||
this._matrix = new Matrix();
|
||||
this._zoom = 1;
|
||||
this._center = this._bounds.center;
|
||||
},
|
||||
|
||||
// TODO: test this.
|
||||
getDocument: function() {
|
||||
return this._document;
|
||||
},
|
||||
|
||||
getSize: function() {
|
||||
return LinkedSize.create(this, 'setSize',
|
||||
this._size.width, this._size.height);
|
||||
},
|
||||
|
||||
setSize: function(size) {
|
||||
this._size = Size.read(arguments);
|
||||
this._canvas.width = this._size.width;
|
||||
this._canvas.height = this._size.height;
|
||||
},
|
||||
|
||||
getBounds: function() {
|
||||
return this._bounds;
|
||||
},
|
||||
|
||||
getCenter: function() {
|
||||
return this._center;
|
||||
},
|
||||
|
||||
setCenter: function(center) {
|
||||
center = Point.read(arguments);
|
||||
var delta = center.subtract(this._center);
|
||||
this.scrollBy(delta);
|
||||
this._center = center;
|
||||
},
|
||||
|
||||
getZoom: function() {
|
||||
|
@ -42,7 +104,7 @@ var DocumentView = this.DocumentView = Base.extend({
|
|||
},
|
||||
|
||||
setZoom: function(zoom) {
|
||||
// TODO: clamp the view between 1/32 and 64?
|
||||
// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
|
||||
var mx = new Matrix();
|
||||
mx.scale(zoom / this._zoom, this._center);
|
||||
this.transform(mx);
|
||||
|
@ -50,8 +112,29 @@ var DocumentView = this.DocumentView = Base.extend({
|
|||
},
|
||||
|
||||
scrollBy: function(point) {
|
||||
point = Point.read(arguments);
|
||||
this.transform(new Matrix().translate(point.negate()));
|
||||
this.transform(new Matrix().translate(Point.read(arguments).negate()));
|
||||
},
|
||||
|
||||
draw: function() {
|
||||
if (this._stats)
|
||||
this._stats.update();
|
||||
|
||||
// Initial tests conclude that clearing the canvas using clearRect
|
||||
// is always faster than setting canvas.width = canvas.width
|
||||
// http://jsperf.com/clearrect-vs-setting-width/7
|
||||
this._context.clearRect(0, 0, this._size.width + 1, this._size.height + 1);
|
||||
|
||||
this._document.draw(this._context);
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this._document.activeView = this;
|
||||
},
|
||||
|
||||
remove: function() {
|
||||
var res = Base.splice(this._document.views, null, this._index, 1);
|
||||
this._document = null;
|
||||
return !!res.length;
|
||||
},
|
||||
|
||||
transform: function(matrix, flags) {
|
||||
|
@ -61,24 +144,11 @@ var DocumentView = this.DocumentView = Base.extend({
|
|||
},
|
||||
|
||||
_getInverse: function() {
|
||||
if (!this._inverse) {
|
||||
if (!this._inverse)
|
||||
this._inverse = this._matrix.createInverse();
|
||||
}
|
||||
return this._inverse;
|
||||
},
|
||||
|
||||
getBounds: function() {
|
||||
if (!this._bounds) {
|
||||
this._bounds = this._matrix.transformBounds(this.document.bounds);
|
||||
}
|
||||
return this._bounds;
|
||||
},
|
||||
|
||||
// TODO:
|
||||
// setBounds: function(rect) {
|
||||
//
|
||||
// },
|
||||
|
||||
// TODO: getInvalidBounds
|
||||
// TODO: invalidate(rect)
|
||||
// TODO: style: artwork / preview / raster / opaque / ink
|
||||
|
|
|
@ -98,7 +98,7 @@ var Tool = this.Tool = ToolHandler.extend(new function() {
|
|||
}
|
||||
};
|
||||
|
||||
DomEvent.add(doc.canvas, events);
|
||||
DomEvent.add(doc.activeView._canvas, events);
|
||||
},
|
||||
|
||||
getDocument: function() {
|
||||
|
|
Loading…
Reference in a new issue