понедельник, 12 марта 2012 г.

Add arrows to OpenLayers layer.

I have a task to render a traffic vectors on top map using OpenLayes API.

As I noticed Yandex maps uses pregenerated tiles and just render png images on top of the base layer.


The OpenStreetMap based on OpenLayers uses svg (vector graphic) (or canvas) to draw tracks and roads on top of the map. As well as Google Maps.

To render  arrows firstly we need to find out the direction of arrows. I calculate it at frontend using function calculateAngle. To find out direction we need to have a vector (two points A[x1,y1], B[x2,y2]).

function calculateAngle(x1, y1, x2, y2){
     var dx = x2 - x1;
     var dy = y2 - y2;
     // Calculates angle between vector and x axis
     var angle2  = Math.atan(dy/dx)*180/Math.PI;

     // Rotates angle according to vector direction
     var angle = getQuadrantAngle(angle, dx, dy);
     return (angle);
}

function getQuadrantAngle(angle, dx, dy)
{
        var qAngle = [-1, 90, -90, 270, 90];
        var Quadrant = 0;
        if(dx>=0 && dy>=0)
            Quadrant = 1;
        else if(dx>=0 && dy<0)
            Quadrant = 4;
        else if(dx<=0 && dy>=0)
            Quadrant = 2;
        else if(dx<=0 && dy<0)
            Quadrant = 3;

        return (-angle + qAngle[Quadrant]);
}


After, you need to add arrow image to layer style

var myMapStyle = {
        cursor     : 'pointer',
        strokeColor: color,
        fillColor  : color,
        fillOpacity: 1,
        rotation:"${angle}", // we take it from feature attribute
        externalGraphic: arrow_url,
        graphicWidth:15,
        graphicHeight: 15,
        graphicYOffset:"${getYOffset}",
        strokeWidth: this.defaults.traffic.strokeWidth
    }


So the function for adding arrows to layer linesLayer

/*
 *  Добавляем слой стрелок для дорог
 * @params position - позиция стрелки на сегменте дороги
 * @params uri - адрес файла со списком узлов сегментов разбиения дороги в geojson, тип данных Point
 * */
Traffic.addArrows = function (linesLayer, param)
{
    var features = [];

    if(this.utils.isset(param.uri)){
        var geojson = this.getGeoJsonData(param.uri);
        var format = new OpenLayers.Format.GeoJSON({
            'internalProjection': new OpenLayers.Projection("EPSG:900913"),
            'externalProjection': new OpenLayers.Projection("EPSG:4326")
        });

        $(geojson.features).each(function(i,item){
            if(item.properties.arrow == 't')
            {
                /*dataLayer.addFeatures(format.read(item));*/

                var ft = format.read(item);
                var pt = {x1:ft[0].geometry.components[0].x, y1:ft[0].geometry.components[0].y,x2:ft[0].geometry.components[1].x, y2:ft[0].geometry.components[1].y};
                // Вычисляем положение стрелки на сегменте
                if(param.position == 'center'){
                    var xm = (pt.x2 + pt.x1)/2;
                    var ym = (pt.y2 + pt.y1)/2;
                }
                else{
                    var xm = pt.x1;
                    var ym = pt.y1;
                }
                // Вычисляем угол поворота стрелки
                var dx = pt.x2 - pt.x1;
                var dy = pt.y2 - pt.y1;
                var angle  = Math.atan(dy/dx)*180/Math.PI;
                var angle2 = getQuadrantAngle(angle, dx, dy); // формула angle < 0 ? ((-1)*angle+180) : ((-1)*angle+90);

                var ftGeomColl = new OpenLayers.Geometry.Collection();

                // Добавляем вывод стрелок
                ftGeomColl.addComponent(new OpenLayers.Geometry.Point(xm, ym));

                var ftColl = new OpenLayers.Feature.Vector();
                ftColl.geometry = ftGeomColl;
                ftColl.attributes = {};
                ftColl.attributes["angle"] = angle2;
                features.push(ftColl);
            }
        });
    }
    linesLayer.addFeatures(features);
}



Комментариев нет:

Отправить комментарий