Using LibCanvas to draw an image - javascript

Im am currently using LibCanvas to do canvas drawing in my html page, but I can't seem to figure out how to draw an image. Can anyone help me with this?
http://libcanvas.github.com/
EDIT: I am currently using this piece code, I see the image being drawn but then it dissapears;
var libcanvas = new LibCanvas('canvas', { preloadImages: false }).start();
var img = new Image();
img.src = 'images/draw.png';
img.width = 400;
img.height = 400;
libcanvas.addEvent('ready', function()
{
libcanvas.ctx.drawImage(img);
});

It depends on your aim.
If you just want to draw image - you can use plain context, without creating LibCanvas object:
var img = atom.dom.create( 'img', { src: 'images/draw.png' })
.bind( 'load', function () {
atom.dom( 'canvas' ).first
.getContext( '2d-libcanvas' )
.drawImage( img );
});
Your image dissapears because you draw it not in frame. So, second way - is to draw it in "render" part:
new LibCanvas('canvas', {
preloadImages: { foo: 'images/draw.png' }
}).start(function () {
this.ctx.drawImage( this.getImage('foo') );
});
The right way if you try to create big app - is creating special object:
LibCanvas.extract();
var ImageDrawer = atom.Class({
Extends: DrawableSprite,
initialize: function (sprite, shape) {
this.sprite = sprite;
this.shape = shape;
}
});
new LibCanvas('canvas', {
preloadImages: { foo: 'images/draw.png' }
})
.start()
.addEvent('ready', function () {
var drawTo = new Rectangle( 0, 0, 100, 100 );
var drawer = new ImageDrawer( this.getImage('foo'), drawTo );
this.addElement( drawer );
});
In such way you can easy make it, e.g. draggable:
LibCanvas.extract();
var ImageDrawer = atom.Class({
Extends: DrawableSprite,
Implements: [ Draggable ],
initialize: function (sprite, shape) {
this.sprite = sprite;
this.shape = shape;
}
});
new LibCanvas('canvas', {
preloadImages: { foo: 'images/draw.png' }
})
.start()
.addEvent('ready', function () {
var drawTo = new Rectangle( 0, 0, 100, 100 );
var drawer = new ImageDrawer( this.getImage('foo'), drawTo );
this.addElement( drawer );
drawer.draggable();
});
For answers about LibCanvas you can write to me, shocksilien#gmail.com

Look at one of the examples provided that uses images and do what it does.
http://libcanvas.github.com/games/asteroids/
For example:
this.libcanvas.ctx.drawImage({
image : engines[type].image,
center : this.somePosition,
angle : this.angle
});

Related

Can't figure out how to fix this: "Uncaught TypeError (webcam.snap is not a function)" <-- javascript

I have a JavaScript script that I am getting an error for that I can't figure out. I am trying to take a picture of the webcam feed using JavaScript
The error is:
Uncaught TypeError: webcam.snap is not a function
I am using webcam.js to take the snapshot.
Here is my JavaScript code:
<script>
var video = document.createElement("video");
var canvasElement = document.getElementById("canvas");
var canvas = canvasElement.getContext("2d");
var loadingMessage = document.getElementById("loadingMessage");
var outputContainer = document.getElementById("output");
var outputMessage = document.getElementById("outputMessage");
var outputData = document.getElementById("outputData");
const jsQR = require("jsqr");
function drawLine(begin, end, color) {
canvas.beginPath();
canvas.moveTo(begin.x, begin.y);
canvas.lineTo(end.x, end.y);
canvas.lineWidth = 4;
canvas.strokeStyle = color;
canvas.stroke();
}
// Use facingMode: environment to attemt to get the front camera on phones
navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }).then(function(stream) {
video.srcObject = stream;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
video.play();
requestAnimationFrame(tick);
});
function tick() {
loadingMessage.innerText = "⌛ Loading video..."
if (video.readyState === video.HAVE_ENOUGH_DATA) {
loadingMessage.hidden = true;
canvasElement.hidden = false;
outputContainer.hidden = false;
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
var imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
var code = jsQR(imageData.data, imageData.width, imageData.height, {
inversionAttempts: "invertFirst",
});
if (code) {
drawLine(code.location.topLeftCorner, code.location.topRightCorner, "#FF3B58");
drawLine(code.location.topRightCorner, code.location.bottomRightCorner, "#FF3B58");
drawLine(code.location.bottomRightCorner, code.location.bottomLeftCorner, "#FF3B58");
drawLine(code.location.bottomLeftCorner, code.location.topLeftCorner, "#FF3B58");
outputMessage.hidden = true;
outputData.parentElement.hidden = false;
outputData.innerText = code.data;
takeSnapShot();
}
else {
outputMessage.hidden = false;
outputData.parentElement.hidden = true;
}
}
requestAnimationFrame(tick);
}
// TAKE A SNAPSHOT.
takeSnapShot = function () {
webcam.snap(function (data_uri) {
downloadImage('video', data_uri);
});
}
// DOWNLOAD THE IMAGE.
downloadImage = function (name, datauri) {
var a = document.createElement('a');
a.setAttribute('download', name + '.png');
a.setAttribute('href', datauri);
a.click();
}
</script>
This is the first line that causes a problem:
webcam.snap(function (data_uri) {
downloadImage('video', data_uri);
});
This is the second line that causes a problem:
takeSnapShot();
how do I correct this properly?
****** UPDATE ******
The version of webcam.js I am using is WebcamJS v1.0.26. My application is a Django application that launches the HTML file as defined in main.js.
snap: function(user_callback, user_canvas) {
// use global callback and canvas if not defined as parameter
if (!user_callback) user_callback = this.params.user_callback;
if (!user_canvas) user_canvas = this.params.user_canvas;
// take snapshot and return image data uri
var self = this;
var params = this.params;
if (!this.loaded) return this.dispatch('error', new WebcamError("Webcam is not loaded yet"));
// if (!this.live) return this.dispatch('error', new WebcamError("Webcam is not live yet"));
if (!user_callback) return this.dispatch('error', new WebcamError("Please provide a callback function or canvas to snap()"));
// if we have an active preview freeze, use that
if (this.preview_active) {
this.savePreview( user_callback, user_canvas );
return null;
}
// create offscreen canvas element to hold pixels
var canvas = document.createElement('canvas');
canvas.width = this.params.dest_width;
canvas.height = this.params.dest_height;
var context = canvas.getContext('2d');
// flip canvas horizontally if desired
if (this.params.flip_horiz) {
context.translate( params.dest_width, 0 );
context.scale( -1, 1 );
}
// create inline function, called after image load (flash) or immediately (native)
var func = function() {
// render image if needed (flash)
if (this.src && this.width && this.height) {
context.drawImage(this, 0, 0, params.dest_width, params.dest_height);
}
// crop if desired
if (params.crop_width && params.crop_height) {
var crop_canvas = document.createElement('canvas');
crop_canvas.width = params.crop_width;
crop_canvas.height = params.crop_height;
var crop_context = crop_canvas.getContext('2d');
crop_context.drawImage( canvas,
Math.floor( (params.dest_width / 2) - (params.crop_width / 2) ),
Math.floor( (params.dest_height / 2) - (params.crop_height / 2) ),
params.crop_width,
params.crop_height,
0,
0,
params.crop_width,
params.crop_height
);
// swap canvases
context = crop_context;
canvas = crop_canvas;
}
// render to user canvas if desired
if (user_canvas) {
var user_context = user_canvas.getContext('2d');
user_context.drawImage( canvas, 0, 0 );
}
// fire user callback if desired
user_callback(
user_canvas ? null : canvas.toDataURL('image/' + params.image_format, params.jpeg_quality / 100 ),
canvas,
context
);
};
// grab image frame from userMedia or flash movie
if (this.userMedia) {
// native implementation
context.drawImage(this.video, 0, 0, this.params.dest_width, this.params.dest_height);
// fire callback right away
func();
}
else if (this.iOS) {
var div = document.getElementById(this.container.id+'-ios_div');
var img = document.getElementById(this.container.id+'-ios_img');
var input = document.getElementById(this.container.id+'-ios_input');
// function for handle snapshot event (call user_callback and reset the interface)
iFunc = function(event) {
func.call(img);
img.removeEventListener('load', iFunc);
div.style.backgroundImage = 'none';
img.removeAttribute('src');
input.value = null;
};
if (!input.value) {
// No image selected yet, activate input field
img.addEventListener('load', iFunc);
input.style.display = 'block';
input.focus();
input.click();
input.style.display = 'none';
} else {
// Image already selected
iFunc(null);
}
}
else {
// flash fallback
var raw_data = this.getMovie()._snap();
// render to image, fire callback when complete
var img = new Image();
img.onload = func;
img.src = 'data:image/'+this.params.image_format+';base64,' + raw_data;
}
return null;
},
Your implementation doesn't need Webcamjs, because you're using navigator media devices.
You can either use WebcamJS by initializing it at first and attaching it to some canvas, like in the following code
Webcam.set({
width: 320,
height: 240,
image_format: 'jpeg',
jpeg_quality: 90
});
Webcam.attach( '#my_camera' );
Or you can update your takeSnapShot function to the following :
takeSnapShot = function () {
downloadImage('video',canvasElement.toDataURL())
// Webcam.snap(function (data_uri) {
// downloadImage('video', data_uri);
// });
}
Here's a working example based on your code https://codepen.io/majdsalloum/pen/RwVKBbK
It seems like either:
the webcam's code are missing (not imported)
in this case you need to first call the script from the URL and add it with script tag
<script src="WEBCAM_JS_SOURCE">
or
they are imported, but used with typo. From the webcam source code it is defined as:
var Webcam = {
version: '1.0.26',
// globals
...
};
so you should use with a capital one.

Why do I get "Cannot read property...of undefined with this object?

Could someone help me figure out what the problem is. I get the error "TypeError: Cannot read property 'draw_map' of undefined(…)" in browser when running the code below:
$(document).ready(function() {
Maps = function(id, img_src, width, height) {
var self = {
id: id,
img: new Image(),
width: width,
height: height
}
self.img.src = img_src;
self.draw_map = function() {
ctx.drawImage(self.img, 0, 0, self.img.width, self.img.height, 100, 100, self.img.width * 2, self.img.height * 2);
}
}
function update_canvas() {
current_map.draw_map();
}
///////////////////////////////////////////
// get context to draw on canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Load Image for map
var current_map = Maps("field", "img/dirt.jpeg", 120, 480);
// Drawing
setInterval(update_canvas, 500);
}); // End of Document.ready
Probably because the function
Maps = function(...) { ... }
doesn't return self object.
Probably you want to use it as a construction function so change this line using new operator:
var current_map = new Maps("field", "img/dirt.jpeg", 120, 480);
Here is a working code (with the HTML elements commented out). The problem was that you are not using the this reference inside the function constructor and then not using the new operator to create an instance.
$(document).ready(function() {
Maps = function(id, img_src, width, height) {
this.id = id;
this.width = width;
this.height = height;
this.img = new Image() // replace with your Image
this.img.src = img_src;
var self = this; // Required for the draw_map function
this.draw_map = function() {
console.log("Draw image", self.img.width, self.img.height);
// Uncomment in your code: ctx.drawImage(self.img, 0, 0, self.img.width, self.img.height, 100, 100, self.img.width * 2, self.img.height * 2);
}
}
function update_canvas() {
current_map.draw_map();
}
///////////////////////////////////////////
// get context to draw on canvas. Uncomment
//var canvas = document.getElementById("canvas");
//var ctx = canvas.getContext("2d");
// Load Image for map
var current_map = new Maps("field", "img/dirt.jpeg", 120, 480);
// Drawing
setInterval(update_canvas, 500);
}); // End of Document.ready
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Three.js + OrbitControls - Uncaught TypeError: Cannot read property 'render' of undefined

I am writing a class for rotating cube, but every time i rotate it or zoom, i get an error "Cannot read property 'render' of undefined". What am i doing wrong? I guess something is wrong with the scopes. Here is my class:
myclass = function() {
this.camera = null;
this.scene = null;
this.renderer = null;
this.product = null;
this.init = function (container) {
this.scene = new THREE.Scene();
this.camera = createCamera();
this.product = createProduct();
this.scene.add(this.product);
this.createRenderer();
this.setControls();
container.appendChild(this.renderer.domElement);
this.animate();
};
function createCamera() {
var camera = new THREE.PerspectiveCamera(20, 300 / 400, 1, 10000);
camera.position.z = 1800;
return camera;
}
function createProduct() {
var geometry = new THREE.BoxGeometry(300, 200, 200);
var materials = ...;
var product = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(materials));
return product;
}
this.createRenderer = function () {
this.renderer = new THREE.WebGLRenderer({antialias: true});
this.renderer.setClearColor(0xffffff);
this.renderer.setSize(this.sceneWidth, this.sceneHeight);
};
this.setControls = function () {
this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this.controls.addEventListener('change', this.render);
};
this.animate = function () {
requestAnimationFrame(this.animate.bind(this));
this.render();
};
this.render = function () {
this.renderer.render(this.scene, this.camera);
};
};
Tnanks.
You have a scoping problem in the callback specified here:
this.controls.addEventListener( 'change', this.render );
In your class, add
var scope = this;
Then rewrite your render() method like so:
this.render = function () {
scope.renderer.render( scope.scene, scope.camera );
};
Also, the point of adding the event listener is to remove the animation loop.
So..., remove it, and only render when the mouse causes the camera to move.
You will also have to call render() once initially, and after models load.
three.js r.69
You can use bind method as follows it will hold the scope for the render method
this.controls.addEventListener( 'change', this.render.bind(this) );

Issue with scoping, when calling a function in a callback

when clicking inside the canvas it will generate a ball and move to the clicked location
when the ball get's to its location I want it to remove itself. But i think i have a problem
with the scope when calling the removeBall() function.
You can find a working example her: jsfiddle
/*
* Main app logic
*/
function Main() {
this.canvas = "canvas";
this.stage = null;
this.WIDTH = 0;
this.HEIGHT = 0;
this.init();
}
Main.prototype.init = function() {
console.clear();
this.stage = new createjs.Stage(this.canvas);
this.resize();
//start game loop
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", this.gameLoop);
//click event handler
this.stage.on("stagemousedown", function(evt) {
main.fireBall(evt);
});
};
Main.prototype.fireBall = function(evt) {
var bal = new Bal(evt.stageX, evt.stageY);
};
Main.prototype.resize = function() {
//resize the canvas to take max width
this.WIDTH = window.innerWidth;
this.HEIGHT = Math.floor(window.innerWidth * 9 / 16);
this.stage.canvas.width = this.WIDTH;
this.stage.canvas.height = this.HEIGHT;
};
Main.prototype.gameLoop = function() {
//game loop
main.stage.update();
};
/*
* Ball logic
*/
function Bal(toX, toY) {
this.toX = toX ;
this.toY = toY;
this.widthPerc = 8;
this.init();
}
Bal.prototype.width = function() {
return Math.floor(main.stage.canvas.width / 100 * this.widthPerc);
};
Bal.prototype.init = function() {
//create a new ball
this.ball = new createjs.Shape();
this.ball.graphics.beginFill("green").drawCircle(0, 0, this.width());
this.ball.x = (main.stage.canvas.width / 2) - (this.width() / 2);
this.ball.y = main.stage.canvas.height - 20;
main.stage.addChild(this.ball);
this.move();
};
Bal.prototype.move = function() {
//create a tween to cliked coordinates
createjs.Tween.get(this.ball).to({
x: this.toX ,
y: this.toY ,
scaleX:0.4,scaleY:0.4,
rotation: 180
},
750, //speed
createjs.Ease.none
).call(this.removeBall); // <---- How can i pass the correct scope to the called function?
};
Bal.prototype.removeBall = function() {
//try to remove the ball
main.stage.removeChild(this.ball);
};
var main = new Main();
The solution above using bind works, however there is a much better solution. Bind is not available in all browsers (most notably Safari 5.1, which is a modern browser). http://kangax.github.io/es5-compat-table/#Function.prototype.bind
TweenJS has built-in support for scoping functions when using call(). Just pass the scope as the 3rd argument.
Ball.prototype.move = function() {
console.log(this.toX +","+this.toY);
createjs.Tween.get(this.ball).to({
x: this.toX ,
y: this.toY ,
scaleX:0.4,scaleY:0.4,
rotation: 180
},
750, //speed
createjs.Ease.none
).call(this.removeBall, null, this);
};
You can also pass an array of function arguments as the second parameter.
Tween.call(this.removeBall, [this.ball], this);
Ok found a solution! using the bind() functionality.
Bal.prototype.move = function() {
console.log(this.toX +","+this.toY);
createjs.Tween.get(this.ball).to({
x: this.toX ,
y: this.toY ,
scaleX:0.4,scaleY:0.4,
rotation: 180
},
750, //speed
createjs.Ease.none
).call(this.removeBall.bind(this));
};

Overlay rectangle on Fabric.js image

I have a custom image class as follows. What i want to do is after applying a certain logic, I want to show a colored border on the bounding box of the image. Since setting the borders makes the image selectable i was wondering if there was a way to somehow overlay a rectangle and make it transparent and just toggle its border color. How could that be done with a custom image class.
If there is a better way to accomplish this, please let us know
fabric.CustomImage = fabric.util.createClass(fabric.Image, {
type: 'named-image',
initialize: function (element, options) {
this.callSuper('initialize', element, options);
options && this.set('name', options.name);
options && this.set('rot', options.rot);
options && this.set('rawURL', options.rawURL);
options && this.set('belongsto', options.belongsto);
},
toObject: function () {
return fabric.util.object.extend(this.callSuper('toObject'),
{ name: this.name, rot: this.rot });
}
});
based on the suggestions tried the following
/////////////////////////////////////////////////////////////
//// create Custom Image class from Image class
fabric.CustomImage = fabric.util.createClass(fabric.Image, {
type: 'named-image',
initialize: function (element, options) {
this.callSuper('initialize', element, options);
options && this.set('name', options.name);
options && this.set('rot', options.rot);
options && this.set('rawURL', options.rawURL);
options && this.set('belongsto', options.belongsto);
options && this.set('myrect', true);
},
toObject: function () {
return fabric.util.object.extend(this.callSuper('toObject'),
{
name: this.name,
rot: this.rot,
myrect : ''
});
},
_render: function (ctx) {
this.callSuper('_render', ctx);
var r = new fabric.Rect();
r.left = this.left;
r.top = this.top;
r.height = this.height;
r.width = this.width;
r.borderColor = 'red';
r.strokeWidth = 2;
ctx.myrect = (r);
// ctx.add(r);
}
});
still not working, any ideas?
ok, so i am trying the following code but still cannot see a border around the image
var currentObj = ChrImages.d[j];
//closure, create a scope for specific variables
(function (obj) {
fabric.util.loadImage(obj.URL, function (img) {
var customImage = new fabric.CustomImage(img, {
name: obj.Name,
rot: obj.Rotation,
rawURL: obj.RawURL,
belongsto: obj.BelongsTo,
left: obj.PosX,
top: obj.PosY,
angle: obj.Rotation,
perPixelTargetFind: true,
});
customImage.stroke = true;
customImage.strokeWidth = 2;
customImage.lockScalingX = true;
customImage.lockScalingY = true;
customImage.filters.push(new fabric.Image.filters.RemoveWhite());
canvas.add(customImage);
groupWorkingImages.add(customImage);
});
})(currentObj);
any thoughts?

Categories