Higcharts: Arrow segment drawn with single click, can not be selected nor dragged - highcharts

I have my code in this JSFiddle. I can draw annotations with click-and-drag, using the plugins: user click and hold the mouse (drawing starts on mouse-down), start to drag around and drawing is completed when user releases the mouse (mouse-up event).
The issue here is: when we have a single-click in a certain point, an arrow symbol appears and this can not be selected nor draggable. In cases of single-click, will be ideal if mouse-up event to not complete the drawing and instead drawing to be completed on the next mouse-down event.
Here in this video we can see the behavior of how the single-click acts at the moment and also there I commented one condition to show how I expect this to behave. I am already successfully having the check if we have a single-click while drawing in the part with console.log("this is a single click");.
The two most important blocks of the code-snippet are given below, and what I don't understand is why this is not working as I described above, since I am already terminating the function in case single-click is detected (with return).
//on mouse-down event, if cursor is inside of the chart and if drawing tool is selected, set the
//flag "isAddingAnnotations" to true and store the coordinates from where the drawing started
navigation.eventsToUnbind.push(addEvent(chart.container, 'mousedown', function(e) {
if (!chart.cancelClick &&
chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop))
{
navigation.bindingsChartClick(chart, e);
if (!navigation.selectedButton) {
chart.isAddingAnnotations = false;
} else {
chart.isAddingAnnotations = true;
chart.addingAnnotationsX = e.clientX;
chart.addingAnnotationsY = e.clientY;
}
}
}));
//on mouse-up event, set the flag "isAddingAnnotations" to false (since drawing ended)
//additionally, if drawing was in progress and if ending coordinates are matching with
//starting coordinates, drawing should still be active
navigation.eventsToUnbind.push(addEvent(chart.container, 'mouseup', function(e) {
if (chart.isAddingAnnotations &&
chart.addingAnnotationsX == e.clientX &&
chart.addingAnnotationsY == e.clientY)
{
console.log("this is a single click");
return;
}
chart.pointer.normalize(e);
navigation.bindingsChartClick(chart, e);
chart.isAddingAnnotations = false;
}));

Related

Very slow hover interactions in OpenLayers 3 with any browser except Chrome

