$('#myCanvas').click(function (e) { //Default mouse Position
console.log(e.pageX);
$("#myCanvas2").attr("width", e.pageX );
$("#myCanvas3").attr("width", e.pageX );
var imageData = context.getImageData(0, 0, e.pageX,400);
context2.putImageData(imageData,0,0);
context3.putImageData(imageData,0,0);
context.clearRect ( 0 , 0 , 2000 , 2000 );
$("#myCanvas3").css("scale", "(-1, 1)" );
$("#myCanvas3").css("transform", "scale(-1,1)");
var canvas4 = document.getElementById('myCanvas4');
var context4 = canvas4.getContext('2d');
context4.drawImage( myCanvas2, 0,0 );
context4.drawImage(myCanvas3, e.pageX,0 );
context3.scale(3,3);
});
I am trying to scale my canvas with the scale command.
What am I doing wrong?
I'm not clear what you're trying to do, but these thoughts come to mind:
To get an accurate canvas mouse position, calculate relative to the canvas element:
$('myCanvas').click(function(e){
var BB=canvas.getBoundingClientRect();
var mouseX=parseInt(e.clientX-BB.left);
var mouseY=parseInt(e.clientY-BB.top);
}
About mixing CSS and Canvas:
CSS scale will operate on the center of the element.
Canvas scale will operate from the origin (the origin defaults to 0,0).
CSS scaling will not affect Canvas drawing. So if you "flip" using CSS scaling and then you draw the flipped element to a canvas, the resulting canvas drawing is not flipped.
Changing the canvas element width will also automatically clear the canvas content.
Changing CSS width will retain the canvas content, but will "stretch" the existing pixels into the new width (the content will appear deformed).
Canvas scaling commands only affect drawings done after the scale command. So your context3.scale(3,3) will not affect anything you have previously drawn on myCanvas3.
Here's how to horizontally flip an image on a canvas element:
Example code and a Demo: http://jsfiddle.net/m1erickson/tSPB2/
var img=document.getElementById("theImg");
var iw=img.width;
var ih=img.height;
var canvas2=document.getElementById('myCanvas2');
var context2=canvas2.getContext('2d');
canvas2.width=iw;
canvas2.height=ih;
context2.save();
context2.translate(iw,0);
context2.scale(-1,1);
context2.drawImage(img,0,0);
context2.restore();
Related
I'm using html5 canvas and JS.
I'm drawing an image on the canvas with CanvasRenderingContext2D.drawImage(). This image is 15x15 black square, with a 1 pixel wide white border: so 16x16 total.
Is there a way to read image data in JS, and only scale up the border width of that image. So, leave the inner black square 15x15, but make the white border width 3 pixels wide?
As far as I can tell, the CanvasRenderingContext2D.getImageData() can only select an area, but you cannot seclude an area, to use the rest.
Thanks :)
You can not change the size of a canvas without clearing its content. The only way to resize the canvas is to create a second canvas, copy the existing content to the new canvas while adding the new content.
The following function will pad a canvas with a boarder by creating a second canvas. Filling it with the padding color, adding the original canvas image to it. Then resize the original and copying the new content to it.
// padCanvas(canvas, padAmount, padColor)
// canvas : HTMLCanvasElement Canvas to pad
// Note all state setting on the input canvas will be reset
// padAmount : Number Amount to pad canvas in pixels
// padColor : String Color of padding as CSS style color string. eg "White"
// Returns the original canvas,
function padCanvas(canvas, padAmount, padColor) {
// create a canvas with the padded size
const can = Object.assign(
document.createElement("canvas"), {
width: canvas.width + padAmount * 2,
height: canvas.height + padAmount * 2
}
);
// add padding color and source (image)
const ctx = can.getContext("2d");
ctx.fillStyle = padColor;
ctx.fillRect(0, 0, can.width, can.height);
ctx.drawImage(canvas, padAmount, padAmount);
// Resize original image and add new content
Object.assign(canvas, {width: can.width, height: can.height});
canvas.getContext("2d").drawImage(can, 0, 0);
return canvas;
}
I'm creating an application to calculate how much solar panels would fit on a specific roof.
Users can input the dimensions of their roof.
We only have on size of solar panels available.
I thought a canvas was the way to go but I don't seem to find the information I need..
Requirements
1) Based on the input of the user the canvas should be resized (currently I have a rectangle inside the canvas changing to this size)
2) User should be able to create (and size) objects to put on the roof (chimney, window,..)
3) Based on the open space left solar panels (rectangles) should be automaticly drawn on the canvas
Dimensions and limitations
1px = 2cm
Spacing to edge of roof and object is 7px (14cm)
Solar panel is 169 cm height and 102 cm width
I've checked out the fabric.js library but can't seem to find something close to what I need.
The js I got so far to draw the canvas:
var canvas=document.getElementById("c");
var ctx=canvas.getContext("2d");
var width=50;
var height=35;
var $width=document.getElementById('width');
var $height=document.getElementById('height');
var paneelWidth=101;
var peneelHeight=170;
$width.value=width;
$height.value=height;
draw();
$width.addEventListener("keyup", function(){
width=this.value/2;
draw();
}, false);
$height.addEventListener("keyup", function(){
height=this.value/2;
draw();
}, false);
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(10,10,width,height)
}
Update
The canvas now does resize in a dynamic way based on user input.
I also found the function createPattern(), which is bringing me closer to the solution.
I've added this code to generate a pattern of solar panels in the canvas:
function placepanels(direction) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var img = document.getElementById("paneel");
var pat = ctx.createPattern(img, direction);
var w2 = canvas.width - 7;
var h2 = canvas.height - 7;
ctx.rect(7, 7, w2, h2);
ctx.fillStyle = pat;
ctx.fill();
}
The -7 on width and height is beacause I need 14cm space on each size of the canvas. Hence why I offset the rectangle containing the pattern 7px from left and top. Currently not able to achieve this on right and bottom side.
Current issue
The result I'm getting is not looking correct, it seems like the pattern repeats wrong (to much repeats) or it's not getting the proper size of the image to repeat.
Updated fiddle: https://jsfiddle.net/8e05ghqy/3/
As for the canvas resize, this function would do it:
changeCanvasSize = function( width, height ) {
$('canvas').width(width)
$('canvas').height(height)
}
Example of usage: changeCanvasSize(450,250) would change the canvas size to 450px of width and 250px of height.
I am just resizing the HTML <canvas> element .width( value ) and .height( value ) works for any HTML element.
I'm trying to draw some stuff over loaded image. However, for some reason canvas appears below the image not on top. I'm doing it as follows:
I have the following container:
<div id="container">
<img src="{{url_for('static', filename='nature.jpg')}}" id="target" style="zIndex=1">
</div>>
And the I'm trying to add canvas as follows:
window.onload = function() {
var img = document.getElementById('target');
var width = img.naturalWidth;
var height = img.naturalHeight;
var canvas = document.createElement('canvas'); //Create a canvas element
//Set canvas width/height
canvas.style.width=width;
canvas.id = 'mycanvas';
canvas.style.height=height;
//Set canvas drawing area width/height
canvas.width = width;
canvas.height = height;
//Position canvas
canvas.style.position='absolute';
canvas.style.left=0;
canvas.style.top=0;
canvas.style.zIndex=100000;
canvas.style.pointerEvents='none'; //Make sure you can click 'through' the canvas
$('#container').append(canvas);
}
However, canvas appears below the image rather than on top of it. What am I doing wrong?
thanks
You've used the wrong syntax for the inline style style="zIndex=1", it should be style="z-index: 1", still, for z-index to work its element need a position other than static
In this case, since the img has no position, you can actually drop the z-index all together, as the canvas has a position, position: absolute, and will be layered on top of the image because of that alone.
For the canvas to be positioned relative to the container, the container need a position, i.e. position: relative
I want to plot x and y coordinates on an image by drawing a circle around the point.
I am getting the image from the server as an array buffer. After the image is displayed i need to mark the corners in the image using coordinates sent as a json from a service.
How can i do this using javascript jquery?
I was thinking of doing the same by overlaying the image with a canvas layer.
How can i implement this?
I have tried the below method but the points were getting plotted outside the image
jQuery('#plotCoordinates').on('click',function(){
jQuery.getJSON( "plot.json", function( response ) {
console.log("response >> " ,response);
var imageCanvas = $('#imageCan');
jQuery.each(response,function(i,obj){
console.log('obj >> ',obj);
point = $('<div class="plot-point"></div>');
x = obj.x,
y = obj.y;
point.css({
left: x + "px",
top: y + "px"
});
point.appendTo(imageCanvas);
});
});
});
You can certainly do it using a canvas.Do the following steps-->
Draw image on canvas as image size=canvas size.
Now, overlay another canvas with a higher z-index exactly on the previous canvas(canvas is transparent by default).
Now use the coordinates of the points you fetched using json to mark the corners in the image by plotting them on this overlayed canvas.
Then you can draw circles around these points on the upper canvas using simple context functions.
As canvas size is same as image size these coordinates will exactly coincide and you can achieve want you want :).In short you draw your circles and markings on the upper canvas and simply draw image on the lower canvas.Easy huhh??:)
Note:Both the canvases and the image itself should be of equal dimensions to exactly coincide.
Have a look at this example https://jsfiddle.net/rbrv949d/
<canvas id="c" style="z-index: 1;"></canvas>
<canvas id="cover" style="z-index: 2;"></canvas>
JS onload
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var canover=document.getElementById('cover');
var ctxover = canvas.getContext('2d');
// Create an image element
var img = new Image();
// When the image is loaded, draw it
img.onload = function () {
ctx.drawImage(img, 0, 0);
ctxover.fillRect(0,0,10,10);
ctxover.fillRect(0,20,10,10);
}
// Specify the src to load the image
img.src = "http://www.experts-exchange.com/images/experts-exchange/experts-exchange-logo.png";
canvas.width=img.width;
canvas.height=img.height;
canover.width=img.width;
canover.height=img.height;
Here , ctxover.fillRect(xposition,yposition,widthinpixels,heightinpixels)
In your case,the xposition and yposition are the one fetched from json.
You can also draw those markings on the same canvas without using the overlayed canvas.Its upto you.Provided if you clear this canvas those markings will also get cleared unlike the other case :)
I'm trying to do a responsive canvas. All my tests has been doing with a 600x600 canvas and with that height and width it works OK and paint every line correctly. The problem is that I have tried this:
#myCanvas {
background-color: #ffffff;
border:1px solid #000000;
min-height: 600px;
height: 100%;
width: 100%;
}
Just for the record, myCanvas is inside a sm-col-8.
And it looks nice on my laptop and looks nice on my phone but (because of my draw() function, because it was thinking for a square) the draw starts more like in the down-left corner (nearby) and it should start at up-right corner.
So, I don't want to change my draw() function but what I'm looking for is to reescale the canvas size. I mean: If I'm in a laptop/tablet.. with 600x600, show it at that size, but if I'm on my phone which has 384x640 show it like 300x300? I don't know if it could be a good solution.
My draw function:
function drawLines(lines,i,table,xtotal,ytotal){
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var xIni;
var xFin;
var yIni;
var yFin;
xIni = (c.width*parseInt(lines[i][1])/xtotal);
yIni = (c.height*parseInt(lines[i][2])/ytotal);
xFin = (c.width*parseInt(lines[i][3])/xtotal);
yFin = (c.height*parseInt(lines[i][4])/ytotal);
ctx.beginPath();
ctx.moveTo(xIni,c.height-yIni);
ctx.lineTo(xFin,c.height-yFin);
ctx.lineWidth=4;
ctx.strokeStyle = colorAleatorio();
ctx.stroke();
}
With Bootstrap, use:
<canvas id="canvas" class='img-responsive' style="border: 1px solid black;"></canvas>
You can make your html Canvas responsive by using the context.scale command.
The .scale command will scale the internal coordinates system used by canvas.
This means you do not need to change any of your own drawing coordinates because canvas will automatically transform your coordinates into scaled canvas coordinates for you.
// save the original width,height used in drawLines()
var origWidth=600;
var origHeight=600;
var scale=1.00;
// reference to canvas and context
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// call this after resizing
// send in the new maximum width,height desired
function resizeAndRedraw(newMaxWidth,newMaxHeight){
// calc the global scaling factor that fits into the new size
// and also maintains the original aspect ratio
scale=Math.min((newMaxWidth/origWidth),(newMaxHeight/origHeight))
// resize the canvas while maintaining correct aspect ratio
canvas.width=origWidth*scale;
canvas.height=origHeight*scale;
// Note: changing the canvas element's width or height will
// erase the canvas so you must reissue all your drawing commands
drawLines(lines,i,table,xtotal,ytotal);
}
// call drawLines
function drawLines(lines,i,table,xtotal,ytotal){
// scale the canvas coordinate system to the current scale
// Note: This scales the coordinates used internally
// by canvas. It does not resize the canvas element
ctx.scale(s,s);
// now do your drawing commands
// You do not need to adjust your drawing coordinates because
// the Canvas will do that for you
var xIni;
var xFin;
var yIni;
var yFin;
xIni = (c.width*parseInt(lines[i][1])/xtotal);
yIni = (c.height*parseInt(lines[i][2])/ytotal);
xFin = (c.width*parseInt(lines[i][3])/xtotal);
yFin = (c.height*parseInt(lines[i][4])/ytotal);
ctx.beginPath();
ctx.moveTo(xIni,c.height-yIni);
ctx.lineTo(xFin,c.height-yFin);
ctx.lineWidth=4;
ctx.strokeStyle = colorAleatorio();
ctx.stroke();
// restore the context to it's unscaled state
ctx.scale(-s,-s);
}