In this jsFiddle I have a Fabric rect that can be dragged. What I need to know is how much the rect was dragged horizontally (X) and vertically (Y).
I'm capturing the moving event, but I have trouble finding the shift in X and Y. How to print the X/Y measure taken from the event? Note that the initial position is x=50, y=50. if I move the rect, then stop and then move again, the shift should be relative to x=50, y=50.
var canvas = new fabric.Canvas('c');
var coords = new fabric.Textbox("not moved yet", {
fontSize: 16,
width: 300
});
var text = new fabric.Textbox("Drag me", {
left: 50,
top: 50,
width: 100,
backgroundColor: 'yellow',
});
canvas.add(coords,text);
canvas.on('object:moving', function(e) {
console.log(e);
var x = e.target.transform.ex;
var y = e.target.transform.ey;
coords.text = 'Moved x = ' + x + ', y = ' + y;
});
You can keep track of the change yourself, just save the initial coordinates into separate variables.
let lastX = text.left
let lastY = text.top
canvas.on('object:moving', function (e) {
const diffX = e.target.left - lastX
const diffY = e.target.top - lastY
coords.text = 'Moved x = ' + diffX + ', y = ' + diffY
})
Related
I have 2 canvas elements on top of each other and i want to move the canvas element on top on mouse drag but it produces weird results.
This is my code for the events (the variable cvs is the canvas element which is on top of other canvas element)
var drag = false;
cvs.addEventListener('mousedown', function(event) {
drag = true;
});
cvs.addEventListener('mouseup', function(event) {
drag = false;
});
cvs.addEventListener('mousemove', function(event) {
if (drag) {
const rect = cvs.getBoundingClientRect()
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
cvs.style.left = x + "px";
cvs.style.top = y + "px";
console.log(x, y);
}
});
When I drag the top canvas it starts to flicker back-and-forth between 2 positions
At a glance, it looks like you are using a relative value to set an absolute position.
So, first iteration, the left position updates to x, then the next iteration you subtract the last value of x from the mouse position. I think this is going to move it on and off screen.
say, clientX is at 100, and left is at 10.
T1 -> x = 100 - 10 = 90,
T2 -> x = 100 - 90 = 10.
Hence the "flickering"
What you want to do, is take the relative movement value of the mouse and move the element by the same amount.
So on mouse down, record the mouse initial position and element initial position.
Subtract the initial mouse position from the mouse position on each mouse move iteration, and assign the initial element position plus the relative change to the element.
var initialPosition = null
var initialMouseCoords = null
cvs.addEventListener('mousedown', function(event) {
initialPosition = cvs.getBoundingClientRect()
initialMouseCoords = {clientX: event.clientX, clientY: event.clientY}
});
cvs.addEventListener('mouseup', function(event) {
initialPosition = null
initialMouseCoords = null
});
cvs.addEventListener('mousemove', function(event) {
if (initialMouseCoords) {
const dx = event.clientX - initialMouseCoords.clientX;
const dy = event.clientY - initialMouseCoords.clientY;
cvs.style.left = initialPosition.left + dx;
cvs.style.top = initialPosition.top + dy;
console.log(dx, dy);
}
});
Bare in mind there are drag events depending on your use case, you might want to explore that as an alternative.
i am getting X,Y on single click.on the map with help of code bellow:
map.on('singleclick', function(event) {
var coordinate = event.coordinate;
}
This should do it
map.on('singleclick', function(event) {
var x = event.pixel[0];
var y = event.pixel[1];
var extent = ol.extent.boundingExtent([
map.getCoordinateFromPixel([x - 25, y - 25]),
map.getCoordinateFromPixel([x + 25, y - 25]),
map.getCoordinateFromPixel([x + 25, y + 25]),
map.getCoordinateFromPixel([x - 25, y + 25])
]);
}
I have created a circle slider using JavaScript, and I need it to act right if it gets zoomed in or out.
My issue is when the circle slider gets zoomed in eg. (zoom: 0.5) , the mouse event listener for the slider will not act probably.
This issue only happen if I set the the zoom property to less or bigger than 1 .
You can try and see the differences: https://jsfiddle.net/mqgfxkjf/8/
Change:
<div style="zoom: 1.0">
To:
<div style="zoom: 0.5">
And you will find that it's not acting right while moving the slider to all-directions.
Tested on Chrome
You have to scale the mouse position accordingly to the zoom value.
Let's say you have set zoom value to 0.5, you will have to scale the mouse position (x and y) with the same value. So in order to fix this exact problem, you can do something as simple as just dividing by the scale value: var mPos = {x: (e.clientX / 0.5) - elPos.x, y: (e.clientY / 0.5) - elPos.y };.
I highly suggest that you let the script handle the scale / zoom value so that you can set it as a variable in your script. I.e. something like this:
(function () {
var scaleValue = 0.5;
addZoom(scaleValue);
var $container = $('#container');
var $slider = $('#slider');
var sliderW2 = $slider.width()/2;
var sliderH2 = $slider.height()/2;
var radius = 200;
var deg = 0;
var elP = $('#container').offset();
var elPos = { x: elP.left, y: elP.top};
var X = 0, Y = 0;
var mdown = false;
$('#container')
.mousedown(function (e) { mdown = true; })
.mouseup(function (e) { mdown = false; })
.mousemove(function (e) {
if (mdown) {
var mPos = {x: (e.clientX / scaleValue) - elPos.x, y: (e.clientY / scaleValue) - elPos.y };
var atan = Math.atan2(mPos.x-radius, mPos.y-radius);
deg = -atan/(Math.PI/180) + 180; // final (0-360 positive) degrees from mouse position
X = Math.round(radius* Math.sin(deg*Math.PI/180));
Y = Math.round(radius* -Math.cos(deg*Math.PI/180));
$slider.css({ left: X+radius-sliderW2, top: Y+radius-sliderH2 });
// AND FINALLY apply exact degrees to ball rotation
$slider.css({ WebkitTransform: 'rotate(' + deg + 'deg)'});
$slider.css({ '-moz-transform': 'rotate(' + deg + 'deg)'});
//
// PRINT DEGREES
$('#value').html('angle deg= '+deg);
}
});
})();
function addZoom(scaleValue) {
$('#zoom-container').css('zoom', scaleValue);
}
Fiddle:
https://jsfiddle.net/mqgfxkjf/10/
Hitbox Overlay IIFE Code
//CSS Hitbox Solution 08-26-2015
//StackOverflow - https://stackoverflow.com/questions/32233084/show-an-element-without-hitbox-does-not-take-mouse-touch-input
//Detect MouseOver https://stackoverflow.com/questions/1273566/how-do-i-check-if-the-mouse-is-over-an-element-in-jquery
//Source: https://stackoverflow.com/questions/3942776/using-jquery-to-find-an-element-at-a-particular-position
//https://css-tricks.com/snippets/jquery/get-x-y-mouse-coordinates/
(function($) {
$.mlp = {
x: 0,
y: 0
}; // Mouse Last Position
function documentHandler() {
var $current = this === document ? $(this) : $(this).contents();
$current.mousemove(function(e) {
jQuery.mlp = {
x: e.pageX,
y: e.pageY
};
});
$current.find("iframe").load(documentHandler);
}
$(documentHandler);
$.fn.ismouseover = function(overThis) {
var result = false;
this.eq(0).each(function() {
var $current = $(this).is("iframe") ? $(this).contents().find("body") : $(this);
var offset = $current.offset();
result = offset.left <= $.mlp.x && offset.left + $current.outerWidth() > $.mlp.x && offset.top <= $.mlp.y && offset.top + $current.outerHeight() > $.mlp.y;
});
return result;
};
})(jQuery);
$('.notification-box').on("click", function() {
$("button").each(function(i) {
var iteratedButton = $('button:eq(' + i + ')');
var buttonID = iteratedButton.attr("id");
if (iteratedButton.ismouseover()) {
iteratedButton.toggleClass(buttonID);
}
});
});
Example 01: Overlay Example for context
Example 02: Concept for auto generating content - Derived from this stackoverflow question.
There is a way by which one can have multiple objects underneath an overlay that masks them. Then, there is a way to have the pointer interact with the elements underneath said overlay if the user clicks at the predetermined point. My question is, may someone please write the code that would, marry the concept of the <map> tag with the IIFE that detects if the point of reference the user clicked is that image and then, act as though it was clicked.
If that did not make sense, simply, I am looking for a process that deviates away from manually setting up coordinates for <area> or having to use tool (which are profound) such as http://www.image-maps.com/. Rather, we would let the pointer do all the work.
We have the following high utility + highly compatible methods: .offset(), .position(), elementFromPoint() and the ability to put elements behind a mask utilizing basic CSS.
So we could combine the IIFE Overlay hitbox method above + ???? = Profit (good bye mapping coordinates via <map>).
I just do not know what the ???? is. I do know that whatever the solution is, I would prefer that it works in all browsers (including IE 5).
Lastly, the process should be fairly automatic in design, setup and implementation.
Whoever creates it, please dub it autoMapperJs (as it would not be limited to images).
Update:
A core feature component of the ???? has been realized as noted by #Alex in the comments. CreateJs notices when the pointer is hovered over a non-transparent area of a image. That is powerful and should be standard in the tool created. It also seems to utilize .mousemove() and z-index. Please keep commenting, as collectively, I feel a solution can be found.
Here's a start. Put images into an array of layers and placements on canvas then run through them on mouse over for hit. Also put over images in layers array to draw that image when hit.
var can = document.getElementById('image-map');
var W = can.width;
var H = can.height;
var ctx = can.getContext('2d');
var layers = [];
var mouse = {x:0,y:0};
can.addEventListener('mousemove', function(evt) {
mouse = getMousePos(can, evt);
drawCanvas();
}, false);
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
main();
function main() {
initLayers();
drawCanvas();
}
function drawCanvas() {
ctx.clearRect(0, 0, W, H);
var hit = -1;
for (var i =layers.length; i--;) {
var c = layers[i];
if(maskHit(c.img, c.x, c.y)) {
hit = i;
break;
}
}
for (var i =0; i < layers.length; i++) {
var c = layers[i];
var img = hit === i ? c.hov : c.img;
ctx.drawImage(img, c.x, c.y);
}
ctx.drawImage(circ(10,"rgba(255,200,0,.75)"), mouse.x-10/2,mouse.y-10/2);
}
// UTILITY TO DRAW SAMPLE IMAGES
function circ(size, color) {
var can = document.createElement('canvas');
can.width = can.height = size;
var to_rad = Math.PI / 180;
var ctx = can.getContext('2d');
ctx.beginPath();
ctx.moveTo(size, size / 2);
ctx.arc(size / 2, size / 2, size / 2, 0, 360 * to_rad);
ctx.fillStyle = color;
ctx.fill();
return can;
}
function initLayers() {
var s = 75; // size
// PUT YOUR IMAGES IN A LAYERS ARRAY WITH X,Y COORDS FOR CANVAS
// PLACEMENT. X AND Y ARE TOP LEFT CORNDER OF IMAGE. STORE HOVER
// IMAGE FOR MOUSE HIT.
layers = [{
img: circ(s, "#090"),
hov: circ(s, "#C0C"),
x: 123,
y: 12
}, {
img: circ(s, "#F00"),
hov: circ(s, "#C0C"),
x: 63,
y: 12
}, {
img: circ(s, "#00F"),
hov: circ(s, "#C0C"),
x: 3,
y: 12
}];
}
var maskCan = document.createElement("canvas");
maskCan.width=maskCan.height=1;
var maskCtx = maskCan.getContext('2d');
function maskHit(img, x, y) {
// get relative coords to image upper left corner
x = mouse.x - x;
y = mouse.y - y;
if (x < 0 || y < 0 || x > img.width || y > img.height) return false;
//return 1; // square hit, no alpha check
// ALPHA CHECK - draw one pixel, get and check alpha.
// sx sy sw sh dx dy dw dh
maskCtx.clearRect(0,0,1,1);
maskCtx.drawImage(img, x, y, 1, 1, 0, 0, 1, 1);
var imageData = maskCtx.getImageData(0,0,1,1);
//console.log(imageData.data[3])
return imageData.data[3] === 255;
}
#image-map {
border: 1px solid #ACE;
}
<canvas id="image-map" width="200" height="100"></canvas>
im stuck resolving an issue.
i want to build a bar chart using raphaeljs or another, the main funccionality is that once drawn, the bars should be resizable by the mouse dragging and be able to get their current value once the drag stopped.
i have tried the bellow code but its not working.
function drawchart()
{
var data = [1,2,3];
/*
* Create an instance of raphael and specify:
* the ID of the div where to insert the graph
* the width
* the height
* Tip: Remember that the reference point (0, 0) is at the top left position.
*/
var r = Raphael("holder",600,300);
// start, move, and up are the drag functions
start = function () {
// storing original coordinates
this.ox = this.attr("x");
this.oy = this.attr("y");
this.attr({opacity: 1});
this.sizer.ox = this.sizer.attr("x");
this.sizer.oy = this.sizer.attr("y");
this.sizer.attr({opacity: 1});
},
move = function (dx, dy) {
// move will be called with dx and dy
this.attr({x: this.ox + dx, y: this.oy + dy});
this.sizer.attr({x: this.sizer.ox + dx, y: this.sizer.oy + dy});
},
up = function () {
// restoring state
this.attr({opacity: .5});
this.sizer.attr({opacity: .5});
},
rstart = function () {
// storing original coordinates
this.ox = this.attr("x");
this.oy = this.attr("y");
this.box.ow = this.box.attr("width");
this.box.oh = this.box.attr("height");
},
rmove = function (dx, dy) {
// move will be called with dx and dy
this.attr({x: this.ox + dx, y: this.oy + dy});
this.box.attr({width: this.box.ow + dx, height: this.box.oh + dy});
};
var chart = r.g.barchart(5, 5, 200, 280, data, {stacked: false, type: "square"}).label(['a','b','c']);
chart.drag(move, start, up);
chart.hover(function() {
// Create a popup element on top of the bar
this.flag = r.g.popup(this.bar.x, this.bar.y, (this.bar.value || "0") + "%").insertBefore(this);
}, function() {
// hide the popup element with an animation and remove the popup element at the end
this.flag.animate({opacity: 0}, 300, function () {this.remove();});
});
/*
* Define the default text attributes before writing the labels
*/
r.g.txtattr = {font:"12px Fontin-Sans, Arial, sans-serif", fill:"#000", "font-weight": "bold"};
// iterate over all the bar
for (var i = 0; i < chart.bars[0].length; i++) {
var bar = chart.bars[0][i];
// if the value of the bar is greater or equals to 15 we change the color to red
if (bar.value >= 15) {
bar.attr("fill", "#bf2f2f");
bar.attr("stroke", "#bf2f2f");
}
}
}
any kind of help will be appreciated.
thanks in advance