I added amCharts chart to OpenLayers map overlay but chart cursor zoom not work like the image provided below:
The example provided below:
// Overlays init variables and function
var container;
var content;
var closer = document.getElementById('popup-closer');
var overlay;
function createOverlay(width) {
container = document.getElementById('popup');
container.style.width = width;
content = document.getElementById('popup-content');
closer = document.getElementById('popup-closer');
return container;
}
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([51.338076, 35.699756]),
zoom: 12
})
});
map.on("click", function(e) {
let coordinates = e.coordinate;
createOverlay("500px");
content.innerHTML = '<div id="chartdiv" class="ltr"></div>';
am4core.ready(function() {
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
var chart = am4core.create("chartdiv", am4charts.XYChart);
var data = [];
var value = 50;
for(let i = 0; i < 300; i++){
let date = new Date();
date.setHours(0,0,0,0);
date.setDate(i);
value -= Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
data.push({date:date, value: value});
}
chart.data = data;
// Create axes
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.minGridDistance = 60;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = "value";
series.dataFields.dateX = "date";
series.tooltipText = "{value}"
series.tooltip.pointerOrientation = "vertical";
chart.cursor = new am4charts.XYCursor();
chart.cursor.snapToSeries = series;
chart.cursor.xAxis = dateAxis;
//chart.scrollbarY = new am4core.Scrollbar();
chart.scrollbarX = new am4core.Scrollbar();
}); // end am4core.ready()
$(".ol-popup").show();
overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanMargin: 20,
autoPanAnimation: {
duration: 50
}
});
map.addOverlay(overlay);
overlay.setPosition(coordinates);
});
/* ol PopUp */
.ol-popup {
text-align: right;
position: absolute;
background-color: white;
-webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
border-radius: 10px;
bottom: 12px;
transform: translateX(50%);
display: none;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 50%;
transform: translateX(-50%);
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 50%;
transform: translateX(-50%);
}
.ol-popup-closer {
text-decoration: none !important;
font-size: 16px;
position: absolute;
top: 5px;
right: 8px;
cursor: pointer;
}
.map {
height: 400px;
width: 100%;
}
#chartdiv {
width: 100%;
height: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet"/>
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="map" class="map"></div>
<div id="popup" class="ol-popup">
<i class="fas fa-times ol-popup-closer" id="popup-closer"></i>
<div id="popup-content" class="p-4"></div>
</div>
As you can see, I created a dynamic overlay and add it to map and when user click on map then overlay popup will be shown to the user after that chart created and the chart cursor zoom not work but in the other place of my website it works perfectly.
This occurs due to OpenLayers Overlay entity stopping the event propagation (e.g. click & drag event on chart)
This can be disabled very easily via stopEvent: false;
overlay = new ol.Overlay({
element: container,
stopEvent: false,
autoPan: true,
autoPanMargin: 20,
autoPanAnimation: {
duration: 50
}
});
More on OpenLayers Overlay
The problem with this is that, the same click & drag event will be propagated to the map in the back, and the selection of the chart will be impossible to do. Example of this trouble can be seen on this fiddle. Also there is a ticket on Github regarding this exact issue.
To resolve this I've used a very simple idea, to track when the cursor is on the overlay, and disable map events during those times;
var mouseOver = false;
function createOverlay(width) {
container = document.getElementById('popup');
container.style.width = width;
container.onmouseover = function() {
mouseOver = true; // when cursor is targeting overlay we enable this boolean
};
container.onmouseout = function() {
mouseOver = false; // and disable when out
};
...
}
Then using this boolean as following;
map.on("pointerdrag", function(e) {
if (mouseOver) {
e.stopPropagation();
return;
}
});
to disable dragging event, and;
map.on("click", function(e) {
if (mouseOver) {
return;
}
// rest of chart creation logic here
}
to disable a new overlay creation event.
Final perfectly working fiddle can be found
here
Pirooz bashi buddy
Related
eduReveal = 400;
var eduAni = false;
var education = document.getElementById('education');
var track = document.getElementById('track');
var plane = document.getElementById('plane');
window.addEventListener('scroll', function() {
var topMost = window.innerHeight;
var trackPos = education.getBoundingClientRect().top;
if (eduAni == false && (topMost - eduReveal) > trackPos) {
track.style.width = '100%';
plane.style.transform = 'translate(800px)';
plane.style.transitionDuration = '5s';
track.style.transitionDuration = '5s';
eduAni = true;
console.log("Track");
}
});
#trackBox {
width: 800px;
height: 2px;
transform: rotate(-20deg);
}
#track {
width: 0%;
height: 100%;
background-color: white;
}
#plane {
color: white;
position: relative;
transform: scale(2);
}
<div id="trackBox">
<div id="track"><i class="fa-solid fa-plane" id="plane"></i></div>
</div>
All the parts of the puzzle are given above. When I change the size of an element using transform: scale(), and then using javascript translate that element, its size turns down to normal again.
When you set the CSS transform property, you reset any transformations that were previously on it. So when you were setting your translate in JS, you were overwriting the scale that was set in your CSS. An easy solution is to store your transformations individually as custom properties like so:
eduReveal = 400;
var eduAni = false;
var education = document.getElementById('education');
var track = document.getElementById('track');
var plane = document.getElementById('plane');
window.addEventListener('scroll', function() {
var topMost = window.innerHeight;
var trackPos = education.getBoundingClientRect().top;
if (eduAni == false && (topMost - eduReveal) > trackPos) {
track.style.width = '100%';
plane.style.transform = 'scale(var(--scale, 2)) translate(800px)';
plane.style.transitionDuration = '5s';
track.style.transitionDuration = '5s';
eduAni = true;
console.log("Track");
}
});
body {
min-height: 101vh;
background-color: skyblue;
}
#trackBox {
width: 800px;
height: 2px;
transform: rotate(-20deg);
}
#track {
width: 0%;
height: 100%;
background-color: white;
}
#plane {
--scale: 2;
color: white;
position: relative;
}
<div id="education">
<div id="trackBox">
<div id="track"><i class="fa-solid fa-plane" id="plane">Plane Icon</i></div>
</div>
</div>
I want to implement a draggable map containing certain elements.
--> See JSFiddle: https://jsfiddle.net/7ndx7s25/7/
By use of mousedown, mousemove and mouseup I achieved the dragging.
However I am facing problems:
When pressing the mouse button down and then moving outside the window I do not get a mouseup event. Reentering the window (having released the mouse button long ago) my map still thinks the button is down and misbehaves accordingly.
When there are objects on the map, I do not get mousemove events while moving through these objects. Therefore the map hangs and jumps as I enter and leave such an object.
While over such objects I still want to have a move mouse cursor. I could change the cursor style on each object (in the Fiddle I did this for Object 1 as an example), but this doesn't seem like a good way. Is there a more elegant solution?
You need e.g. mouseout to catch when leaving the canvas, though that event will also fire when the cursor move over the other elements.
One easy fix is to simply add a class to canvas, that set pointer-events: none on those.
With that class you can control the cursor as well, and avoid setting it with the script.
Stack snippet
updateInfo = function() {
document.getElementById('info').innerHTML =
'Position = ' + JSON.stringify(position) +
'<br />dragInfo = ' + JSON.stringify(dragInfo);
};
const canvas = document.getElementsByTagName('canvas')[0];
let position = { x: 0, y : 0 };
let dragInfo = null;
updateInfo();
canvas.addEventListener('mousedown', function(e) {
dragInfo = {
startEvent: {
x: e.clientX,
y: e.clientY,
},
startPosition: position
};
canvas.classList.add('dragging');
updateInfo();
});
canvas.addEventListener('mousemove', function(e) {
if (dragInfo === null) return;
position = {
x: dragInfo.startPosition.x - (e.clientX - dragInfo.startEvent.x),
y: dragInfo.startPosition.y - (e.clientY - dragInfo.startEvent.y)
};
updateInfo();
});
canvas.addEventListener('mouseup', function(e) {
dragInfo = null;
canvas.classList.remove('dragging');
updateInfo();
});
canvas.addEventListener('mouseout', function(e) {
dragInfo = null;
canvas.classList.remove('dragging');
updateInfo();
});
* {
user-select: none;
font-family: monospace;
}
canvas {
background: black;
border: 1px solid red;
}
.dragging {
cursor: move;
}
.obj {
position: absolute;
width: 50px;
height: 50px;
background: green;
color: white;
text-align: center;
line-height: 50px;
font-weight: bold;
}
.dragging ~ .obj {
pointer-events: none;
}
<div id="myMap-ish">
<canvas width="500" height="300"></canvas>
<div class="obj" style="left: 30px; top: 35px">1</div>
<div class="obj" style="left: 175px; top: 79px">2</div>
<div class="obj" style="left: 214px; top: 145px">3</div>
<div class="obj" style="left: 314px; top: 215px">4</div>
</div>
<div id="info"></div>
Another option could be to use mouseleave, on the outer wrapper, the myMap-ish element, which could be combined with the above added class to simply cursor handling.
The main difference between mouseout and mouseleave is that the latter won't fire when hovering children, as shown in below sample, so we don't need to toggle pointer-events as we did in the first sample.
Note, to simply use mouseleave in the first sample, on canvas, will have the same issue mouseout has, since the "other element" aren't children of the canvas.
Stack snippet
updateInfo = function() {
document.getElementById('info').innerHTML =
'Position = ' + JSON.stringify(position) +
'<br />dragInfo = ' + JSON.stringify(dragInfo);
};
const canvas = document.getElementById('myMap-ish');
let position = { x: 0, y : 0 };
let dragInfo = null;
updateInfo();
canvas.addEventListener('mousedown', function(e) {
dragInfo = {
startEvent: {
x: e.clientX,
y: e.clientY,
},
startPosition: position
};
canvas.style.cursor = 'move';
document.querySelectorAll('.obj')[0].style.cursor = 'move'; // TODO for all objects
updateInfo();
});
canvas.addEventListener('mousemove', function(e) {
if (dragInfo === null) return;
position = {
x: dragInfo.startPosition.x - (e.clientX - dragInfo.startEvent.x),
y: dragInfo.startPosition.y - (e.clientY - dragInfo.startEvent.y)
};
updateInfo();
});
canvas.addEventListener('mouseup', function(e) {
dragInfo = null;
canvas.style.cursor = 'default';
document.querySelectorAll('.obj')[0].style.cursor = 'default'; // TODO for all objects
updateInfo();
});
canvas.addEventListener('mouseleave', function(e) {
dragInfo = null;
canvas.style.cursor = 'default';
document.querySelectorAll('.obj')[0].style.cursor = 'default'; // TODO for all objects
updateInfo();
});
* {
user-select: none;
font-family: monospace;
}
canvas {
background: black;
border: 1px solid red;
}
.obj {
position: absolute;
width: 50px;
height: 50px;
background: green;
color: white;
text-align: center;
line-height: 50px;
font-weight: bold;
}
<div id="myMap-ish">
<canvas width="500" height="300"></canvas>
<div class="obj" style="left: 30px; top: 35px">1</div>
<div class="obj" style="left: 175px; top: 79px">2</div>
<div class="obj" style="left: 214px; top: 145px">3</div>
<div class="obj" style="left: 314px; top: 215px">4</div>
</div>
<div id="info"></div>
html, body {
height: 100%;
padding: 0;
margin: 0;
font-family: sans-serif;
font-size: small;
}
#map {
width: 100%;
height: 60%;
}
#selection-map {
height: 40%;
width: 100%;
background-color: whitesmoke;
}
.selection-title {
height: 15%;
width: 15%;
margin: auto;
position: relative;
border-bottom: 3px solid #DA1A21;
font-size: 30px;
top: 30px;
color: #DA1A21;
}
.selection-form {
height: 20%;
width: 100%;
text-align: center;
top: 100px;
position: relative;
}
.selection-form input {
height: 20px;
width: 300px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>SouthWest Airport Map</title>
<link rel="stylesheet" href="lib/ol3/ol.css" />
<link rel="stylesheet" href="ol3.css" />
</head>
<body>
<div id="map" class="map"></div>
<div id="selection-map" class="map">
<h2 class="selection-title">Airports Selected</h2>
<form class="selection-form" method="post" action="traitement.php">
<p><input type="text" id="input-airports" placeholder="Click a marker" /></p>
<p>For Selecting Multiple Airpots, please press Shift and select all the markers that you need</p>
</form>
</div>
<script src="../common/lib/reqwest.min.js"></script>
<script src="lib/proj4.js"></script>
<script src="lib/ol3/ol.js"></script>
<script src="ol3.js"></script>
</body>
</html>
I implemented a map with markers pointing to airports, and when I click on a marker the name of the airport appears in a field. (All data included in a GEOJson external file). I just have a last problem that I can't resolve :
I can only select one marker at a time, and i want to be able to select multiples Markers, and make all the name appears in the field. I think that my problem are that I need to change the calling my features, but i don't know what to write instead. I already tried to change my function from "forEachFeatureAtPixel" to "forFeatureAtPixel" or things like that, but every time I break my map.
I'm a beginner in Javascript :/ Here is my JS code
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
format: new ol.format.GeoJSON(),
url: '//localhost/osgis-ol3-leaflet-master/ol3/data.geojson'
}),
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({
color: 'green'
})
})
})
});
var rasterLayer = new ol.layer.Tile({
source: new ol.source.TileJSON({
url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.json',
crossOrigin: ''
})
});
var map = new ol.Map({
layers: [rasterLayer, vectorLayer],
target: document.getElementById('map'),
view: new ol.View({
center: [0, 0],
zoom: 3
})
});
var input = document.getElementById('id-airports');
var select_interaction = new ol.interaction.Select();
map.addInteraction(select_interaction);
select_interaction.on('select', function(evt) {
var features = select_interaction.getFeatures();
var value = '';
features.forEach(function(feature){
// change this to your own needs
value += feature.get('name') + ', ';
});
input.value = value;
});
map.on('pointermove', function(e) {
if (e.dragging) return;
var hit = map.hasFeatureAtPixel(map.getEventPixel(e.originalEvent));
map.getTarget().style.cursor = hit ? 'pointer' : '';
});
UPDATE:
(fiddle) — To select multiple use Shift + Click
You will remove that another approach:
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(
evt.pixel, function(ft, l) { return ft; });
if (feature) ...
});
And use ol.interaction.Select, see bellow.
There's a select interaction that you can add to your map with a lot of options, see ol.interaction.Select. You can set, for instance some conditions:
// only select with Mouse Hover
var select_interaction = new ol.interaction.Select({
condition: ol.events.condition.pointerMove
});
Another condition:
// only select with Alt key + Click
var select_interaction = new ol.interaction.Select({
condition: function(mapBrowserEvent) {
return ol.events.condition.click(mapBrowserEvent) &&
ol.events.condition.altKeyOnly(mapBrowserEvent);
}
});
In your case, putting all together would be something like:
var select_interaction = new ol.interaction.Select();
map.addInteraction(select_interaction);
// add a listener to know when features are selected
select_interaction.on('select', function(evt) {
var features = select_interaction.getFeatures();
features.forEach(function(feature){
// change this to your own needs
input.value += feature.get('name') + ', ';
});
});
I'm trying to understand how can I display markers/popups on osm map with openlayers3, I have found examples in examples on ol3 web page, but...
Is there more examples for coding markers/popups with javascript or jquery, preferably something like this or similar examples.
The idea is to mark a building, by clicking on the marker it will popup some info for the building, further more I would like to connect important places from the city to this building (library, restaurants, bus stops, etc). I wish if someone can explain me how to start up building this, and I don't want to use bootstrap3 for this ( I have seen overlay example), instead want pure html5, css3, javascript/jquery)
You can create a popup with pure HTML, CSS and JavaScript, as shown in the popup example. A fully working example for what you want is here: http://jsfiddle.net/ahocevar/z86zc9fz/1/.
The HTML for the popup is simple:
<div id="popup" class="ol-popup">
<div id="popup-content"></div>
</div>
The CSS is a bit more involved:
.ol-popup {
position: absolute;
background-color: white;
-webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 12px;
left: -50px;
min-width: 80px;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.ol-popup-closer:after {
content: "✖";
}
To make a popup, use ol.Overlay:
var container = document.getElementById('popup');
var overlay = new ol.Overlay({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
});
map.addOverlay(overlay);
var closer = document.getElementById('popup-closer');
closer.onclick = function() {
overlay.setPosition(undefined);
closer.blur();
return false;
};
To make features clickable, use
var content = document.getElementById('popup-content');
map.on('singleclick', function(evt) {
var name = map.forEachFeatureAtPixel(evt.pixel, function(feature) {
return feature.get('name');
});
var coordinate = evt.coordinate;
content.innerHTML = name;
overlay.setPosition(coordinate);
});
For visual feedback when the pointer is over a feature, use
map.on('pointermove', function(evt) {
map.getTargetElement().style.cursor = map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
});
The features (i.e. markers) come from a vector layer:
var markers = new ol.layer.Vector({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([16.37, 48.2])),
name: 'Vienna',
type: 'City'
}),
new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([-0.13, 51.51])),
name: 'London',
type: 'City'
})
]
}),
style: new ol.style.Style({
image: new ol.style.Icon({
src: '//openlayers.org/en/v3.12.1/examples/data/icon.png',
anchor: [0.5, 1]
})
})
});
map.addLayer(markers);
The above snippet uses a fixed style, i.e. the same icon for all types of features. If you have different types of features, you can define a style function instead of a fixed style:
var cityStyle = new ol.style.Style({
image: new ol.style.Icon({
src: '//openlayers.org/en/v3.12.1/examples/data/icon.png',
anchor: [0.5, 1]
})
});
var otherStyle = new ol.style.Style({
image: new ol.style.Icon({
src: '//openlayers.org/en/v3.12.1/examples/data/Butterfly.png'
})
});
var markers = new ol.layer.Vector({
// ...
style: function(feature, resolution) {
if (feature.get('type') == 'City' {
return cityStyle;
}
return otherStyle;
}
});
I have a page with several different views. At the top there is a small gogole map for searching. One of the views has a results map.
Site done in MVC 5 bootstrap 4.
Both were working together but as you do was adding/changing things. Now they don't play well together.
When the results map is shown - the smaller search map does not display the roadmap. Map seems to have initialised ok - but doesn't show the roads/map. If I change to Satellite - it seems to show within part of the map/frame only. I've also noticed that the MapType control has changed from a bar to a drop-down, which is the default for smaller screens.
As far as I can see - bot maps use separate variables.
Won't post the code here initially as there's a fair bit - and I thought I'd make a preliminary query in case someone has experienced such behaviour before.
If I disable the results map the search map works again.
Correct search map, when shown on a page/view without second map :
On page/view where the second map is displayed. Note change of map type control:
If I change to display Satellite rather than road - a portion displays. This is drageable to a certain extent but portion will then change:
Any ideas ?
Could bootstrap be sending incorrect screen size signals ?
Can post the code if think it will help.
To clarify:
MVC = ASP.Net MVC
Bootstrap = http://getbootstrap.com v 3.3.4
Search Map definition.
Note HTML and JS contains some ASP.Net MVC Razor code prefixed with "#"
Also the map is only initialised when the Bootstrap panel is opened not on window load.
< script >
var markersSearch = [];
var mapSearch;
function ClearSearch() {
//clear values + submmit form empty
var form = document.getElementById("searchform");
document.getElementById("Search").value = "";
document.getElementById("eventtypeID").selectedIndex = 0;
document.getElementById("EventFrom").value = "";
document.getElementById("EventTo").value = "";
document.getElementById("Free").checked = false;
document.getElementById("hidLat").value = "";
document.getElementById("hidLng").value = "";
document.getElementById("distance").selectedIndex = 1;
ClearLocations();
form.submit();
}
function showsearch() {
//show serch panel
//only initialise map if not already done
if (typeof mapSearch == 'undefined') {
initializeSearch();
}
}
function SetMyLocation() {
//clear existing markers
ClearLocations();
//set to current pos
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
mapSearch.setCenter(initialLocation);
// Create a marker for each place.
var marker = new google.maps.Marker({
map: mapSearch,
//icon: image,
title: 'My Location',
position: initialLocation,
draggable: true
});
//display
markersSearch.push(marker);
//zoom
mapSearch.setZoom(16);
//listener
google.maps.event.addListener(marker, 'drag', function(event) {
SetHtmlLocation(event.latLng.lat(), event.latLng.lng());
});
google.maps.event.addListener(marker, 'dragend', function(event) {
SeHtmltLocation(event.latLng.lat(), event.latLng.lng());
});
SetHtmlLocation(position.coords.latitude, position.coords.longitude);
});
}
}
function SetLocation(lat, lng) {
ClearLocations();
var setLocation = new google.maps.LatLng(lat, lng);
// Create a marker for each place.
var markerSetLoc = new google.maps.Marker({
map: mapSearch,
//icon: image,
title: 'My Location',
position: setLocation,
draggable: true
});
mapSearch.setCenter(setLocation);
//zoom
mapSearch.setZoom(16);
//listener
google.maps.event.addListener(markerSetLoc, 'drag', function(event) {
SetHtmlLocation(event.latLng.lat(), event.latLng.lng());
});
google.maps.event.addListener(markerSetLoc, 'dragend', function(event) {
SetHtmlLocation(event.latLng.lat(), event.latLng.lng());
});
//addd to array
markersSearch.push(markerSetLoc);
SetHtmlLocation(lat, lng);
} //SetLocation
function SetHtmlLocation(lat, lng) {
document.getElementById("hidLat").value = lat;
document.getElementById("hidLng").value = lng;
}
function ClearLocationsIncInput() {
document.getElementById("pac-input").value = '';
ClearLocations();
}
function ClearLocations() {
for (var i = 0; i < markersSearch.length; i++) {
google.maps.event.clearInstanceListeners(markersSearch[i]);
markersSearch[i].setMap(null);
}
markersSearch = [];
SetHtmlLocation(null, null);
}
function initializeSearch() {
//initialise starting point if form re-submited
#
if (!string.IsNullOrEmpty(ViewBag.currentLat)) {#: var londonLatLong = new google.maps.LatLng(#ViewBag.currentLat, #ViewBag.currentLng);#: var zoom = 16;
//SetHtmlLocation done in control itself
} else {#: var londonLatLong = new google.maps.LatLng(51.507, -0.1277);#: var zoom = 13;
}
var mapOptionsSearch = {
center: londonLatLong,
zoom: zoom,
streetViewControl: false,
zoomControlOptions: {
style: google.maps.ZoomControlStyle.SMALL,
position: google.maps.ControlPosition.RIGHT_BOTTOM
},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
mapSearch = new google.maps.Map(document.getElementById('event-map-search'), mapOptionsSearch);
//IF ORIGINALLY PLACED - set marker on postback
#
if (!string.IsNullOrEmpty(ViewBag.currentLat)) {
#: SetLocation(#ViewBag.currentLat, #ViewBag.currentLng);
}
// Create the search box and link it to the UI element.
var input = /** ##type {HTMLInputElement} */ (
document.getElementById('pac-input'));
var inputgroup = (document.getElementById('pac-input-group'));
//mapSearch.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
mapSearch.controls[google.maps.ControlPosition.TOP_LEFT].push(inputgroup);
var searchBox = new google.maps.places.SearchBox( /** ##type {HTMLInputElement} */ (input));
// [START region_getplaces]
// Listen for the event fired when the user selects an item from the
// pick list. Retrieve the matching places for that item.
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
if (places.length == 0) {
return;
}
for (var i = 0, marker; marker = markersSearch[i]; i++) {
marker.setMap(null);
}
// For each place, get the icon, place name, and location.
ClearLocations();
//use places[0]
SetLocation(places[0].geometry.location.lat(), places[0].geometry.location.lng());
});
// [END region_getplaces]
// Bias the SearchBox results towards places that are within the bounds of the
// current map's viewport.
google.maps.event.addListener(mapSearch, 'bounds_changed', function() {
var boundsBias = mapSearch.getBounds();
searchBox.setBounds(boundsBias);
});
//google.maps.event.addDomListener(window, 'load', initialize);
} //initialize
$(function() {
$('[data-toggle="tooltip"]').tooltip()
})
< /script>
<style type="text/css"> #event-map-search {
height: 100%;
width: 100%;
min-width: 200px;
min-height: 200px;
margin: 0;
padding: 0;
}
.controls {
margin-top: 16px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
/*Auto complete ?*/
#type-selector {
color: #fff;
background-color: #4d90fe;
padding: 5px 11px 0px 11px;
}
#type-selector label {
/*font-family: Roboto;*/
font-size: 13px;
font-weight: 300;
}
#pac-input {
background-color: #fff;
/*font-family: Roboto;*/
/*font-size: 10px;*/
font-weight: 300;
width: 280px;
/*padding: 0 11px 0 13px;*/
text-overflow: ellipsis;
}
#pac-input-group {
width: 300px;
margin-top: 6px;
margin-left: 6px;
}
#pac-input:focus {
border-color: #4d90fe;
}
/*TODO - move to CSS*/
</style>
<div id="pac-input-group" class="input-group">
<input id="pac-input" class="form-control input-sm" type="text" placeholder="Choose a location">
<span class="input-group-btn">
<button class="btn btn-default btn-sm" type="button" data-toggle="tooltip" data-placement="bottom" title="Set to my location" onclick="javascript: SetMyLocation();">
<span class="glyphicon glyphicon-record" aria-hidden="true"></span>
</button>
<button class="btn btn-default btn-sm" type="button" data-toggle="tooltip" data-placement="bottom" title="Clear Location" onclick="javascript: ClearLocationsIncInput();">
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
</button>
</span>
</div>
<div id="event-map-search"></div>
#Html.Hidden("hidLat", (object)ViewBag.currentLat) #Html.Hidden("hidLng", (object)ViewBag.currentLng)
Code for the Display map, in one view which is included as a Razor/MVC:
Html.RenderPartial("EventsMap", Model);
< script type = "text/javascript" >
var markersDisplay = [];
var mapDisplay;
var boundsDisplay = new google.maps.LatLngBounds();
function initializeDisplayMap() {
#
if (Model.Count > 0) {#: var firstPointDisplay = new google.maps.LatLng(#Model.FirstOrDefault().address_latitude, #Model.FirstOrDefault().address_longitude);
} else {#: var firstPointDisplay = new google.maps.LatLng(51.507, -0.1277);
}
var mapOptionsDisplay = {
zoom: 13,
center: firstPointDisplay,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
mapDisplay = new google.maps.Map(document.getElementById('event-map-display'), mapOptionsDisplay);
//draw marker code from C#
#
foreach(var item in Model) {#: addMarkerDisplay(#item.address_latitude, #item.address_longitude, '#Html.EncodeJsString(item.event_title)', #item.event_ID);
}
//collect all in bounds
for (i = 0; i < markersDisplay.length; i++) {
boundsDisplay.extend(markersDisplay[i].getPosition());
}
//bounds map
mapDisplay.fitBounds(boundsDisplay);
}
function addMarkerDisplay(x, y, ptitle, eID) {
var location = new google.maps.LatLng(x, y);
var newmarkerDisplay = new google.maps.Marker({
position: location,
title: ptitle,
map: mapDisplay,
draggable: false,
id: eID
});
markersDisplay.push(newmarkerDisplay);
google.maps.event.addListener(newmarkerDisplay, 'click', function() {
highlightevent(this.id);
});
}
google.maps.event.addDomListener(window, 'load', initializeDisplayMap);
function highlightevent(id) {
$('#eventMapTable tr').each(function() {
//alert($(this).data('id'));
$(this).removeClass("eventMapRowHighlight");
if ($(this).data('id') == id) {
$(this).addClass("eventMapRowHighlight");
}
});
}
< /script>
/*---------------Events--------------------------*/
#event-map-display {
height: 100%;
width: 100%;
min-width: 300px;
min-height: 500px;
margin: 0;
padding: 0;
}
.eventTable tbody tr:hover td {
background-color: black;
color: white;
}
.eventTable tbody tr {
cursor: pointer;
}
#EventListImageContainer {
padding-top: 5px;
height: 100%;
}
#EventMapContainer {
padding-top: 5px;
height: 100%;
}
#EventListImageContainer img {
display: block;
margin-left: auto;
margin-right: auto;
}
.eventMapRowHighlight {
background-color: #highlightcol1;
-webkit-transition: background 0.5s linear;
-moz-transition: background 0.5s linear;
-ms-transition: background 0.5s linear;
-o-transition: background 0.5s linear;
transition: background 0.5s linear;
}
<div id="EventMapContainer" class="col-lg-5 col-md-5 col-sm-5 col-xs-12">
<div id="event-map-display"></div>
</div>
Fixed it. :)
Was calling the faulty map initialise routine from a onclick of the button that opened the Boostrap panel where it was located.
This had been working and still did when the page did not contain another map.
Thought I'd check for events fired after the boostrap panel had finished opening as it seemed to be a peculiarity to do with sizing.
So instead of firing on the button onclick I implemented the bootstrap event "shown.bs.collapse" : This event is fired when a collapse element has been made visible to the user (will wait for CSS transitions to complete).
Thus:
$('#searchpanel').on('shown.bs.collapse', function () {
if (typeof mapSearch == 'undefined') {
initializeSearch();
}
})