I have two styles of interactions, one highlights the feature, the second places a tooltop with the feature name. Commenting both out, they're very fast, leave either in, the map application slows in IE and Firefox (but not Chrome).
map.addInteraction(new ol.interaction.Select({
condition: ol.events.condition.pointerMove,
layers: [stationLayer],
style: null // this is actually a style function but even as null it slows
}));
$(map.getViewport()).on('mousemove', function(evt) {
if(!dragging) {
var pixel = map.getEventPixel(evt.originalEvent);
var feature = null;
// this block directly below is the offending function, comment it out and it works fine
map.forEachFeatureAtPixel(pixel, function(f, l) {
if(f.get("type") === "station") {
feature = f;
}
});
// commenting out just below (getting the feature but doing nothing with it, still slow
if(feature) {
target.css("cursor", "pointer");
$("#FeatureTooltip").html(feature.get("name"))
.css({
top: pixel[1]-10,
left: pixel[0]+15
}).show();
} else {
target.css("cursor", "");
$("#FeatureTooltip").hide();
}
}
});
I mean this seems like an issue with OpenLayers-3 but I just wanted to be sure I wasn't overlooking something else here.
Oh yeah, there's roughly 600+ points. Which is a lot, but not unreasonably so I would think. Zooming-in to limit the features in view definitely helps. So I guess this is a # of features issue.
This is a known bug and needs more investigation. You can track progress here: https://github.com/openlayers/ol3/issues/4232.
However, there is one thing you can do to make things faster: return a truthy value from map.forEachFeatureAtPixel to stop checking for features once one was found:
var feature = map.forEachFeatureAtPixel(pixel, function(f) {
if (f.get('type') == 'station') {
return feature;
}
});
i had same issue, solved a problem by setInterval, about this later
1) every mouse move to 1 pixel fires event, and you will have a quee of event till you stop moving, and the quee will run in calback function, and freezes
2) if you have an objects with difficult styles, all element shown in canvas will take time to calculate for if they hit the cursor
resolve:
1. use setInterval
2. check for pixels moved size from preview, if less than N, return
3. for layers where multiple styles, try to simplify them by dividing into multiple ones, and let only one layer by interactive for cursor move
function mouseMove(evt) {
clearTimeout(mm.sheduled);
function squareDist(coord1, coord2) {
var dx = coord1[0] - coord2[0];
var dy = coord1[1] - coord2[1];
return dx * dx + dy * dy;
}
if (mm.isActive === false) {
map.unByKey(mm.listener);
return;
}
//shedules FIFO, last pixel processed after 200msec last process
const elapsed = (performance.now() - mm.finishTime);
const pixel = evt.pixel;
const distance = squareDist(mm.lastP, pixel);
if (distance > 0) {
mm.lastP = pixel;
mm.finishTime = performance.now();
mm.sheduled = setTimeout(function () {
mouseMove(evt);
}, MIN_ELAPSE_MSEC);
return;
} else if (elapsed < MIN_ELAPSE_MSEC || mm.working === true) {
// console.log(`distance = ${distance} and elapsed = ${elapsed} mesc , it never should happen`);
mm.sheduled = setTimeout(function () {
mouseMove(evt);
}, MIN_ELAPSE_MSEC);
return;
}
//while multithreading is not working on browsers, this flag is unusable
mm.working = true;
let t = performance.now();
//region drag map
const vStyle = map.getViewport().style;
vStyle.cursor = 'default';
if (evt.dragging) {
vStyle.cursor = 'grabbing';
}//endregion
else {
//todo replace calback with cursor=wait,cursor=busy
UtGeo.doInCallback(function () {
checkPixel(pixel);
});
}
mm.finishTime = performance.now();
mm.working = false;
console.log('mm finished', performance.now() - t);
}
In addition to #ahocevar's answer, a possible optimization for you is to utilize the select interaction's select event.
It appears that both the select interaction and your mousemove listener are both checking for hits on the same layers, doing double work. The select interaction will trigger select events whenever the set of selected features changes. You could listen to it, and show the popup whenever some feature is selected and hide it when not.
This should reduce the work by half, assuming that forEachFeatureAtPixel is what's hogging the system.

Stupid mouse move coordinates in dart

I am learning Dart and I was trying to make a very simple drageable HTML element. I followed patterns I'm used to from javascript but it doesn't work as expected.
When making drageable object from scratch you usually do the following:
Listen on mouse down event on that object
Upon mouse down, remember mouse coordinates relative to the object's top-left corner
Listen for any mouse movement. For every move operation, move the object to cursor location minus the coordinates you remembered earlier.
Upon any mouse up event, stop following mouse movement.
So I produced this code:
class DrageableControl {
DivElement _elm;
DrageableControl(String txt, int x, int y) {
//Create element and set up styles
var elm = this.setupElement(x, y);
//Append element to document, add some text and start listeners
document.body.append(elm);
elm.text = txt;
setupEvents();
}
//This function creates all event necessary for drag operations
setupEvents() {
Point relativeMouseOffset = null;
_elm.onMouseDown.listen((MouseEvent e) {
Rectangle myPos = _elm.getBoundingClientRect();
relativeMouseOffset = new Point(e.offset.x-myPos.left, e.offset.y-myPos.top);
e.preventDefault();
return false;
});
//Of course this is completely wrong, the listener should only be added for the duration of dragging
document.onMouseMove.listen((MouseEvent e) {
if(relativeMouseOffset!=null) {
print("Clicked at: ${relativeMouseOffset}\nCurrent mouse position:${e.offset}");
_elm.style.top = "${(e.offset.y/*-relativeMouseOffset.y*/)}px";
_elm.style.left = "${(e.offset.x/*-relativeMouseOffset.x*/)}px";
}
});
document.onMouseUp.listen((MouseEvent e){
relativeMouseOffset = null;
});
}
setupElement(int x, int y) {
var elm = this._elm = new DivElement();
//TODO: Use css?
elm.style.position = "absolute";
elm.style.top = "${y}px";
elm.style.left = "${x}px";
elm.style.border = "1px solid red";
elm.style.backgroundColor = "#FFAAAA";
elm.style.cursor = "default";
//elm.style.transition = "top 1s";
return elm;
}
}
Problem is, that some coordinates delivered by MouseMove are complete nonsense. See the console:
Clicked at: Point(-76.0, -143.0)
Current mouse position:Point(1, 1)
Clicked at: Point(-76.0, -143.0)
Current mouse position:Point(374, 272)
Clicked at: Point(-76.0, -143.0)
Current mouse position:Point(1, 0)
Clicked at: Point(-76.0, -143.0)
Current mouse position:Point(376, 273)
Clicked at: Point(-76.0, -143.0)
Current mouse position:Point(0, 1)
As you can see every second mouse move event delivers broken data - coordinates right around [0, 0]. So how can I filter out this invalid data? Why does it happen?
So far I'm probably fixing this by adding:
if(e.offset.x+e.offset.y<5)
return;
Use e.client.x/e.client.y instead.

Extracting chart coordinates from touch events for custom HighCharts interaction

I am having some issues working with Touch events in HighCharts. I am able to receive the events, but I haven't been able to figure out how to translate the coordinates given to chart coordinates. For mouse events, I can use the following to retrieve the chart X value:
chart.xAxis[0].toValue(e.offsetX)
However, touch events have no offsetX. For clicks, there is also e.originalEvent.chartX, which seems to be identical to e.offsetX, but again it is missing for touch events. By inspecting the touch event I can find clientX, screenX, and pageX, but axis.toValue does not return the correct chart X for any of these values.
touch event support in highchart for iphone/ipads or any touchable devices
and
Highcharts: how to handle touch events via plotOptions.series.events
both mention using a "tracker" object to call normalizeMouseEvent, but I can't seem to find it in the API reference or by inspecting the relevant objects.
How can I extract the correct X and Y chart values from a touch event?
You can extract that from changedTouches object.
e.originalEvent.changedTouches[0].pageX
e.originalEvent.changedTouches[0].pageY
In order to extract the equivalent of event.offsetX that I am using for mouse events, I ended up using the following code:
function accumulate_offset(next_container) {
offset = 0;
while (next_container != null) {
offset += next_container.offsetLeft;
next_container = next_container.offsetParent;
}
return offset;
}
// then in handler
if (e.type.slice(0,5) == 'mouse') {
xVal = e.offsetX;
} else {
xVal = e.originalEvent.changedTouches[0].pageX - accumulate_offset(e.currentTarget);
}
x = axis.toValue(xVal);
Hopefully this is helpful to someone.

how to stop a rotating movieclip at different angles with other movieclips following, actionscript 3

