Extract value of png image pixel in javascript - javascript

In javascript I am trying to extract the (R, G, B) value of a clicked pixel from the following image:
http://map1.vis.earthdata.nasa.gov/wmts-webmerc/MODIS_Terra_Snow_Cover/default/2015-05-25/GoogleMapsCompatible_Level8/8/97/49.png
I am using the element and I set the crossOrigin="anonymous" attribute so that I can work with the data.
Here is my html and javascript code:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
<img src="http://map1.vis.earthdata.nasa.gov/wmts-webmerc/MODIS_Terra_Snow_Cover/default/2015-05-25/GoogleMapsCompatible_Level8/8/97/49.png"
crossOrigin="anonymous" width="256" height="256">
<pre id="output"></pre>
<script>
$(function() {
$('img').click(function(e) {
if(!this.canvas) {
this.canvas = $('<canvas/>').css({width:256 + 'px', height: 256 + 'px'})[0];
this.canvas.getContext('2d').drawImage(this, 0, 0, 256, 256);
}
var offX = (e.offsetX || e.clientX - $(e.target).offset().left);
var offY = (e.offsetY || e.clientY - $(e.target).offset().top);
console.log(offX + ' ' + offY);
var pixelData = this.canvas.getContext('2d').getImageData(offX, offY, 1, 1).data;
$('#output').html('offX:' + offX + ' offY:' + offY +
'<br>R: ' + pixelData[0] +
'<br>G: ' + pixelData[1] +
'<br>B: ' + pixelData[2] +
'<br>A: ' + pixelData[3]);
});
});
</script>
</body>
</html>
I've also put my code on jsfiddle:
http://jsfiddle.net/32beaobL/
The problem is that this code gets the correct RGB value of the clicked pixel only until around row 149 of the image. for rows 149 and greater, it returns (0,0,0) for any pixel even though the pixel has a non-white color.
Any idea what's going on?

You resized the canvas with CSS, so the canvas was never over 150px tall (default canvas size is 300 x 150).
Here is your example fixed: http://jsfiddle.net/32beaobL/1/
This is the code that changed
if(!this.canvas) {
this.canvas = document.createElement('canvas');
this.canvas.width = 256;
this.canvas.height = 256;
this.canvas.getContext('2d').drawImage(this, 0, 0, 256, 256);
}

Related

how to pass a value from Js to PHP within the same page [duplicate]

This question already has answers here:
Passing variable from JS to PHP within the same page [closed]
(2 answers)
How do I pass JavaScript variables to PHP?
(16 answers)
Closed 1 year ago.
I have a Canvas and I already drew my circles there (centers and radius from MySQL DB).
Also, the circles are filled in red under some conditions (from DB).
Now I have to do this:
when the user clicks on a red circle, I should show a popup (I thought to an alert) with data taken from MySQL
I'm already able to locate, with Javascript, the coordinates of the pixel the user clicks and I'm able to get the color of that pixel.
What I would need is:
if the pixel is red I should pass that info to PHP (same page) and then I should get some data from DB.
I found lots of functions on the web, Ajax or JQuery, but I'm really unable to integrate into my PHP...
my relevant code below:
//this Js function get the coordinates and the color of the pixel where the user clicks
<script language="javascript">
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
//console.log("x: " + x + " y: " + y);
var ctx = canvas.getContext("2d");
ctx.beginPath();
var pixel = ctx.getImageData(x, y, 1, 1).data;
var hex = "#" + ("000000" + rgbToHex(pixel[0], pixel[1], pixel[2])).slice(-6);
alert("x: " + x + " y: " + y + " hex: " + hex);
}
</script>
...
// draw the canvas and listen for the event mousedown
<?php
echo("<div id='text' style='text-align:center;'>");
echo("<canvas id='myCanvas' width='400' height='600' style='border:1px solid #000000;'></canvas>");
?>
<script>
var canvas = document.getElementById('myCanvas');
canvas.addEventListener("mousedown", function (e) { getCursorPosition(canvas, e);});
</script>
<?php
echo("</div>");
...
//loop getting centers and radius from DB and draws the circles on the canvas
$sqltextval = "SELECT * FROM table WHERE col='somevalue'";
$connval = mysqli_query($id,$sqltextval);
if ($rowval = mysqli_fetch_object($connval))
{
//fill circle in red
echo("<script type='text/javascript'>");
echo("fill_circle($X, $Y, $radius);");
echo("</script>;");
}
else
{
//circle not filled in
echo("<script type='text/javascript'>");
echo("draw_circle($X, $Y, $radius);");
echo("</script>;");
}
I suggest you try fetch
const componentToHex = c => {
let hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex
};
const rgbToHex = (r, g, b) => "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
function getCursorPosition(canvas, event) {
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
//console.log("x: " + x + " y: " + y);
var ctx = canvas.getContext("2d");
ctx.beginPath();
var pixel = ctx.getImageData(x, y, 1, 1).data;
var hex = "#" + ("000000" + rgbToHex(pixel[0], pixel[1], pixel[2])).slice(-6);
return "x: " + x + " y: " + y + " hex: " + hex;
}
var canvas = document.getElementById('myCanvas');
canvas.addEventListener("mousedown", function(e) {
const pos = getCursorPosition(canvas, e);
console.log(pos);
// uncomment next line to send to server
// fetch('server.php?' + new URLSearchParams({ pos: pos }))
});
<div id='text' style='text-align:center;'>
<canvas id='myCanvas' width='400' height='600' style='border:1px solid #000000;'></canvas>
</div>

