Постановка задачи.
Необходимо создать сайт с картой, на которую нанесены объекты.
Объекты заданы таблицей в БД MS SQL Server (листинг 1). Данные объекты необходимо нанести на карту, используя модуль Yandex.Maps от Yandex, т.к. объекты находятся там, где указанный модуль имеет лучшую детализацию, чем другие поставщики карт (например, google). При написании сайта должны использоваться технологии: html, CSS, js, ASP.Net (C#).
Листинг 1 – Таблица с объектами
CREATE TABLE [dbo].[t_Map] (
[id] int IDENTITY(1, 1) NOT NULL,
[ObjectName_Var] nvarchar(128) COLLATE Cyrillic_General_CI_AS NULL,
[Address_Var] nvarchar(256) COLLATE Cyrillic_General_CI_AS NULL,
[Longitude_Var] nvarchar(128) COLLATE Cyrillic_General_CI_AS NULL,
[Latitude_Var] nvarchar(1) COLLATE Cyrillic_General_CI_AS NULL,
PRIMARY KEY CLUSTERED ([id])
)
Решение.
Особенность данной задачи заключается в том, что API Яндекс.Карты написано на javascript (js), который является «клиентским» языком. В то же самое время мы должны получать данные с сервера из БД MS SQL Server посредством ASP.Net.
Очевидно, что тут должна помочь технология AJAX (Asynchronous Javascript And Xml - технология для взаимодействия с сервером без перезагрузки страниц), а точнее фреймворк jQuery, который несколько упрощает написание кода.
На стороне сервера будет создан специальный обработчик http, к которому будет обращатся клиент для получения данных из БД.
Итак, начнем. Для начала, создадим заготовку страницы с картой, на которую будут нанесены наши объекты (листинг 2).
Листинг 2 – Заготовка с картой
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Наша карта</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="http://api-maps.yandex.ru/1.1/index.xml?key=ANpUFEkBAAAAf7jmJwMAHGZHrcKNDsbEqEVjEUtCmufxQMwAAAAAAAAAAAAvVrubVT4btztbduoIgTLAeFILaQ==" type="text/javascript"></script>
<script type="text/javascript" src="http://js.static.yandex.net/jquery/1.3.2/_jquery.js">
</script>
<script type="text/javascript">
// Создание обработчика для события window.onLoad
YMaps.jQuery(function () {
// Создание экземпляра карты и его привязка к созданному контейнеру
var map = new YMaps.Map(YMaps.jQuery("#YMapsID")[0]);
// Установка для карты ее центра и масштаба
map.setCenter(new YMaps.GeoPoint(55.983161, 54.73794), 12);
})
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="YMapsID" style="width:600px;height:400px"></div>
</form>
</body>
</html>
Далее напишем запрос к БД, который бы получал необходимые нам данные (Листинг 3).
Листинг 3 – Запрос к БД для получения данных об объектах
CREATE PROCEDURE dbo.p_Get_ObjectData
AS
BEGIN
SELECT
m.ObjectName_Var,
m.Address_Var,
m.Longitude_Var,
m.Latitude_Var
FROM t_Map m
END
Теперь напишем обработчик http (handler), который будет брать данные в БД и отправлять их на клиент (листинг 4).
Листинг 4 – Обрабтчик для получения данных и отправки на клиент
<%@ WebHandler Language="C#" Class="Handler" %>
using System;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Configuration;
using System.Data.SqlClient;
using System.Net;
using System.Collections.Generic;
public class Handler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
//сформируем список, в котором будут находиться наши объекты
List<object> list = new List<object>();
string connString = WebConfigurationManager.ConnectionStrings["UfaolapSite"].ConnectionString;
using (SqlConnection con = new SqlConnection(connString))
{
string sql = "exec p_Get_ObjectData";
SqlCommand cmd = new SqlCommand(sql, con);
con.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var data = new
{
Name = reader.GetString(0),
Address = reader.GetString(1), //адрес
Longitude = reader.GetString(2), //долгота
Latitude = reader.GetString(3), //широта
};
list.Add(data);
}
}
con.Close();
}
//сериализуем данный спиок для получения его в формате JSON
JavaScriptSerializer serializer = new JavaScriptSerializer();
string output = string.Format("var data = [{0}];", string.Join(",", list.ConvertAll<string>(serializer.Serialize).ToArray()));
context.Response.ContentType = "text/plain";
context.Response.Write(output);
context.Response.End();
context.Response.Cache.SetNoServerCaching();
}
public bool IsReusable {
get {
return false;
}
}
}
Тут немного поясню. Сначала мы считали данные об объектах – тут все ясно. А дальше мы сериализуем этот список в формат JSON (JavaScript Object Notation – представление объектов JavaScript) с тем, чтоб его удобно и легко было принять на стороне клиента, и выглядеть это будет, как показано на листинге 5.
Листинг 5 – Список объектов в формате JSON
var data = [{"Name":"Памятник Салавату Юлаеву","Address":"Уфа, Заки Валиди, 2","Longitude":"55.925869","Latitude":"54.718393"},{"Name":"УГАТУ","Address":"Уфа, Карла Маркса, 12","Longitude":"55.942434","Latitude":"54.72497}, …];
Теперь можно модифицировать нашу заготовку html (листинг 6).
Листинг 6 – Получение данных на клиенте
<script type="text/javascript">
// Создание обработчика для события window.onLoad
YMaps.jQuery(function () {
// Создание экземпляра карты и его привязка к созданному контейнеру
var map = new YMaps.Map(YMaps.jQuery("#YMapsID")[0]);
// Установка для карты ее центра и масштаба
map.setCenter(new YMaps.GeoPoint(55.983161, 54.73794), 12);
// Добавим инструменты
map.addControl(new YMaps.ToolBar());
map.addControl(new YMaps.Zoom());
map.addControl(new YMaps.TypeControl());
map.enableScrollZoom();
$.post('Handler.ashx', '', function(response)
{
// распаковываем JSON, в результате чего получаем
// массив data c данными об объектах
eval(response);
// Создание стиля для значка метки
s = new YMaps.Style();
s.iconStyle = new YMaps.IconStyle();
s.iconStyle.size = new YMaps.Point(18, 18);
s.iconStyle.offset = new YMaps.Point(-9, -9);
s.balloonContentStyle = new YMaps.BalloonContentStyle(
new YMaps.Template("<div>$[description]</div>")
);
for (i in data)
{
var point = new YMaps.GeoPoint(data[i].Longitude, data[i].Latitude);
var placemark = new YMaps.Placemark(point, {hasHint: 1, style: s});
placemark.name = data[i].Name;
placemark.description = data[i].Name + "<br />" + data[i].Address;
map.addOverlay(placemark);
}
});
})
</script>
Вот и все. На выходе получим страницу как на рисунке 1.
Рисунок 1 – Карта с объектами
Как видно, получился довольно простой и удобный механизм «общения» клиента с сервером и БД. Замечу, что с клиента серверу можно передать параметр, который бы мог служить условием для отбора, например. Как это будет выглядеть показано на листинге 7.
Листинг 7 – Передача параметра с запросом
$.post('Handler.ashx', 'parametr = 0', function(response) {…}
В следующей статье рассмотрим формирование YMapsML-файл из БД SQL Server.
Успехов в программировании!
10 комментариев:
Добрый день.
У меня возникла следующая проблема.
Формирование запроса я производил не с помощью хранимой процедуры, а путем составления строки запроса.
Сейчас возникла необходимость фильтровать выводимые на карту данные. Таким образом суть задачи сводится к составлению запроса, удовлетворяющего конкретным условиям.
Условия необходимо получать из DropDownList'a, который расположен на форме.
По сути, вся задача сводится к передаче значения строковой переменной с формы в файл handler.ashx.
Каким образом можно и возможно ли вообще провести эту "операцию".
Заранее благодарен.
С уважением, Павел.
C вопросом разобрался.
В качестве параметра я передавал строку и при получении строки в hendler'e сбивалась кодировка.
С уважением, Павел.
Вот и отлично!
А то в первом посте проблемы я не увидел, оттого как то загрузился слегка )))
Я просто не ожидал именно такой проблемы, а отладчиком пройтись, что бы проверить передаваемые значения, возможности не было.
А как в базе появились вообще данные о памятнике с долготой и широтой?
Как получать эти данные?
Спасибо.
А в чем именно затруднение - получить координаты с карты или в базу запейсать?
Уважаемый автор! Подскажите как бы вы решили проблему, если у вас в базе лежало бы 1 000 000 адресов?
Даже, если заранее выгрузить сериализованный текс объектов в файл, то скорее всего проблемы возникнут в yandex, он не помрет от такокго количества точек?
На практике задача с одновременным отображением такого количества объектов встречается редко, мне кажется. Но способы борьбы с большим количеством меток существуют. Например, вот: http://habrahabr.ru/post/145832/
Не поможете с примитивной проблемой?
я пытаюсь сделать то же самое на js. из вэбметода возвращается json, он корректно распарсивается, а дальше я в цикле по элементам массива получившегося после распарсивания выполняю:
ymaps.geocode(c[i].addressString, { results: 1 }).then(function (res) { var firstGeoObject = res.geoObjects.get(0); myPlacemark = new ymaps.Placemark(firstGeoObject.geometry.getCoordinates(), {
content: c[i].addressString,
balloonContent: ''
}, { preset: 'twirl#violetIcon' })
проблема заключается в том что я в пресеты плэйсмарка не могу доставить переменные из свойств объекта. (они внутри функции по созданию плэйсмарка не доступны). Ума не приложу что с этим делать. Нужны свойства чтобы их отображать в балуне, в зависимости от них выбирать цвета и т.п.
Вот это уже не работает:
content: c[i].addressString
JavaScript runtime error: Unable to get property 'addressString' of undefined or null reference
Отправить комментарий