We are showing US States using GWC.

When the user selects a state, we show a "selected polygon" layer on top of it:

enter image description here

As you can see from the image, the yellow Highlighted WMS layer is incorrectly rendering on top of the red GWC layer of states.

Both are the same layer in Geoserver. The layer has two styles available: the thin red line and the thicker yellow line.

We are rendering it once with plain GWC, and once as a WMS layer (with a filter on it to only show the selected state).

Both the GWC and WMS layers are in Google Maps, which is requesting 256 x 256 tiles.

BTW this only happens at lower zoom levels. As you zoom in, the two line up better until they completely overlap at about zoom level 7.

Again, this is the exact same layer, the only difference is the service endpoint: GWC in one, and WMS in the other.

Edit: Ian asked me to post this additional information:

Here is the GetCapabilities info for this layer:

  <Layer queryable="1" opaque="0">
    <LatLonBoundingBox minx="-180.0" miny="-90.0" maxx="180.0" maxy="90.0"/>
    <BoundingBox SRS="EPSG:4326" minx="-180.0" miny="-90.0" maxx="180.0" maxy="90.0"/>
      <Title>Default Polygon</Title>
      <Abstract>A sample style that draws a polygon</Abstract>
      <LegendURL width="20" height="20">
        <OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://tiles.MyWorkspace.com:80/geoserver/wms?request=GetLegendGraphic&amp;format=image%2Fpng&amp;width=20&amp;height=20&amp;layer=MyWorkspace%3Astate"/>
      <Title>Default Polygon</Title>
      <Abstract>A sample style that draws a polygon</Abstract>
      <LegendURL width="20" height="20">
        <OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" xlink:href="http://tiles.MyWorkspace.com:80/geoserver/wms?request=GetLegendGraphic&amp;format=image%2Fpng&amp;width=20&amp;height=20&amp;layer=MyWorkspace%3Astate&amp;style=state"/>

I can't actually post my code, but here are sample URLs:

GWC URL: /geoserver/gwc/service/gmaps?layers=MyWorkspace:state&zoom=6&x=17&y=25&format=image/png&styles=MyWorkspace:state

WMS (GetMap) URL: /geoserver/wms?request=GetMap&service=WMS&version=1.1.1&layers=state&srs=EPSG:4326&format=image%2Fpng&bbox=-101.25,40.97989806962013,-90,48.922499263758255&width=256&height=256&tiled=true&format=image/png&transparent=true&styles=PolygonHighlight&cql_filter=id%20=%2044

Another Edit:

It looks like this may be a screen coordinates to map coordinates conversion issue. We use Google Maps' ImageMapType class (https://developers.google.com/maps/documentation/javascript/reference/image-overlay#ImageMapType) to render both our GWC and WMS layers. But GWC doesn't require conversion of screen coordinates to map coordinates. It takes screen coordinates (tile numbers) as inputs. The WMS endpoint, however, requires a bounding box. Since the version of the Google Maps API that we are using didn't offer a fromPointToLatLng method, we relied on some conversion code I found on the internet (http://blog.canberraphotography.com.au/googlewms/ was the url, but it's dead now). It looks like upgrading to the latest google maps API may be the answer.

  • you probably have a difference in the tile origin or resolutions between the server and client - please add the code you are using and the WMTS (or TMS) getcapabailities entry for the layer.
    – Ian Turton
    Commented Oct 16, 2018 at 8:20
  • Thanks @IanTurton for the reply. I've edited my post to include the GetCapabilities for that layer and a sample URL of the GWC and WMS endpoints. Commented Oct 16, 2018 at 13:54

1 Answer 1


Okay, we figured this out. It turns out that the tile bounding box (the bbox of the 256 x 256 tile you are rendering) needs to be in EPSG:900913 (Spherical Mercator), even if geoserver's underlying SRS is Lat/Lng. Also, Spherical Mercator uses meters as units, so we needed to convert degrees to meters using the code below, which we found on the web.

function degrees2meters(lon,lat) {
    var x = lon * 20037508.34 / 180;
    var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
    y = y * 20037508.34 / 180;
    return [x, y]

Hopefully this will help someone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.