طراحی اپلیکیشن با الگوهای ArcGIS و Dojo

 طراحی اپلیکیشن با الگوهای ArcGIS و Dojo


عملیات geoprocessing-موسسه چشم انداز هزاره سوم ملل-آموزش کاربردی GIS و RS

اگر بخواهید روی یک لایه رودخانه حریم (buffer) ایجاد کنید و لایه‌ی پوشش گیاهی را از این لایه‌ی بافر شده بردارید از عملیات geoprocessing استفاده می‌کنید. می‌توانید یک مدل در ArcGIS for Desktop ایجاد کنید و این مدل را در محیط ArcGIS for Desktop و یا سرور مرکزی اجرا کنید. این سرور مرکزی می‌تواند به وب اپلیکیشن دسترسی داشته باشد. هر ابزاری که در ArcToolbox وجود دارد، اگر این ابزار به صورت پیش فرض در نرم افزار ArcGIS باشد یا آن را خودتان ساخته باشید و یا یک ابزار سفارشی باشد، می‌تواند در مدل استفاده شود و با دیگر ابزارهای مدل ادغام و ترکیب شود. در این فصل ابزارهای geoprocessing را توسط ArcGIS API for JavaScript استفاده می‌کنیم.

این فصل مطالب زیر را پوشش می‌دهد:

1- مدل‌ها در ArcGIS Server

2- استفاده از Geoprocessor

3- مفهوم صفحه‌ی سرویس

4- وظیفه‌ی Geoprocessor

5- اجرای عملیات geoprocessing

6- ایجاد اپلیکیشن با ابزارهای geoprocessing

در زیر یک مدل می‌بینید:

نمودار بالا مدل ساخته شده با ModelBuilder را نشان می‌دهد. این مدل‌ها در ArcGIS Server منتشر شده و سپس در اپلیکیشن وب قابل دسترس هستند.

مدل‌ها در ArcGIS Server

مدل‌ها در ArcGIS for Desktop با ModelBuilder ایجاد و سپس در ArcGIS Server منتشر می‌شوند تا در عملیات geoprocessing استفاده شوند. اپلیکیشن برای دسترسی به عملیات Geoprocessing و بازیابی اطلاعات، از شی Geoprocessor استفاده می‌کند. این ابزارها و مدل‌ها در ArcGIS Server اجرا می‌شوند. عملیاتی که در ArcGIS Server ثبت می‌شوند، نتایجشان نیز از سرور برداشت می‌شوند. ثبت عملیات و بازیابی نتایج با شی Geoprocessor صورت می‌گیرد.

استفاده از Geoprocessor

برای استفاده از سرویس geoprocessing دانستن سه موضوع مهم است:

1- باید آدرس URL جایی که مدل یا ابزار در آن جا قرار دارد را داشته باشید. به عنوان مثال آدرس زیر، URL سرویس geoprocessing است.

http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/GPServer/PopulationSummary

2- زمانی که به لینک URL سرویس geoprocessing می‌روید، اطلاعاتی در مورد پارامترهای ورودی و خروجی، عملیات و همزمانی و غیر همزمانی عملیات را می‌بینید. باید نوع داده‌ای که پارامترهای ورودی و خروجی با آن نوع داده تنظیم شده را بدانید.

3- سرانجام بر اساس نوع عملیات (همزمان یا غیر همزمان) کد خود را پیکربندی و بنویسید. همه‌ی این اطلاعات در صفحه‌ی سرویس geoprocessing وجود دارد.

 مفهوم صفحه‌ی سرویس geoprocessing

صفحه‌ی سرویس شامل اطلاعاتی در مورد سرویس است. این اطلاعات شامل نوع اجرای عملیات (همزمان و غیرهمزمان) است. در تصویر زیر، اجرای عملیات geoprocessing در سرویس PopulationSummary از نوع همزمان است و اپلیکیشن در انتظار نتایج عملیات geoprocessing می‌ماند تا به طور کامل عملیات انجام شود. این نوع اجرای همزمان برای کارهایی که به سرعت اجرا می‌شوند، مناسب است. وقتی عملیات همزمان به طور کامل اجرا شوند، به اپلیکیشن شما یک هشدار می‌فرستد و نتایج آماده است. اطلاعات دیگری شامل نام پارامترها، نوع داده‌ی پارامتر، کدام پارامتر ورودی و کدام خروجی، کدام پارامتر الزامی و کدام اختیاری است، نوع هندسه و سیستم مختصات ارجاع مکانی(WKID) و فیلدها نیز در صفحه‌ی سرویس وجود دارد.