How to get drawline to work in Internet Explorer?

I have a function that draws a line inside a div (adapted from this solution), used in an e-learning module (explains the weird parts of the code).
My problem is that it doesn't seem to work in IE11.
Here is the code:
var player = GetPlayer();
var progress = player.GetVar("score");
var h = 600; //the height of your slide, as set in Story Size
var w = 1000; //the width of your slide, as set in Story Size
var t = 4; //the desired thickness of the progress bar in px, as based on the size of the styry slide
var c = "#00cc3399"; //the desired color of the progress bar, in hex. The last 2 digits are opacity. See codes below:
var startY = 40; //the desired start coordinate, from the top of the page
var startX = 0; //the desired start coordinate, from the left side of the page. Set to "0" as standard
var aspectRatio = h/w;
var totalW = $('.slide-container').width(); //get the actual width of the slide. only relevant if storyline is set to "Scale to fill browser window"
var totalH = totalW*aspectRatio; //calculate the actual height of the slide. only relevant if storyline is set to "Scale to fill browser window"
console.log("totalW: " + totalW);
var wFactor = totalW/w; //used to calculate the x-position on the slide. only relevant if storyline is set to "Scale to fill browser window"
var hFactor = totalH/h //used to calculate the y-position on the slide. only relevant if storyline is set to "Scale to fill browser window"
var endPointX = totalW*progress/100; //calculate the length of the progress bar
var endPointY = startY*hFactor; //calculate y-position, based on where you want it to be on the slide. The number is the position on the slide, as seen from the top. This is based on a horizontal progress bar
console.log("endPointX: " + endPointX + ", endPointY: " + endPointY)
x1 = startX, y1 = startY, //Start of the bar
x2 = endPointX, y2 = endPointY; //end of the bar
drawline(x1, y1, x2, y2);
//all the technical stuff:
function drawline(ax, ay, bx, by) {
console.log('ax: ' + ax);
console.log('ay: ' + ay);
console.log('bx: ' + bx);
console.log('by: ' + by);
if (ax > bx) {
bx = ax + bx;
ax = bx - ax;
bx = bx - ax;
by = ay + by;
ay = by - ay;
by = by - ay;
}
console.log('by: ' + by);
var angle = Math.atan((ay - by) / (bx - ax));
angle = (angle * 180 / Math.PI);
angle = -angle;
var length = Math.sqrt((ax - bx) * (ax - bx) + (ay - by) * (ay - by));
console.log('length: ' + length);
var style = ""
style += "left:" + (ax) + "px;"
style += "top:" + (ay) + "px;"
style += "width:" + length + "px;"
style += "height:"+t*hFactor+"px;" //set the thickness of the progress bar
style += "background-color:"+c+";"
style += "position:absolute;"
style += "transform:rotate(" + angle + "deg);"
style += "-ms-transform:rotate(" + angle + "deg);"
style += "transform-origin:0% 0%;"
style += "-moz-transform:rotate(" + angle + "deg);"
style += "-moz-transform-origin:0% 0%;"
style += "-webkit-transform:rotate(" + angle + "deg);"
style += "-webkit-transform-origin:0% 0%;"
style += "-o-transform:rotate(" + angle + "deg);"
style += "-o-transform-origin:0% 0%;"
style += "z-index:99;"
$("<div id='progressBar' style='" + style + "'></div>").appendTo('.slide-container');
};
In chrome this function draws a line based on the user's score. In IE nothing happens.
I found the solution myself. It turns out that IE redefined the 8-digit HEX value to RGBa, and turned it white. Replacing the 8-digit HEX value with it's corresponding RGBa value made it work.

