I'm having trouble getting the correct mouse coordinates on the canvas after preforming pan or zoom.
I have this code for sampling coordinates and RGB:
canvas1.on('mouse:move', function (e) {
//allowing pan only if the image is zoomed.
if (panning && e && e.e) {
var delta = new fabric.Point(e.e.movementX, e.e.movementY);
canvas1.relativePan(delta);
} else {//Read the RGB value of the mouse point
var mouse = canvas1.getPointer(e.e);
var x = parseInt(mouse.x);
var y = parseInt(mouse.y);
// get the color array for the pixel under the mouse
var px = ctx.getImageData(x, y, 1, 1).data;
// report that pixel data
results.innerHTML = 'At [' + x + ' / ' + y + ']: Red/Green/Blue/Alpha = [' + px[0] + ' / ' + px[1] + ' / ' + px[2] + ' / ' + px[3] + ']';
}
});
problem is that after zoom/pan the coordinates are 'wrong',
for example the top left corner in not (0, 0) but (-someX, -someY)...
any help will be appreciated
EDIT: I've found the mistake,
this will fix it. hope it will be useful for someone else
var x = e.e.offsetX;//parseInt(mouse.x);
var y = e.e.offsetY;//parseInt(mouse.y);
This code solves it,
Hope it could be useful for others.
canvas1.on('mouse:move', function (e) {
//allowing pan only if the image is zoomed.
if (panning && e && e.e) {
var delta = new fabric.Point(e.e.movementX, e.e.movementY);
canvas1.relativePan(delta);
} else {//Read the RGB value of the mouse point
var mouse = canvas1.getPointer(e.e);
var x = e.e.offsetX;//parseInt(mouse.x);
var y = e.e.offsetY;//parseInt(mouse.y);
// get the color array for the pixel under the mouse
var px = ctx.getImageData(x, y, 1, 1).data;
// report that pixel data
results.innerHTML = 'At [' + x + ' / ' + y + ']: Red/Green/Blue/Alpha = [' + px[0] + ' / ' + px[1] + ' / ' + px[2] + ' / ' + px[3] + ']';
}
});
Related
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>
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.
I like to make the aircraft follow the path. But whatever I have tried there is a shift between the transition path and the actual drawn path on the screen. Please look at the jsfiddle
d3.selectAll('.aircraft').transition()
.duration(7500)
.attrTween('transform', translateAlong(d3.select('#samplePath').node()))
function translateAlong(path) {
let l = path.getTotalLength()
// debugger
return function (i) {
return function (t) {
let p = path.getPointAtLength(t * l)
console.log(p.x, p.y)
return 'matrix(-0.359863 -0.230143 0.230143 -0.359863' + p.x + ' ' + p.y + ')'
}
}
}
You are missing a space after the second -0.359863 in the matrix definition:
return 'matrix(-0.359863 -0.230143 0.230143 -0.359863 ' + p.x + ' ' + p.y + ')'
Im trying to develop script where I can click on image and get the X/Y of the click. This part Ive implemented, the problem Im having occurs when I try to zoom the picture. Subseqent clicks on zoomed picture should return the same coordinates, and thats where I fail to success.
clicked(event) {
let pos_x = event.offsetX ? (event.offsetX) : event.pageX - document.getElementById("pointer_div").offsetLeft;
let pos_y = event.offsetY ? (event.offsetY) : event.pageY - document.getElementById("pointer_div").offsetTop;
let offsetLeft = document.getElementById("textLayer").offsetWidth;
let offsetTop = document.getElementById("textLayer").offsetHeight;
console.log("zoom " + this.zoom);
console.log("pozycja x " + event.clientX/this.zoom);
console.log("pozycja y " + event.clientY/this.zoom);
console.log("szerokosc elementu " + offsetLeft);
console.log("wysokosc elementu " + offsetTop);
}
zoomView(): void {
this.zoom = this.zoom + 2.0;
}
this is what ihve wrote. And the template to the component:
<pdf-viewer style="position: absolute" id="textLayer" [src]="'http://localhost:8080/get.pdf'"
[page]="page"
[original-size]="true"
style="display: block;"
[zoom]="[zoom]"
(click)="clicked($event)"
></pdf-viewer>
since Ive found a solution =>
var x = event.pageX - (document.getElementById("textLayer").offsetLeft);
var y = event.pageY - (document.getElementById("textLayer").offsetTop);
console.log("zoom " + this.zoom);
console.log("pozycja x " + x/this.zoom);
console.log("pozycja y " + y/this.zoom);
console.log("szerokosc elementu " + offsetLeft);
console.log("wysokosc elementu " + offsetTop);
console.log("wysokosc elementussssssssssssss " + offsetTop);
The penultimate line gives an "Invalid argument" error in IE11 - other browsers are fine run the code fine.
var active = $('.interactivemap-minimap-active', this.el);
if (x === undefined) x = self.x;
if (y === undefined) y = self.y;
var width = Math.round(self.container.width() / self.contentWidth / self.scale * this.el.width()),
height = Math.round(self.container.height() / self.contentHeight / self.scale * this.el.height()),
top = Math.round(-y / self.contentHeight / self.scale * this.el.height()),
left = Math.round(-x / self.contentWidth / self.scale * this.el.width()),
right = left + width,
bottom = top + height;
console.log("pass2: width=" + width + ", height=" + height + ", top=" + top + ", left=" + left + ", right=" + right + ", bottom=" + bottom);
active.each(function() {
$(this)[0].style.clip = 'rect(' + top + 'px, ' + right + 'px, ' + bottom + 'px, ' + left + 'px)';
});
the console.log will show:
width=Nan , height=Nan , top=Nan , left=Nan , right=Nan , bottom=Nan
If I comment out the troublesome line, the console.log will show:
width=Nan , height=Nan , top=Nan , left=Nan , right=Nan , bottom=Nan
width=140 , height=162 , top=-1 , left=0 , right=140 , bottom=161
So it looks like it takes a moment to populate those variables with actual data but it starts the last function when the are still equal to Nan and then errors.
Is there any way to get around this?