mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-03-16 22:10:32 +00:00
Move Cufon methods to text.cufon. Move drawControls to Canvas (from StaticCanvas). Move dataURL-exporting methods to dataurl_exporter mixin.
This commit is contained in:
parent
e1f93a3668
commit
51b7c09314
10 changed files with 501 additions and 515 deletions
2
build.js
2
build.js
|
|
@ -147,6 +147,7 @@ var filesToInclude = [
|
|||
ifSpecifiedInclude('interaction', 'src/mixins/canvas_events.mixin.js'),
|
||||
|
||||
'src/mixins/canvas_animation.mixin.js',
|
||||
'src/mixins/canvas_dataurl_exporter.mixin.js',
|
||||
|
||||
ifSpecifiedInclude('serialization', 'src/mixins/canvas_serialization.mixin.js'),
|
||||
ifSpecifiedInclude('gestures', 'src/mixins/canvas_gestures.mixin.js'),
|
||||
|
|
@ -185,6 +186,7 @@ var filesToInclude = [
|
|||
ifSpecifiedInclude('image_filters', 'src/filters/tint_filter.class.js'),
|
||||
|
||||
ifSpecifiedInclude('text', 'src/shapes/text.class.js'),
|
||||
ifSpecifiedInclude('cufon', 'src/shapes/text.cufon.js'),
|
||||
|
||||
ifSpecifiedInclude('node', 'src/node.js')
|
||||
];
|
||||
|
|
|
|||
504
dist/all.js
vendored
504
dist/all.js
vendored
|
|
@ -5424,7 +5424,7 @@ fabric.util.string = {
|
|||
this.coords.x1, this.coords.y1, this.coords.r1, this.coords.x2, this.coords.y2, this.coords.r2);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.colorStops.length; i++) {
|
||||
for (var i = 0, len = this.colorStops.length; i < len; i++) {
|
||||
var color = this.colorStops[i].color,
|
||||
opacity = this.colorStops[i].opacity,
|
||||
offset = this.colorStops[i].offset;
|
||||
|
|
@ -6412,6 +6412,7 @@ fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {
|
|||
|
||||
extend(fabric.StaticCanvas.prototype, fabric.Observable);
|
||||
extend(fabric.StaticCanvas.prototype, fabric.Collection);
|
||||
extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);
|
||||
|
||||
extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
|
||||
|
||||
|
|
@ -6931,7 +6932,7 @@ fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {
|
|||
canvasToDrawOn.drawImage(this.overlayImage, this.overlayImageLeft, this.overlayImageTop);
|
||||
}
|
||||
|
||||
if (this.controlsAboveOverlay) {
|
||||
if (this.controlsAboveOverlay && this.interactive) {
|
||||
this.drawControls(canvasToDrawOn);
|
||||
}
|
||||
|
||||
|
|
@ -6987,167 +6988,6 @@ fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {
|
|||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Draws objects' controls (borders/controls)
|
||||
* @param {Object} ctx context to render controls on
|
||||
*/
|
||||
drawControls: function(ctx) {
|
||||
var activeGroup = this.getActiveGroup();
|
||||
if (activeGroup) {
|
||||
ctx.save();
|
||||
fabric.Group.prototype.transform.call(activeGroup, ctx);
|
||||
activeGroup.drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
}
|
||||
else {
|
||||
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
||||
if (!this._objects[i] || !this._objects[i].active) continue;
|
||||
|
||||
ctx.save();
|
||||
fabric.Object.prototype.transform.call(this._objects[i], ctx);
|
||||
this._objects[i].drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
|
||||
this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image.
|
||||
* @param {Object} options
|
||||
*
|
||||
* `format` the format of the output image. Either "jpeg" or "png".
|
||||
* `quality` quality level (0..1)
|
||||
* `multiplier` multiplier to scale by {Number}
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURL: function (options) {
|
||||
options || (options = { });
|
||||
|
||||
var format = options.format || 'png',
|
||||
quality = options.quality || 1,
|
||||
multiplier = options.multiplier || 1;
|
||||
|
||||
if (multiplier !== 1) {
|
||||
return this.__toDataURLWithMultiplier(format, quality, multiplier);
|
||||
}
|
||||
else {
|
||||
return this.__toDataURL(format, quality);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURL: function(format, quality) {
|
||||
this.renderAll(true);
|
||||
var canvasEl = this.upperCanvasEl || this.lowerCanvasEl;
|
||||
var data = (fabric.StaticCanvas.supports('toDataURLWithQuality'))
|
||||
? canvasEl.toDataURL('image/' + format, quality)
|
||||
: canvasEl.toDataURL('image/' + format);
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURLWithMultiplier: function(format, quality, multiplier) {
|
||||
|
||||
var origWidth = this.getWidth(),
|
||||
origHeight = this.getHeight(),
|
||||
scaledWidth = origWidth * multiplier,
|
||||
scaledHeight = origHeight * multiplier,
|
||||
activeObject = this.getActiveObject(),
|
||||
activeGroup = this.getActiveGroup(),
|
||||
|
||||
ctx = this.contextTop || this.contextContainer;
|
||||
|
||||
this.setWidth(scaledWidth).setHeight(scaledHeight);
|
||||
ctx.scale(multiplier, multiplier);
|
||||
|
||||
if (activeGroup) {
|
||||
// not removing group due to complications with restoring it with correct state afterwords
|
||||
this._tempRemoveBordersControlsFromGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.deactivateAll) {
|
||||
this.deactivateAll();
|
||||
}
|
||||
|
||||
// restoring width, height for `renderAll` to draw
|
||||
// background properly (while context is scaled)
|
||||
this.width = origWidth;
|
||||
this.height = origHeight;
|
||||
|
||||
this.renderAll(true);
|
||||
|
||||
var data = this.__toDataURL(format, quality);
|
||||
|
||||
ctx.scale(1 / multiplier, 1 / multiplier);
|
||||
this.setWidth(origWidth).setHeight(origHeight);
|
||||
|
||||
if (activeGroup) {
|
||||
this._restoreBordersControlsOnGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.setActiveObject) {
|
||||
this.setActiveObject(activeObject);
|
||||
}
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image (allowing to change image size via multiplier).
|
||||
* @deprecated since 1.0.13
|
||||
* @param {String} format (png|jpeg)
|
||||
* @param {Number} multiplier
|
||||
* @param {Number} quality (0..1)
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURLWithMultiplier: function (format, multiplier, quality) {
|
||||
return this.toDataURL({
|
||||
format: format,
|
||||
multiplier: multiplier,
|
||||
quality: quality
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_tempRemoveBordersControlsFromGroup: function(group) {
|
||||
group.origHasControls = group.hasControls;
|
||||
group.origBorderColor = group.borderColor;
|
||||
|
||||
group.hasControls = true;
|
||||
group.borderColor = 'rgba(0,0,0,0)';
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.origBorderColor = o.borderColor;
|
||||
o.borderColor = 'rgba(0,0,0,0)';
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_restoreBordersControlsOnGroup: function(group) {
|
||||
group.hideControls = group.origHideControls;
|
||||
group.borderColor = group.origBorderColor;
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.borderColor = o.origBorderColor;
|
||||
delete o.origBorderColor;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns coordinates of a center of canvas.
|
||||
* Returned value is an object with top and left properties
|
||||
|
|
@ -7488,21 +7328,6 @@ fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {
|
|||
removeListener(fabric.window, 'resize', this._onResize);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {HTMLImageElement} imgEl
|
||||
*/
|
||||
_resizeImageToFit: function (imgEl) {
|
||||
|
||||
var imageWidth = imgEl.width || imgEl.offsetWidth,
|
||||
widthScaleFactor = this.getWidth() / imageWidth;
|
||||
|
||||
// scale image down so that it has original dimensions when printed in large resolution
|
||||
if (imageWidth) {
|
||||
imgEl.width = imageWidth * widthScaleFactor;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -9228,6 +9053,32 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
|
|||
this.fire('selection:cleared');
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Draws objects' controls (borders/controls)
|
||||
* @param {Object} ctx context to render controls on
|
||||
*/
|
||||
drawControls: function(ctx) {
|
||||
var activeGroup = this.getActiveGroup();
|
||||
if (activeGroup) {
|
||||
ctx.save();
|
||||
fabric.Group.prototype.transform.call(activeGroup, ctx);
|
||||
activeGroup.drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
}
|
||||
else {
|
||||
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
||||
if (!this._objects[i] || !this._objects[i].active) continue;
|
||||
|
||||
ctx.save();
|
||||
fabric.Object.prototype.transform.call(this._objects[i], ctx);
|
||||
this._objects[i].drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
|
||||
this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -9806,6 +9657,145 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|||
});
|
||||
|
||||
|
||||
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image.
|
||||
* @param {Object} options
|
||||
*
|
||||
* `format` the format of the output image. Either "jpeg" or "png".
|
||||
* `quality` quality level (0..1)
|
||||
* `multiplier` multiplier to scale by {Number}
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURL: function (options) {
|
||||
options || (options = { });
|
||||
|
||||
var format = options.format || 'png',
|
||||
quality = options.quality || 1,
|
||||
multiplier = options.multiplier || 1;
|
||||
|
||||
if (multiplier !== 1) {
|
||||
return this.__toDataURLWithMultiplier(format, quality, multiplier);
|
||||
}
|
||||
else {
|
||||
return this.__toDataURL(format, quality);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURL: function(format, quality) {
|
||||
this.renderAll(true);
|
||||
var canvasEl = this.upperCanvasEl || this.lowerCanvasEl;
|
||||
var data = (fabric.StaticCanvas.supports('toDataURLWithQuality'))
|
||||
? canvasEl.toDataURL('image/' + format, quality)
|
||||
: canvasEl.toDataURL('image/' + format);
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURLWithMultiplier: function(format, quality, multiplier) {
|
||||
|
||||
var origWidth = this.getWidth(),
|
||||
origHeight = this.getHeight(),
|
||||
scaledWidth = origWidth * multiplier,
|
||||
scaledHeight = origHeight * multiplier,
|
||||
activeObject = this.getActiveObject(),
|
||||
activeGroup = this.getActiveGroup(),
|
||||
|
||||
ctx = this.contextTop || this.contextContainer;
|
||||
|
||||
this.setWidth(scaledWidth).setHeight(scaledHeight);
|
||||
ctx.scale(multiplier, multiplier);
|
||||
|
||||
if (activeGroup) {
|
||||
// not removing group due to complications with restoring it with correct state afterwords
|
||||
this._tempRemoveBordersControlsFromGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.deactivateAll) {
|
||||
this.deactivateAll();
|
||||
}
|
||||
|
||||
// restoring width, height for `renderAll` to draw
|
||||
// background properly (while context is scaled)
|
||||
this.width = origWidth;
|
||||
this.height = origHeight;
|
||||
|
||||
this.renderAll(true);
|
||||
|
||||
var data = this.__toDataURL(format, quality);
|
||||
|
||||
ctx.scale(1 / multiplier, 1 / multiplier);
|
||||
this.setWidth(origWidth).setHeight(origHeight);
|
||||
|
||||
if (activeGroup) {
|
||||
this._restoreBordersControlsOnGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.setActiveObject) {
|
||||
this.setActiveObject(activeObject);
|
||||
}
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image (allowing to change image size via multiplier).
|
||||
* @deprecated since 1.0.13
|
||||
* @param {String} format (png|jpeg)
|
||||
* @param {Number} multiplier
|
||||
* @param {Number} quality (0..1)
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURLWithMultiplier: function (format, multiplier, quality) {
|
||||
return this.toDataURL({
|
||||
format: format,
|
||||
multiplier: multiplier,
|
||||
quality: quality
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_tempRemoveBordersControlsFromGroup: function(group) {
|
||||
group.origHasControls = group.hasControls;
|
||||
group.origBorderColor = group.borderColor;
|
||||
|
||||
group.hasControls = true;
|
||||
group.borderColor = 'rgba(0,0,0,0)';
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.origBorderColor = o.borderColor;
|
||||
o.borderColor = 'rgba(0,0,0,0)';
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_restoreBordersControlsOnGroup: function(group) {
|
||||
group.hideControls = group.origHideControls;
|
||||
group.borderColor = group.origBorderColor;
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.borderColor = o.origBorderColor;
|
||||
delete o.origBorderColor;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
|
||||
|
||||
/**
|
||||
|
|
@ -16833,57 +16823,6 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderViaCufon: function(ctx) {
|
||||
var o = Cufon.textOptions || (Cufon.textOptions = { });
|
||||
|
||||
// export options to be used by cufon.js
|
||||
o.left = this.left;
|
||||
o.top = this.top;
|
||||
o.context = ctx;
|
||||
o.color = this.fill;
|
||||
|
||||
var el = this._initDummyElementForCufon();
|
||||
|
||||
// set "cursor" to top/left corner
|
||||
this.transform(ctx);
|
||||
|
||||
// draw text
|
||||
Cufon.replaceElement(el, {
|
||||
engine: 'canvas',
|
||||
separate: 'none',
|
||||
fontFamily: this.fontFamily,
|
||||
fontWeight: this.fontWeight,
|
||||
textDecoration: this.textDecoration,
|
||||
textShadow: this.textShadow,
|
||||
textAlign: this.textAlign,
|
||||
fontStyle: this.fontStyle,
|
||||
lineHeight: this.lineHeight,
|
||||
stroke: this.stroke,
|
||||
strokeWidth: this.strokeWidth,
|
||||
backgroundColor: this.backgroundColor,
|
||||
textBackgroundColor: this.textBackgroundColor
|
||||
});
|
||||
|
||||
// update width, height
|
||||
this.width = o.width;
|
||||
this.height = o.height;
|
||||
|
||||
this._totalLineHeight = o.totalLineHeight;
|
||||
this._fontAscent = o.fontAscent;
|
||||
this._boundaries = o.boundaries;
|
||||
this._shadowOffsets = o.shadowOffsets;
|
||||
this._shadows = o.shadows || [ ];
|
||||
|
||||
el = null;
|
||||
|
||||
// need to set coords _after_ the width/height was retreived from Cufon
|
||||
this.setCoords();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
|
|
@ -17289,32 +17228,6 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|||
].join(' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initDummyElementForCufon: function() {
|
||||
var el = fabric.document.createElement('pre'),
|
||||
container = fabric.document.createElement('div');
|
||||
|
||||
// Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
|
||||
container.appendChild(el);
|
||||
|
||||
if (typeof G_vmlCanvasManager === 'undefined') {
|
||||
el.innerHTML = this.text;
|
||||
}
|
||||
else {
|
||||
// IE 7 & 8 drop newlines and white space on text nodes
|
||||
// see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
|
||||
// see: http://www.w3schools.com/dom/dom_mozilla_vs_ie.asp
|
||||
el.innerText = this.text.replace(/\r?\n/gi, '\r');
|
||||
}
|
||||
|
||||
el.style.fontSize = this.fontSize + 'px';
|
||||
el.style.letterSpacing = 'normal';
|
||||
|
||||
return el;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders text instance on a specified context
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
|
|
@ -17627,6 +17540,87 @@ fabric.Image.filters.Tint.fromObject = function(object) {
|
|||
})(typeof exports !== 'undefined' ? exports : this);
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
fabric.util.object.extend(fabric.Text.prototype, {
|
||||
_renderViaCufon: function(ctx) {
|
||||
|
||||
var o = Cufon.textOptions || (Cufon.textOptions = { });
|
||||
|
||||
// export options to be used by cufon.js
|
||||
o.left = this.left;
|
||||
o.top = this.top;
|
||||
o.context = ctx;
|
||||
o.color = this.fill;
|
||||
|
||||
var el = this._initDummyElementForCufon();
|
||||
|
||||
// set "cursor" to top/left corner
|
||||
this.transform(ctx);
|
||||
|
||||
// draw text
|
||||
Cufon.replaceElement(el, {
|
||||
engine: 'canvas',
|
||||
separate: 'none',
|
||||
fontFamily: this.fontFamily,
|
||||
fontWeight: this.fontWeight,
|
||||
textDecoration: this.textDecoration,
|
||||
textShadow: this.textShadow,
|
||||
textAlign: this.textAlign,
|
||||
fontStyle: this.fontStyle,
|
||||
lineHeight: this.lineHeight,
|
||||
stroke: this.stroke,
|
||||
strokeWidth: this.strokeWidth,
|
||||
backgroundColor: this.backgroundColor,
|
||||
textBackgroundColor: this.textBackgroundColor
|
||||
});
|
||||
|
||||
// update width, height
|
||||
this.width = o.width;
|
||||
this.height = o.height;
|
||||
|
||||
this._totalLineHeight = o.totalLineHeight;
|
||||
this._fontAscent = o.fontAscent;
|
||||
this._boundaries = o.boundaries;
|
||||
this._shadowOffsets = o.shadowOffsets;
|
||||
this._shadows = o.shadows || [ ];
|
||||
|
||||
el = null;
|
||||
|
||||
// need to set coords _after_ the width/height was retreived from Cufon
|
||||
this.setCoords();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initDummyElementForCufon: function() {
|
||||
var el = fabric.document.createElement('pre'),
|
||||
container = fabric.document.createElement('div');
|
||||
|
||||
// Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
|
||||
container.appendChild(el);
|
||||
|
||||
if (typeof G_vmlCanvasManager === 'undefined') {
|
||||
el.innerHTML = this.text;
|
||||
}
|
||||
else {
|
||||
// IE 7 & 8 drop newlines and white space on text nodes
|
||||
// see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
|
||||
// see: http://www.w3schools.com/dom/dom_mozilla_vs_ie.asp
|
||||
el.innerText = this.text.replace(/\r?\n/gi, '\r');
|
||||
}
|
||||
|
||||
el.style.fontSize = this.fontSize + 'px';
|
||||
el.style.letterSpacing = 'normal';
|
||||
|
||||
return el;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
|
|
|
|||
10
dist/all.min.js
vendored
10
dist/all.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/all.min.js.gz
vendored
BIN
dist/all.min.js.gz
vendored
Binary file not shown.
|
|
@ -937,6 +937,32 @@
|
|||
this.fire('selection:cleared');
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Draws objects' controls (borders/controls)
|
||||
* @param {Object} ctx context to render controls on
|
||||
*/
|
||||
drawControls: function(ctx) {
|
||||
var activeGroup = this.getActiveGroup();
|
||||
if (activeGroup) {
|
||||
ctx.save();
|
||||
fabric.Group.prototype.transform.call(activeGroup, ctx);
|
||||
activeGroup.drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
}
|
||||
else {
|
||||
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
||||
if (!this._objects[i] || !this._objects[i].active) continue;
|
||||
|
||||
ctx.save();
|
||||
fabric.Object.prototype.transform.call(this._objects[i], ctx);
|
||||
this._objects[i].drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
|
||||
this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@
|
|||
this.coords.x1, this.coords.y1, this.coords.r1, this.coords.x2, this.coords.y2, this.coords.r2);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.colorStops.length; i++) {
|
||||
for (var i = 0, len = this.colorStops.length; i < len; i++) {
|
||||
var color = this.colorStops[i].color,
|
||||
opacity = this.colorStops[i].opacity,
|
||||
offset = this.colorStops[i].offset;
|
||||
|
|
|
|||
137
src/mixins/canvas_dataurl_exporter.mixin.js
Normal file
137
src/mixins/canvas_dataurl_exporter.mixin.js
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image.
|
||||
* @param {Object} options
|
||||
*
|
||||
* `format` the format of the output image. Either "jpeg" or "png".
|
||||
* `quality` quality level (0..1)
|
||||
* `multiplier` multiplier to scale by {Number}
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURL: function (options) {
|
||||
options || (options = { });
|
||||
|
||||
var format = options.format || 'png',
|
||||
quality = options.quality || 1,
|
||||
multiplier = options.multiplier || 1;
|
||||
|
||||
if (multiplier !== 1) {
|
||||
return this.__toDataURLWithMultiplier(format, quality, multiplier);
|
||||
}
|
||||
else {
|
||||
return this.__toDataURL(format, quality);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURL: function(format, quality) {
|
||||
this.renderAll(true);
|
||||
var canvasEl = this.upperCanvasEl || this.lowerCanvasEl;
|
||||
var data = (fabric.StaticCanvas.supports('toDataURLWithQuality'))
|
||||
? canvasEl.toDataURL('image/' + format, quality)
|
||||
: canvasEl.toDataURL('image/' + format);
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURLWithMultiplier: function(format, quality, multiplier) {
|
||||
|
||||
var origWidth = this.getWidth(),
|
||||
origHeight = this.getHeight(),
|
||||
scaledWidth = origWidth * multiplier,
|
||||
scaledHeight = origHeight * multiplier,
|
||||
activeObject = this.getActiveObject(),
|
||||
activeGroup = this.getActiveGroup(),
|
||||
|
||||
ctx = this.contextTop || this.contextContainer;
|
||||
|
||||
this.setWidth(scaledWidth).setHeight(scaledHeight);
|
||||
ctx.scale(multiplier, multiplier);
|
||||
|
||||
if (activeGroup) {
|
||||
// not removing group due to complications with restoring it with correct state afterwords
|
||||
this._tempRemoveBordersControlsFromGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.deactivateAll) {
|
||||
this.deactivateAll();
|
||||
}
|
||||
|
||||
// restoring width, height for `renderAll` to draw
|
||||
// background properly (while context is scaled)
|
||||
this.width = origWidth;
|
||||
this.height = origHeight;
|
||||
|
||||
this.renderAll(true);
|
||||
|
||||
var data = this.__toDataURL(format, quality);
|
||||
|
||||
ctx.scale(1 / multiplier, 1 / multiplier);
|
||||
this.setWidth(origWidth).setHeight(origHeight);
|
||||
|
||||
if (activeGroup) {
|
||||
this._restoreBordersControlsOnGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.setActiveObject) {
|
||||
this.setActiveObject(activeObject);
|
||||
}
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image (allowing to change image size via multiplier).
|
||||
* @deprecated since 1.0.13
|
||||
* @param {String} format (png|jpeg)
|
||||
* @param {Number} multiplier
|
||||
* @param {Number} quality (0..1)
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURLWithMultiplier: function (format, multiplier, quality) {
|
||||
return this.toDataURL({
|
||||
format: format,
|
||||
multiplier: multiplier,
|
||||
quality: quality
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_tempRemoveBordersControlsFromGroup: function(group) {
|
||||
group.origHasControls = group.hasControls;
|
||||
group.origBorderColor = group.borderColor;
|
||||
|
||||
group.hasControls = true;
|
||||
group.borderColor = 'rgba(0,0,0,0)';
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.origBorderColor = o.borderColor;
|
||||
o.borderColor = 'rgba(0,0,0,0)';
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_restoreBordersControlsOnGroup: function(group) {
|
||||
group.hideControls = group.origHideControls;
|
||||
group.borderColor = group.origBorderColor;
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.borderColor = o.origBorderColor;
|
||||
delete o.origBorderColor;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -211,57 +211,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderViaCufon: function(ctx) {
|
||||
var o = Cufon.textOptions || (Cufon.textOptions = { });
|
||||
|
||||
// export options to be used by cufon.js
|
||||
o.left = this.left;
|
||||
o.top = this.top;
|
||||
o.context = ctx;
|
||||
o.color = this.fill;
|
||||
|
||||
var el = this._initDummyElementForCufon();
|
||||
|
||||
// set "cursor" to top/left corner
|
||||
this.transform(ctx);
|
||||
|
||||
// draw text
|
||||
Cufon.replaceElement(el, {
|
||||
engine: 'canvas',
|
||||
separate: 'none',
|
||||
fontFamily: this.fontFamily,
|
||||
fontWeight: this.fontWeight,
|
||||
textDecoration: this.textDecoration,
|
||||
textShadow: this.textShadow,
|
||||
textAlign: this.textAlign,
|
||||
fontStyle: this.fontStyle,
|
||||
lineHeight: this.lineHeight,
|
||||
stroke: this.stroke,
|
||||
strokeWidth: this.strokeWidth,
|
||||
backgroundColor: this.backgroundColor,
|
||||
textBackgroundColor: this.textBackgroundColor
|
||||
});
|
||||
|
||||
// update width, height
|
||||
this.width = o.width;
|
||||
this.height = o.height;
|
||||
|
||||
this._totalLineHeight = o.totalLineHeight;
|
||||
this._fontAscent = o.fontAscent;
|
||||
this._boundaries = o.boundaries;
|
||||
this._shadowOffsets = o.shadowOffsets;
|
||||
this._shadows = o.shadows || [ ];
|
||||
|
||||
el = null;
|
||||
|
||||
// need to set coords _after_ the width/height was retreived from Cufon
|
||||
this.setCoords();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
|
|
@ -667,32 +616,6 @@
|
|||
].join(' ');
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initDummyElementForCufon: function() {
|
||||
var el = fabric.document.createElement('pre'),
|
||||
container = fabric.document.createElement('div');
|
||||
|
||||
// Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
|
||||
container.appendChild(el);
|
||||
|
||||
if (typeof G_vmlCanvasManager === 'undefined') {
|
||||
el.innerHTML = this.text;
|
||||
}
|
||||
else {
|
||||
// IE 7 & 8 drop newlines and white space on text nodes
|
||||
// see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
|
||||
// see: http://www.w3schools.com/dom/dom_mozilla_vs_ie.asp
|
||||
el.innerText = this.text.replace(/\r?\n/gi, '\r');
|
||||
}
|
||||
|
||||
el.style.fontSize = this.fontSize + 'px';
|
||||
el.style.letterSpacing = 'normal';
|
||||
|
||||
return el;
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders text instance on a specified context
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
|
|
|
|||
79
src/shapes/text.cufon.js
Normal file
79
src/shapes/text.cufon.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
fabric.util.object.extend(fabric.Text.prototype, {
|
||||
_renderViaCufon: function(ctx) {
|
||||
|
||||
var o = Cufon.textOptions || (Cufon.textOptions = { });
|
||||
|
||||
// export options to be used by cufon.js
|
||||
o.left = this.left;
|
||||
o.top = this.top;
|
||||
o.context = ctx;
|
||||
o.color = this.fill;
|
||||
|
||||
var el = this._initDummyElementForCufon();
|
||||
|
||||
// set "cursor" to top/left corner
|
||||
this.transform(ctx);
|
||||
|
||||
// draw text
|
||||
Cufon.replaceElement(el, {
|
||||
engine: 'canvas',
|
||||
separate: 'none',
|
||||
fontFamily: this.fontFamily,
|
||||
fontWeight: this.fontWeight,
|
||||
textDecoration: this.textDecoration,
|
||||
textShadow: this.textShadow,
|
||||
textAlign: this.textAlign,
|
||||
fontStyle: this.fontStyle,
|
||||
lineHeight: this.lineHeight,
|
||||
stroke: this.stroke,
|
||||
strokeWidth: this.strokeWidth,
|
||||
backgroundColor: this.backgroundColor,
|
||||
textBackgroundColor: this.textBackgroundColor
|
||||
});
|
||||
|
||||
// update width, height
|
||||
this.width = o.width;
|
||||
this.height = o.height;
|
||||
|
||||
this._totalLineHeight = o.totalLineHeight;
|
||||
this._fontAscent = o.fontAscent;
|
||||
this._boundaries = o.boundaries;
|
||||
this._shadowOffsets = o.shadowOffsets;
|
||||
this._shadows = o.shadows || [ ];
|
||||
|
||||
el = null;
|
||||
|
||||
// need to set coords _after_ the width/height was retreived from Cufon
|
||||
this.setCoords();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initDummyElementForCufon: function() {
|
||||
var el = fabric.document.createElement('pre'),
|
||||
container = fabric.document.createElement('div');
|
||||
|
||||
// Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
|
||||
container.appendChild(el);
|
||||
|
||||
if (typeof G_vmlCanvasManager === 'undefined') {
|
||||
el.innerHTML = this.text;
|
||||
}
|
||||
else {
|
||||
// IE 7 & 8 drop newlines and white space on text nodes
|
||||
// see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
|
||||
// see: http://www.w3schools.com/dom/dom_mozilla_vs_ie.asp
|
||||
el.innerText = this.text.replace(/\r?\n/gi, '\r');
|
||||
}
|
||||
|
||||
el.style.fontSize = this.fontSize + 'px';
|
||||
el.style.letterSpacing = 'normal';
|
||||
|
||||
return el;
|
||||
}
|
||||
});
|
||||
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
extend(fabric.StaticCanvas.prototype, fabric.Observable);
|
||||
extend(fabric.StaticCanvas.prototype, fabric.Collection);
|
||||
extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);
|
||||
|
||||
extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {
|
||||
|
||||
|
|
@ -554,7 +555,7 @@
|
|||
canvasToDrawOn.drawImage(this.overlayImage, this.overlayImageLeft, this.overlayImageTop);
|
||||
}
|
||||
|
||||
if (this.controlsAboveOverlay) {
|
||||
if (this.controlsAboveOverlay && this.interactive) {
|
||||
this.drawControls(canvasToDrawOn);
|
||||
}
|
||||
|
||||
|
|
@ -610,167 +611,6 @@
|
|||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Draws objects' controls (borders/controls)
|
||||
* @param {Object} ctx context to render controls on
|
||||
*/
|
||||
drawControls: function(ctx) {
|
||||
var activeGroup = this.getActiveGroup();
|
||||
if (activeGroup) {
|
||||
ctx.save();
|
||||
fabric.Group.prototype.transform.call(activeGroup, ctx);
|
||||
activeGroup.drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
}
|
||||
else {
|
||||
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
||||
if (!this._objects[i] || !this._objects[i].active) continue;
|
||||
|
||||
ctx.save();
|
||||
fabric.Object.prototype.transform.call(this._objects[i], ctx);
|
||||
this._objects[i].drawBorders(ctx).drawControls(ctx);
|
||||
ctx.restore();
|
||||
|
||||
this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image.
|
||||
* @param {Object} options
|
||||
*
|
||||
* `format` the format of the output image. Either "jpeg" or "png".
|
||||
* `quality` quality level (0..1)
|
||||
* `multiplier` multiplier to scale by {Number}
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURL: function (options) {
|
||||
options || (options = { });
|
||||
|
||||
var format = options.format || 'png',
|
||||
quality = options.quality || 1,
|
||||
multiplier = options.multiplier || 1;
|
||||
|
||||
if (multiplier !== 1) {
|
||||
return this.__toDataURLWithMultiplier(format, quality, multiplier);
|
||||
}
|
||||
else {
|
||||
return this.__toDataURL(format, quality);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURL: function(format, quality) {
|
||||
this.renderAll(true);
|
||||
var canvasEl = this.upperCanvasEl || this.lowerCanvasEl;
|
||||
var data = (fabric.StaticCanvas.supports('toDataURLWithQuality'))
|
||||
? canvasEl.toDataURL('image/' + format, quality)
|
||||
: canvasEl.toDataURL('image/' + format);
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
__toDataURLWithMultiplier: function(format, quality, multiplier) {
|
||||
|
||||
var origWidth = this.getWidth(),
|
||||
origHeight = this.getHeight(),
|
||||
scaledWidth = origWidth * multiplier,
|
||||
scaledHeight = origHeight * multiplier,
|
||||
activeObject = this.getActiveObject(),
|
||||
activeGroup = this.getActiveGroup(),
|
||||
|
||||
ctx = this.contextTop || this.contextContainer;
|
||||
|
||||
this.setWidth(scaledWidth).setHeight(scaledHeight);
|
||||
ctx.scale(multiplier, multiplier);
|
||||
|
||||
if (activeGroup) {
|
||||
// not removing group due to complications with restoring it with correct state afterwords
|
||||
this._tempRemoveBordersControlsFromGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.deactivateAll) {
|
||||
this.deactivateAll();
|
||||
}
|
||||
|
||||
// restoring width, height for `renderAll` to draw
|
||||
// background properly (while context is scaled)
|
||||
this.width = origWidth;
|
||||
this.height = origHeight;
|
||||
|
||||
this.renderAll(true);
|
||||
|
||||
var data = this.__toDataURL(format, quality);
|
||||
|
||||
ctx.scale(1 / multiplier, 1 / multiplier);
|
||||
this.setWidth(origWidth).setHeight(origHeight);
|
||||
|
||||
if (activeGroup) {
|
||||
this._restoreBordersControlsOnGroup(activeGroup);
|
||||
}
|
||||
else if (activeObject && this.setActiveObject) {
|
||||
this.setActiveObject(activeObject);
|
||||
}
|
||||
|
||||
this.contextTop && this.clearContext(this.contextTop);
|
||||
this.renderAll();
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* Exports canvas element to a dataurl image (allowing to change image size via multiplier).
|
||||
* @deprecated since 1.0.13
|
||||
* @param {String} format (png|jpeg)
|
||||
* @param {Number} multiplier
|
||||
* @param {Number} quality (0..1)
|
||||
* @return {String}
|
||||
*/
|
||||
toDataURLWithMultiplier: function (format, multiplier, quality) {
|
||||
return this.toDataURL({
|
||||
format: format,
|
||||
multiplier: multiplier,
|
||||
quality: quality
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_tempRemoveBordersControlsFromGroup: function(group) {
|
||||
group.origHasControls = group.hasControls;
|
||||
group.origBorderColor = group.borderColor;
|
||||
|
||||
group.hasControls = true;
|
||||
group.borderColor = 'rgba(0,0,0,0)';
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.origBorderColor = o.borderColor;
|
||||
o.borderColor = 'rgba(0,0,0,0)';
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_restoreBordersControlsOnGroup: function(group) {
|
||||
group.hideControls = group.origHideControls;
|
||||
group.borderColor = group.origBorderColor;
|
||||
|
||||
group.forEachObject(function(o) {
|
||||
o.borderColor = o.origBorderColor;
|
||||
delete o.origBorderColor;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns coordinates of a center of canvas.
|
||||
* Returned value is an object with top and left properties
|
||||
|
|
@ -1111,21 +951,6 @@
|
|||
removeListener(fabric.window, 'resize', this._onResize);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {HTMLImageElement} imgEl
|
||||
*/
|
||||
_resizeImageToFit: function (imgEl) {
|
||||
|
||||
var imageWidth = imgEl.width || imgEl.offsetWidth,
|
||||
widthScaleFactor = this.getWidth() / imageWidth;
|
||||
|
||||
// scale image down so that it has original dimensions when printed in large resolution
|
||||
if (imageWidth) {
|
||||
imgEl.width = imageWidth * widthScaleFactor;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue