Javascript / HTML5 - Canvas get selected objects dimensions - javascript

I have an image in a canvas. The image contains squares of different colors. I'd to click on a square and get the dimensions of the square. (pixels)
For example click on a red square with yellow border and return 24 X 100
I have seen code like this . which I think is part of the solution.... but can't seem to get it work.
Any ideas?
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
// Let's draw a green square
ctx.fillStyle = "rgb(0,127,0)";
ctx.fillRect(10, 10, 20, 20);
// We will now get two pixels, the first one filling inside the above square and the other outside the square
var Pixel = ctx.getImageData(29, 10, 2, 1);
// Let's print out the colour values of the first pixel. Since we have set the colour of the
// square as rgb(0,127,0), that is what the alert should print out. Since we have not set
// any alpha value, Pixel.data[3] should be the defualt 255.
alert("Pixel 1: " + Pixel.data[0] + ", " + Pixel.data[1] + ", " + Pixel.data[2] + ", " + Pixel.data[3]);
// Print out the second pixel, which is outside the square.
// since we have drawn nothing there yet, it will show the default values 0,0,0,0 (Transparent Black)
alert("Pixel 2: " + Pixel.data[4] + ", " + Pixel.data[5] + ", " + Pixel.data[6] + ", " + Pixel.data[7]);
// Let's get the width and height data from Pixel
alert("Pixels Width: " + Pixel.width);
alert("Pixels Height: " + Pixel.height);
}
}