I have a manometer, this needs to spin from a minimum value to a maximum. right now I have the manometer as a picture and the arrow as a movieclip. I've got it spinning at the right speed, but don't know how to stop it at the lowest/highest pressure.
It's suppose to work like this:
I have two movieclip/buttons; one for simulating more pressure, and one for less.
when the user presses the "more pressure" movieclip/button the pressure begins to rise and the arrow inside the manometer begin to turn.
At the same time as the pressure rises, another movieclip ("stamp") will push uppwards.
then another movieclip/button, "less pressure" simulates pressure drop; when pressed, the same point as the arrow stopped at when pressure rised, will start sinking towards minimum, and the stamp will go down again.
so, when the user presses "more pressure" pressure rises towards maximum, and as soon as the user stop pressing the button, the animation stops (both the stamp and the arrow). And if the user presses "lower pressure", the arrow starts sinking from where it stopped.
heres my code so far: pil1 = manometerarrow, the stamp = stamp, and "less pressure"/"more pressure" = Lpress / mpress
addEventListener (Event.ENTER_FRAME, rotate);
function rotate(event:Event):void
{
pil1.rotation = pil1.rotation+1;
}
ymutlu is on the right track. The mouse down event will only execute once when the mouse is depressed. To make the object rotate continuously while the mouse is depressed you need to increment or decrement the rotation of the object on each frame. I think the following should do the trick:
import flash.events.MouseEvent;
import flash.events.Event;
var rotate = 0;
Hpress.addEventListener(MouseEvent.MOUSE_DOWN, Hpressed);
Hpress.addEventListener(MouseEvent.MOUSE_UP, removeEnterFrame);
Lpress.addEventListener(MouseEvent.MOUSE_DOWN, Lpressed);
Lpress.addEventListener(MouseEvent.MOUSE_UP, removeEnterFrame);
function Hpressed(e:MouseEvent):void
{
rotate = 1;
addEnterFrame();
}
function Lpressed(e:MouseEvent):void
{
rotate = -1;
addEnterFrame();
}
function addEnterFrame():void
{
this.addEventListener(Event.ENTER_FRAME, update);
}
function removeEnterFrame(e:MouseEvent):void
{
this.removeEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void
{
pil1.rotation += rotate;
}
hold to varaible that states if max button down or min button down, and check it in enterframe loop. Edited answer on your comment, hope you can sort it out.
addEventListener (Event.ENTER_FRAME, rotate);
function rotate(event:Event):void
{
if(isMaxDown) // true when max button down
pil1.rotation = Math.min(presMax,pil1.rotation+1); // presMax is max value that pressure can go
if(isMinDown) // true when min button down
pil1.rotation = Math.max(presMin,pil1.rotation-1);// presMin is min value that pressure can go
}
// isMaxDown and isMinDown are global values.
Hpress.addEventListener(MouseEvent.MOUSE_DOWN, Hpressed);
Lpress.addEventListener(MouseEvent.MOUSE_DOWN, Lpressed);
Hpress.addEventListener(MouseEvent.MOUSE_UP, H_up);
Lpress.addEventListener(MouseEvent.MOUSE_UP, L_up);
function H_up(e:MouseEvent):void {
isMaxDown=false;
}
function L_up(e:MouseEvent):void {
isMinDown=false;
}
function Hpressed(e:MouseEvent):void {
isMaxDown=true;
}
function Lpressed(e:MouseEvent):void {
isMinDown=true;
}
This code would help you but prob this is not a path to fallow to do somthing like that.

Blackberry Storm Emulator - TouchGesture events not firing, how to get a Swipe to work?

Been playing with the Storm Emulator and the 4.7 JDE, for the life of me I can't figure out how to fire gesture events in the emulator.
Below is the touch event code for the RIM sample app EmbeddedMapDemo. It seems straightforward enough, but touchGesture.getEvent() == TouchGesture.SWIPE never seems to register to true.
How can I register swipes in the Emulator? With my mouse I try doing left-click and drag but that does not seem to work.
/**
* #see Field#touchEvent(TouchEvent)
*/
protected boolean touchEvent(TouchEvent message)
{
boolean isConsumed = false;
if(_mapField.isClicked())
{
TouchGesture touchGesture = message.getGesture();
if (touchGesture != null)
{
// If the user has performed a swipe gesture we will
// move the map accordingly.
if (touchGesture.getEvent() == TouchGesture.SWIPE)
{
// Retrieve the swipe magnitude so we know how
// far to move the map.
int magnitude = touchGesture.getSwipeMagnitude();
// Move the map in the direction of the swipe.
switch(touchGesture.getSwipeDirection())
{
case TouchGesture.SWIPE_NORTH:
_mapField.move(0, - magnitude);
break;
case TouchGesture.SWIPE_SOUTH:
_mapField.move(0, magnitude);
break;
case TouchGesture.SWIPE_EAST:
_mapField.move(- magnitude, 0);
break;
case TouchGesture.SWIPE_WEST:
_mapField.move(magnitude, 0);
break;
}
// We've consumed the touch event.
isConsumed = true;
}
}
}
return isConsumed;
}
Pressing the left mouse button simulates clicking down the screen... the simulator (and also an actual Storm device, I think) won't fire TouchGesture events while you're clicking down on the screen.
What you want to do is hold down the right mouse button and drag, since the right mouse button simulates a screen tap, without click. This way, you should be able to get TouchGestures to fire.
It's a little hard to do a gesture on the simulator, you kinda have to move fast, but if you use the right mouse button you should be able to do it.

Resources