Customize OpenLayers Control - javascript

How can I easily customize OpenLayers map controls? Or at least, how can I minimize the controls' height?
Thank you.
PS. Is there any CSS override?

You can sub-class any of the openLayers controls. I just made a 'zoom-slider' by sub-classing PanZoomBar (panZoomBar.js), overriding the draw() method and commenting out all the button elements, just leaving the zoom slider.. like this:
function zoomSlider(options) {
this.control = new OpenLayers.Control.PanZoomBar(options);
OpenLayers.Util.extend(this.control,{
draw: function(px) {
// initialize our internal div
OpenLayers.Control.prototype.draw.apply(this, arguments);
px = this.position.clone();
// place the controls
this.buttons = [];
var sz = new OpenLayers.Size(18,18);
var centered = new OpenLayers.Pixel(px.x+sz.w/2, px.y);
this._addButton("zoomin", "zoom-plus-mini.png", centered.add(0, 5), sz);
centered = this._addZoomBar(centered.add(0, sz.h + 5));
this._addButton("zoomout", "zoom-minus-mini.png", centered, sz);
return this.div;
}
});
return this.control;
}
var panel = new OpenLayers.Control.Panel();
panel.addControls([
new zoomSlider({zoomStopHeight:11}),
new OpenLayers.Control.LayerSwitcher({'ascending':false}),
]);
map.addControl(panel);

There is a CSS file that comes with can controls all of the CSS commands for within openlayers generally .olZoombar { here}
It is probably the easiest way to edit those sorts of things otherwise you can edit the actual .js file for the control.

If you are talking about the PanZoomBar or ZoomBar, as has been mentioned, you need to edit the zoomStopHeight. However, You do not need to edit OpenLayers.js.
new OpenLayers.Control.PanZoomBar({zoomStopHeight: 7})
You could consider trying PanZoom, which has no bar.

To minimize the ZoomBar search for zoomStopHeight in OpenLayers.js and edit it as you wish.
Further reference: Link.

Take a look here - http://geojavaflex.blogspot.com/
I am in the process of showing how to do an involved customization of the LayerSwitcher. This might give you ideas on how to do what you are after.
There is a map on the page that shows how the control works, and subsequent posts will discuss the code in detail.
If you are just interested in code see the source of the page and look for the link to CustomLayerSwitcher.js for the customized version of the switcher.

Related

QML Map Smooth Zooming using Buttons

I am trying to create a map of a small area. On this map I have 2 buttons, one is for zooming in and the other is for out. I have created 2 buttons and 1 loader, then connected these together to make it work. My code for buttons and loader:
Loader.qml
Loader {
id: mapLoader
source: "map.qml"
function reload () {
source = ""
source = "map.qml"
console.log("Map Updated")
}
}
Buttons.qml
// This button zooms in 1 unit
// get_Zoomlevel() works on C++; therefore, it isn'T affected from qml reloads.
Button {
...
onClicked: {
map.setZoomLevel(map.get_ZoomLevel() + 1)
mapLoader.reload()
}
...
}
After all, it works as expected, I can zoom in and out easily. However, since the loader loads all the map components from scratch it takes a little longer for a normal and smooth user experience. Therefore, I am looking for a better way of loading or any other advice. Thanks in advance.
I have found the answer and I want to share for the future.
I thought that zoomLevel property of QML Map was only for reading, but I noticed I can also write; therefore, when I noticed it just becomes easy.
I created a variable,
property int zoomLv = 15 // default zoom level
and whenever I zoomed in/ out using buttons I just edited this variable instead of reloading the full map Item.
onClicked: {
zoomLv += 1
}

amCharts - amMap Home Button Method

I am creating an amMap through amCharts http://docs.amcharts.com/3/javascriptmaps/AmMap and it comes with its own home button which you can click and reverts to the map default.
I would like to do this externally through my own button, but can't quite find the methods that amCharts uses to achieve this.
A few methods I've used are:
chart.zoomTo(), chart.zoomToLongLat(), chart.zoomToXY() using the correct values of when the chart is initialized. This works fine when the chart is not resized ever, but when the chart is resized (not re-initialized), those values become undependable, yet the home button is still able to bring me back to the default zoom.
What method does this home button use? Or I can use to replicate what the home button does?
You need to call zoomToLongLat and pass in your map object's initialZoomLevel, initialZoomLongitude and initialZoomLatitude. From the demo on AmChart's knowledge base for its custom external home button:
function centerMap() {
map.zoomToLongLat(map.initialZoomLevel, map.initialZoomLongitude, map.initialZoomLatitude);
}
You can resize the frame on the codepen demo to see that it resets itself correctly each time.
Yes.. it very simple,
I did it this way:
map.addListener("rendered", function(event) {
var map = event.chart;
map.initialZoomLevel = map.zoomLevel();
map.initialZoomLatitude = map.zoomLatitude();
map.initialZoomLongitude = map.zoomLongitude();
});
function centerMap() {
map.zoomToLongLat(map.initialZoomLevel, map.initialZoomLongitude, map.initialZoomLatitude);
}
<div onclick="centerMap();" class="icon-home"></div>