You could use .getImageData, but there's a much easier way...
Save the information about each square you're drawing in an object:
var green={x:10,y:10,width:20,height:20,color:"rgb(0,127,0)"};
Put all objects in an array:
var squares=[];
squares.push(green);
Then when the user clicks, enumerate all the saved squares and see if the mouse is over one:
for(var i=0;i<squares.length;i++){
var s=squares[i];
if(mouseX>=s.x && mouseX<=s.x+s.width && mouseY>=s.y && mouseY<=s.y+s.height){
alert("You clicked on a square with size: "+s.width+"x"+s.height);
}
}
[ Addition based on questioner's comment (that comment was deleted by questioner) ]
Questioner's deleted comment:
What if I don't have info on the squares. The squares are from a photo?
Assuming the canvas contains colored rectangles, here's how to calculate the width x height of the colored rectangle containing the specified x,y coordinate:
function calcColorBounds(x,y){
var data=ctx.getImageData(0,0,canvas.width,canvas.height).data;
var n=i=(y*canvas.width+x)*4;
var r=data[i];
var g=data[i+1];
var b=data[i+2];
var minX=x;
while(minX>=0 && data[i]==r && data[i+1]==g && data[i+2]==b){
minX--;
i=(y*canvas.width+minX)*4;
}
i=n;
var maxX=x;
while(maxX<=canvas.width && data[i]==r && data[i+1]==g && data[i+2]==b){
maxX++;
i=(y*canvas.width+maxX)*4;
}
i=n;
var minY=y;
while(minY>=0 && data[i]==r && data[i+1]==g && data[i+2]==b){
minY--;
i=(minY*canvas.width+x)*4;
}
i=n;
var maxY=y;
while(maxY<=canvas.height && data[i]==r && data[i+1]==g && data[i+2]==b){
maxY++;
i=(maxY*canvas.width+x)*4;
}
alert("size",maxX-minX-1,"x",maxY-minY-1);
}

Related

Fabric.js: Problem while resizing the rectangle

Code: https://codepen.io/eajithkumar128/pen/poNwJJv?editors=0010
I have a table like structure in the canvas drawn using a rectangle, I have drawn lines in the row and column ends like below (lines in blue color are rectangle and red color lines are the fabric line object)
I am trying to adjust the size of the rectangles by moving the lines, whenever I am moving the column lines I could see the entire rectangle itself moving wherein I am only trying to update the width, Also I could see an imaginary rectangle drawn behind it which has correct width, but the original rectangle is not resizing correctly. Please refer to the image below.
Code to get the rect object before and after lines while selecting the line:
canvas.on('selection:created', function(e){
let targetEle = e.target;
initialPosition = e.left;
selectedBoxesLeft = []
selectedBoxesRight = []
canvas.forEachObject((v)=>{
if(v.left+v.width === targetEle.left && v.type==="rect"){
selectedBoxesLeft.push(v);
}
if(v.left === targetEle.left && v.type==="rect"){
selectedBoxesRight.push(v);
}
});
console.log(selectedBoxesLeft);
console.log(selectedBoxesRight);
});
Code to resize while moving:
canvas.on('object:moving',function(e){
let target = e.target;
if(target.left < initialPosition){
selectedBoxesLeft.forEach((v)=>{
v.width =target.left - v.left
})
selectedBoxesRight.forEach((v)=>{
let left = v.left
v.left = target.left;
v.width = v.width + (left- target.left)
});
canvas.renderAll()
}else{
// selectedBoxesLeft.forEach((v)=>{
// v.width = v.width + (target.left - v.width)
// })
// selectedBoxesRight.forEach((v)=>{
// // v.width = v.width + (v.left - target.left)
// v.left = target.left;
// v.width = v.width - target.left;
// })
}
});
While Resizing the rectangle instead of using
v.width =target.left - v.left
changed it to
v.set('width', target.left - v.left)
resolved the issue

How to make a circle grow depending on how long the user holds (Java Script)

ok here is the deal, I want a circle to grow on a canvas depending on how long you hold your mouse button. I was able to make it draw a circle of fixed width where my mouse was when I clicked, but I want to be able to determine size based on how long I hold. Ideally, you will be able to see it grow as you hold.
CODE
var c = document.getElementById("canvas");
var ctx = c.getContext('2d');
document.addEventListener("mousedown", draw);
document.addEventListener("mousedown", time1);
document.addEventListener("mouseup", time2);
//Size
function time1(event) {
var a = new Date().getTime() + 1;
return a;
}
function time2(event) {
var b = new Date().getTime() + 4;
return b;
}
var c ="Time: " + (time2 - time1);
document.getElementById("time").innerHTML = c;
function draw(event, a , b) {
//Cords
var x = event.clientX;
var y = event.clientY;
//Fill
ctx.fillStyle = "#0c67f9";
//Draw
ctx.beginPath();
ctx.arc(x ,y ,(b - a),0,Math.PI * 2, true);
ctx.fill();
}
function showCoords(event) {
var x = event.clientX;
var y = event.clientY;
var coords = "X coords: " + x + ", Y coords: " + y;
document.getElementById("demo").innerHTML = coords;
}
/*function grow(event) {
var z = event.time;
}*/
<canvas id="canvas" width="690" height="651" onclick="showCoords(event)" style ="border: 1px solid #e21313"></canvas>
<p id="demo"></p>
<p id="time"></p>
Here is your groing circle:
Here
But I don't want to give you the copy & paste solution.
So with my help I believe you can figure it out.
First of all you need to change the event listener so it doesn't get triggered if you hold down your mouse somewhere in the html area (like it is now). Set it from $("html") to $("#your-canvas").
Since you also don't want to see your circle the whole time and it can't have a static position you also want to change the CSS attributes of the .dot class. I believe display: none; and position: absolute; will do.
The last thing you want to do is to get the exact mouse position (with offset and everything) and set it as CSS attributes top and left (don't forget to set the display: none to display: block).
Boom you got your growing circle.
However I didn't really understand what you mean by:
but I want to be able to determine size based on how long I hold.

javascript to add area element with onmouseover attribute

I am trying to add area elements to an image map dynamically. The image is set to display transparently superimposed over a canvas. My goal is to write text on the canvas, use the same coordinates to create the area element on the map, and draw a rectangle on the canvas surrounding the text when the user hovers over the text. (Ultimately I want it to trigger a tooltip, too.) I have done this already with the same map and canvas setup using area elements hardcoded in HTML.
My problem is that I can create the area, appendChild it to the map element and add attributes. However, mousing over the text never triggers the function call to draw the rectangle.
The function used to add the areas to the map (shown as cMap) is "addArea", and the function to draw the rectangle on the canvas (context is ctx) is "labelHover". I have tried every different syntax I have seen demonstrated for adding the .onmouseover attribute to the area, but the alert in the labelHover function never triggers.
function addArea(pX, lY, idX, tipText) {
var labelArea = document.createElement('area');
cMap.appendChild(labelArea);
labelArea.className = "labelArea";
var tlTipID = "tlTip" + idX;
labelArea.id = tlTipID;
labelArea.shape = "rect";
areaCoords = pX + "," + (lY + 42) + "," + (pX + 100) + "," + (lY + 54);
labelArea.coords = areaCoords;
// alert(labelArea.coords);
labelArea.onmouseover = function(){labelHover(pX, lY+42)};
labelArea.onmouseleave = function(){labelLeave(pX, lY+42)};
}
and
function labelHover(ulx,uly) {
ctx.lineWidth = "1";
ctx.strokeStyle = "#ff0000";
ctx.strokeRect(ulx,uly,100,12);
alert(ulx);
}
Thanks for any help.
try this:
labelArea.setAttribute('onmouseover', "labelHover('" + pX + "," + (lY+42) + "')");
labelArea.setAttribute('onmouseout', "labelLeave('" + pX + "," + (lY+42) + "')");

How to get images from a texture atlas with Javascript?

A spritesheet image object that contains sprites...
var spritesheet = new Image(); spritesheet.src ="foo.png";
I would like to be able to get a sub image from that spritesheet variable with the desired x, y, width, and height. And then assign a variable that is the sub image of the spritesheet.
How do I do that?
Using a div with backgroundPosition makes this easy since it will auto-clip for us without having to use overflow.
For example, here is the texture atlas from the popular Cookie Clicker idle game.
Using a negative offset for x and y we can select a sub-sprite from the texture atlas:
// Inputs -- change this based on your art
var tw = 48; // Texture Atlas Tile Width (pixels)
var th = 48; // Texture Atlas Tile Height (pixels)
var tx = 3; // tile index x (relative) (column)
var ty = 2; // tile index y (relative) (row)
var src = 'http://orteil.dashnet.org/cookieclicker/img/icons.png';
// Calculations -- common code to sub-image of texture atlas
var div = document.getElementById('clip');
var x = (tx*tw); // tile offset x position (absolute)
var y = (ty*th); // tile offset y position (absolute)
div.style.width = tw + 'px';
div.style.height = th + 'px';
div.style.backgroundImage = "url('" + src + "')";
div.style.backgroundPosition = '-' + x + 'px -' + y + 'px';
// You don't need the remaining parts. They are only to
// show the sub-sprite in relation to the texture atlas
div.style.border = "1px solid blue"; // only for demo purposes
// highlight where in the original texture the sub sprite is
var rect = document.getElementById('sprites').parentNode.getBoundingClientRect();
var hi = document.getElementById('highlight');
hi.style.zIndex = 999; // force to be on top
hi.style.position = "absolute";
hi.style.width = tw + 'px';
hi.style.height = th + 'px';
hi.style.left = (rect.left + x) + 'px';
hi.style.top = (rect.top + th + y) + 'px'; // skip sub-sprite height
hi.style.border = '1px solid red';
<div id="clip"></div>
<img id="sprites" src="http://orteil.dashnet.org/cookieclicker/img/icons.png">
<div id="highlight"></div>
Here's one way:
Create an in-memory canvas to clip the subsprite pixels from the spritesheet and draw those clipped pixels on that canvas
Create a new subsprite image from that canvas's dataURL.
Example code (not tested--may need tweeking):
var spritesheet = new Image();
spritesheet.onload=function(){
// specify desired x,y,width,height
// to be clipped from the spritesheet
var x=0;
var y=0;
var w=10;
var h=10;
// create an in-memory canvas
var canvas=document.createElement('canvas');
var ctx=canvas.getContext('2d');
// size the canvas to the desired sub-sprite size
canvas.width=w;
canvas.height=h;
// clip the sub-sprite from x,y,w,h on the spritesheet image
// and draw the clipped sub-sprite on the canvas at 0,0
ctx.drawImage(spritesheet, x,y,w,h, 0,0,w,y);
// convert the canvas to an image
var subsprite=new Image();
subsprite.onload=function(){ doCallback(subsprite); };
subsprite.src=canvas.toDataURL();
}
spritesheet.src ="foo.png";
function doCallback(img){
// do something with the new subsprite image
}

How to scale text using Raphael.js

I came to know about Raphael.js recently and I was trying to do some hands on.
I would like to scale a text but it is not working.
After searching a lot in Google I have not find any idea.
Code is:
var paper = Raphael("paper1", 1000,1000);
var txt = paper.text(20,50,"Hello World").attr({
"font-family":"Arial","font-size":"30px", "font-weight": "normal",
fill: "#000000", stroke:"black", "stroke-width": "0px",
"text-anchor" : "start" , "font-style": "normal"});
flip is working by txt.scale(-1,1)
but txt.scale(2,1) is not scaling the text.
Is there a way to scale a text?
Note: Font size of the text needs to remain same i.e 30px in my case.
Is there a way to scale a text?
DEMO
I checked and it works like a charm
var r = Raphael('test');
var t = r.text(200, 100, "I am a text").attr({fill:'red', 'font-size':30});
$('#zoomin').click(function() {
t.scale(2);
});
$('#zoomout').click(function() {
t.scale(.5);
});
If we scale the text only then font size shall be changed.
We need to convert the text into an image and the we need to scale it.
To do that I have used a hidden canvas.
Following code works for me.
<canvas id='textCanvas' style="display:none"></canvas>
<script>
var paper = Raphael("paper1", 1000,1000);
var img = paper.image(getTxtImg("Hello World","italic","bold","15px","arial",
"#000000",130,35),20,28,300,80)
img.scale(2,1) //Double in width
img.scale(.5,1) //Half in width
function getTxtImg(txt,style,weight,fontsize,fontfamily,color,w,h)
{
var tCtx = document.getElementById('textCanvas').getContext('2d');
tCtx.canvas.width = w;
tCtx.canvas.height = h ;
var fontstr = "" + style + " " + weight + " " + fontsize + " " + fontfamily + " ";
tCtx.font = fontstr
tCtx.fillStyle = color
tCtx.fillText(txt, 0, h);
return tCtx.canvas.toDataURL();
}
</script>

Categories

Resources