پارامترهای ورودی

همه‌ی کارهای geoprocessing به یک یا چند پارامتر الزامی یا اختیاری نیاز دارد. این پارامترها به صورت شی JSON ذخیره می‌شوند. در این بخش نحوه‌ی ایجاد اشیاء JSON را یاد می‌گیرید. زمانی که پارامترها به صورت اشیاء JSON ایجاد می‌شوند، باید پارامترها را به ترتیبی که در صفحه‌ی سرویس ظاهر شده اند، ایجاد کنید. نام پارامترها دقیقاً باید همان نامی باشد که در صفحه‌ی وب دارند. تصویر زیر چگونگی خواندن پارامترهای ورودی را از صفحه‌ی سرویس نشان می‌دهد.

در کد زیر، نام پارامترهای تعریف شده و ترتیب تعریف پارامترها دقیقاً مطابق همان چیزی است که در صفحه‌ی سرویس بالا آمده است.

var params = {
Input_Observation_Point: featureSetPoints,
Viewshed_Distance: 250
};

تصویر قبلی پارامترهای ورودی عملیات geoprocessing را تعیین می‌کند. زمانی که شی JSON کدنویسی می‌شود، بسیار ضروری است که نام پارامترها و ترتیب پارامترها مطابق آنچه که در صفحه‌ی سرویس آمده است، باشند.

Geoprocessor

منبع GP برای انجام یک کار در سرویس geoprocessing به کار می‌رود. متدGeoprocessor.execute() یا متد Geoprocessor.submitJob() پارامترهای ورودی را به کلاس Geoprocessor می‌فرستند. تفاوت‌های این دو متد را توضیح خواهیم داد. نتایج نهایی در شی Geoprocessor قرار می‌گیرند. این شی خروجی با تابع callback پردازش می‌شود. درون شی Geoprocessor، URL صفحه‌ای که سرویس geoprocessing در آنجا است، قرار می‌گیرد. برای استفاده از این شی باید منبع esri/tasks/gp را به کد اضافه کنید. قطعه کد زیر یک نمونه از شی Geoprocessor ایجاد می‌کند.

gp = new Geoprocessor(url);

اجرای عملیات geoprocessing

خوب حالا که مفهوم مدل‌ها و ابزارهای geoprocessing را در یک نمونه از ArcGIS Server یاد گرفتید، برای انجام عملیات geoprocessing کدنویسی را شروع می‌کنیم. Geoprocessing می‌تواند به صورت عملیات همزمان یا غیر همزمان در ArcGIS Server ثبت شود. در اجرای همزمان، وقتی کاربر عملیات همزمان را صدا می‌زند، اپلیکیشن قبل از اجرای ادامه‌ی کد باید منتظر نتایج بماند و پس از گرفتن نتایج بقیه کد اپلیکیشن اجرا می‌شود. در اجرای غیر همزمان، وقتی کاربر عملیات مورد نظرش را درخواست کرد، ادامه‌ی کد و توابع نیز اجرا می‌شوند و کاربر می‌تواند روند اجرای درخواستش را بررسی کند. به صورت پیش فرض کاربر می‌تواند درخواستش را تا لحظه‌ی تکمیل هر لحظه بررسی کند. نوع عملیات هنگام انتشار مدل در سرویس، تنظیم می‌شود. بعد از انتشار در سرویس، تغییر نوع عملیات غیر ممکن است.

 عملیات همزمان

در عملیات همزمان، اپلیکیشن باید یک کار را ثبت و اجرا کند و قبل از اجرای بقیه‌ی کد، منتظر نتایج کار بماند. کاربران باید منتظر نتایج بازگشتی بمانند و بعد از گرفتن نتایج می‌توانند مجدد با اپلیکیشن تعامل و محاوره داشته باشند. این نوع اجرا برای کارهایی که به سرعت نتیجه را برمی‌گردانند، استفاده می‌شود و اگر اجرای کار بیشتر از چند ثانیه زمان می‌برد باید از نوع غیر همزمان تعیین شود.

