i need to draw a graph of semi circle on a leaflet map.
It should look like the following image:
How can i do it?
Thanks
Efrat
Have you seen leaflet-semicircle? Not exactly what you need, but might give you enough clues to implement what you want.
Did a quick example (demo here):
function rangerings (latlng, options) {
options = L.extend({
count: 8,
interval: 1000,
direction: 0,
spread: 120
}, options);
var layer = L.featureGroup();
for (var i = 1; i <= options.count; i++) {
L.semiCircle(latlng, {
radius: i * options.interval,
fill: false,
color: '#000',
weight: 1
}).setDirection(options.direction, options.spread).addTo(layer);
}
return layer;
}
code on github
Related
So, I was looking into making minecraft/terraria block lighting
(like how some tiles are dark)
So far, I've seen the high level idea being
"set the sky block to the max light level, and reduce by x for every block, get light level by averaging light levels"
So my question is Mainly, How can I implement this in phaser? would I need to give every tile the value and calculate it?
There is an official example, that covers answers you question (if I undertand your question correct).
Here a slightly alter version of the example:
(it is a very crude example, to show case the idea)
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
preload,
create
}
};
var game = new Phaser.Game(config);
function preload (){
this.load.image('tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'https://labs.phaser.io/assets/tilemaps/csv/catastrophi_level2.csv');
}
function create () {
this.add.text(10, 10, 'Click to change light position')
.setOrigin(0)
.setDepth(100)
.setStyle({fontFamily: 'Arial'});
let map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
let tileset = map.addTilesetImage('tiles');
map.createLayer(0, tileset, 0, 0);
let lightSource = {x: 0, y: 0};
updateMap(map, lightSource);
this.input.on('pointerdown', (pointer) => updateMap(map, pointer));
}
function updateMap (map, lightSource) {
let fullLightDistanceInTiles = 3;
let origin = map.getTileAtWorldXY(lightSource.x, lightSource.y);
map.forEachTile(function (tile) {
var dist = Phaser.Math.Distance.Chebyshev(
origin.x,
origin.y,
tile.x,
tile.y
) - fullLightDistanceInTiles;
tile.setAlpha(1 - 0.1 * dist);
});
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
It basically just calculates the distance from the player to the tiles and set the alpha value. You would have to modify it so, that the distance is caluclate from a fixed sun/light position or so. (and recalculation would only be necessary if the sun/light position move)
if you don't want to set the alpha on the map tiles you could create a second layer with only black/grey tiles above, and set the alpha on this layer, but this would muddy the colors abit.
Alternatively, if: the light is horizontal and has the same level, you could simply overlay a gradient image or so. This would be better for performance and less work.
Here a demo using a phaser generated gradient:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
scene: {
preload,
create
}
};
var game = new Phaser.Game(config);
function preload (){
this.load.image('tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/catastrophi_tiles_16.png');
this.load.tilemapCSV('map', 'https://labs.phaser.io/assets/tilemaps/csv/catastrophi_level2.csv');
}
function create () {
this.add.text(10, 10, 'fixed horizontal darkness')
.setOrigin(0)
.setDepth(100)
.setStyle({fontFamily: 'Arial'});
let map = this.make.tilemap({ key: 'map', tileWidth: 16, tileHeight: 16 });
let tileset = map.addTilesetImage('tiles');
map.createLayer(0, tileset, 0, 0);
var graphicsOverlay = this.add.graphics();
graphicsOverlay.fillGradientStyle(0x0, 0x0, 0x0, 0x0, 0,0,1,1);
graphicsOverlay.fillRect(0, config.height/3, config.width, config.height*2/3);
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I have a line chart with some background polygons that need labels, much like in this post. However, my chart uses the zoom capabilities of HighCharts. The chart.events.render will draw new labels on zoom, but it doesn't remove the old ones, which do not zoom either. Using this.customLabel.destroy() doesn't seem to do the job. So I end up with excess labels in the wrong places. How do I remove the old labels with each new render, or is there now a better way to label polygons?
Try this approach:
chart: {
events: {
render() {
const chart = this;
if (chart.customLabel) {
chart.customLabel.destroy()
}
chart.customLabel = chart.renderer.label('test label', Math.random() * 200 + chart.plotLeft, Math.random() * 200 + chart.plotTop)
.css({
color: '#FFFFFF'
})
.attr({
fill: 'rgba(0, 0, 0, 0.75)',
padding: 8,
r: 5,
zIndex: 6
})
.add();
}
}
},
Demo: https://jsfiddle.net/BlackLabel/g1v4dwcn/ - resize the viewer in the jsfiddle to see the effect.
Edit by original poster: see comment about "two different SVG Elements"
im trying to put the marker-mid on the line element, im using SVG.js. For example im using this code:
var draw = SVG('yourdivid');
var line = draw.line( 100, 100, 0, 0).move(20, 20);
line.stroke({ color: '#000', width: 2};
now how can i put the marker at the mid of this line using the marker-mid?
i read the doc of svg.js and also this" https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/marker-mid#Examples"
they say that you can use the marker-mid element also with the line, i know that this marker works with the path element, but i need to use it with a line, can you help me please?
thank you for your help
You could just work out the mid point of the line yourself and draw a circle at that point.
var start = [100, 100];
var end = [0, 0];
function midPoint(start, end) {
return [
(start[0] + end[0]) / 2,
(start[1] + end[1]) / 2
];
}
var lineGroup = svg.group();
lineGroup.line(start[0][0], start[0][1], end[0][0], end[0][1]);
var dot = lineGroup.circle(3);
var mid = midPoint(start, end);
dot.cx(mid[0]);
dot.cy(mid[1]);
marker-mid does not work on lines. To have start and end markers, this code would do it:
var draw = SVG('yourdivid');
draw.line( 100, 100, 0, 0)
.move(20, 20)
.stroke({ color: '#000', width: 2})
.marker('start', 10, 10, function(add){
add.circle(10).center(5,5)
})
However, to have markers at the mid of a line see p0wdr.com's answer
Please bear with me, I'm still new to Javascript...
Here are two fiddles. The only difference between them is one has a text object as a title and the other does not; but this difference profoundly affects what happens when I mouseover the circle objects.
What I want is the behavior of the second fiddle, when there is a title like the first fiddle.
I've been trying to figure out how to get my function out of the loop so JSHint stops giving me an error... I have a feeling this behavior is caused by my lack of understanding of closure, binding, etc.
Fiddle 1 with title, mouseover is weird
Fiddle 2 no title, mouseover works
//Code for Fiddle 1: the only difference in Fiddle 2 is the indicated portion is commented out
var rsr = Raphael("holder", '1160', '1400');
// in the next fiddle this will be commented out
rsr.text(220, 50, 'Title').attr({
'font-size': 32,
'text-anchor': 'middle'
});
// end of comment out in Fiddle 2
var cir = []; // an array of circles
var xco = [206, 144.9, 317.4, 317.5]; // x coordinates of circle centers
var yco = [167.7, 231.8, 191.4, 256.8]; // y coordinates of circle centers
var rd = [25.5, 46, 34, 18.5]; // radii of circles
var circcolr = ['#939dac', '#000000', '#ecea5a', '#0da9f2']; // fill colors of circles
for (var i = 0; i < 4; i++) { // loop to draw circles
cir[i] = rsr.circle(xco[i], yco[i], rd[i]);
cir[i].attr({
fill: circcolr[i],
'fill-opacity': 1,
stroke: 'none'
});
}
for (var i in cir) {
(function (st) {
console.log(st.id);
st.node.onmouseover = function () {
st.animate({
r: rd[st.id] * 1.2
}, 200);
};
st.node.onmouseout = function () {
st.animate({
r: rd[st.id]
}, 100);
};
})(cir[i]);
}
The answer is pretty much there in the console logging you're already doing.
In the first case you create 5 objects the title and 4 circles so the title has id = 0 and the circles have id = 1, 2, 3, and 4.
In the second case you're only creating the circles so they have id = 0, 1, 2, 3
When you index into the rd array you're off by one in the title case. Changing the code at the end to this makes it work the same...
for (var i in cir) {
(function (cir, i) {
console.log(cir[i]);
cir[i].node.onmouseover = function () {
cir[i].animate({
r: rd[i] * 1.2
}, 200);
};
cir[i].node.onmouseout = function () {
cir[i].animate({
r: rd[i]
}, 100);
};
})(cir, i);
}
Another frustrating issue I have with Jvectormap, I wish to focus on a Marker on page/map load via lngLat, how would I do this? Ideally it would be good to say focus on this marker or focus on latlng. I will only be displaying 1 marker per map but I won't know the x/y just the lngLat or possibly countrycode. There might be an easier way altogether to do this so suggestions would be welcome. Thanks for your help in advanced
var markers = [ {latLng: [47.774099, -52.793427], name: "loc 1", label: "This blahblah"}]
$(function(){
$('#map1').vectorMap({
map: 'world_mill_en',
scale: ['#C8EEFF', '#0071A4'],
normalizeFunction: 'polynomial',
hoverOpacity: 0.7,
hoverColor: false,
markerStyle: {
initial: {
fill: '#F8E23B',
stroke: '#383f47'
}
},
backgroundColor: '#383f47',
markers: markers,
focusOn:{
latLng: [47.774099, -52.793427],
scale: 5
},
onMarkerLabelShow: function(event, label, index) {
label.html( ''+markers[index].label+'');
}
});
});
I needed the same thing as you and came across your unanswered question. This is the code I wrote (slash copied, pasted & modified from jVectorMap source) to solve the problem for myself. I hope you and others find it helpful.
Simply pass the scale, longitude, and latitude to setFocusLatLng.
I may attempt to get this or something similar accepted into the jVectorMap project on GitHub, so there may be a better way to do this later.
Disclaimer: Points on the edge of the map will not be centered. They should be in the view, though.
EDIT: As requested, here is the whole thing on jsfiddle:
http://jsfiddle.net/BryanTheScott/rs7H5/
EDIT: Also added the rest of the JS below:
$(function(){
var smallMap = $('#my_map_container').vectorMap({
map: 'world_mill_en',
zoomOnScroll: true,
zoomMax:5,
zoomMin:5,
regionStyle: {
initial: {
fill: '#222222',
"fill-opacity": 1,
stroke: '#444444',
"stroke-width": 1,
"stroke-opacity": 0.7
},
hover: {
"fill-opacity": 0.8,
fill: '#333333'
}
},
markerStyle: {
initial: {
fill: "#000000",
"stroke": "#7FC556",
"stroke-width": 2,
r: 3
}
},
markers: [[37.770172,-122.422771]]
});
var mapObj = $('#my_map_container').vectorMap('get', 'mapObject');
mapObj.setFocusLatLng = function(scale, lat, lng){
var point,
proj = jvm.WorldMap.maps[this.params.map].projection,
centralMeridian = proj.centralMeridian,
width = this.width - this.baseTransX * 2 * this.baseScale,
height = this.height - this.baseTransY * 2 * this.baseScale,
inset,
bbox,
scaleFactor = this.scale / this.baseScale,
centerX,
centerY;
if (lng < (-180 + centralMeridian)) {
lng += 360;
}
point = jvm.Proj[proj.type](lat, lng, centralMeridian);
inset = this.getInsetForPoint(point.x, point.y);
if (inset) {
bbox = inset.bbox;
centerX = (point.x - bbox[0].x) / (bbox[1].x - bbox[0].x);
centerY = (point.y - bbox[0].y) / (bbox[1].y - bbox[0].y);
this.setFocus(scale, centerX, centerY);
}
}
mapObj.setFocusLatLng(5, 37.770172,-122.422771);
});
Very late to the party here, but I needed a way to center on a marker even after the map had initially loaded, and here is what I came up with:
var yourMapHere = $(yourMapObject).vectorMap('get', 'mapObject');
var point = yourMapHere.latLngToPoint(yourMarkerLat, yourMarkerLng);
var x = yourMapHere.transX - point.x / yourMapHere.scale;
var y = yourMapHere.transY - point.y / yourMapHere.scale;
yourMapHere.setScale(yourScaleValueHere, x, y, true, true);