Can I get the size of an html element in screen pixels (not abstract html pixels)?

I wish to use javascript to render a bitmap in a canvas at screen resolution, whatever the zoom level. Is there a way to do it?
I found a similar unanswered question there:
How to get size of an element in physical pixels?
I noticed that html pixels match physical pixels at the default zoom level in Firefox on my desktop. But if I zoom in or out, then they don't match any more. Is there a way to know the zoom level?
Edit: here is my best attempt so far. It does not work with Chrome on Android:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<p id="myp"></p>
<p id="resize"></p>
<canvas id="canvas" width="1" height="1" style="width:50%"></canvas>
<script type="text/javascript">
function reDraw(id)
{
canvas = document.getElementById(id);
rect = canvas.getBoundingClientRect();
size = Math.round((rect.right - rect.left) * window.devicePixelRatio);
canvas.width = size
canvas.height = size
context = canvas.getContext("2d");
imageData = context.createImageData(size, size);
for (i = 0; i < size * size; i++)
{
j = (i / size) + (i % size);
imageData.data[4 * i + 0] = 255*(j & 1);
imageData.data[4 * i + 1] = 255*(j & 1);
imageData.data[4 * i + 2] = 255*(j & 1);
imageData.data[4 * i + 3] = 255;
}
context.putImageData(imageData, 0, 0);
document.getElementById("myp").innerHTML =
"devicePixelRatio = " + window.devicePixelRatio + "; bitmap size = " + size;
}
var x = 0;
function refresh()
{
x += 1;
document.getElementById("resize").innerHTML = "resize counter: " + x;
reDraw("canvas");
}
window.addEventListener('resize', refresh);
refresh()
</script>
</body>
</html>
window.devicePixelRatio returns a ratio of physical pixels to CSS pixels. On desktop this will usually be the zoom level, on mobile devices it is approximately a ratio of device resolution to 96dpi but it varies highly between the vendors.

How do I dynamically scale elements in a specific Javascript that only uses pixels?

