css-positioncustom-controlsopenlayers-3dynamic-ui

Relative positioning of custom controls with OpenLayers 3


A map that I am building with OpenLayers 3 has some buttons, which may or may not be available depending on some other things. So I want to keep the unavailable buttons hidden, and others will use their space. The available options can change, so sometimes a button may become (in)visible.

There are some tutorials for creating custom controls with OpenLayers 3. The problem is that all samples I have seen use absolute positioning for the controls. One needs to know how many controls will be visible, and hard-code the coordinates in CSS. Or change the coordinates using Javascript. I.e., from the above link:

.rotate-north {
  top: 65px;
  left: .5em;
}

I have tried just setting the element with position:relative, but then they appear below the map, as the controls are added to the page after the map. So, one could use relative positioning with negative coordinates, but then if the map changes size you have to rewrite the coordinates in Javascript.

.ol-control.left-top {
  position: relative;
  top: -400px; /*map height*/
}

Is there a way to elegantly implement relative-positioned custom controls with OpenLayers 3, ideally with only CSS?

I guess I am trying to get a similar functionality as in the Google Maps API:

map.controls[google.maps.ControlPosition.LEFT_TOP].push(controlDiv);

Solution

  • Though it is not a good solution for my use case, since it is not supported by Android 4.3 and earlier, one could use CSS calc as suggested by @Jonatas:

    html:

    <div class="parent">
      <div class="map"></div>
      <div class="control"><button>CONTROL</button></div>
    </div>
    

    css:

    .map {
      width: 100%;
      height: calc(100vh - 2em);
      background-color: green;
    }
    
    .control {
      position: relative;
      left: .5em;
      top: calc(-100vh + 2em + .5em);
    }
    

    This would probably have to use viewport units (also not supported by Android 4.3 and earlier), as calc can only calculate values based on the parent element.

    jsfiddle: https://jsfiddle.net/adlerhn/zjt53nmf/