From e42529308cfdfe1c43de961e5033bb60b263b863 Mon Sep 17 00:00:00 2001 From: Baxter Date: Wed, 19 Dec 2018 11:49:49 +0100 Subject: [PATCH 1/2] created image class created image class to be able to add images by using the image tag, it does not need an enviroment with header. --- src/image.js | 105 ++++++++++++++++++++++++++++++++++++++++++++ src/renderer/svg.js | 61 +++++++++++++++++++++++++ utils/build.js | 1 + 3 files changed, 167 insertions(+) create mode 100644 src/image.js diff --git a/src/image.js b/src/image.js new file mode 100644 index 000000000..7aab6201f --- /dev/null +++ b/src/image.js @@ -0,0 +1,105 @@ +(function(Two) { + +// output example: +// +// + + var _ = Two.Utils; + + /** + * @class + * @description Class that renders an image as an Image tag, it does not use the SVG header. + * @param {number} x x position at center + * @param {numbert} y y position at center + * @param {number} width Width of image + * @param {number} height Height of image + * @param {string} imageDataSource Image data encoded as a base 64 string + * @param {boolean} preserveAspectRatio Boolean to preserve the aspect ratio + */ + var Image = Two.Image = function(x, y, width, height, imageDataSource, preserveAspectRatio) { + Two.Shape.call(this); + + this._renderer.type = 'image'; + + this.width = width; + this.height = height; + this.href = imageDataSource; + this.opacity = 1.0; + this.className = ''; + this.visible = true; + + // this should better be in future an enum that can describe what all renders can do. + // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio + this.preserveAspectRatio = preserveAspectRatio; + + this._update(); + this.translation.set(x, y); + }; + + _.extend(Image, { + + Properties: [ + 'width', + 'height', + 'href', + 'preserveAspectRatio', + 'opacity', + 'className', + 'visible'], + + MakeObservable: function(obj) { + Two.Shape.MakeObservable(obj); + _.each(Image.Properties, Two.Utils.defineProperty, obj); + } + + }); + + _.extend(Image.prototype, Two.Shape.prototype, { + _width: 0, + _height: 0, + _href: '', + _preserveAspectRatio: false, + _opacity: 1.0, + _className: '', + _visible: true, + + _flagWidth: false, + _flagHeight: false, + _flagHref: false, + _flagPreserveAspectRatio: false, + _flagVisible: false, + _flagClassName: false, + _flagOpacity: false, + + constructor: Image, + + _update: function() { + + Two.Shape.prototype._update.call(this); + return this; + }, + + flagReset: function() { + + this._flagWidth + = this._flagHeight + = this._flagHref + = this._flagPreserveAspectRatio + = this._flagVisible + = this._flagClassName + = this._flagOpacity + = false; + + Two.Shape.prototype.flagReset.call(this); + return this; + } +}); + + Image.MakeObservable(Image.prototype); + +})((typeof global !== 'undefined' ? global : (this || window)).Two); diff --git a/src/renderer/svg.js b/src/renderer/svg.js index 4bea64994..c229c31ee 100644 --- a/src/renderer/svg.js +++ b/src/renderer/svg.js @@ -883,8 +883,69 @@ } + }, + + image: { + + render: function(domElement) { + + this._update(); + + var changed = {}; + + var flagMatrix = this._matrix.manual || this._flagMatrix; + + if (flagMatrix) { + changed.transform = 'matrix(' + this._matrix.toString() + ')'; + } + + if (this._flagWidth) { + changed['width'] = this._width; + } + + if (this._flagHeight) { + changed['height'] = this._height; + } + + if (this._flagHref) { + changed['href'] = this._href; + } + + if (this._flagPreserveAspectRatio) { + changed['preserveAspectRatio'] = this._preserveAspectRatio ? 'none' : 'meet'; + } + + if (this._flagOpacity) { + changed.opacity = this._opacity; + } + + if (this._flagClassName) { + changed['class'] = this._className; + } + + if (this._flagVisible) { + changed.visibility = this._visible ? 'visible' : 'hidden'; + } + + if (!this._renderer.elem) { + + changed.id = this.id; + + this._renderer.elem = svg.createElement('image', changed); + domElement.defs.appendChild(this._renderer.elem); + + } else { + + svg.setAttributes(this._renderer.elem, changed); + + } + return this.flagReset(); + + } + } + }; /** diff --git a/utils/build.js b/utils/build.js index aa2ebbc17..2c805e211 100644 --- a/utils/build.js +++ b/utils/build.js @@ -20,6 +20,7 @@ var files = [ path.resolve(__dirname, '../src/renderer/webgl.js'), path.resolve(__dirname, '../src/shape.js'), path.resolve(__dirname, '../src/path.js'), + path.resolve(__dirname, '../src/image.js'), path.resolve(__dirname, '../src/shapes/line.js'), path.resolve(__dirname, '../src/shapes/rectangle.js'), path.resolve(__dirname, '../src/shapes/ellipse.js'), From 99a0e50d6c9429a56470cc2af92c7e27a291fb52 Mon Sep 17 00:00:00 2001 From: Jono Date: Tue, 15 Jan 2019 08:47:59 +0100 Subject: [PATCH 2/2] Partial addition to CanvasRenderer --- src/effects/texture.js | 10 ++-- src/image.js | 114 ++++++++++++++++++++++------------------- src/renderer/canvas.js | 34 ++++++++++++ 3 files changed, 100 insertions(+), 58 deletions(-) diff --git a/src/effects/texture.js b/src/effects/texture.js index ec7c0d10f..165dc1a60 100644 --- a/src/effects/texture.js +++ b/src/effects/texture.js @@ -13,7 +13,7 @@ anchor = document.createElement('a'); } - var Texture = Two.Texture = function(src, callback) { + var Texture = Two.Texture = function(source, callback) { this._renderer = {}; this._renderer.type = 'texture'; @@ -35,10 +35,10 @@ this.bind(Two.Events.load, loaded); } - if (_.isString(src)) { - this.src = src; - } else if (_.isElement(src)) { - this.image = src; + if (_.isString(source)) { + this.src = source; + } else if (_.isElement(source)) { + this.image = source; } this._update(); diff --git a/src/image.js b/src/image.js index 7aab6201f..bdaa73763 100644 --- a/src/image.js +++ b/src/image.js @@ -2,32 +2,34 @@ // output example: // -// +// /> var _ = Two.Utils; /** * @class * @description Class that renders an image as an Image tag, it does not use the SVG header. - * @param {number} x x position at center - * @param {numbert} y y position at center - * @param {number} width Width of image - * @param {number} height Height of image - * @param {string} imageDataSource Image data encoded as a base 64 string - * @param {boolean} preserveAspectRatio Boolean to preserve the aspect ratio + * @param {number} [x=0] - x position at center + * @param {numbert} [y=0] - y position at center + * @param {number} [width] - width of image + * @param {number} [height] - height of image + * @param {string} [imageDataSource] - image data encoded as a base 64 string + * @param {boolean} [preserveAspectRatio] - boolean to preserve the aspect ratio */ var Image = Two.Image = function(x, y, width, height, imageDataSource, preserveAspectRatio) { + Two.Shape.call(this); this._renderer.type = 'image'; this.width = width; this.height = height; + this.href = imageDataSource; this.opacity = 1.0; this.className = ''; @@ -35,71 +37,77 @@ // this should better be in future an enum that can describe what all renders can do. // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio - this.preserveAspectRatio = preserveAspectRatio; + if (!_.isUndefined(preserveAspectRatio)) { + this.preserveAspectRatio = !!preserveAspectRatio; + } + + if (_.isNumber(x) && _.isNumber(y)) { + this.translation.set(x, y); + } this._update(); - this.translation.set(x, y); + }; _.extend(Image, { Properties: [ - 'width', - 'height', - 'href', - 'preserveAspectRatio', - 'opacity', - 'className', - 'visible'], + 'width', + 'height', + 'href', + 'preserveAspectRatio', + 'opacity', + 'className', + 'visible' + ], MakeObservable: function(obj) { - Two.Shape.MakeObservable(obj); + Two.Shape.MakeObservable(obj); _.each(Image.Properties, Two.Utils.defineProperty, obj); } }); - _.extend(Image.prototype, Two.Shape.prototype, { - _width: 0, - _height: 0, - _href: '', - _preserveAspectRatio: false, - _opacity: 1.0, - _className: '', - _visible: true, - - _flagWidth: false, - _flagHeight: false, - _flagHref: false, - _flagPreserveAspectRatio: false, - _flagVisible: false, - _flagClassName: false, - _flagOpacity: false, - - constructor: Image, + _.extend(Image.prototype, Two.Shape.prototype, { + + _flagWidth: false, + _flagHeight: false, + _flagHref: false, + _flagPreserveAspectRatio: false, + _flagVisible: false, + _flagClassName: false, + _flagOpacity: false, + + _width: 0, + _height: 0, + _href: '', + _preserveAspectRatio: false, + _opacity: 1.0, + _className: '', + _visible: true, + + constructor: Image, _update: function() { - Two.Shape.prototype._update.call(this); + Two.Shape.prototype._update.call(this); return this; + }, flagReset: function() { - this._flagWidth - = this._flagHeight - = this._flagHref - = this._flagPreserveAspectRatio - = this._flagVisible - = this._flagClassName - = this._flagOpacity - = false; - - Two.Shape.prototype.flagReset.call(this); - return this; + this._flagWidth = this._flagHeight = this._flagHref + = this._flagPreserveAspectRatio = this._flagVisible + = this._flagClassName = this._flagOpacity = false; + + Two.Shape.prototype.flagReset.call(this); + return this; + } -}); - Image.MakeObservable(Image.prototype); + }); + + Image.MakeObservable(Image.prototype); })((typeof global !== 'undefined' ? global : (this || window)).Two); diff --git a/src/renderer/canvas.js b/src/renderer/canvas.js index 86d246633..e137a356b 100644 --- a/src/renderer/canvas.js +++ b/src/renderer/canvas.js @@ -614,6 +614,40 @@ return this.flagReset(); + }, + + image: function(ctx, forced) { + + var matrix = this._matrix.elements; + var width = this._width; + var height = this._height; + var href = this._href; + var preserveAspectRatio = this._preserveAspectRatio; + var opacity = this._opacity; + var visible = this._visible; + var defaultMatrix = isDefaultMatrix(matrix); + + if (!forced && (!visible)) { + return this; + } + + if (!defaultMatrix) { + ctx.save(); + ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); + } + + // TODO: Handle `preserveAspectRatio` intelligently... + var image = Two.Texture.getImage(href); + + if (image) { + ctx.save(); + ctx.translate(x, y); + ctx.drawImage(image, - width / 2, - height / 2, width, height); + ctx.restore(); + } + + return this.flagReset(); + } },