I have setup a map with polygons around the countries on the map, and want to add an infobox so that on hover some information will be displayed for each country.
I can get infoboxes displaying easy enough without the polygons, but when assigning them to the PolygonOptions class, nothing happens. The docs say that so long as I have the Bing Themes module loaded (Which I do), the infoboxes will show up on hover and click.
There seems to be zero documentation/examples of this, so hoping you clever folks can help out.
Here is some of the relevant code;
var center = this.map.getCenter();
// Create an info box
var infoboxOptions = {
width: 300,
height: 100,
title: 'Testing', // sourceItems.data.dataset[0].data[index].key,
description: "Visits: 20", // + sourceItems.data.dataset[0].data[index].visits,
showPointer: true,
titleClickHandler: this.polygonInfo,
offset: new Microsoft.Maps.Point(-100, 0),
typeName: Microsoft.Maps.InfoboxType.mini,
zIndex: 1000
};
var polyinfobox = new Microsoft.Maps.Infobox(center, infoboxOptions);
var polygonOptions = {
fillColor: Microsoft.Maps.Color.fromHex(fillColour),
strokeColor: Microsoft.Maps.Color.fromHex(fillColour),
strokeThickness: 1,
infobox: polyinfobox
};
var result = new Microsoft.Maps.Polygon(vertices, polygonOptions);
There is a working code sample in the interactive SDK for the Bing Maps V7 control here: http://www.bingmapsportal.com/ISDK/AjaxV7#BingThemeModule6
Note that creating an infobox for each shape is very inefficient and will hurt performance if you have a lot of shapes. A better method is to have one infobox and dynamically populate it's data. I wrote a blog post on this here: http://rbrundritt.wordpress.com/2011/10/13/multiple-pushpins-and-infoboxes-in-bing-maps-v7/ If you want to use this approach here is a code sample:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
<script type="text/javascript">
var map, dataLayer, infobox;
function GetMap()
{
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {
credentials: "YOUR_BING_MAPS_KEY"
});
dataLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(dataLayer);
var infoboxLayer = new Microsoft.Maps.EntityCollection();
map.entities.push(infoboxLayer);
infobox = new Microsoft.Maps.Infobox(new Microsoft.Maps.Location(0, 0), { visible: false });
infoboxLayer.push(infobox);
AddData();
}
function AddData(){
var polygon = new Microsoft.Maps.Polygon([
new Microsoft.Maps.Location(45, -110),
new Microsoft.Maps.Location(65, -90),
new Microsoft.Maps.Location(45, -70)]);
polygon.Metadata = {
title: 'Hello',
description: 'World'
};
dataLayer.push(polygon);
Microsoft.Maps.Events.addHandler(polygon, 'click', displayInfobox);
Microsoft.Maps.Events.addHandler(polygon, 'mouseover', displayInfobox);
}
function displayInfobox(e){
if(e.target){
var point = new Microsoft.Maps.Point(e.getX(), e.getY());
var loc = map.tryPixelToLocation(point);
infobox.setLocation(loc);
var opt = e.target.Metadata;
if(opt){
if(e.target.getIcon){ //is pushpin
opt.offset = new Microsoft.Maps.Point(0,20);
}else{
opt.offset = new Microsoft.Maps.Point(0,0);
}
opt.visible = true;
infobox.setOptions(opt);
}
}
}
</script>
</head>
<body onload="GetMap();">
<div id='mapDiv' style="position:relative; width:600px; height:600px;"></div>
</body>
</html>
Related
I create a line layer and add it to the map.
But I then need to put this line layer into edit mode the user can stretch and manipulate the line, or whatever shape that I had added to the map.
The only reference I could find in MS Docs is how to put a 'shape' into edit mode, but this does not seem to be relevant and after trying their example, nothing works for me.
//Create a data source and add it to the map.
var dataSource = new atlas.source.DataSource();
map.sources.add(dataSource);
//Create a line and add it to the data source.
dataSource.add(new atlas.data.LineString([[-73.972340, 40.743270], [-74.004420, 40.756800]]));
//Create a line layer to render the line to the map.
map.layers.add(new atlas.layer.LineLayer(dataSource, null, {
strokeColor: 'blue',
strokeWidth: 5
}));
The code above creates the line, renders it to the map, but when clicking/hovering over the line I can't select it to edit it, really need some help with the missing code to do this. thanks
I think you need to use the drawing module for that. It allows you to create a DrawingManager to edit a shape by setting the mode to edit-geometry.
I reworked a bit your example with the LineString to put it automatically on edit when the map is ready.
<!DOCTYPE html>
<html lang="en">
<head>
<title>AzureMaps</title>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta http-equiv="x-ua-compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css"
type="text/css" />
<link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.css"
type="text/css" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script src="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.js"></script>
<script type='text/javascript'>
function GetMap() {
//Initialize a map instance.
const map = new atlas.Map('myMap', {
view: 'Auto',
center: [-73.972340, 40.743270],
zoom: 13,
//Add your Azure Maps key to the map SDK. Get an Azure Maps key at https://azure.com/maps. NOTE: The primary key should be used as the key.
authOptions: {
authType: 'subscriptionKey',
subscriptionKey: '<enter-your-subscription-key>'
}
});
map.events.add('ready', () => {
//Create a data source and add it to the map.
var dataSource = new atlas.source.DataSource();
map.sources.add(dataSource);
const lineString = new atlas.data.LineString([[-73.972340, 40.743270], [-74.004420, 40.756800]]);
//Create a line and add it to the data source.
dataSource.add(lineString);
const lineStringShape = dataSource.getShapes()[0];
//Create a line layer to render the line to the map.
map.layers.add(new atlas.layer.LineLayer(dataSource, null, {
strokeColor: 'blue',
strokeWidth: 5
}));
var drawingManager = new atlas.drawing.DrawingManager(map, {
mode: 'edit-geometry'
});
drawingManager.edit(lineStringShape);
});
}
</script>
</head>
<body onload="GetMap()">
<div id="myMap" style="position:relative;width:100%;min-width:290px;height:600px;"></div>
</body>
</html>
Important thing is, you need to reference the atlas-drawing scripts and styles :
<script src="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.js"></script>
<link rel="stylesheet" href="https://atlas.microsoft.com/sdk/javascript/drawing/1/atlas-drawing.min.css"
type="text/css" />
You can find more information on the Drawing Manager here.
Edit - Change only color and width
If you want to change only the strokeColor and the strokeWidth of your line string, you don't actually need the drawing manager for that. I would recommend to set expressions on the strokeColor and strokeWidth of your line layer to read the values from the properties of each shape.
The following example displays two line strings with different width and colors :
//Initialize a map instance.
const map = new atlas.Map('myMap', {
view: 'Auto',
center: [-73.972340, 40.743270],
zoom: 13,
//Add your Azure Maps key to the map SDK. Get an Azure Maps key at https://azure.com/maps. NOTE: The primary key should be used as the key.
authOptions: {
authType: 'subscriptionKey',
subscriptionKey: '<enter-your-subscription-key>'
}
});
map.events.add('ready', () => {
//Create a data source and add it to the map.
const dataSource = new atlas.source.DataSource();
map.sources.add(dataSource);
const firstLineString = new atlas.data.LineString([[-73.972340, 40.743270], [-74.004420, 40.756800]]);
const secondLineString = new atlas.data.LineString([[-73.972340, 40.733270], [-74.004420, 40.746800]]);
//Create a line and add it to the data source.
dataSource.add(firstLineString);
dataSource.add(secondLineString);
//Add properties on the shapes
const shapes = dataSource.getShapes()
const firstLineStringShape = shapes[0];
firstLineStringShape.addProperty('color', '#ed5a10');
firstLineStringShape.addProperty('strokeWidth', 10);
const secondLineStringShape = shapes[1];
secondLineStringShape.addProperty('color', '#0e41ea');
secondLineStringShape.addProperty('strokeWidth', 5);
//Create a line layer to render the line to the map.
//strokeColor and strokeWidth are defined on the properties of each line string
map.layers.add(new atlas.layer.LineLayer(dataSource, null, {
strokeColor: ['get', 'color'],
strokeWidth: ['get', 'strokeWidth']
}));
});
It is still done when the map is ready in this example for convenience, but you can set the properties of a shape whenever you need to update it using either addProperty if your property was never set, or a combination of getProperties and setProperties.
You can find more information on the data driven expressions here : https://learn.microsoft.com/en-us/azure/azure-maps/data-driven-style-expressions-web-sdk
Is it possible to insert custom HTML-code as a xaxisLabel of a bar - graph?
Like
xaxisLabels: ['<i class="fa fas fa-check fa-2x"></i>']
In the result, the closing-Tag (</i>) is missing.
There's no option to add custom HTML to labels but since the labels are DOM nodes (if you're using DOM text - which is on by default) you can manipulate them to you hearts content that way. Here's an example:
<!DOCTYPE html>
<html>
<head>
<script src="https://www.rgraph.net/libraries/RGraph.common.core.js"></script>
<script src="https://www.rgraph.net/libraries/RGraph.bar.js"></script>
</head>
<body>
<h1>Clickable labels</h1>
<canvas id="cvs1" width="600" height="250">[No canvas support]</canvas>
<script>
bar = new RGraph.Bar({
id:'cvs1',
data: '8,4,6,3,5,4,2'.split(','),
options: {
xaxisLabels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
textAccessiblePointerevents: true,
// If you just want to manipulate the style of the labels
// there are these five properties
//xaxisLabelsSize: 16,
//xaxisLabelsFont: 'Verdana',
//xaxiLabelsBold: true,
//xaxisLabelsItalic: true,
//xaxisLabelsColor: 'red'
}
}).draw();
labels = document.getElementsByClassName('rgraph_accessible_text_xaxis_labels');
// Maniuplate the style
for (i=0; i<labels.length; ++i) {
labels[i].style.fontWeight = 'bold';
labels[i].style.fontStyle = 'italic';
labels[i].style.fontSize = '14pt';
labels[i].style.color = 'red';
labels[i].style.fontFamily = 'Verdana';
}
// Add a click event listener
labels[0].addEventListener('click', function (e)
{
alert('Label was clicked');
}, false);
// Add a mousemove event listener
labels[0].addEventListener('mousemove', function (e)
{
e.target.style.cursor = 'pointer';
}, false);
</script>
</body>
</html>
And on codepen:
https://codepen.io/rgraph/pen/poEOKPV
EDIT:
In addition you could also use the RGraph.text.find() function after you create the chart like this:
labels = RGraph.text.find({
object: bar,
text: 'Wed'
});
labels[0].style.fontWeight = 'bold';
labels[0].style.cursor = 'pointer';
labels[0].addEventListener('click', function (e)
{
alert('My label!');
}, false);
I want want to put several markers on the map, these markers are consisting of "parent" markers and "child" markers. All parent markers should be visible on the map the same time, whereas the child-markers of a specific parent-marker should be toggled on/off if clicking onto the specific parent-marker
I created the following working example to demonstrate:
<!DOCTYPE html>
<html>
<head>
<title>Test 1</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<style>
body {padding: 0; margin: 0;}
html, body, #map {height: 100%;}
</style>
</head>
<body>
<div id='map'></div>
<script>
var thunder = L.tileLayer('https://{s}.tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png', {subdomains:'abc', attribution:'Thunderforest | OpenStreetMap' });
var map = L.map('map',{layers: [thunder]}).setView([50.08, 10.08], 12);
var parent1 = L.marker([50.0, 10.0]).bindPopup('Marker 1');
var parent2 = L.marker([50.1, 10.1]).bindPopup('Marker 2');;
var layergroupParents = L.layerGroup([parent1, parent2]);
layergroupParents.addTo(map);
var child1a = L.marker([50.02, 10.02],{title: 'Child 1a'});
var child1b = L.marker([50.04, 10.04],{title: 'Child 1b'});
var layergroupChilds1 = L.layerGroup([child1a, child1b]);
var child2a = L.marker([50.12, 10.12],{title: 'Child 2a'});
var child2b = L.marker([50.14, 10.14],{title: 'Child 2b'});
var layergroupChilds2 = L.layerGroup([child2a, child2b]);
parent1.on('click', function(){
if (map.hasLayer(layergroupChilds1)) {
map.removeLayer(layergroupChilds1)
} else {
layergroupChilds1.addTo(map);
}
});
parent2.on('click', function(){
if (map.hasLayer(layergroupChilds2)) {
map.removeLayer(layergroupChilds2)
} else {
layergroupChilds2.addTo(map);
}
});
</script>
</body>
</html>
Since I want to display quite a lot markers, I want put the marker's properties into an Array ("markerArray") and process its markers by the help of For-Loops:
<!DOCTYPE html>
<html>
<head>
<title>Test 2</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.0.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.0.1/dist/leaflet.js"></script>
<style>
body {padding: 0; margin: 0;}
html, body, #map {height: 100%;}
</style>
</head>
<body>
<div id='map'></div>
<script>
var thunder = L.tileLayer('https://{s}.tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png', {subdomains:'abc', attribution:'Thunderforest | OpenStreetMap' });
var map = L.map('map',{layers: [thunder]}).setView([50.08, 10.08], 12);
var markerArray = [
["Marker 1", 50.0, 10.0, [["Child 1a", 50.02, 10.02], ["Child 1b", 50.04, 10.04]]],
["Marker 2", 50.1, 10.1, [["Child 1a", 50.12, 10.12], ["Child 1b", 50.14, 10.14]]],
];
var numberParents = markerArray.length;
var layergroupParents = L.layerGroup();
for (cnt1=0; cnt1<numberParents; cnt1++) {
var parentObject = L.marker([markerArray[cnt1][1], markerArray[cnt1][2]]);
parentObject.bindPopup(markerArray[cnt1][0]);
layergroupParents.addLayer (parentObject);
var numberChilds = markerArray[cnt1][3].length;
var layergroupChilds = L.layerGroup();
for (cnt2=0; cnt2<numberChilds; cnt2++) {
var childObject = L.marker([markerArray[cnt1][3][cnt2][1], markerArray[cnt1][3][cnt2][2]], {title: markerArray[cnt1][3][cnt2][0]});
layergroupChilds.addLayer (childObject);
}
parentObject.on('click', function(){
if (map.hasLayer(layergroupChilds)) {
map.removeLayer(layergroupChilds)
} else {
layergroupChilds.addTo(map);
}
});
}
layergroupParents.addTo(map);
</script>
</body>
</html>
If you execute these script you will see, that there's some problem with assigning an individual 'click' event to each individual parent-marker. Right now just the child-markers of the last parent-marker are toggled on/off even if I click onto the first parent-marker.
Do you have an idea how I could solve these problem and Script 2 is working like in Script 1?
For it to work, you have to attach the children to the parent (using a javascript property)
var layergroupChilds = L.layerGroup();
parentObject.layergroupChilds = layergroupChilds;
When parent receives a click, you can find the parent object in the event e, and hence its children.
parentObject.on('click', function(e){
if (map.hasLayer(e.target.layergroupChilds)) {
map.removeLayer(e.target.layergroupChilds)
} else {
e.target.layergroupChilds.addTo(map);
}
});
Here is your code with corrections
I have a few map markers that are located all over the place and I want to auto zoom to show them all.
The code I have should work fine but sometimes (seems to depend whereabouts the map markers are) it doesn't always zoom correctly to show the markers.
Here's a fiddle (with example markers to show the problem): http://jsfiddle.net/amnesia7/9YUVe/embedded/result/ using the following marker locations:
// Add markers to the map for each location
addMarker(1, "Hello 1", [-18,178.333]);
addMarker(2, "Hello 2", [-18.5,180]);
addMarker(3, "Hello 3", [-18.5,-178.333]);
The auto-zoom has gone completely wrong and seems to be zoomed in on the sea somewhere.
Looks to be a bug to me because it seems to depend on whereabouts the map markers are as to whether it zoom correctly or not.
UPDATE
I've created, what I hope will be, a simpler version using the HERE developer demo for "Zoom to a set of markers"
http://jsfiddle.net/amnesia7/uhZVz/
You need to zoom the map out to see the markers that should be in view by default.
Thanks
It looks like a bug to me too, and only occurs when markers cluster around the 180th line of longitude.
Seems that the zoomTo() calculation is incorrect in this case, only taking in to account the last marker since it is on the "wrong" side of the international date line.
Anyway, getWidth() on the viewport does seem to work, so you could hack in your own zoomTo() function as shown in the kludge below.
Also note the use of kml=auto&map=js-p2d-dom when loading the library - this uses the DOM implementation rather than the canvas implementation this properly shows markers on both sides of the 180th line of longitude.
<!DOCTYPE HTML SYSTEM>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9" />
<style type="text/css">
html {
overflow:hidden;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
position: absolute;
}
#mapContainer {
width:100%;
height: 100%;
left: 0;
top: 0;
position: absolute;
}
</style>
<script type="text/javascript" charset="UTF-8" src="http://api.maps.nokia.com/2.2.3/jsl.js?kml=auto&map=js-p2d-dom"></script>
</head>
<body>
<div id="mapContainer"></div>
<script type="text/javascript">
/* Set authentication token and appid
* WARNING: this is a demo-only key
* please register on http://api.developer.nokia.com/
* and obtain your own developer's API key
*/
nokia.Settings.set("appId", "APP_ID");
nokia.Settings.set("authenticationToken", "TOKEN");
// Get the DOM node to which we will append the map
var mapContainer = document.getElementById("mapContainer");
// Create a map inside the map container DOM node
var map = new nokia.maps.map.Display(mapContainer, {
// initial center and zoom level of the map
center: [52.51, 13.4],
zoomLevel: 13,
components: [
// We add the behavior component to allow panning / zooming of the map
new nokia.maps.map.component.Behavior()
]
});
// We create an instance of Container to store markers per city
var myContainer = new nokia.maps.map.Container();
/* We add all of the city containers to map's object collection so that
* when we add markers to them they will be rendered onto the map
*/
map.objects.add(myContainer);
// We create several of marker for a variety of famous landmarks
var firstMarker = new nokia.maps.map.StandardMarker(
[-18, 178.333],
{ text: 1 }
),
secondMarker = new nokia.maps.map.StandardMarker(
[-18.5, 180],
{ text: 2 }
),
thirdMarker = new nokia.maps.map.StandardMarker(
[-18.5, -178.333],
{ text: 3 }
);
// Add the newly created landmakers per city to its container
myContainer.objects.addAll([firstMarker, secondMarker, thirdMarker]);
/* Now we calculate the bounding boxes for every container.
* A bounding box represents a rectangular area in the geographic coordinate system.
*/
var myBoundingBox = myContainer.getBoundingBox();
zoom = 1;
map.setCenter(myBoundingBox.getCenter());
map.setZoomLevel(zoom);
while (map.getViewBounds().getWidth() > myBoundingBox.getWidth()) {
zoom++;
map.setZoomLevel(zoom);
}
zoom--
map.setZoomLevel(zoom--);
</script>
</body>
</html>
I'm fairly new to javascript and kinetic-js.
A while ago I created a script containing a Shape with Kinetic-js 3.9.0.
It was something like this (just the relevant code):
popup = new Kinetic.Shape({
drawFunc: function() {
item = itemlist[0];
},
itemlist: []
}
With 3.9.0 that worked in Firefox, but as of 3.9.2 it doesn't work any more.
Ther error console gives the message "TypeError: popup.itemlist is undefined".
What am I doing wrong?
I think you should initialize the itemlist variable after declaring the popup object.
It seems that Kinetic doesn't accepts user variables in their constructors methods.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.10.5.js"></script>
<script>
function draw() {
var stage = new Kinetic.Stage({
container : "container",
width : 800,
height : 600
});
var layer = new Kinetic.Layer();
var popup = new Kinetic.Shape({
drawFunc: function(context) {
context.fillText(this.itemlist[0], 10,10);
context.fillText(this.itemlist[1], 10,50);
context.fillText(this.itemlist[2], 10,90);
this.fill(context);
this.stroke(context);
},
fill: "red",
stroke: "green", strokeWidth:1
});
popup.itemlist = ["one", "two", "three"];
layer.add(popup);
// Add the layer to the stage
stage.add(layer);
};
window.onload = draw;
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>