I am trying to use the jQuery plugin: Floating boxes with easing and motion-blur in jQuery By: Marcell Jusztin.
I have it working just fine and understand how to tweak most attributes, but I am a Javascript rookie and really do not understand the mechanics involved in changing how it uses math to place the elements I want to animate. What I want to do is change the set x and y offset coordinates (which are in pixels of course) to a set of percentages so that the elements will dynamically scale in position based on screen resolution. Here is the script in its entirety:
jQuery.fn.floatingBox = function ( userOptions ) {
options = jQuery.extend ({
parent : 'backdrop',
stage : 'backdrop',
scale : 0.3,
xOffset : 0,
yOffset : 0,
blur : false,
isText : false,
blurColor : '#888',
frameRate : 40,
}, userOptions);
var parent = options.parent;
var stage = options.stage;
var scale = options.scale;
var xOffset = options.xOffset;
var yOffset = options.yOffset;
var blur = options.blur;
var isText = options.isText;
var blurColor = options.blurColor;
var frameRate = options.frameRate;
var midX = $('#' + stage).width() / 2;
var midY = $('#' + stage).height() / 2;
var _x = midX;
var _y = midY;
var xx = midX;
var yy = midY;
var objectId = $(this).attr('id');
$('#' + objectId).css('position','absolute');
shadowAmount = 0;
window["timer" + objectId] = window.setInterval(update,frameRate);
$('#' + parent).mousemove(function(event){
_x = event.pageX;
_y = event.pageY;
if( shadowAmount < 5 && blur == true ) shadowAmount += scale;
});
factor = scale * 0.5;
function update() {
xx += (((_x - midX) * -scale) - xx) * factor;
yy += (((_y - midY) * -scale) - yy) * factor;
$('#' + objectId).css('left', xx + xOffset + $('#' + parent).position().left);
$('#' + objectId).css('top', yy + yOffset + $('#' + parent).position().top);
if(blur){
if(!isText){
$('#' + objectId).css('box-shadow', '0px 0px ' + shadowAmount + 'px ' + blurColor );
$('#' + objectId).css('-moz-box-shadow', '0px 0px ' + shadowAmount + 'px ' + blurColor );
$('#' + objectId).css('-webkit-box-shadow', '0px 0px ' + shadowAmount + 'px ' + blurColor );
$('#' + objectId).css('-o-box-shadow', '0px 0px ' + shadowAmount + 'px ' + blurColor );
}else{
$('#' + objectId).css('text-shadow', '0px 0px ' + shadowAmount + 'px ' + blurColor );
}
if(shadowAmount > 0 ) shadowAmount -= scale;
}
}
}
Here is the script that initiates the javascript in the HTML document:
<script type="text/javascript">
jQuery(function(){
$('#biglogo').floatingBox({
scale : 0.09,
blur : false,
isText : false,
xOffset : 400,
yOffset: 200,
});
$('#biglogo2').floatingBox({
scale : 0.08,
blur : false,
isText : false,
xOffset : 405,
yOffset: 205,
});
});
</script>
I have two transparent png files that are layered over each other with a minor offset of 5 pixels (or maybe its considered 10), but would rather the two images be centered in all browser windows and not just mine. The scale indicates how fast and far the elements move. The xOffset and yOffset parameters are of course fixed numbers that don't scale based on browser window size.
I have attempted to research this but ultimately, I'm neither finding that it can't be done, nor that it can because no one response seems to address the specific issue I am having. Perhaps I am not wording it correctly.
Thanks!
From the looks of the script I would say that it already takes the necessary calculations into accout. Try setting the parent and stage options and leave out the offset parameters. I.e
$('#biglogo').floatingBox({
parent: 'container-id',
stage: 'container-id',
scale: 0.09,
blur: false,
isText: false
});
Edit: I created a fiddle with some modifications to the plugin that shows how to get centering working, http://jsfiddle.net/wwBJt/

Error when trying to make a canvas

I'm trying to use <canvas> to construct a grid. Please note - the code below is not my code and I remember finding it on stack overflow somewhere:
Here is my error:
Cannot call method 'getContext' of undefined
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
background: lightblue;
}
canvas {
background: #fff;
margin: 20px;
}
</style>
<!-- JQ Lib -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script type="text/javascript">
//grid width and height
var bw = 400;
var bh = 400;
//padding around grid
var p = 10;
//size of canvas
var cw = bw + (p*2) + 1;
var ch = bh + (p*2) + 1;
var canvas = $('#canvas').attr({width: cw, height: ch}).appendTo('body');
var context = canvas.get(0).getContext("2d");
function drawBoard(){
for (var x = 0; x <= bw; x += 40) {
context.moveTo(0.5 + x + p, p);
context.lineTo(0.5 + x + p, bh + p);
}
for (var x = 0; x <= bh; x += 40) {
context.moveTo(p, 0.5 + x + p);
context.lineTo(bw + p, 0.5 + x + p);
}
context.strokeStyle = "black";
context.stroke();
}
drawBoard();
</script>
</head>
<body>
<canvas id="canvas"> </canvas>
</body>
</html>
The error is originating on this line:
var canvas = $('#canvas').attr({width: cw, height: ch}).appendTo('body');
I have tried many different ways of doing this, but I keep getting the above error. Am I just making a mindless mistake here?
You haven't defined $, which is a common (but meaningless) variable name used by a variety of different libraries including Protoype.js, Mootools and jQuery.
That syntax looks like jQuery so you will need to include the script for that library or rewrite it using built-in functions.

Categories

Resources