I'm trying to display an Image on the FabricJS Canvas inside my Polymer Element. By doing this, this error appears:
Uncaught TypeError: Cannot read property '_set' of undefined
at klass._onObjectAdded (fabric.js:6964)
at klass.add (fabric.js:260)
at HTMLElement.ready (convert-section.html:97)
at HTMLElement._enableProperties (property-accessors.html:531)
at HTMLElement.connectedCallback (element-mixin.html:630)
at HTMLElement._attachDom (element-mixin.html:690)
at HTMLElement._readyClients (element-mixin.html:663)
at HTMLElement._flushClients (property-effects.html:1518)
at HTMLElement._propertiesChanged (property-effects.html:1644)
at HTMLElement._flushProperties (property-accessors.html:549)
Is it possible to display an Image on a FabricJs canvas inside my Polymer Element? Or did I made an misstake? I'm new to Polymer and I don't have much experience.
I can display shapes like triangles etc.
Here is my Element:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="my-paper-element-styles.html">
<dom-module id="convert-section">
<template>
<style include="my-paper-element-styles">
</style>
<canvas id="convertCanvas" ></canvas>
</template>
<script>
class ConvertSection extends Polymer.Element {
static get is() {
return 'convert-section';
}
static get properties() {
return {
imageLocationPath: {
type: String,
notify: true
}
};
}
disconnectedCallback() {
super.disconnectedCallback();
this.imageLocationPath = "";
}
ready() {
super.ready();
this.canvas = this.__canvas = new fabric.Canvas(this.$.convertCanvas);
var height = window.innerHeight - 48;
var width = window.innerWidth - 300;
this.canvas.setHeight(height);
this.canvas.setWidth(width);
var image = fabric.Image.fromURL('img/viper-board.png');
this.canvas.add(image);
}
}
window.customElements.define(ConvertSection.is, ConvertSection);
</script>
<script src="../../node_modules/fabric/dist/fabric.js"></script>
</dom-module>
ready() {
super.ready();
var self = this;
self.canvas = self.__canvas = new fabric.Canvas(self.$.convertCanvas);
var height = window.innerHeight - 48;
var width = window.innerWidth - 300;
self.canvas.setHeight(height);
self.canvas.setWidth(width);
fabric.Image.fromURL('img/viper-board.png',function(oImg){
oImg.set({
left:10,
top:10
});
self.canvas.add(oImg);
});
}
As you can see fromURL doesn't return anything. You need to pass source url and a callback function and add that image inside callback function.
Related
I want to add my canvas inside a specific div and I want it to be as big as the canvas size.
For example on this code I would like the canvas to be inside the div "p5-div" and to be as big as it is. Having in consideration that the size of the div is unpredictable because is set by css and this can change.
<!doctype html>
<html lang="en">
<head>
<style>
#p5-div {
width: 50%;
height: 300px
}
</style>
</head>
<body>
<h1>My Sketch</h1>
<div id="p5-div">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.min.js" integrity="sha512-NxocnqsXP3zm0Xb42zqVMvjQIktKEpTIbCXXyhBPxqGZHqhcOXHs4pXI/GoZ8lE+2NJONRifuBpi9DxC58L0Lw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
function setup() {
createCanvas(100, 100); // this has to be adapted in load time to the side of the div
}
function draw(){
background(33);
}
</script>
</body>
</html>
To allocate your canvas inside an specific div you have to use this code in your setup():
function setup() {
const myCanvas = createCanvas(divWidth, divHeight);
myCanvas.parent("div-id");
}
Now, in order to know the size of the canvas it gets a bit more complicated, this is my solution:
class Utils {
// Calculate the Width in pixels of a Dom element
static elementWidth(element) {
return (
element.clientWidth -
parseFloat(window.getComputedStyle(element, null).getPropertyValue("padding-left")) -
parseFloat(window.getComputedStyle(element, null).getPropertyValue("padding-right"))
)
}
// Calculate the Height in pixels of a Dom element
static elementHeight(element) {
return (
element.clientHeight -
parseFloat(window.getComputedStyle(element, null).getPropertyValue("padding-top")) -
parseFloat(window.getComputedStyle(element, null).getPropertyValue("padding-bottom"))
)
}
}
Then we can do:
function setup() {
p5Div = document.getElementById("div-id");
const p5Canvas = createCanvas(Utils.elementWidth(p5Div), Utils.elementHeight(p5Div));
p5Canvas.parent(p5Div);
}
I have a root component that renders <Particle /> components and <Particle /> component render function is:
render: function(){
var data = this.props.data,
canvas = document.createElement('canvas'),
context;
canvas.style.position = 'absolute';
canvas.style.top = data.y + 'px';
canvas.style.left = data.x + 'px';
context = canvas.getContext('2d');
context.drawImage(data.img, data.x, data.y, data.tileSize, data.tileSize, 0, 0, data.tileSize, data.tileSize);
return canvas;
}
And this returns the following error:
Uncaught Error: Invariant Violation: Particle.render(): A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
I had a look at Flipboard's react-canvas but I couldn't find any good examples similar to my situation.
So any help would be much appreciated.
You should just return a single canvas element with a reference to it. This element is not the same as a DOM node; React transforms it into a React Component using JSX:
render: function() {
return <canvas ref="canvas" />
}
Then modify it inside a lifecycle method:
componentWillReceiveProps: function() {
var canvas = React.findDOMNode(this.refs.canvas);
canvas.style.position = 'absolute';
// etc ...
}
You could also set some inline style attributes inside the render:
render: function() {
var styles = {
position: 'absolute',
top: this.props.data.y,
left: this.props.data.x
}
return <canvas ref="canvas" style={styles} />
}
...but the context/drawimage would be best to put in a lifecycle method since you need access to the dom node.
I'm trying to find the width of an <img> to center it via JavaScript.
Trying to calculate the width of this react.js DOM node returns 0.
var Player = React.createClass({
componentDidMount:function(){
var imgEl = this.refs.imgSize.getDOMNode();
console.log(imgEl.offsetWidth);
},
render: function () {
return (
<img ref="imgSize" src={this.props.imageURL} />
);
}
});
You could use the image's onLoad event to make sure it's loaded before you try this:
<script src="http://fb.me/react-0.12.2.js"></script>
<script src="http://fb.me/JSXTransformer-0.12.2.js"></script>
<script type="text/jsx;harmony=true">void function() { "use strict";
var Player = React.createClass({
_onLoad(e) {
console.log(e.target.offsetWidth)
},
render() {
return <img src={this.props.imageURL} onLoad={this._onLoad}/>
}
})
React.render(<Player imageURL="http://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg"/>, document.body)
}()</script>
I wrote a React library that exposes a size object (with width and height props) to your components.
You can use it like so for your use case:
var SizeMe = require('react-sizeme');
var Player = React.createClass({
componentDidMount:function(){
var imgEl = this.refs.imgSize.getDOMNode();
console.log(imgEl.offsetWidth);
},
render: function () {
// height and width via props!!
var width = this.props.width;
var height = this.props.height;
return (
<img ref="imgSize" src={this.props.imageURL} />
);
}
});
// Wrap your component with the SizeMe HOC!
module.exports = SizeMe()(Player);
Demo: https://react-sizeme-example-esbefmsitg.now.sh/
Github: https://github.com/ctrlplusb/react-sizeme
I am creating a sample program to display an image on canvas but would like to enclose actual drawing process into a custom object.
The following code won't show the image as pictFrame.img.onload can't catch onload event of image file. Chrome console says "TypeError: Cannot set property 'onload' of undefined" with the expression although it can correctly evaluate pictFrame.img.src or pictFrame.img.height.
How should I detect image loading which is being initiated when the object is created?
<html>
<head>
<script type="text/javascript">
function pictFrame(context, imgsrc, pos_x, pos_y, size_x, size_y)
{
this.context = context;
this.img = new Image();
this.img.src = imgsrc;
this.pos_x = pos_x;
this.pos_y = pos_y;
this.size_x = size_x;
this.size_y = size_y;
this.draw = function() {
this.context.drawImage(this.img, this.pos_x, this.pos_y, this.size_x, this.size_y);
};
}
// These variables must live while the page is being displayed.
// Therefore, they can't be defined within window.onload function.
var canvas;
var context;
var pictFrame;
window.onload = function()
{
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
pictFrame = new pictFrame(context, "darwin.jpg", 10, 10, 200, 200);
};
pictFrame.img.onload = function() // Can't catch onload event
{
pictFrame.draw();
}
</script>
</head>
<body>
<canvas id="canvas" width="500" height="300"></canvas>
</body>
</html>
Its because you are calling before pictFrame gets instantiated. You get this in chrome,
Uncaught TypeError: Cannot set property 'onload' of undefined
do like below instead,
window.onload = function()
{
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
pictFrame = new pictFrame(context, "images/bahu.png", 10, 10, 200, 200);
console.log("called");
pictFrame.img.onload = function()
{
console.log(" onload called");
pictFrame.draw();
}
};
I mean, do onload call after window.onload has finished instead of calling it before.
I have this code:
function myClient() {
if (!(this instanceof arguments.callee)) {
return new arguments.callee(arguments);
}
var self = this;
this.init = function() {
self.viewResized();
self.drawSvg();
};
this.viewResized = function () {
var width = $('body').width(),
windowHeight = $(window).height(),
svgCanvasHeight = width * (369.0 / 567.0);
$('#svg').css({
'margin-top': 10
});
}
this.drawSvg = function() {
// ...
}
var myClient;
jQuery(function() {
myClient = new myClient();
$(window).resize(function() {
console.log("window resized");
myClient.viewResized();
});
});
How do I get the svgCanvasHeight in drawSvg dynamically so that when the window is resized, so does the svg's viewBox and svg?
Answered here: Get the real size of a SVG/G element
With regards to viewBox:
I have had a lot of problems with SVG and jQuery.
While html attributes are case-insensitive the svg ones (like viewBox) aren't. I'd try using the element.setAttribute(name, value) native JS function. This worked for me, and make sure you're using viewBox with the capital B.