mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-16 09:43:11 +00:00
Implement zoom for brushes, various zoom fixes, remove canvasBorder.
This commit is contained in:
parent
328f14f388
commit
88b589b3d6
12 changed files with 5063 additions and 556 deletions
2540
dist/all.js
vendored
2540
dist/all.js
vendored
File diff suppressed because it is too large
Load diff
2842
dist/all.require.js
vendored
2842
dist/all.require.js
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -76,6 +76,7 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
|
|||
circles.push(circle);
|
||||
}
|
||||
var group = new fabric.Group(circles);
|
||||
group.canvas = this.canvas;
|
||||
|
||||
this.canvas.add(group);
|
||||
this.canvas.fire('path:created', { path: group });
|
||||
|
|
|
|||
|
|
@ -141,6 +141,10 @@
|
|||
* @private
|
||||
*/
|
||||
_getSVGPathData: function() {
|
||||
var ivt = fabric.util.invertTransform(this.canvas.viewportTransform);
|
||||
for (var i = 0, len = this._points.length; i < len; i++) {
|
||||
this._points[i] = fabric.util.transformPoint(this._points[i], ivt);
|
||||
}
|
||||
this.box = this.getPathBoundingBox(this._points);
|
||||
return this.convertPointsToSVGPath(
|
||||
this._points, this.box.minx, this.box.maxx, this.box.miny, this.box.maxy);
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
|
|||
}
|
||||
|
||||
var group = new fabric.Group(rects);
|
||||
group.canvas = this.canvas;
|
||||
|
||||
this.canvas.add(group);
|
||||
this.canvas.fire('path:created', { path: group });
|
||||
|
||||
|
|
@ -145,9 +147,13 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
|
|||
var ctx = this.canvas.contextTop;
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.save();
|
||||
var ivt = fabric.util.invertTransform(this.canvas.viewportTransform);
|
||||
|
||||
for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) {
|
||||
var point = this.sprayChunkPoints[i];
|
||||
var tpoint = fabric.util.transformPoint({x: point.x, y: point.y}, ivt);
|
||||
point.x = tpoint.x;
|
||||
point.y = tpoint.y;
|
||||
if (typeof point.opacity !== 'undefined') {
|
||||
ctx.globalAlpha = point.opacity;
|
||||
}
|
||||
|
|
@ -163,6 +169,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
|
|||
this.sprayChunkPoints = [ ];
|
||||
|
||||
var x, y, width, radius = this.width / 2;
|
||||
var vpt = this.canvas.viewportTransform;
|
||||
|
||||
for (var i = 0; i < this.density; i++) {
|
||||
|
||||
|
|
@ -178,8 +185,10 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
|
|||
else {
|
||||
width = this.dotWidth;
|
||||
}
|
||||
|
||||
var point = { x: x, y: y, width: width };
|
||||
|
||||
var point = new fabric.Point(x, y);
|
||||
point = fabric.util.transformPoint(point, vpt);
|
||||
point.width = width
|
||||
|
||||
if (this.randomOpacity) {
|
||||
point.opacity = fabric.util.getRandomInt(0, 100) / 100;
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@
|
|||
* @return {Boolean} true if point is contained within an area of given object
|
||||
*/
|
||||
containsPoint: function (e, target) {
|
||||
var pointer = this.getPointer(e),
|
||||
var pointer = this.getPointer(e, true),
|
||||
xy = this._normalizePointer(target, pointer);
|
||||
|
||||
// http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html
|
||||
|
|
@ -504,6 +504,7 @@
|
|||
var isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target);
|
||||
var group = new fabric.Group(
|
||||
isActiveLower ? [ target, this._activeObject ] : [ this._activeObject, target ]);
|
||||
group.canvas = this;
|
||||
|
||||
this.setActiveGroup(group);
|
||||
this._activeObject = null;
|
||||
|
|
@ -783,6 +784,7 @@
|
|||
}
|
||||
else if (group.length > 1) {
|
||||
group = new fabric.Group(group.reverse());
|
||||
group.canvas = this;
|
||||
this.setActiveGroup(group);
|
||||
group.saveCoords();
|
||||
this.fire('selection:created', { target: group });
|
||||
|
|
@ -799,7 +801,7 @@
|
|||
if (this.skipTargetFind) return;
|
||||
|
||||
var target,
|
||||
pointer = this.getPointer(e);
|
||||
pointer = this.getPointer(e, true);
|
||||
|
||||
if (this.controlsAboveOverlay &&
|
||||
this.lastRenderedObjectWithControlsAboveOverlay &&
|
||||
|
|
@ -839,7 +841,7 @@
|
|||
}
|
||||
}
|
||||
for (var j = 0, len = possibleTargets.length; j < len; j++) {
|
||||
pointer = this.getPointer(e);
|
||||
pointer = this.getPointer(e, true);
|
||||
var isTransparent = this.isTargetTransparent(possibleTargets[j], pointer.x, pointer.y);
|
||||
if (!isTransparent) {
|
||||
target = possibleTargets[j];
|
||||
|
|
@ -856,8 +858,17 @@
|
|||
* @param {Event} e
|
||||
* @return {Object} object with "x" and "y" number values
|
||||
*/
|
||||
getPointer: function (e) {
|
||||
var pointer = getPointer(e, this.upperCanvasEl);
|
||||
getPointer: function (e, ignoreZoom, upperCanvasEl) {
|
||||
if (!upperCanvasEl) {
|
||||
upperCanvasEl = this.upperCanvasEl;
|
||||
}
|
||||
var pointer = getPointer(e, upperCanvasEl);
|
||||
if (!ignoreZoom) {
|
||||
pointer = fabric.util.transformPoint(
|
||||
pointer,
|
||||
fabric.util.invertTransform(this.viewportTransform)
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
x: pointer.x - this._offset.left,
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@
|
|||
}
|
||||
}
|
||||
else {
|
||||
pointer = this.getPointer(e);
|
||||
pointer = this.getPointer(e, true);
|
||||
}
|
||||
|
||||
render = this._shouldRender(target, pointer);
|
||||
|
|
@ -235,7 +235,7 @@
|
|||
if (this.clipTo) {
|
||||
fabric.util.clipContext(this, this.contextTop);
|
||||
}
|
||||
this.freeDrawingBrush.onMouseDown(this.getPointer(e));
|
||||
this.freeDrawingBrush.onMouseDown(this.getPointer(e, true));
|
||||
this.fire('mouse:down', { e: e });
|
||||
},
|
||||
|
||||
|
|
@ -261,7 +261,7 @@
|
|||
if (this._currentTransform) return;
|
||||
|
||||
var target = this.findTarget(e),
|
||||
pointer = this.getPointer(e),
|
||||
pointer = this.getPointer(e, true),
|
||||
corner,
|
||||
render;
|
||||
|
||||
|
|
@ -362,8 +362,7 @@
|
|||
|
||||
if (this.isDrawingMode) {
|
||||
if (this._isCurrentlyDrawing) {
|
||||
pointer = this.getPointer(e);
|
||||
this.freeDrawingBrush.onMouseMove(pointer);
|
||||
this.freeDrawingBrush.onMouseMove(this.getPointer(e, true));
|
||||
}
|
||||
this.upperCanvasEl.style.cursor = this.freeDrawingCursor;
|
||||
this.fire('mouse:move', { e: e });
|
||||
|
|
@ -374,10 +373,10 @@
|
|||
|
||||
// We initially clicked in an empty area, so we draw a box for multiple selection.
|
||||
if (groupSelector) {
|
||||
pointer = getPointer(e, this.upperCanvasEl);
|
||||
pointer = this.getPointer(e, true);
|
||||
|
||||
groupSelector.left = pointer.x - this._offset.left - groupSelector.ex;
|
||||
groupSelector.top = pointer.y - this._offset.top - groupSelector.ey;
|
||||
groupSelector.left = pointer.x - groupSelector.ex;
|
||||
groupSelector.top = pointer.y - groupSelector.ey;
|
||||
this.renderTop();
|
||||
}
|
||||
else if (!this._currentTransform) {
|
||||
|
|
|
|||
|
|
@ -306,10 +306,21 @@
|
|||
|
||||
var strokeWidth = this.strokeWidth > 1 ? this.strokeWidth : 0,
|
||||
padding = this.padding,
|
||||
theta = degreesToRadians(this.angle);
|
||||
theta = degreesToRadians(this.angle),
|
||||
vpt;
|
||||
if (this.canvas) {
|
||||
vpt = this.canvas.viewportTransform;
|
||||
}
|
||||
if (!vpt) { // TODO
|
||||
vpt = [1, 0, 0, 1, 0, 0];
|
||||
};
|
||||
|
||||
this.currentWidth = (this.width + strokeWidth) * this.scaleX + padding * 2;
|
||||
this.currentHeight = (this.height + strokeWidth) * this.scaleY + padding * 2;
|
||||
var f = function (p) {
|
||||
return fabric.util.transformPoint(p, vpt);
|
||||
}
|
||||
|
||||
this.currentWidth = (this.width + strokeWidth) * this.scaleX;
|
||||
this.currentHeight = (this.height + strokeWidth) * this.scaleY;
|
||||
|
||||
// If width is negative, make postive. Fixes path selection issue
|
||||
if (this.currentWidth < 0) {
|
||||
|
|
@ -329,42 +340,32 @@
|
|||
cosTh = Math.cos(theta),
|
||||
coords = this.getCenterPoint(),
|
||||
wh = new fabric.Point(this.currentWidth, this.currentHeight);
|
||||
var tl = {
|
||||
x: coords.x - offsetX,
|
||||
y: coords.y - offsetY
|
||||
};
|
||||
var tr = {
|
||||
x: tl.x + (wh.x * cosTh),
|
||||
y: tl.y + (wh.x * sinTh)
|
||||
};
|
||||
var br = {
|
||||
x: tr.x - (wh.y * sinTh),
|
||||
y: tr.y + (wh.y * cosTh)
|
||||
};
|
||||
var bl = {
|
||||
x: tl.x - (wh.y * sinTh),
|
||||
y: tl.y + (wh.y * cosTh)
|
||||
};
|
||||
var ml = {
|
||||
x: tl.x - (wh.y/2 * sinTh),
|
||||
y: tl.y + (wh.y/2 * cosTh)
|
||||
};
|
||||
var mt = {
|
||||
x: tl.x + (wh.x/2 * cosTh),
|
||||
y: tl.y + (wh.x/2 * sinTh)
|
||||
};
|
||||
var mr = {
|
||||
x: tr.x - (wh.y/2 * sinTh),
|
||||
y: tr.y + (wh.y/2 * cosTh)
|
||||
};
|
||||
var mb = {
|
||||
x: bl.x + (wh.x/2 * cosTh),
|
||||
y: bl.y + (wh.x/2 * sinTh)
|
||||
};
|
||||
var mtr = {
|
||||
x: mt.x,
|
||||
y: mt.y
|
||||
};
|
||||
var _tl = new fabric.Point(coords.x - offsetX, coords.y - offsetY);
|
||||
var _tr = new fabric.Point(_tl.x + (wh.x * cosTh), _tl.y + (wh.x * sinTh));
|
||||
var _bl = new fabric.Point(_tl.x - (wh.y * sinTh), _tl.y + (wh.y * cosTh));
|
||||
var _mt = new fabric.Point(_tl.x + (wh.x/2 * cosTh), _tl.y + (wh.x/2 * sinTh));
|
||||
var tl = f(_tl);
|
||||
var tr = f(_tr);
|
||||
var br = f(new fabric.Point(_tr.x - (wh.y * sinTh), _tr.y + (wh.y * cosTh)));
|
||||
var bl = f(_bl);
|
||||
var ml = f(new fabric.Point(_tl.x - (wh.y/2 * sinTh), _tl.y + (wh.y/2 * cosTh)));
|
||||
var mt = f(_mt);
|
||||
var mr = f(new fabric.Point(_tr.x - (wh.y/2 * sinTh), _tr.y + (wh.y/2 * cosTh)));
|
||||
var mb = f(new fabric.Point(_bl.x + (wh.x/2 * cosTh), _bl.y + (wh.x/2 * sinTh)));
|
||||
var mtr = f(new fabric.Point(_mt.x, _mt.y));
|
||||
|
||||
// padding
|
||||
var padX = Math.cos(_angle + theta) * this.padding * Math.sqrt(2),
|
||||
padY = Math.sin(_angle + theta) * this.padding * Math.sqrt(2);
|
||||
tl = tl.add(new fabric.Point(-padX, -padY));
|
||||
tr = tr.add(new fabric.Point(padY, -padX));
|
||||
br = br.add(new fabric.Point(padX, padY));
|
||||
bl = bl.add(new fabric.Point(-padY, padX));
|
||||
ml = ml.add(new fabric.Point((-padX - padY) / 2, (-padY + padX) / 2));
|
||||
mt = mt.add(new fabric.Point((padY - padX) / 2, -(padY + padX) / 2));
|
||||
mr = mr.add(new fabric.Point((padY + padX) / 2, (padY - padX) / 2));
|
||||
mb = mb.add(new fabric.Point((padX - padY) / 2, (padX + padY) / 2));
|
||||
mtr = mtr.add(new fabric.Point((padY - padX) / 2, -(padY + padX) / 2));
|
||||
|
||||
// debugging
|
||||
|
||||
|
|
@ -389,22 +390,6 @@
|
|||
mtr: mtr
|
||||
};
|
||||
|
||||
var tform;
|
||||
if (typeof this.canvas == 'undefined') {
|
||||
if (this.type == 'group') {
|
||||
tform = this._objects[0].canvas.viewportTransform;
|
||||
}
|
||||
else {
|
||||
tform = [1, 0, 0, 1, 0, 0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
tform = this.canvas.viewportTransform;
|
||||
}
|
||||
for (c in this.oCoords) {
|
||||
this.oCoords[c] = fabric.util.transformPoint(this.oCoords[c], tform);
|
||||
}
|
||||
|
||||
// set coordinates of the draggable boxes in the corners used to scale/rotate the image
|
||||
this._setCornerCoords && this._setCornerCoords();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@
|
|||
_findTargetCorner: function(e, offset) {
|
||||
if (!this.hasControls || !this.active) return false;
|
||||
|
||||
var pointer = getPointer(e, this.canvas.upperCanvasEl),
|
||||
ex = pointer.x - offset.left,
|
||||
ey = pointer.y - offset.top,
|
||||
var pointer = this.canvas.getPointer(e, true),
|
||||
ex = pointer.x,
|
||||
ey = pointer.y,
|
||||
xPoints,
|
||||
lines;
|
||||
|
||||
|
|
@ -267,15 +267,16 @@
|
|||
|
||||
ctx.lineWidth = 1 / this.borderScaleFactor;
|
||||
|
||||
var wh = fabric.util.transformPoint(new fabric.Point(this.getWidth(), this.getHeight()), this.canvas.viewportTransform, true),
|
||||
sxy = fabric.util.transformPoint(new fabric.Point(scaleX, scaleY), this.canvas.viewportTransform, true),
|
||||
var vpt = this.canvas.viewportTransform,
|
||||
wh = fabric.util.transformPoint(new fabric.Point(this.getWidth(), this.getHeight()), vpt, true),
|
||||
sxy = fabric.util.transformPoint(new fabric.Point(scaleX, scaleY), vpt, true),
|
||||
w = wh.x,
|
||||
h = wh.y,
|
||||
sx= sxy.x,
|
||||
sy= sxy.y;
|
||||
if (this.get('group')) {
|
||||
w = w * this.get('group').scaleX;
|
||||
h = h * this.get('group').scaleY;
|
||||
if (this.group) {
|
||||
w = w * this.group.scaleX;
|
||||
h = h * this.group.scaleY;
|
||||
}
|
||||
|
||||
ctx.strokeRect(
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
this._objects = objects || [];
|
||||
for (var i = this._objects.length; i--; ) {
|
||||
this._objects[i].group = this;
|
||||
this._objects[i].setCoords();
|
||||
}
|
||||
|
||||
this.originalState = { };
|
||||
|
|
@ -216,13 +217,7 @@
|
|||
if (!this.visible) return;
|
||||
|
||||
ctx.save();
|
||||
var v;
|
||||
if (this.canvas) {
|
||||
v = this.canvas.viewportTransform;
|
||||
}
|
||||
else {
|
||||
v = [1, 0, 0, 1, 0, 0]; // TODO: this isn't a solution
|
||||
}
|
||||
var v = this.canvas.viewportTransform;
|
||||
|
||||
var sxy = fabric.util.transformPoint(
|
||||
new fabric.Point(this.scaleX, this.scaleY),
|
||||
|
|
@ -403,10 +398,9 @@
|
|||
_calcBounds: function() {
|
||||
var aX = [],
|
||||
aY = [],
|
||||
minX, minY, maxX, maxY, o, width, height, minXY, maxXY, ivt, // TODO: cleanup
|
||||
minX, minY, maxX, maxY, o, width, height, minXY, maxXY,
|
||||
i = 0,
|
||||
len = this._objects.length,
|
||||
canvas = this._objects[0].canvas;
|
||||
len = this._objects.length;
|
||||
|
||||
for (; i < len; ++i) {
|
||||
o = this._objects[i];
|
||||
|
|
@ -416,20 +410,18 @@
|
|||
aY.push(o.oCoords[prop].y);
|
||||
}
|
||||
}
|
||||
|
||||
var ivt = fabric.util.invertTransform(canvas.viewportTransform);
|
||||
|
||||
minXY = new fabric.Point(min(aX), min(aY));
|
||||
maxXY = new fabric.Point(max(aX), max(aY));
|
||||
// TODO: cleanup
|
||||
ivt = fabric.util.invertTransform(canvas.viewportTransform);
|
||||
this.width = (maxXY.x - minXY.x) || 0;
|
||||
this.height = (maxXY.y - minXY.y) || 0;
|
||||
|
||||
// TODO: cleanup
|
||||
minXY = fabric.util.transformPoint(minXY, ivt);
|
||||
maxXY = fabric.util.transformPoint(maxXY, ivt);
|
||||
|
||||
this.width = (maxXY.x - minXY.x) || 0;
|
||||
this.height = (maxXY.y - minXY.y) || 0;
|
||||
|
||||
|
||||
this.left = (minXY.x + maxXY.x) / 2 || 0;
|
||||
this.top = (minXY.y + maxXY.y) / 2 || 0;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -730,6 +730,9 @@
|
|||
* @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node
|
||||
*/
|
||||
transform: function(ctx, fromLeft) {
|
||||
if (this.group) {
|
||||
this.group.transform(ctx, fromLeft);
|
||||
}
|
||||
ctx.globalAlpha = this.opacity;
|
||||
|
||||
var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
|
||||
|
|
@ -1027,9 +1030,6 @@
|
|||
}
|
||||
|
||||
if (!noTransform) {
|
||||
if (this.group) {
|
||||
this.group.transform(ctx);
|
||||
}
|
||||
this.transform(ctx);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -146,13 +146,6 @@
|
|||
*/
|
||||
viewportTransform: [1, 0, 0, 1, 0, 0],
|
||||
|
||||
/**
|
||||
* Color of canvas border
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
canvasBorderColor: '',
|
||||
|
||||
/**
|
||||
* Callback; invoked right before object is about to be scaled/rotated
|
||||
* @param {fabric.Object} target Object that's about to be scaled/rotated
|
||||
|
|
@ -474,6 +467,10 @@
|
|||
// TODO: just change the scale, preserve other transformations
|
||||
this.viewportTransform[0] = value;
|
||||
this.viewportTransform[3] = value;
|
||||
this.renderAll();
|
||||
for (var i = 0, len = this._objects.length; i < len; i++) {
|
||||
this._objects[i].setCoords();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -491,6 +488,7 @@
|
|||
);
|
||||
this.viewportTransform[4] = x - wh.x/2;
|
||||
this.viewportTransform[5] = y - wh.y/2;
|
||||
this.renderAll();
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -554,8 +552,14 @@
|
|||
*/
|
||||
_onObjectAdded: function(obj) {
|
||||
this.stateful && obj.setupState();
|
||||
obj.setCoords();
|
||||
obj.canvas = this;
|
||||
obj.setCoords();
|
||||
if (obj._objects) {
|
||||
for (var i = 0, len = obj._objects.length; i < len; i++) {
|
||||
obj._objects[i].canvas = this;
|
||||
obj._objects[i].setCoords();
|
||||
}
|
||||
}
|
||||
this.fire('object:added', { target: obj });
|
||||
obj.fire('added');
|
||||
},
|
||||
|
|
@ -657,10 +661,6 @@
|
|||
if (typeof this.backgroundImage === 'object') {
|
||||
this._drawBackroundImage(canvasToDrawOn);
|
||||
}
|
||||
|
||||
if (this.canvasBorderColor) {
|
||||
this._drawCanvasBorder(canvasToDrawOn);
|
||||
}
|
||||
|
||||
var activeGroup = this.getActiveGroup();
|
||||
for (var i = 0, length = this._objects.length; i < length; ++i) {
|
||||
|
|
@ -717,23 +717,6 @@
|
|||
canvasToDrawOn.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} canvasToDrawOn Context to render on
|
||||
*/
|
||||
_drawCanvasBorder: function(canvasToDrawOn) {
|
||||
var xy = fabric.util.transformPoint(new fabric.Point(0, 0), this.viewportTransform),
|
||||
wh = fabric.util.transformPoint(
|
||||
new fabric.Point(this.getWidth(), this.getHeight()),
|
||||
this.viewportTransform, true
|
||||
);
|
||||
canvasToDrawOn.save();
|
||||
canvasToDrawOn.lineWidth = 1;
|
||||
canvasToDrawOn.strokeStyle = this.canvasBorderColor;
|
||||
canvasToDrawOn.strokeRect(xy.x - 1.5, xy.y - 1.5, wh.x + 2, wh.y + 2);
|
||||
canvasToDrawOn.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* Method to render only the top canvas.
|
||||
* Also used to render the group selection box.
|
||||
|
|
|
|||
Loading…
Reference in a new issue