I'm unable to add a custom keyboard-event to Openlayers, and can't figure out why. Might it be a bug in relation to the already existing keyboard-events included in Openlayers?
I've tried the following with no result:
this.map.getViewport().addEventListener('keydown', (e) => {
console.log(e);
}, true)
document.getElementById('map').addEventListener('keydown', (e) => {
console.log(e);
})
Listening to clicks on the same elements work fine:
this.map.getViewport().addEventListener('click', (e) => {
console.log(e);
}, true)
document.getElementById('map').addEventListener('click', (e) => {
console.log(e);
})
Any solutions to this?
As mentioned map needs focus. You can use the FocusMap interaction of ol-ext to focus on the map when ckick on it.
See https://github.com/Viglino/ol-ext/blob/master/src/interaction/FocusMap.js
This example use it to handle ctrl+c/ctrl+v on a map.
https://viglino.github.io/ol-ext/examples/interaction/map.interaction.copypaste.html
This problem as Mike mentioned is occurring because of focus issues.
I faced this problem a few months ago, so I searched my old projects and find this:
<div id="map" tabindex="0"></div>
After assigning a tab index to an element you can use javascript focus().
in order to use it (after assigning tab index) use this:
document.getElementById('map').focus();
I think this could help.
Also, there is an answer I found months ago is here. You can find more info about focusing.
The most reliable solution in our angular application was to add a custom Interaction, but you still need to set tabindex="0" on your map ;)
<div class="map" tabindex="0" id="map"></div>
Here is an example:
import { Interaction } from "ol/interaction";
import { MapBrowserEvent } from "ol";
class KeyboardEventInteraction extends Interaction {
constructor() {
super();
}
handleEvent(mapBrowserEvent: MapBrowserEvent<KeyboardEvent>) {
let stopEvent = false;
if (mapBrowserEvent.type === "keydown") {
const keyEvent = mapBrowserEvent.originalEvent;
if (keyEvent.code?.toLowerCase() === "escape") {
// do whatever you want with your escape key
stopEvent = true;
}
// add other keys
if (stopEvent) {
keyEvent.preventDefault();
}
}
return !stopEvent;
}
}
You need to add this handler to your map:
new Map({
//... your map settings
interactions: [
//... your interactions
new KeyboardEventInteraction(),
],
});
Related
I have integrated 'Embed Layout' comet chat on my site. Now I want to open particular friend chat on page load.
In the documentation, I've found below code to do the same. REF : Documentation Link
jqcc.cometchat.chatWith(user_id)
I have included in custom js from admin panel. However, it is showing below error in console
jqcc.cometchat.chatWith is not a function
But If I use same after friends list loaded from the console it is working fine.
How can I fix this issue?
Currently for time being I have fixed this issue by adding below code in custom js
var first_chat_loaded = false;
var first_chat = setInterval(function () {
try {
if (first_chat_loaded === false) {
// Function to get other user id defined in parent html page
var other_userid = parent.get_other_user_id();
jqcc.cometchat.chatWith(other_userid);
first_chat_loaded = true;
clear_first_load();
}
} catch (e) {
}
}, 1000);
function clear_first_load() {
clearInterval(first_chat);
}
Please let me know, If there is any proper way to do the same.
Kindly make use of this code snippet for the above mentioned issue
var checkfn = setInterval(
function(){
if(typeof jqcc.cometchat.chatWith == 'function'){
jqcc.cometchat.chatWith(user_id);
clearInterval(checkfn);
}
},
500);
I need to do some actions after touch in any part of the screen. At this moment, I am using something like this:
update: function() {
if (this.game.input.activePointer.isDown) {
this.game.input.keyboard.onDownCallback = null;
this.start();
}
}
But I just don't feel it right, while I probably can use callbacks as I do with a keyboard:
this.game.input.keyboard.onDownCallback = function(e){
this.game.input.keyboard.onDownCallback = null;
self.start();
}
Is there any way to use callback on touch instead of checking in update?
this.game.input.onDown.add(function() {
console.log("input captured");
});
As simple as that. It will work for mouse and for touch.
I have seen similar questions - but not that fix my problem!
I have audio on my page and when one ends, I want the next to start, but I can't even get the ended to trigger...
I cut the code down to this:
function DaisyChainAudio() {
$().on('ended', 'audio','' ,function () {
alert('done');
});
}
This is called from my page/code (and is executed, setting a break point shows that).
As far as I understand this should set the handler at the document level, so any 'ended' events from any 'audio' tag (even if added dynamically) should be trapped and show me that alert...
But it never fires.
edit
With some borrowing from Çağatay Gürtürk's suggestion so far have this...
function DaisyChainAudio() {
$(function () {
$('audio').on('ended', function (e) {
$(e.target).load();
var next = $(e.target).nextAll('audio');
if (!next.length) next = $(e.target).parent().nextAll().find('audio');
if (!next.length) next = $(e.target).parent().parent().nextAll().find('audio');
if (next.length) $(next[0]).trigger('play');
});
});
}
I'd still like to set this at the document level so I don't need to worry about adding it when dynamic elements are added...
The reason it does not fire is, media events( those specifically belonging to audio or video like play, pause, timeupdate, etc) do not get bubbled. you can find the explanation for that in the answer to this question.
So using their solution, I captured the ended event, and this would allow setting triggers for dynamically added audio elements.
$.createEventCapturing(['ended']); // add all the triggers for which you like to catch.
$('body').on('ended', 'audio', onEnded); // now this would work.
JSFiddle demo
the code for event capturing( taken from the other SO answer):
$.createEventCapturing = (function () {
var special = $.event.special;
return function (names) {
if (!document.addEventListener) {
return;
}
if (typeof names == 'string') {
names = [names];
}
$.each(names, function (i, name) {
var handler = function (e) {
e = $.event.fix(e);
return $.event.dispatch.call(this, e);
};
special[name] = special[name] || {};
if (special[name].setup || special[name].teardown) {
return;
}
$.extend(special[name], {
setup: function () {
this.addEventListener(name, handler, true);
},
teardown: function () {
this.removeEventListener(name, handler, true);
}
});
});
};
})();
Try this:
$('audio').on('ended', function (e) {
alert('done');
var endedTag=e.target; //this gives the ended audio, so you can find the next one and play it.
});
Note that when you create a new audio dynamically, you should assign the events. A quick and dirty solution would be:
function bindEvents(){
$('audio').off('ended').on('ended', function (e) {
alert('done');
var endedTag=e.target; //this gives the ended audio, so you can find the next one and play it.
});
}
and run bindEvents whenever you create/delete an audio element.
Can anybody tell me what are the possible solutions for these??
Question 1: A web page as a form with the id "my_form" and a few elements with the class "excluded" applied. How can you make a copy of the form and get rid of all elements with the excluded class, only from the new copy of the form?
Question 2: Examine this code snippet. What do you think it's supposed to do? Why doesn't it work? How would you fix it?
$("li").each(function () {
if ($(this).find("ul")) {
$(this).css("background-color", "gray");
} else {
$(this).css("background-color", "white");
}
});
Question 3: A user is complaining that audio is playing even after hitting the play/pause button. Given the below implementation, why would that happen? How would you fix it?
// Pause Button Implementation:
$("#togglePlayPause").on("click", function () {
if (audio.paused === true) {
audio.play();
} else {
audio.pause();
}
});
// when the current audio has played all the way through, read the next element.
audio.addEventListener("ended", function () {
if (audio.paused === false) {
var nextElement = _getNextElement();
// scroll the page so that the next element we're reading is at the top of the browser window.
$(window).animate(scrollTop: nextElement.offset().top, 400, function () {
_playElementAudio(nextElement);
});
}
});
Any help will be appreciated..
Question 1
$("#form").not(".excluded").clone().appendTo("#anotherForm");
I'm using Hammer.js to listen for horizontal pan on an element.
When the deltaX has reached a threshold I would like to kill the current pan forcing a "panend" and resuming panning the next time a user attempts a "panstart".
Reading through the documentation it doesn't appear to be possible with the library right now.
Anyone know of a solution?
var mc = new Hammer.Manager(#option_elm.get(0),
recognizers: [
[Hammer.Pan,{direction: Hammer.DIRECTION_HORIZONTAL}]
]
)
mc.on('panleft', function(e) {
e.kill() // something simple like this...?
})
I had the same problem. Hammer.js has a build in method named stop();. You can use it like this inside your "penleft" event function: mc.stop();
http://hammerjs.github.io/api/#stop%28[force]%29
This wont force "penend". Hammer.js will just ignore all inputs. Unfortunately this method has a huge bug. The event object will have wrong parameters on all new inputs:
https://github.com/hammerjs/hammer.js/issues/811
So i used to use a helper variable, called "isFired". Your code can look something like this:
var mc = new Hammer.Manager(#option_elm.get(0),
recognizers: [
[Hammer.Pan,{direction: Hammer.DIRECTION_HORIZONTAL}]
]
),
isFired = false;
mc.on('panstart', function(e) {
isFired = false;
});
mc.on('panleft', function(e) {
if (!isFired) {
isFired = true;
yourCustomCallback();
}
});
mc.on('panend', function(e) {
isFired = false;
});
It is important to reset this variable to false on "penstart" and "panend".