در عملیات همزمان، باید از متد Geoprocessor.execute() همراه با پارامترهای ورودی استفاده کنید و یک تابع بازخوردی نیز تعبیه کنید. این تابع هنگامی که نتایج عملیات geoprocessing برمی‌گردند، اجرا می‌شود. نتایج در آرایه‌ای به نام ParameterValue ذخیره می‌شوند.

عملیات غیر همزمان

در این نوع عملیات، ابتدا یک کار را ثبت می‌کنید و تا هنگام برگشت نتایج، روی بقیه‌ی توابع نیز می‌توانید کار ‌کنید. در این نوع اجرا کاربر منتظر نتایج عملیات نمی‌ماند و می‌تواند در حین اجرای درخواستش با اپلیکیشن تعامل داشته باشد. وقتی عملیات کاملاً اجرا شد یک پیام در اپلیکیشن ظاهر می‌شود و آنگاه می‌توانید از نتایج برگشتی در اپلیکیشن استفاده ‌کنید. متد Geoprocessor.submitJob() یک کار از نوع geoprocessing را ثبت می‌کند. باید پارامترهای ورودی، یک تابع بازخوردی و وضعیت تابع بازخوردی را تعیین کنید. هر بار که اپلیکیشن شما برای نتایج بررسی می‌شود؛ وضعیت تابع بازخوردی بررسی می‌شود. به طور پیش فرض وضعیت در هر ثانیه بررسی می‌شود. تناوب زمانی با متد Geoprocessor.setUpdateDelay() قابل تغییر است. هر بار که وضعیت بررسی می‌شود، یک شی JobInfo برگردانده می‌شود که شامل وضعیت عملیات است. زمانی که ویژگی JobInfo. jobStatus را با مقدار STATUS_SUCCEEDED تنظیم می‌کنید، تابع بازخوردی صدا زده می‌شود تا نتایج عملیات را برگرداند؛ زیرا این ویژگی اجرای کامل عملیات را نشان می‌دهد.

نمودار زیر نحوه‌ی اجرای عملیات غیر همزمان را نشان می‌دهد. پارامترهای ورودی ایجاد و در شی Geoprocessor قرار می‌گیرند. این شی با استفاده از پارامترهای ورودی، عملیات geoprocessing را در ArcGIS Server ثبت می‌کند. سپس تابع statusCallback() در یک تناوب زمانی مشخص اجرا می‌شود. سرویس geoprocessing این تابع را طی تناوب زمانی بررسی می‌کند. هر بار که تابع statusCallback() اجرا می‌شود، یک شی JobInfo برگردانده می‌شود. این شی وضعیت اجرا را نشان می‌دهد. این فرآیند تا زمانی که عملیات کامل شود، اجرا می‌شود. پس از اجرای کامل عملیات تابع complete callback اجرا می‌شود و نتایج را می‌فرستد.

ایجاد اپلیکیشن با ابزارهای geoprocessing

در اینجا یک اپلیکیشن ساده را کدنویسی می‌کنیم. ابتدا کاربر بر روی یک نقطه از نقشه کلیک می‌کند. مناطقی که طی یک، دو و سه دقیقه رانندگی تا این نقطه قابل دسترس هستند را به صورت پولیگون نشان می‌دهد.

1- Sandbox را باز کنید.

2- همه‌ی محتویات تگ <script> را پاک کنید.

3- منابع زیر را برای استفاده از اشیاء مورد نیازاضافه کنید:

<script>
require([
“esri/map”,
“esri/graphic”,
“esri/graphicsUtils”,
“esri/tasks/Geoprocessor”,
“esri/tasks/FeatureSet”,
“esri/symbols/SimpleMarkerSymbol”,
“esri/symbols/SimpleLineSymbol”,
“esri/symbols/SimpleFillSymbol”,
“dojo/_base/Color”],
function(Map, Graphic, graphicsUtils, Geoprocessor, FeatureSet,
SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol,
Color){
});
</script>

4- شی map و متغیرهایی را برای نگهداری شی Geoprocessor و مدت زمان رانندگی ایجاد کنید.

<script>
require([
“esri/map”,
“esri/graphic”,
“esri/graphicsUtils”,
“esri/tasks/Geoprocessor”,
“esri/tasks/FeatureSet”,
“esri/symbols/SimpleMarkerSymbol”,
“esri/symbols/SimpleLineSymbol”,
“esri/symbols/SimpleFillSymbol”,
“dojo/_base/Color”],
function(Map, Graphic, graphicsUtils, Geoprocessor,
FeatureSet, SimpleMarkerSymbol, SimpleLineSymbol,
SimpleFillSymbol, Color){
var map, gp;
var driveTimes = “1 2 3”;
// Initialize map, GP and image params
map = new Map(“mapDiv”, {
basemap: “streets”,
center:[-117.148, 32.706], //long, lat
zoom: 12
}); });
</script>

5- درون تابع require() یک شی Geoprocessor ایجاد و ارجاع مکانی را مشخص کنید.

// Initialize map, GP and image params
map = new Map(“mapDiv”, {
basemap: “streets”,
center:[-117.148, 32.706], //long, lat
zoom: 12
});
gp = new
Geoprocessor(“http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Network/ESRI_DriveTime_US/GPServer/ CreateDriveTimePolygons”);
gp.setOutputSpatialReference({wkid:102100});

6- برای رویداد کلیک نقشه، یک رویداد تنظیم کنید. هر بار که کاربر بر روی نقطه‌ای از نقشه کلیک کند، این رویداد، عملیات geoprocessing را صدا می‌زند و مدت زمان رانندگی را محاسبه می‌کند.

gp = new Geoprocessor(“http://sampleserver1.arcgisonline.
com/ArcGIS/rest/services/Network/ESRI_DriveTime_US/GPServer/
CreateDriveTimePolygons”);
gp.setOutputSpatialReference({wkid:102100});
map.on(“click”, computeServiceArea);

7- حال تابع computeServiceArea() را ایجاد کنید. این تابع هنگامی که Map.click() انجام شود، اجرا می‌شود. این تابع همه‌ی گرافیک‌های موجود در نقشه را پاک و یک گرافیک نقطه‌ای ایجاد می‌کند و جایی که کاربر کلیک کرده را با یک گرافیک نقطه‌ای نشان می‌دهد و در نهایت عملیات geoprocessing را اجرا می‌کند.

gp = new Geoprocessor(“http://sampleserver1.arcgisonline.
com/ArcGIS/rest/services/Network/ESRI_DriveTime_US/GPServer/
CreateDriveTimePolygons”);
gp.setOutputSpatialReference({wkid:102100});
map.on(“click”, computeServiceArea);
function computeServiceArea(evt) {
}

8- همه‌ی گرافیک‌ها را پاک کنید و در جایی که کاربر کلیک کرده یک گرافیک نقطه‌ای ایجاد کنید:

function computeServiceArea(evt) {
map.graphics.clear();
var pointSymbol = new SimpleMarkerSymbol();
pointSymbol.setOutline = new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([255, 0, 0]), 1);
pointSymbol.setSize(14);
pointSymbol.setColor(new Color([0, 255, 0, 0.25]));
}

9- وقتی کاربر بر روی نقشه کلیک کند، یک شی Event ایجاد می‌شود. این شی در متغیر evt قرار داده می‌شود و این متغیر به تابع computeServiceArea() فرستاده می‌شود. در مرحله‌ی بعدی با استفاده از ویژگی Event.mapPoint یک شی Graphic ایجاد می‌کنیم. سپس این گرافیک را به لایه‌ی گرافیکی اضافه ‌می‌کنیم تا در نقشه نمایش داده شود.

function computeServiceArea(evt) {
map.graphics.clear();
varpointSymbol = new SimpleMarkerSymbol();
pointSymbol.setOutline = new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([255, 0, 0]), 1);
pointSymbol.setSize(14);
pointSymbol.setColor(new Color([0, 255, 0, 0.25]));
var graphic = new Graphic(evt.mapPoint,pointSymbol);
map.graphics.add(graphic);
}

10- حال آرایه‌ای به نام features ایجاد کرده و شی graphic را درون این آرایه قرار می‌دهیم. این آرایه از گرافیک‌ها به شی FeatureSet فرستاده می‌شود تا این شی به عملیات geoprocessing فرستاده شود.

Function computeServiceArea(evt) {
map.graphics.clear();
var pointSymbol = new SimpleMarkerSymbol();
pointSymbol.setOutline = new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([255, 0, 0]), 1);
pointSymbol.setSize(14);
pointSymbol.setColor(new Color([0, 255, 0, 0.25]));
var graphic = new Graphic(evt.mapPoint,pointSymbol);
map.graphics.add(graphic);
var features= [];
features.push(graphic);
}

11- یک شی FeatureSet تعریف می‌کنیم و آرایه‌ی گرافیک‌ها را به ویژگی FeatureSet.features اضافه می‌کنیم.

function computeServiceArea(evt) {
map.graphics.clear();
var pointSymbol = new SimpleMarkerSymbol();
pointSymbol.setOutline = new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([255, 0, 0]), 1);
pointSymbol.setSize(14);
pointSymbol.setColor(new Color([0, 255, 0, 0.25]));
var graphic = new Graphic(evt.mapPoint,pointSymbol);
map.graphics.add(graphic); var features= [];
features.push(graphic);
var featureSet = new FeatureSet();
featureSet.features = features;
}

12- یک شی JSON برای نگه داری پارامترهای ورودی Input_Location و Drive_Times ایجاد می‌کنیم. سپس متد Geoprocessor.execute() را صدا می‌زنیم. به خاطر داشته باشید که نام پارامترها و ترتیب آن‌ها را مطابق آنچه که در صفحه‌ی سرویس هستند، تعیین کنید. پارامتر Input_Location را برای قرارگیری در شی FeatureSet تعریف می‌کنیم. شی FeatureSet آرایه‌ای از گرافیک‌ها است که در این مثال تنها یک گرافیک نقطه در این آرایه قرار می‌گیرد. شی Drive_Times با مقادیر 2،1 و 3 مقدار دهی می‌شود و این شی در متغیر driveTimes قرار می‌گیرد. سپس متد Geoprocessor.execute() را صدا می‌زنیم. تابع بازخوردی را به عنوان پارامتر ورودی به این متد می‌فرستیم. در قدم بعدی تابع بازخوردی را ایجاد می‌کنیم.

function computeServiceArea(evt) {
map.graphics.clear();
varpointSymbol = new SimpleMarkerSymbol();
pointSymbol.setOutline = new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([255, 0, 0]), 1);
pointSymbol.setSize(14);
pointSymbol.setColor(new Color([0, 255, 0, 0.25]));
var graphic = new Graphic(evt.mapPoint,pointSymbol);
map.graphics.add(graphic);
var features= [];
features.push(graphic);
varfeatureSet = new FeatureSet();
featureSet.features = features;
var params = { “Input_Location”:featureSet,
“Drive_Times”:driveTimes };
gp.execute(params, getDriveTimePolys);
}

13- در آخرین مرحله، یک تابع بازخوردی به نام getDriveTimePolys() ایجاد می‌کنیم. پس از اجرای کامل عملیات geoprocessing، تابع getDriveTimePolys() اجرا می‌شود. درست در زیر براکت بسته‌ی تابع computeServiceArea() کد زیر را بنویسید:

function getDriveTimePolys(results, messages) {
}

14- تابع getDriveTimePolys() شامل دو پارامتر شی نتیجه و پیام است. متغیری به نام features برای نگه داری شی FeatureSet تعریف کنید.

function getDriveTimePolys(results, messages) {
var features = results[0].value.features;
}

15- عملیات geoprocessing سه گرافیک پولیگونی برای هر زمان رانندگی برمی‌گردانند. یک حلقه‌ی for برای پردازش پولیگون‌ها ایجاد کنید:

function getDriveTimePolys(results, messages) {
var features = results[0].value.features;
for (var f=0, fl=features.length; f<fl; f++) {
}
}

16- حلقه‌ی for به هر کدام از پولیگون‌ها، طرح بندی و گرافیک اعمال می‌کند که هر سه پولیگون در شی FeatureSet قرار می‌گیرند. گرافیک‌های پولیگون‌ها به لایه­ی گرافیکی اضافه می‌شوند.

function getDriveTimePolys(results, messages) {
var features = results[0].value.features;
for (var f=0, fl=features.length; f<fl; f++) {
var feature = features[f];
if(f == 0) {
var polySymbolRed = new SimpleFillSymbol();
polySymbolRed.setOutline(new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([0,0,0,0.5]), 1));
polySymbolRed.setColor(new Color([255,0,0,0.7]));
feature.setSymbol(polySymbolRed); }
else if(f == 1) {
var polySymbolGreen = new SimpleFillSymbol();
polySymbolGreen.setOutline(new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([0,0,0,0.5]), 1));
polySymbolGreen.setColor(new Color([0,255,0,0.7]));
feature.setSymbol(polySymbolGreen);
}
else if(f == 2) {
var polySymbolBlue = new SimpleFillSymbol();
polySymbolBlue.setOutline(new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([0,0,0,0.5]), 1));
polySymbolBlue.setColor(new Color([0,0,255,0.7]));
feature.setSymbol(polySymbolBlue);
}
map.graphics.add(feature);
}

17- Extent نقشه را با Extent لایه‌ی گرافیکی تنظیم کنید.

function getDriveTimePolys(results, messages) {
var features = results[0].value.features;
for (var f=0, fl=features.length; f<fl; f++) {
var feature = features[f];
if(f === 0) {
var polySymbolRed = new SimpleFillSymbol();
polySymbolRed.setOutline(new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([0,0,0,0.5]), 1));
polySymbolRed.setColor(new Color([255,0,0,0.7]));
feature.setSymbol(polySymbolRed);
}
else if(f == 1) {
var polySymbolGreen = new SimpleFillSymbol();
polySymbolGreen.setOutline(new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([0,0,0,0.5]), 1));
polySymbolGreen.setColor(new Color([0,255,0,0.7]));
feature.setSymbol(polySymbolGreen);
}
else if(f == 2) {
var polySymbolBlue = new SimpleFillSymbol();polySymbolBlue.setOutline(new
SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new
Color([0,0,0,0.5]), 1));
polySymbolBlue.setColor(new Color([0,0,255,0.7]));
feature.setSymbol(polySymbolBlue);
}
map.graphics.add(feature);
}
map.setExtent(graphicsUtils.graphicsExtent
(map.graphics.graphics), true);
}

18- یک تگ <div> برای نگهداری متن دستورالعمل استفاده از اپلیکیشن تعریف کنید.

<body>
<div id=”mapDiv”></div>
<div id=”info” class=”esriSimpleSlider”>
Click on the map to use a Geoprocessing(GP) task to
generate and zoom to drive time polygons. The drive time
polygons are 1, 2, and 3 minutes.
</div>
</body>

19- در تگ <style> که در بالای کد قرار دارد، کد زیر را اضافه کنید:

<style>
html, body, #mapDiv {
height: 100%;
margin: 0;
padding: 0;
width: 100%;
}
#info {
bottom: 20px;
color: #444;
height: auto;
font-family: arial;
left: 20px;
margin: 5px;
padding: 10px;
position: absolute;
text-align: left;
width: 200px;
z-index: 40;
}
</style>

20- می‌توانید با استفاده از فایل drivetimes.html موجود در پوشه‌ی 7956OT – Code/Chapter 10 صحت کد خود را بررسی کنید.

21- روی دکمه‌ی run کلیک کنید. تصویری مشابه زیر ظاهر خواهد شد:

22- در هر جایی از نقشه کلیک کنید. در عرض کمتر از یک دقیقه، پولیگون‌هایی ظاهر می‌شوند که طی رانندگی 2،1 و 3 دقیقه‌ای از مکان کلیک شما قابل دسترس هستند.

برگرفته از کتاب تولید و طراحی اپلیکیشن‌ های Web GIS و Mobile GIS با استفاده از ArcGIS API for JavaScript

نویسنده: دکتر محمد بافقی زاده

نشر: انتشارات اکادمیک

1,570 نظرات

دیدگاهتان را بنویسید