Change Right and Left click functionality on MapboxGl - javascript

I want to change mouse click functionality on mapboxGl. I need to implement right click panning on map, but there is no documentation about it. So I tried to disable map rotating on right click and enable panning but nothing worked, it just disabled rotation but panning is not triggered.
I want to know if there is a way to programmatically start and stop dragging/panning, I know you can enable it, but I need to actually start panning.
Want to make it clean and easy, I figured you can add listener on mousemove then change map boundaries but it doesn't look nice. Is there any easier way to start dragPan?

I don't know why you want to change left and right click if you want it for left-handed, they should change the mouse settings.
But, anyway, it's possible to make right click for dragging the map.
map.dragPan.disable();
map.dragRotate.disable();
var isMoving = false;
var offset;
map.on("contextmenu", (e) => {});
map.on("mousedown", (e) => {
if (e.originalEvent.button === 2) {
isMoving = true;
offset = e.point;
}
});
map.on("mousemove", (e) => {
if (isMoving) {
map.panBy([offset.x - e.point.x, offset.y - e.point.y], {
duration: 0,
});
offset = e.point;
}
});
map.on("mouseup", (e) => {
isMoving = false;
});
https://jsfiddle.net/cs09g/cnz4xhkt/4/

Related

Bootstrap 5.2, prevent closing tooltip if cursor is back on triggering element

TLDR: moving the cursor from tooltip back to triggering element closes, shows and closes the tooltip (flickers).
I need to make the tooltips open on hover and make their content clickable. I have found a working example here on SO.
As you hover over the element it shows you a tooltip which can be interacted with, once you move the cursor away from the tooltip it closes.
There is a problem though.
If you leave the tooltip and move the cursor back on the element which triggered the tooltip, the tooltip pops back up, but dissapears after a moment ("flickering"). You need to move the cursor away from the element and back on the element for the tooltip to show again.
What I am trying to do, is check if the cursor is back on the triggering element and if that is the case not run the closing function (tooltip.hide()).
I have tried to do this by imitating the existing process from the example found on SO. That is, check if the tooltip has lost :hover, setTimout (300ms) and check if cursor is now positioned on the triggering element or back on the tooltip.
Here is a jsFiddle example.
This is the code. The problematic code is between the two looong comment lines.
Note: Moving the cursor away from the triggering element and back on the triggering element also triggers the flickering.
//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
tt.setAttribute("data-bs-placement","top")
}
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl, {
trigger: "manual",
'customClass': 'custom-tooltip'
})
let tooltipElTimeout;
let currentToolTip;
let currentTooltipTimeout;
tooltipTriggerEl.addEventListener("mouseenter", function () {
let toolTipID;
// Clear Set Timeout
clearTimeout(currentTooltipTimeout);
// Show Tooltip
tooltip.show();
// Assign current tooltip ID to toolTipID variable
toolTipID = tooltipTriggerEl.getAttribute("aria-describedby");
// Assign current tooltip to currentToolTip variable
currentToolTip = document.querySelector(`#${toolTipID}`);
/*******************************************************************/
// Hide tooltip on tooltip mouse leave
currentToolTip.addEventListener("mouseleave", function () {
currentTooltipTimeout = setTimeout(()=>{
console.log("!currentToolTip.matches(':hover')");
console.log(!currentToolTip.matches(":hover"));
if(!tooltipTriggerEl.matches(":hover")){
console.log("!tooltipTriggerEl.matches(':hover')");
console.log(!tooltipTriggerEl.matches(":hover"));
if (!currentToolTip.matches(":hover")) {
tooltip.hide();
}
}
}, 300)
});
/***********************************************************************/
});
tooltipTriggerEl.addEventListener("mouseleave", function () {
// SetTimeout before tooltip disappears
tooltipTimeout = setTimeout(function () {
// Hide tooltip if not hovered.
if (!currentToolTip.matches(":hover")) {
tooltip.hide();
}
}, 100);
});
return tooltip;
})
Thank you
Edit:
Amine Ramouls answer is correct. isHidden also needs to bet set to false on the 2cnd eventListener, otherwise the tooltips no longer work (problem with aria-describedby).
in your code you have an event listener wich add an event listner and that's a big mistake because it add an infinit number of eveneent listner to your element.
so you juste have to organize your code like this :
//https://stackoverflow.com/questions/67993080/bootstrap-5-make-tooltip-hoverable-and-link-clickable
var tooltipTriggerList = [].slice.call(document.querySelectorAll('button'))
for (let tt of tooltipTriggerList){
tt.setAttribute("data-bs-placement","top")
}
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl, {
trigger: "manual",
'customClass': 'custom-tooltip'
})
let isHidden = true;
let currentTooltipTimeout;
tooltipTriggerEl.addEventListener("mouseenter", function () {
let toolTipID;
// Clear Set Timeout
clearTimeout(tooltipElTimeout);
clearTimeout(currentTooltipTimeout);
if (isHidden)
{
tooltip.show();
isHidden=false;
}
});
// Hide tooltip on tooltip mouse leave
tooltipTriggerEl.addEventListener("mouseleave", function () {
console.log("!currentToolTip.matches(':hover')");
if(!tooltipTriggerEl.matches(":hover")){
currentTooltipTimeout=setTimeout(()=>{
if (!isHidden && !tooltipTriggerEl.matches(":hover")){
tooltip.hide();
isHidden=true;
}
console.log("!tooltipTriggerEl.matches(':hover')");
console.log(!tooltipTriggerEl.matches(":hover"));
}, 3000)
}
});
return tooltip;
})
now as you can see i juste added the isHidden var to check if the popup info is hidden or not, you can do that with the element if you can get it by a query selector request. that's it. enjoy your life.
Edit: i forget to tell you that i have put 3 seconde before checking the if the popup is hidden or not.

