I have a React implementation of a leaflet map with a custom cursor. The cursor's functionality is determined by:
L.CursorHandler = L.Handler.extend({
addHooks: function () {
this._popup = new L.Popup();
this._map.on('mouseover', this._open, this);
this._map.on('mousemove', this._update, this);
// this._map.on('mouseout', this._close, this);
},
removeHooks: function () {
this._map.off('mouseover', this._open, this);
this._map.off('mousemove', this._update, this);
this._map.off('mouseout', this._close, this);
},
_open: function (e) {
this._update(e);
this._popup.openOn(this._map);
},
_close: function () {
this._map.closePopup(this._popup);
},
_update: function (e) {
var latitude = e.latlng.toString().split(",")[0];
latitude = latitude.replace('LatLng','').replace('(','')
var longitude = e.latlng.toString().split(",")[1];
longitude = longitude.replace('LatLng','').replace(')','')
this._popup.setLatLng(e.latlng)
// .setContent(roundToTwo(parseFloat(latitude)).toString() + String(",") + roundToTwo(parseFloat(longitude)).toString());
.setContent("lat: " + roundToTwo(parseFloat(latitude)).toString() + String(", lon: ") + roundToTwo(parseFloat(longitude)).toString()
+ " | Relative %: " + roundToTwo( parseFloat( getColor(parseFloat(latitude), parseFloat(longitude)) ) ).toString());
}
});
L.Map.addInitHook('addHandler', 'cursor', L.CursorHandler);
When I move the cursor closer to the edges of the map, however, the map pans automatically (eg: when the cursor hovers near the left side of the map, it begins to pan to the left). I do not want this feature, and only want to be able to move the map via a click-and drag motion, rather it panning automatically when the cursor is moved (without a click).
I believe the map is panning to make sure that your popup does not get cropped by the edge of the screen. One fix for this is to check which edge of the screen you are closes to and adjust the offset of the popup accordingly
this._popup({
offset: [0, 0] // change popup position
})
offset: [0, -30] // if you're near the top of the screen
offset: [-30, 0] // if you're near the right of the screen
offset: [30, 0] // if you're near the left of the screen
const midX = window.innerWidth / 2;
const midY = window.innerHeight / 2;
const point = latLngToLayerPoint(e.latlng);
if (point.x < midX) {
// you are closer to left side than right side
}
if (point.y < midY) {
// you are closer to top than bottom
}
The fix was actually incredibly simple. In the
_update: function (e) {}
part of the code, I simply added a clause:
this._popup.options.autoPan = false;
This solves the problem effectively.
Related
Here is my map svg:
useEffect(() => {
const svg = select(svgRef.current)
const { width, height } = wrapperRef.current.getBoundingClientRect();
// projects geo-coordinates on a 2D plane
const projection = geoMercator()
.fitSize([width, height], data)
.precision(100);
// takes geojson data,
// transforms that into the d attribute of a path element
const pathGenerator = geoPath().projection(projection);
initZoom()
// render each country
svg
.selectAll(".country")
.data(data.features)
.join("path")
.attr("class", "country")
.transition()
.attr("fill", 'lightgrey')
.attr("d", feature => pathGenerator(feature));
;
}, [data ]);
And here is the zoom logic:
let zoom = d3.zoom()
.on('zoom', handleZoom);
function handleZoom(e) {
d3.select(svgRef.current)
.attr('transform', e.transform)
}
function initZoom() {
d3.select(svgRef.current)
.call(zoom);
}
Instead of zooming in around the mouse pointer like with examples, it instead zooms out from the bottom right corner. Why is this and how do I fix it?
so after going all over other questions on SOF.
I'm using HighchartsReact wrapper for Highcharts.
Expected behaviour:
show negative values in stacked column chart even in logarithmic scale.
When toggling a series that has y values < 0, log scale hides them. When toggling back to linear scale the hidden points should be visible again.
Actual behaviour:
negative values disappear when going from linear to logarithmic. in addition when going back to linear the negative value that were seen in linear scale before - disappear and are not part of the chart.
It was working before several weeks and stopped working suddenly.
Live demo with steps to reproduce:
demo
official Custom Axis extension to allow emulation of
negative values on a logarithmic
Product version
9.3.2
How can I add this function with using HighchartsReact? I tried passing a callback and also inside React.useEffect to use the chart ref. but anything I do, still negative values are missing. and going back to linear just removes the original negative values from series.
(function (H) {
H.addEvent(H.Axis, 'afterInit', function () {
const logarithmic = this.logarithmic;
if (logarithmic && this.options.custom.allowNegativeLog) {
// Avoid errors on negative numbers on a log axis
this.positiveValuesOnly = false;
// Override the converter functions
logarithmic.log2lin = num => {
const isNegative = num < 0;
let adjustedNum = Math.abs(num);
if (adjustedNum < 10) {
adjustedNum += (10 - adjustedNum) / 10;
}
const result = Math.log(adjustedNum) / Math.LN10;
return isNegative ? -result : result;
};
logarithmic.lin2log = num => {
const isNegative = num < 0;
let result = Math.pow(10, Math.abs(num));
if (result < 10) {
result = (10 * (result - 1)) / (10 - 1);
}
return isNegative ? -result : result;
};
}
});
}(Highcharts));
You need to define the variable chart if you want to see how is changing.
const chart = Highcharts.chart('container', {
});
Live demo: https://jsfiddle.net/BlackLabel/x1zp347m/
Here is the official Highcharts React wrapper where you will find how to use Highcharts at the React.
https://github.com/highcharts/highcharts-react#basic-usage-example
EDIT --------------------------------------------------------------
To extending the chart custom code or edit the core you can fire function after imports.
How to extending Higcharts code:
https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
import React from 'react'
import { render } from 'react-dom'
import Highcharts from 'highcharts'
import HighchartsReact from 'highcharts-react-official'
(function (H) {
H.addEvent(H.Chart, 'load', function (e) {
var chart = e.target;
H.addEvent(chart.container, 'click', function (e) {
e = chart.pointer.normalize(e);
console.log('Clicked chart at ' + e.chartX + ', ' + e.chartY);
});
H.addEvent(chart.xAxis[0], 'afterSetExtremes', function (e) {
console.log('Set extremes to ' + e.min + ', ' + e.max);
});
});
}(Highcharts));
const options = {
title: {
text: 'My chart'
},
plotOptions: {
series: {
enableMouseTracking: true
}
},
series: [{
data: [1, 2, 3]
}]
}
const App = () => <div>
<HighchartsReact
highcharts={Highcharts}
options={options}
/>
</div>
render(<App />, document.getElementById('root'))
https://stackblitz.com/edit/react-t6rh4c?file=components%2FChart.jsx
I'm implementing a Rust alternative to .NET's DragMove method however the result causes the application to flicker between two relative positions.
See screencast and sample project.
Code I'm using to perform the drag move:
let mut mouse_down = false;
let mut last_pos: Option<PhysicalPosition<f64>> = None;
event_loop.run(move |event, _, control_flow| match event {
Event::WindowEvent {
event: WindowEvent::CursorMoved {
position,
..
},
..
} => {
let gl_window = display.gl_window();
let window = gl_window.window();
if mouse_down {
if last_pos.is_some() {
let previous_pos = last_pos.unwrap();
let delta_x = previous_pos.x - position.x;
let delta_y = previous_pos.y - position.y;
window.set_outer_position(PhysicalPosition::new(position.x + delta_x, position.y + delta_y));
}
last_pos = Some(position);
}
}
Event::WindowEvent {
event: WindowEvent::MouseInput{
state,
button,
..
},
..
} => {
mouse_down = button == MouseButton::Left && state == ElementState::Pressed;
if !mouse_down {
last_pos = None;
}
}
_ => {}
});
CursorMoved reports
(x,y) coords in pixels relative to the top-left corner of the window.
When you're later using that position to set_outer_position, you are essentially reinterpreting window-relative coordinates as screen-relative.
You should instead apply the offset to the position returned from outer_position.
While that fixes the immediate problem, I'm not sure it is enough to account for the window movement. When you're handling the next CursorMoved event, the coordinates are still window-relative, but the window has since moved. That may produce artifacts all over.
A more robust solution would store the window's position when the drag-move operation starts, and offset that position by the accumulated deltas.
I am using React to develop a real-time paint app. So, the idea is to store mouse events in an array(to pass it through socket) and pass it to draw function. However, when I move mouse fast, I'm getting a dotted line instead of smooth line. If I directly draw using mouse events instead of an array, I'm getting a smooth line. So I guess the issue is in pushing mouse events into the array.
This is my output:
The following is my PaintCanvas component
function PaintCanvas(props) {
let ctx;
const canvasRef = useRef("");
const [isDrawing, changeIsDrawing] = useState(false);
let strokes = [];
const mouseDownFunction = e => {
changeIsDrawing(true);
if (ctx) {
wrapperForDraw(e);
}
};
const mouseUpFunction = e => {
if (ctx) {
ctx.beginPath();
}
changeIsDrawing(false);
};
const mouseMoveFunction = e => {
if (ctx) {
wrapperForDraw(e);
}
};
const wrapperForDraw = e => {
if (!isDrawing) return;
strokes.push({
x: e.clientX,
y: e.clientY
});
drawFunction(strokes);
};
const drawFunction = strokes => {
let { top, left } = canvasRef.current.getBoundingClientRect();
if (!isDrawing) return;
ctx.lineWidth = 3;
ctx.lineCap = "round";
for (let i = 0; i < strokes.length; i++) {
ctx.beginPath();
//adding 32px to offset my custom mouse icon
ctx.moveTo(strokes[i].x - left, strokes[i].y - top + 32);
ctx.lineTo(strokes[i].x - left, strokes[i].y - top + 32);
ctx.closePath();
ctx.stroke();
}
};
useEffect(() => {
let canvas = canvasRef.current;
ctx = canvas.getContext("2d");
});
return (
<div>
<canvas
ref={canvasRef}
width="500px"
height="500px"
onMouseDown={mouseDownFunction}
onMouseUp={mouseUpFunction}
onMouseMove={mouseMoveFunction}
className={styles.canvasClass}
/>
</div>
);
}
export default PaintCanvas;
How can I get a smooth line using the array implementation.
In your loop where you are drawing the lines, you don't need to call moveTo every iteration. Each call of lineTo() automatically adds to the current sub-path, which means that all the lines will all be stroked or filled together.
You need to pull beginPath out of the loop, remove the moveTo call and take the stroke outside the loop for efficiency.
ctx.beginPath();
for (let i = 0; i < strokes.length; i++) {
//adding 32px to offset my custom mouse icon
//ctx.moveTo(strokes[i].x - left, strokes[i].y - top + 32); // Remove this line
ctx.lineTo(strokes[i].x - left, strokes[i].y - top + 32);
}
// Its also more efficient to call these once for the whole line
ctx.stroke();
I am using DataMap, unlike the normal view for a map, I turned the map upside down, When mouseover, the tooltip location doesn't correspond, to the location of the mouse when I mouseover
I have tried different codes, in other to get accurate coordinates, but none is giving me what I need.
In the map react component
<Map mapRef= {this.myMap} makeMouseMove={this._onMouseMove} />
1st try
_onMouseMove = (e) => {
if (document.querySelector('.hoverinfo')) {
let mapTooltip = document.querySelector('.datamaps-hoverover');
let rect = e.target.getBoundingClientRect();
mapTooltip.style.left = e.clientX - rect.left + 'px';
mapTooltip.style.top = e.clientY - rect.top + 'px';
}
}
2nd Try
_onMouseMove = (e) => {
if (document.querySelector('.hoverinfo')) {
let mapTooltip = document.querySelector('.datamaps-hoverover');
mapTooltip.style.left = e.pageX - mapTooltip.offsetLeft+'px';
mapTooltip.style.left = e.pageY - mapTooltip.offsetTop+'px';
}
}
Unfortunately, I have not been able to achieve what I want to achieve, I would appreciate if someone that has experience handling this Datamap issue helps me with a clue.
In case someone else is having this type of issue, this is what I did to resolve it, apparently, the left value is correct, and there was no need for me to modify it.
_onMouseMove = (e) => {
if (document.querySelector('.hoverinfo')){
let mapTooltip = document.querySelector('.datamaps-hoverover');
let mapHoverSVG = document.querySelector('svg');
let point = mapHoverSVG.createSVGPoint();
point.x = e.clientX;
point.y = e.clientY;
let cursor = point.matrixTransform(mapHoverSVG.getScreenCTM().inverse());
mapTooltip.style.top = (cursor.y + 16) + "px";
console.log(cursor.y);
}
}