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>
Related
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.
In a NR dashboard I'm trying to determine the width and heigth of a widget group:
var groupWidth = document.getElementById('Home_Test2_cards').offsetWidth;
var groupHeight = document.getElementById('Home_Test2_cards').offsetHeight;
It works for groupWidth but not for groupHeight. I found some references that a div will not return its height when set to invisible but this is not the case here. Is there any way to determine the height?
Using jQuery:
Calling var groupHeight = $('#Home_Test2_cards').height(); works but still only returns 0.
Edit:
Browser Screenshot
Dashboard Template content:
<script>
(function(scope) {
scope.$watch('msg.payload', function(data) {
if (data !== undefined) {
imageObj.src=data;
}
});
}(scope));
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var groupWidth = document.getElementById('Home_Test2_cards').offsetWidth;
//var groupHeight = document.getElementById('Home_Test2_cards').offsetHeigth;
var groupHeight = $('#Home_Test2_cards').height();
console.log('Width:' + groupWidth);
console.log('Height:' + groupHeight);
var imageObj = new Image();
imageObj.onload= function() {
var wRatio = groupWidth / imageObj.width;
var hRatio = groupHeight / imageObj.height;
var ratio = Math.min(wRatio, hRatio);
context.drawImage(imageObj, 0, 0, canvas.width, canvas.height, 0, 0, imageObj.width*ratio, imageObj.height*ratio);
};
</script>
<canvas id="myCanvas"></canvas>
Based on the screenshot above I would expect the height to be 351.
The node-red Dashboard includes the JQuery library, so you should be able to use:
var groupWidth = $('#Home_Test2_cards').width;
var groupHeight = $('#Home_Test2_cards').height;
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));
};
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
});
I am new with jquery , i have a small project about display image with canvas. All will good , but i have a trouble when try display all image , i try to use .each(function) or loop but not work
This is my trouble , any one can help ?. Thanks
http://jsfiddle.net/NcKfr/6/
<textarea id="textid">blah blah blah</textarea>
<canvas id="ca1" width="640" height="480"></canvas>
<script>
$(document.body).find('*').each(function() {
var tmp = $("textarea").children().remove();
var text = $("textarea").text();
text = text.replace(/<li>/g, "").replace(/<\/li>/g, "").replace(/<br \/>/g, "").replace(/\/>/g, "").replace(/<img/g, "").replace(/ /g, "");
$("textarea").text(text);
$("textarea").append(tmp);
});
</script>
Script code :
$(function(e) {
var data = $("#textid").val();
rows = data.split('src="');
partNum = [];
var i;
var len = rows.length;
var can = document.getElementsByTagName('canvas')[0];
var ctx = can.getContext('2d');
$(document).ready(function() {
for (i = 1; i < len; i++) {
partNum[i] = rows[i].substr(0,rows[i].indexOf('"'));
$.getImageData({
url: partNum[i],
success: function(image) {
// Set the canvas width and heigh to the same as the image
$(can).attr('width', image.width);
$(can).attr('height', image.height);
$(can).css({
'background-color': 'none',
'border-color': '#fff'
});
// Draw the image on to the canvas
ctx.drawImage(image, 0, 0, image.width, image.height);
},
error: function(xhr, text_status) {
// Handle your error here
}
});
}
});
});
success: function(image) {
script = document.createElement('canvas');
var can = document.body.appendChild(script);
If i change code in two line , i can show all image but i can control it load form 1 to 13. Any body can help me fix it ... thanks
Here is a code which will draw images on one canvas one under another.
var url = "http://farm4.static.flickr.com/",
urls = [
"3002/2758349058_ab6dc9cfdc_z.jpg",
"2445/5852210343_d21767f18d.jpg"],
can = $('#canvas').get(0),
ctx = can.getContext('2d'),
canH = 0,
canW = 0,
h = 0,
images = [],
size = urls.length;
// loop via all images
$.each(urls, function (index, img) {
$.getImageData({
url: url + img,
success: function (image) {
images.push(image);
canH += image.height;
canW = Math.max(canW, image.width);
if (images.length === size) {
can.width = canW;
can.height = canH;
$.each(images, function (i, img) {
ctx.drawImage(img, 0, h);
h += img.height;
});
}
}
});
});
You can also check this: http://jsfiddle.net/HcxG3/6/ (looks like the service behind getImageData is currently down).