Proper Way Of Modifying Toolbar After Init in TinyMCE

I am extending a cloud-hosted LMS with javascript. Therefore, we can add javascript to the page, but cannot modify the vendor javascript for different components.
The LMS uses tinyMCE frequently. The goal is to add a new button on to the toolbar of each tinyMCE editor.
The problem is that since the tinyMCE modules are initialized in the vendor's untouchable code, we cannot modify the init() call. Therefore, we cannot add any text on to the "toolbar" property of the init() object.
So I accomplished this in a moderately hacky way:
tinyMCE.on('AddEditor', function(e){
e.editor.on('init', function(){
tinyMCE.ui.Factory.create({
type: 'button',
icon: 'icon'
}).on('click', function(){
// button pressing logic
})
.renderTo($(e.editor.editorContainer).find('.mce-container-body .mce-toolbar:last .mce-btn-group > div')[0])
});
});
So this works, but needless to say I am not totally comfortable having to look for such a specific location in the DOM like that to insert the button. Although this works, I do not believe it was the creator's intention for it to be used like this.
Is there a proper way to add the button to a toolbar, after initialization, if we cannot modify the initialization code?
I found a more elegant solution, but it still feels a bit like a hack. Here is what I got:
// get an instance of the editor
var editor=tinymce.activeEditor; //or tinymce.editors[0], or loop, whatever
//add a button to the editor buttons
editor.addButton('mysecondbutton', {
text: 'My second button',
icon: false,
onclick: function () {
editor.insertContent(' <b>It\'s my second button!</b> ');
}
});
//the button now becomes
var button=editor.buttons['mysecondbutton'];
//find the buttongroup in the toolbar found in the panel of the theme
var bg=editor.theme.panel.find('toolbar buttongroup')[0];
//without this, the buttons look weird after that
bg._lastRepaintRect=bg._layoutRect;
//append the button to the group
bg.append(button);
I feel like there should be something better than this, but I didn't find it.
Other notes:
the ugly _lastRepaintRect is needed because of the repaint
method, which makes the buttons look ugly regardless if you add new
controls or not
looked in the code, there is no way of adding new controls to the
toolbar without repainting and there is no way to get around it
without the ugly hack
append(b) is equivalent to add(b).renderNew()
you can use the following code to add the button without the hack, but you are shortcircuiting a lot of other stuff:
Code:
bg.add(button);
var buttonElement=bg.items().filter(function(i) { return i.settings.text==button.text; })[0];
var bgElement=bg.getEl('body');
buttonElement.renderTo(bgElement);

OL3 - Trouble detecting clicks on features