Continue drag event without dragging an element further than an arbitrary threshold

I have an element with two markers over it. The first marker sets minimum value of something, and the second, maximum. That said, I want to prevent the "maximum" one be lower than "minimum" one. I'm using jQuery UI's draggable as a wrapper around HTML5 drag and drop, and here's my code:
component = {}; // actually, it's a real component but let's pretend it's simply a plain-object.
component.containerWidth = $('.marker').parent().width();
$('.marker').each(() => {
$(this).draggable({
containment: 'parent',
axis: 'y',
create: (event, ui) => {
if ($(this).hasClass('min')) {
component.minMarker = $(this).position().top;
} else if ($(this).hasClass('max')) {
component.minMarker = $(this).position().top;
}
},
drag: (event, ui) => {
const isDraggingMin = $(this).hasClass('min');
const isDraggingMax = $(this).hasClass('max');
const isMinLower = ui.position.top + $(this).height() <= component.maxMarker;
const isMaxHigher = ui.position.top - $(this).height() >= component.minMarker;
if (isDraggingMin && isMinLower) {
// set actual markers' positions
// do something
} else if (isDraggingMax && isMaxHigher) {
// set actual markers' positions
// do something
} else {
event.preventDefault();
}
}
});
});
The problem is that, when preventDefault gets invoked, the dragging doesn't work anymore until I stop dragging and start it over. It means, if I drag a "minimum" marker as close to "maximum" marker as event.preventDefault() gets fired, then no matter how and where I drag, the marker stays. If I release it and then start dragging again, it drags until it gets into the same conditions.
Simply setting css properties via $(...).css({left: ...}) does not work, and perhaps it shouldn't.
So how do I solve it then? How can I allow dragging without having user to release and grab a marker once in a while when they occasionally approach another marker?
The codepen: http://codepen.io/rishatmuhametshin/pen/WrvoKd
I have some other thing in mind for you,, see this code and I hope that can fit in your need,, or at least can help you to see this through another lens (I'm wearing glasses btw :)
http://codepen.io/mkdizajn/pen/bEdgLQ?editors=001
in place for that preventDefault call I used this peace of code:
$(event.target).css('top', $(event.target).data('startpos') )
in relation to:
$(event.target).data('startpos', ui.position.top);
My idea was to track start/stop evt and to do some stuff there,, you can see and read my comments on codepen,, hope that can be of some help,
cheers, k
You need to change your if statement to this, and get rid of the preventDefault:
if ( draggingMin ) {
if ( isMinLower ) {
component.minPosition = ui.position.top;
} else {
ui.position.top = component.minPosition;
}
} else if (draggingMax) {
if( isMaxHigher ){
component.maxPosition = ui.position.top;
} else {
ui.position.top = component.minPosition;
}
}

Move image to specified minimum value

I have the code
$(document).keydown(function (key) {
switch (parseInt(key.which, 10)) {
case 38://up
mObj.animate({
top: "-=100px"
});
mObj.animate({
top: "+=" + change + "px"
});
break;
default:
break;
}
});
Which moves my image up and down correctly upon the up button, given the up button is not pressed again while Mario is in the air. I would like to remedy this condition (not being able to click up while Mario is in the air) through a method such as the attempted in lines 43-46 of my code found here.
In essence I want to allow Mario to simply fall all the way back down to a set minimum level when not being moved up. Any help on getting it to do this or pointing out why my alternate method (the one commented out in lines 43-46) doesn't work?
As an immediate solution, you could try using this:
$(document).ready(function () {
var jumping = false;
$(document).keydown(function (key) {
switch (parseInt(key.which, 10)) {
case 38://up
if (!jumping) {
jumping = true;
var jumpUp = new $.Deferred();
var jumpDown = new $.Deferred();
mObj.animate({
top: "-=100px"
}, {
done: function () {
jumpUp.resolve();
}
});
mObj.animate({
top: "+=" + change + "px"
}, {
done: function () {
jumpDown.resolve();
}
});
$.when(jumpUp, jumpDown).done(function () {
jumping = false;
});
}
break;
default:
break;
}
});
});
http://jsfiddle.net/wuY9V/1/
It basically just has a "state" of whether or not Mario is jumping. When the "up" arrow is pressed, Mario is jumping. As soon as the animations that move him up and then back down, are done, Mario is no longer jumping. So the function ignores the "up" key when Mario is jumping. I'm sure there's a more elegant way (like built into .animate) but this is what I came up with.
So obviously to test it, try pressing the "up" key at any point during Mario's jumping...it shouldn't do anything.
I didn't look into it too much, but I'm wondering why you have a setInterval for moving Mario? The way I would've done it is only listened for the keydown event. If it's the "up" arrow, animate him to move up and then back down (like you have, and like I've assisted with here). If it's the left arrow, animate him to move left a set distance. If it's the right arrow, animate him to move right a set distance. Is there a reason you have the setInterval to constantly check for a key pressed? Maybe I'm missing something.

When I click on a canvas and drag my mouse, the cursor changes to a text-selection cursor. How can I prevent this?

Here's a fiddle: http://jsfiddle.net/MZ9Xm/
Note: The following occurs in Chrome 22.0.1221.1, but not in Firefox 14.0.1. [Ubuntu linux]
Move your mouse to the top canvas and press and hold the mouse button. Drag the mouse, and the cursor will change to a text-selection mouse cursor (I-bar). This does not happen if there are no other elements on the page.
I've messed around with setting user-selection to none, but have not had any luck.
You can bind a mousedown event in your canvas to prevent default behavior.
Something like:
// with jQuery
$( "#canvasId" ).mousedown(function(event){
event.preventDefault();
});
// without jQuery
document.getElementById( "canvasId" ).onmousedown = function(event){
event.preventDefault();
};
Here is the updated fiddle: http://jsfiddle.net/MZ9Xm/1/
You will need to test this to see if there is some side effect in what you are doing.
Have you tried using the CSS cursor property ?
canvas {
cursor: pointer;
}
It should display the default cursor.
Try this:
var canvasEls = document.getElementsByTagName('canvas'),
preventHl = function () { return false; },
i = 0;
while (i < canvasEls.length) {
canvasEls[i].onmousedown = preventHl;
i += 1;
}
Returning false will prevent default actions such as highlighting from occurring.

Lasso tool in javascript

Hay, I'm writing a simple web based image maker, and would like to know if anyone has any idea's how to implement a lasso tool. I'd like to be able to save all the points so that I can easily send them to a database and retrieve them at a later date.
As a basic plug-in, this would probably look something like this:
$.fn.extend({
lasso: function () {
return this
.mousedown(function (e) {
// left mouse down switches on "capturing mode"
if (e.which === 1 && !$(this).is(".lassoRunning")) {
$(this).addClass("lassoRunning");
$(this).data("lassoPoints", []);
}
})
.mouseup(function (e) {
// left mouse up ends "capturing mode" + triggers "Done" event
if (e.which === 1 && $(this).is(".lassoRunning")) {
$(this).removeClass("lassoRunning");
$(this).trigger("lassoDone", [$(this).data("lassoPoints")]);
}
})
.mousemove(function (e) {
// mouse move captures co-ordinates + triggers "Point" event
if ($(this).hasClass(".lassoRunning")) {
var point = [e.offsetX, e.offsetY];
$(this).data("lassoPoints").push(point);
$(this).trigger("lassoPoint", [point]);
}
});
}
});
later, apply lasso() to any element and handle the events accordingly:
$("#myImg")
.lasso()
.on("lassoDone", function(e, lassoPoints) {
// do something with lassoPoints
})
.bind("lassoPoint", function(e, lassoPoint) {
// do something with lassoPoint
});
lassoPoint will be an array of X,Y co-ordinates. lassoPoints will be an array of lassoPoint.
You should probably include an extra check for a "lasso enabled" flag of some sort into the mousedown handler, so that you can switch it on or off independently.
Heres a plugin that seems to do just that
http://odyniec.net/projects/imgareaselect/examples.html
I haven't used it.
I've never made one, but if you're looking to make your own, id imagine they work like
onmousedown record initial mouse coords(this is the coords of the corner of lasso box)
onmousemove subtract new coords from initial coords to get width and height of div being used for the visual lasso box.
onmouseup, stop listening to mousemove, do something with coords and dimension of any lasso box existing

Categories

Resources