com.mashery.examples.api.client.weatherbug.WeatherBugOverlayView.java Source code

Java tutorial

Introduction

Here is the source code for com.mashery.examples.api.client.weatherbug.WeatherBugOverlayView.java

Source

/*
 * Copyright (c) 2010, 2011 Mashery, Inc. All Rights Reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.mashery.examples.api.client.weatherbug;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.Style.BorderStyle;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.maps.client.HasMapCanvasProjection;
import com.google.gwt.maps.client.base.HasLatLngBounds;
import com.google.gwt.maps.client.base.HasPoint;
import com.google.gwt.maps.client.base.LatLng;
import com.google.gwt.maps.client.base.Point;
import com.google.gwt.maps.client.event.Event;
import com.google.gwt.maps.client.event.EventCallback;
import com.google.gwt.maps.client.event.HasMapsEventListener;
import com.google.gwt.maps.client.overlay.HasProjection;
import com.google.gwt.maps.client.overlay.OverlayView;
import com.google.gwt.user.client.ui.UIObject;

public class WeatherBugOverlayView extends OverlayView {

    private static final int TILE_CACHE_SIZE = 64;

    private static final String WEATHERBUG_ENDPOINT = "http://i.wxbug.net/GEO/Google/${layerType}/GetTile_v2.aspx?as=0&c=0&fq=0&mw=0&ds=0&stl=1&api_key=cn63prcp8pmrzmu7exhg9pgd";

    private static final LayerType DEFAULT_LAYER_TYPE = LayerType.TEMPERATURE;

    private final LinkedHashMap<TileKey, ImageElement> tiles = new LinkedHashMap<TileKey, ImageElement>();

    private LayerType layerType = DEFAULT_LAYER_TYPE;

    private DivElement div;

    private HasMapsEventListener boundsChangedListener, zoomChangedListener;

    public LayerType getLayerType() {
        return layerType;
    }

    public void setLayerType(LayerType layerType) {
        if (layerType == null)
            layerType = DEFAULT_LAYER_TYPE;

        this.layerType = layerType;

        for (ImageElement img : tiles.values())
            img.removeFromParent();

        tiles.clear();

        if (div != null)
            draw();
    }

    @Override
    public void onAdd() {
        Document doc = Document.get();
        DivElement div = doc.createDivElement();
        div.getStyle().setBorderStyle(BorderStyle.NONE);
        div.getStyle().setBorderWidth(0d, Unit.PX);
        div.getStyle().setPosition(Position.ABSOLUTE);
        div.getStyle().setOpacity(0.4d);

        this.div = div;
        getPanes().getOverlayLayer().appendChild(div);

        boundsChangedListener = Event.addListener(getMap(), "bounds_changed", new EventCallback() {
            @Override
            public void callback() {
                WeatherBugOverlayView.this.draw();
            }
        });

        zoomChangedListener = Event.addListener(getMap(), "zoom_changed", new EventCallback() {
            @Override
            public void callback() {
                for (Node child = WeatherBugOverlayView.this.div.getFirstChild(); child != null;) {
                    Node node = child;
                    child = child.getNextSibling();
                    node.removeFromParent();
                }

                tiles.clear();
            }
        });
    }

    @Override
    public void draw() {
        HasLatLngBounds bounds = getMap().getBounds();
        HasMapCanvasProjection ovrPrj = getProjection();
        HasPoint ovrNE = ovrPrj.fromLatLngToDivPixel(bounds.getNorthEast());
        HasPoint ovrSW = ovrPrj.fromLatLngToDivPixel(bounds.getSouthWest());

        div.getStyle().setLeft(ovrSW.getX(), Unit.PX);
        div.getStyle().setTop(ovrNE.getY(), Unit.PX);
        div.getStyle().setWidth(ovrNE.getX() - ovrSW.getX(), Unit.PX);
        div.getStyle().setHeight(ovrSW.getY() - ovrNE.getY(), Unit.PX);

        String endpoint = WEATHERBUG_ENDPOINT.replace("${layerType}", layerType.getPath());
        HashSet<TileKey> usedTiles = new HashSet<TileKey>();

        int zoom = getMap().getZoom();
        double scale = Math.pow(2d, zoom);
        HasProjection prj = getMap().getProjection();
        LatLng nwLatLng = new LatLng(bounds.getNorthEast().getLatitude(), bounds.getSouthWest().getLongitude());
        HasPoint nwRaw = prj.fromLatLngToPoint(nwLatLng);
        LatLng seLatLng = new LatLng(bounds.getSouthWest().getLatitude(), bounds.getNorthEast().getLongitude());
        HasPoint seRaw = prj.fromLatLngToPoint(seLatLng);

        Point nw = new Point(Math.floor(nwRaw.getX() * scale), Math.floor(nwRaw.getY() * scale));
        Point se = new Point(Math.floor(seRaw.getX() * scale), Math.floor(seRaw.getY() * scale));

        double offsetX = nw.getX() % 256d;
        double offsetY = nw.getY() % 256d;
        Point startPoint = new Point(nw.getX() - offsetX, nw.getY() - offsetY);

        while (startPoint.getY() < se.getY()) {
            Point p = new Point(startPoint.getX(), startPoint.getY());
            startPoint = new Point(startPoint.getX(), startPoint.getY() + 256);
            while (p.getX() < se.getX()) {
                int tx = (int) p.getX() / 256;
                int ty = (int) p.getY() / 256;

                TileKey tileKey = new TileKey(tx, ty, zoom);
                usedTiles.add(tileKey);

                ImageElement img = tiles.remove(tileKey);
                if (img == null) {
                    img = Document.get().createImageElement();
                    img.getStyle().setBorderStyle(BorderStyle.NONE);
                    img.getStyle().setBorderWidth(0d, Unit.PX);
                    img.getStyle().setPosition(Position.ABSOLUTE);

                    StringBuilder buf = new StringBuilder(endpoint);
                    buf.append("&tx=").append(tx);
                    buf.append("&ty=").append(ty);
                    buf.append("&zm=").append(zoom);
                    img.setSrc(buf.toString());

                    div.appendChild(img);
                } else {
                    img.getStyle().setVisibility(Visibility.VISIBLE);
                }

                img.getStyle().setLeft(p.getX() - nw.getX(), Unit.PX);
                img.getStyle().setTop(p.getY() - nw.getY(), Unit.PX);
                img.getStyle().setWidth(256d, Unit.PX);
                img.getStyle().setHeight(256d, Unit.PX);
                tiles.put(tileKey, img);

                p = new Point(p.getX() + 256, p.getY());
            }
        }

        for (Iterator<Map.Entry<TileKey, ImageElement>> i = tiles.entrySet().iterator(); i.hasNext();) {
            Map.Entry<TileKey, ImageElement> entry = i.next();
            if (!usedTiles.remove(entry.getKey())) {
                if (tiles.size() > TILE_CACHE_SIZE) {
                    i.remove();
                    entry.getValue().removeFromParent();
                } else {
                    entry.getValue().getStyle().setVisibility(Visibility.HIDDEN);
                }
            }
        }
    }

    @Override
    public void onRemove() {
        Event.removeListener(boundsChangedListener);
        Event.removeListener(zoomChangedListener);
        div.removeFromParent();
        div = null;
        tiles.clear();
    }

    public void show() {
        UIObject.setVisible(div, true);
    }

    public void hide() {
        UIObject.setVisible(div, false);
    }

    private static class TileKey {

        private final int tx;

        private final int ty;

        private final int zoom;

        private final int hashCode;

        public TileKey(int tx, int ty, int zoom) {
            this.tx = tx;
            this.ty = ty;
            this.zoom = zoom;
            int hashCode = 17;
            hashCode = 37 * hashCode + tx;
            hashCode = 37 * hashCode + ty;
            hashCode = 37 * hashCode + zoom;
            this.hashCode = hashCode;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;

            if (obj == null || obj.getClass() != getClass())
                return false;

            TileKey o = (TileKey) obj;
            return tx == o.tx && ty == o.ty && zoom == o.zoom;
        }

        @Override
        public int hashCode() {
            return hashCode;
        }
    }
}