My aim is to create a map for my work in OpenLayers 3 with several layers. One takes a basic feed from OpenStreetMaps. Another will be a transparent layer showing outlines of regions (not done yet). The third one, which is the one I'm having trouble with, shows a series of icons representing indivudal sites of interest on the map. I load the sites from a JS data stucture included as a separate script file. I have managed to get my code to add features that appear at the correct lat/lon. My next step is to get a HTML box (div) to appear in front of the map when they click on an icon (to display details of the site). However, I cannot get this to work. Apologies for my noobish coding, but it's really got me stumped and I'd really appreciate any help.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="ol.css" type="text/css">
<link rel="stylesheet" href="map.css" type="text/css">
<script src="ol.js" type="text/javascript"></script>
<script src="sites.js" type="text/javascript"></script>
<script type="text/javascript">
function buildLayerFromSites(allSites)
// allSites is just an array of data structures
{
var count, site;
// for each site in the array, make a feature
for (count=0;count<allSites.length;count++)
{
geom = new ol.geom.Point(ol.proj.fromLonLat([allSites[count].longitude,allSites[count].latitude]));
site = new ol.Feature(geom);
site.Name = allSites[count].siteName; // <-- can I assign further details in the structure like this?
var siteStyle = new ol.style.Style({
image: new ol.style.Icon ({
src: 'icon-blue.png',
scale: 0.1,
opacity: 0.9,
})
})
site.setStyle(siteStyle);
siteFeatures[count] = site;
}
siteSource = new ol.source.Vector ({
features: siteFeatures
})
siteLayer = new ol.layer.Vector({
source: siteSource
});
map.addLayer(siteLayer);
}
</script>
<title>Map</title>
</head><body>
...
<div id="map" class="map">
...
<script type="text/javascript">
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([115.51, -31.57]),
zoom: 8
})
});
buildLayerFromSites(includeSites); // adds the second layer with the sites
// click event handler, basically same as http://openlayers.org/en/v3.12.1/examples/icon.html
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature,layer) {
return feature;
});
if (feature) {
console.log("feature got clicked on"); // do stuff
} else {
console.log("didn't click a feature");
}
});
</script>
</body>
</html>
The map and the icons load, but when I click the icons, no matter how zoomed in or out I am, it doesn't detect a match with the icon I'm clicking on. The thing is, the event handler code is the same as in the official example, which make me think it's the way I'm creating the features. On the other hand, the features display fine as icons, its just the click event that doesn't seem to work. Similar weird stuff happens for the mouse cursor change from the example. I sorta guess it's because I don't understand the way the data/functions are structured in OL, and I find the documentation doesn't fully explain how it all works, so I've been writing snippets like this trying to take a look:
var myLayers = map.getLayers();
console.log("keys - " + myLayers.getKeys); // prints out 'function (){return Object.keys(this.B)}' - what does that mean?
var mySource = myLayers.getSource;
console.log("source" + mySource.getProjection); // doesn't work
var features = mySource.getFeatures; // says mySource is undefined
Of course it fails totally.
How do I get it to detect the clicks on the icons/features so I can tell a div to appear and display my data at the right time? Am I doing this right? What don't I understand about the way the data/functions work? I'm a big JS noob so I hope I'm not doing something stupid, but it's causing me massive problems and I could really use your help! Thanks all!
If someone else comes upon this issue: my solution was changing the Feature icon PNG image to not have transparency (no color).
If your image is PNG and has transparency,
where it is transparent it won't be clickable
(I'm on OpenLayers v5). For example, I had an image that was a circle and it was transparent inside and just colored on the outside border.
When I changed the image to something without transparency in the middle (it can still be PNG of course) everything was okay. It seems this is how OpenLayers handles pixels for images - if the map can be seen through the image, it's not a 'hover' even though you are on a Feature.
console.log("keys - " + myLayers.getKeys); // prints out 'function (){return Object.keys(this.B)}' - what does that mean?
It means you're trying to print the function itself, not the result of it's execution. Should be
console.log("keys - " + myLayers.getKeys())
Same with
mySource.getProjection();
mySource.getFeatures();
Usually if the attribute name starts with "get" and is written in camelCase - it's a function. Keep that hint in mind :)
After long hours staring at my screen and hitting my head on my desk, I've stumbled across the solution to my problem. It's a little obscure but mind-numbingly simple/stupid/silly. I thought I'd post the solution here for others.
I wrote a couple of lines of code to resize the viewport when the page is loading and again when the window is resized, so the map would adjust to the available user's browser window space. Unfortunately, as far as I can work out, OL doesn't know about it so the icons and the features are no longer in the same place after the resize. I didn't know this though, until after countless hours I was randomly clicking and resizing it detected a feature click.
Luckily there is an easy way to solve it once you figure out this is the problem. Basically just add map.updateSize() to the part of your code that resizes the viewport. So far this seems to have solved the problem.
The functions is only work on pixel of features so to solve this you can add some style with your image with fill with something like rgb(255,0,0,0.001) propert. I have tried it and i worked for me.

using onmouseover to change text hyperlink into an image hyperlink?

Please bear with me I am brand new to learning javascript (self taught)! I am usually one to find answers on my own from just web browsing but so far I haven't found any resources explaining how to accomplish the following:
So, basically all I want to do is change this (HTML):
SPEAKERS
to an image by using javascript.
The image is kept in the same folder as the html and the js.
Here is as far as I know to go with the javascript:
function showImage()
{
picture = new Image(100,100);
picture.src = "icon2.png";
document.getElementById("speakers").innerHTML = picture.src;
}
function goBack()
{
document.getElementById("speakers").innerHTML="SPEAKERS";
}
For clarity, all I would like to do is change the text ("SPEAKERS") to an image using 'onmouseover' while using the same hyperlink in the process.
It seems like a very simple problem but I don't know enough to determine if what I want to do is even possible. If it's not possible that's fine, I would just like to know either way ;P. Thanks ahead of time!
If you're ok with using jquery, you could use .html() and .hover()
http://jsfiddle.net/u8fsU/
Try something like this to get you started (not a complete nor tested solution):
var showImage = function(){
var picture = document.createElement("img");
picture.src = "icon2.png";
picture.href = "link.html";
var speakers = document.getElementById("speakers");
speakers.parentNode.replaceChild(speakers, picture);
}
Please see https://developer.mozilla.org/en-US/docs/Gecko_DOM_Reference for a good reference to some of the available DOM properties and methods.

Categories