воскресенье, 17 марта 2013 г.

Знакомство с Google Maps JavaScript API V3 на примерах


Знакомство с Google Maps JavaScript API V3 на примерах


   Сегодня я хочу рассмотреть Google Maps Java Script API Version 3 на конкретных примерах, которые могут быть востребованы в повседневной работе.

   Для начала необходимо получить ключ, с помощью которого большой брат будет за вами следить, а точнее -  собирать статистику. Если вы превысите определенный лимит (на момент написания статьи это 25 тысяч запросов в день) вам придется начинать платить за дополнительные запросы. Теперь суть ясна, можем перейти к процедуре получения:
1.       Вам необходимо иметь/зарегистрировать  google аккаунт (почта).
2.       Переходим по ссылке https://code.google.com/apis/console
3.       С лева выбираем закладку Services
 
      4.       Находим переключатель Google Maps API v3 и активируем его
     
5.       Отлично, теперь  заходим в пункт API Access
 
6.       И забираем свой ключик


Поздравляю!  Теперь вы можете пользоваться google maps.

   Начнем с простого, но полезного. Разместим на пустой страничке карту и четыре кнопки. На каждую кнопку привяжем по местоположению городов (Санкт-Петербург, Сидней, Нью-Юрк и Лондон). Кликая по каждой кнопке мы будем перемещать карту, и это позволит визуально сравнить размеры городов. Мне довольно любопытно сравнить родной Санкт-Петербург с этими городами, а вы можете немного изменить код и выставить свой город или добавить еще одну кнопку.

   Открываем блокнот, создаем файл Cities.html и вставляем следующий код:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=Your_API_Key&sensor=false"></script>
    <script type="text/javascript">
        function ShowPositon(x, y) {
            var mapOptions = {
                center: new google.maps.LatLng(x, y),
                zoom: 9,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            var map = new google.maps.Map(document.getElementById("map_canvas"),
                mapOptions);
            return (false);
        }
    </script>

</head>
<body onload="ShowPositon(59.940224, 30.308533)">
    <div id="map_canvas" style="width:400px; height:400px"></div>
    <button onclick="ShowPositon(59.940224, 30.308533)">Saint-Petersburg</button>
    <button onclick="ShowPositon(-33.847608, 150.930176)">Sydney</button>
    <button onclick="ShowPositon(40.711353, -74.002533)">NewYork</button>
    <button onclick="ShowPositon(51.510452, -0.127716)">London</button>
</body>
</html>

   Чтобы пример заработал, вам необходимо заменить Your_API_Key на ваш ключик. Вы можете подумать, что опасно размещать в открытую ваш ключ в коде страницы и вы будете на все сто процентов правы, но тут есть одно большое НО:

   Если вы зайдете в API Access -> Simple API Access то найдете там пункт в меню “Edit allowed referers...”, с помощью которого можно создать белый список доменных имен, с которых принимаются запросы, в противном случае они отклоняются. По умолчанию список пуст, что разрешает принимать запросы отовсюду.  
 

Итак, все готово к первому запуску, посмотрев результаты можно заметить что Лондон, Сидней и Санкт-Петербург примерно занимают одинаковую площадь, в отличие от Нью-Юрка, который явно лидирует.

Краткий обзор кода:

1.       Google Api подключается с помощью ссылки на JavaScript файл и личного ключа. <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?key=Your_API_Key&sensor=false"></script>
2.       Можно изменять настройки карты с помощью объекта mapOptions
3.       В названии класса google.maps.LatLng спрятано две аббревиатуры  -  широта (latitude)  и долгота (longitude), собственно их и принимает его конструктор

Теперь поставим собственный, маркер в виде маленького грузовичка и заставим его кататься по прямой от метро «Парк Победы» до «Московская Площадь» я специально выбрал этот маршрут чтоб не сильно думать о логике движения, так как там по прямой.

Создадим новый файл Track.html и скачаем иконку грузовичка Track.png и положим их вместе.
 
Теперь вставим следующий код:

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript"
      src="http://maps.googleapis.com/maps/api/js?key=AIzaSyBXQROV5YMCERGIIuwxrmaZbBl_Wm4Dy5U&sensor=false">
    </script>
    <script type="text/javascript">
        var trackMarker;
        var lat = 59.8659;
        var movingDown = true;
        var movingUp = false;
        var isMoving = false;

        function initialize() {
            var mapOptions = {
                center: new google.maps.LatLng(59.858889, 30.320849),
                zoom: 14,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
           var map = new google.maps.Map(document.getElementById("map_canvas"),
                mapOptions);

            var image = 'track.png';
            var myLatLng = new google.maps.LatLng(lat, 30.320807);
            trackMarker = new google.maps.Marker({
                position: myLatLng,
                map: map,
                icon: image
            });
        }

        function move() {
            if (lat > 59.866) {
                endDrive(true, false);}
            if (lat < 59.851) {
                endDrive(false, true);}
            if (movingDown) lat = lat - 0.0001;
            if (movingUp) lat = lat + 0.0001;           
            trackMarker.setPosition(new google.maps.LatLng(lat, 30.321136));
        }

        function loop() {           
            setTimeout(function () {
                if (isMoving) {
                    move();
                    loop();
                }
            }, 50)
        }

        function endDrive(down, up) {
            movingDown = down;
            movingUp = up;
            isMoving = false;
            document.getElementById("drive_btn").disabled = false;
        }

        function drive() {
            isMoving = true;
            document.getElementById("drive_btn").disabled = true;
            loop();
        }
    </script>
  </head>
  <body onload="initialize()">
    <div id="map_canvas" style="width:400px; height:400px"></div>
      <button id="drive_btn" onclick="drive()">Drive</button>
  </body>
</html>
Сохраним и запустим. Грузовичок катается как надо :) Краткий обзор кода:

1.       Метод initialize запускается как только страничка загружена инициализирует карту и размещает на ней маркер с картинкой.
2.       Метод Drive запускает алгоритм движения, который реализован в методах loop, move и endDrive
3.       Чтобы передвинуть маркер достаточно изменить его позицию через метод  setPosition и передать ему объект класса LatLng с новыми координатами


   Я живу во Фрунзенском районе Санкт-Петербурга, здесь очень много деревьев и практически не слышно вездесущего городского шума. Для демонстрации отображения полигонов я нарисую его на карте. И поможет мне в этом следующий код:

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript"
        src="http://maps.googleapis.com/maps/api/js?key=AIzaSyBXQROV5YMCERGIIuwxrmaZbBl_Wm4Dy5U&sensor=false">
    </script>
    <script type="text/javascript">

        function initialize() {
            var mapOptions = {
                center: new google.maps.LatLng(59.858889, 30.370849),
                zoom: 11,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            var map = new google.maps.Map(document.getElementById("map_canvas"),
                 mapOptions);

            var paths = [new google.maps.LatLng(59.913644, 30.334597),
                new google.maps.LatLng(59.916139, 30.345411),
                new google.maps.LatLng(59.91373, 30.363407),
                new google.maps.LatLng(59.833775, 30.47533),
                new google.maps.LatLng(59.818935, 30.381947),
                new google.maps.LatLng(59.875672, 30.353451),
                new google.maps.LatLng(59.883597, 30.346928),
                new google.maps.LatLng(59.89152, 30.346098)];

            var shape = new google.maps.Polygon({
                paths: paths,
                strokeColor: '#00FF00',
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: '#00FF00',
                fillOpacity: 0.35
            });

            shape.setMap(map);
        }

    </script>
</head>
<body onload="initialize()">
    <div id="map_canvas" style="width: 400px; height: 400px"></div>
</body>
</html>

 

Все очень просто:

1.       Инициализируем карту
2.       Создаем массив координат
3.       Создаем объект класса полигон и выставляем его свойства
4.       Связываем полигон с картой.

Есть желание продолжить? Не проблема!  Здесь вы найдете большое количество примеров - http://code.google.com/apis/ajax/playground/#map_simple_v3


Александр Кобелев.

понедельник, 12 сентября 2011 г.

The Interlocked Anything Pattern

Сегодня, хочу разобрать описанный Джефри Рихтером паттерн - The Interlocked Anything Pattern. Данный паттерн показан к применению для синхронизации потоков с малой конкуренцией, в этом случае он отрабатывает быстрее lock, но с увеличением конкуренции производительность резко падает. Используем мы его очень часто, даже не задумываясь об этом, события это не что иное, как обертка для использования делегатов, с применением The Interlocked Anything Pattern.

Рассмотрим поближе, при объявлении в типе события:


public sealed class SomeType
{
public event DoSomthing SomeEvent;
}
public delegate void DoSomthing();


Компилятор C# создаст следующий код:


public sealed class SomeType
{
private DoSomthing _someEvent;

public event DoSomthing SomeEvent
{
add {
DoSomthing doSomthing = this._someEvent;
DoSomthing comparand;
do {
comparand = doSomthing;
doSomthing = Interlocked.CompareExchange(ref this._someEvent, comparand + value, comparand);
} while (doSomthing != comparand);
}
remove {
DoSomthing doSomthing = this._someEvent;
DoSomthing comparand;
do{
comparand = doSomthing;
doSomthing = Interlocked.CompareExchange(ref this._someEvent, comparand - value, comparand); }
while (doSomthing != comparand);
}
}
}


Где паттерн Interlocked Anything Pattern будет использован дважды: в методах add и remove.

Метод add, без изменений, можно преобразовать в следующий код:


add
{ DoSomthing doSomthing = this._someEvent;
DoSomthing comparand;
do {
comparand = doSomthing;
DoSomthing result = (DoSomthing)Delegate.Combine(comparand, value);
doSomthing = Interlocked.CompareExchange(ref this._someEvent, result, comparand); }
while (doSomthing != comparand);
}


Проще всего понять, как работает данный код в многопоточной среде – на диаграммах.

Предположим, в куче есть объект типа SomeType, поле _someEvent, в данный момент, уже указывает на некий экземпляр делегата DoSomthing, а так же присутствуют два потока, которые начинают одновременно добавлять делегаты в очередь события, через метод add. В стеке потока каждого из них создается указатель doSomthing типа DoSomthing указывающий на тот же экземпляр делегата что и поле _someEvent, далее создается еще один указатель comparand типа DoSomthing который указывает на null.



В данный момент каждый из потоков, как бы бросил «якорь» с помощью указателей doSomthing. Третий поток, теперь может изменять значение указателя в SomeType, и благодаря этому «якорю» изменения будут замечены и корректно обработаны.

Далее, так как третий поток уже мог изменить значение указаетля _someEvent, в цикле do, указателю comparand присваивается значение, на которое указывает «якорь»(doSomthing). Каждый из потоков с помощью метода Delegate.Combine создает свой собственный, результирующий экземпляр DoSomthig (вместо метода Delegate.Combine можно использовать любой другой код, хоть в тысячу строк, результатом которого должен стать новый результирующий объект). Теперь в игру вступает главный игрок – метод Interlocked.CompareExchange, при помощи которого происходит атомарная замена значения указателя _someEvent на результирующий объект, в метод передается три аргумента : указатель, по ссылке, значение которого будет изменено(ref this._someEvent), объект (result)на который будет указывать указатель(ref this._someEvent), после успешного выполнения операции, а так же объект(comparand) для сравнения. В случае если объект, на который указывает указатель(ref this._someEvent) равен объекту (comparand), то метод перепишет указатель (ref this._someEvent) на объект result. В случае если объекты не равны то замещения не произойдет.

Предположим второй поток выполняет метод Interlocked.CompareExchange раньше, и до этого объект SomeType не изменялся, с момента, когда был брошен «якорь». Указатель comparand указывает на тот же объект что и _someEvent, сравнивание объектов проходит успешно и происходит замещение, так же метод возвращает изначальное значение _someEvent и переписывает значение указателя doSomthing, после чего производит сравнивание объектов на которые указывают указатели doSomthing и comparand. Так как это один и тот же объект, сравнивание проходит успешно, значит метод Interlocked.CompareExchange удачно отработал и выполнение метода можно завершать.



Вернемся к первому потоку, теперь он начинает выполнять метод Interlocked.CompareExchange, в результате которого doSomthing будет перезаписана на тот объект, что содержался в this._someEvent, на начало выполнения метода Interlocked.CompareExchange, а это уже объект, созданный вторым потоком. При сравнении doSomthing с comparand - результат будет отрицательным, говорящий потоку о том, что другой поток внес изменения, с момента когда первый поток поставил «якорь», метод Interlocked.CompareExchange не выполнил замещения _someEvent на result, что приводит к повторения цикла do и повторной попытке внести изменения, с учетом изменений сделанных вторым потоком.


Александр Кобелев, aka Megano