地圖要素動畫應用場景:動態顯示地圖上的要素的屬性隨着時間的改變而改變,並根據其屬性的變化設置其渲染.比如:某水域項目中,隨着時間的變化,動態展現水域的清淤進度
本文目的:對ArcGIS JavaScript 官網示例中的代碼進行分析注解.下述代碼對官網示例進行了部分調整
示例網址1:
以下為代碼注釋:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <!--The viewport meta tag is used to improve the presentation and behavior of the samples on iOS devices--> <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"> <title>LLC動態圖測試</title> <link rel="stylesheet" href="http://**.**.**.**/arcgis_js_api/library/3.15/3.15/esri/css/esri.css"> <style> html, body, #mainWindow { height: 100%; width: 100%; margin: 0; padding: 0; } body { background-color: white; overflow: hidden; font-family: "Trebuchet MS"; } #loading { background: #fff; height: 100%; overflow: hidden; position: absolute; width: 100%; z-index: 100; } #loadingMessage { color: #000; margin: 0 auto; padding: 150px 0 0 0; text-align: center; width: 200px; } .shadow { -moz-box-shadow: 0 0 5px #888; -webkit-box-shadow: 0 0 5px #888; box-shadow: 0 0 5px #888; } #map { background-color: white; } #feedback { background: #fff; color: #000; font-family: arial; height: auto; left: 30px; margin: 5px; padding: 10px; position: absolute; text-align: center; top: 30px; visibility: hidden; width: 200px; z-index: 10; } #currentYear { display: inline-block; height: 25px; text-align: center; width: 50px; } #play, #pause { cursor: pointer; display: none; width: 50px; } #legend { padding: 10px 0 0 0; } #legend table table td { text-align: left; } /* animate color transition when years change */ /*The LLC Guess:the CSS name seems to be useless,maybe you can edit it arbitrary*/ /*以下為地圖的顯示樣式,相關內容查詢svg,path[]中的內容,即為要素分類的類別*/ #counties_layer path { transition: fill 1.15s, fill-opacity 1.15s, stroke 1.15s, stroke-opacity 1.15s; -webkit-transition: fill 1.15s, fill-opacity 1.15s, stroke 1.15s, stroke-opacity 1.15s; } #counties_layer path[data-relgrowth="no-data"] { stroke: rgb(255, 255, 255); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="zero-or-less"] { fill: rgb(175, 141, 195); /* purple */ fill-opacity: 1; stroke: rgb(175, 141, 195); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="lt-US"] { fill: rgb(225, 236, 231); /* light */ fill-opacity: 1; stroke: rgb(225, 236, 231); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="gt-US"] { fill: rgb(127, 191, 123); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="llcStyle"] { fill: rgb(0, 0, 0); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="1"] { fill: rgb(0, 0, 0); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="2"] { fill: rgb(255, 0, 0); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="3"] { fill: rgb(0, 255, 0); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="4"] { fill: rgb(0, 0, 255); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="5"] { fill: rgb(255, 255, 0); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } #counties_layer path[data-relgrowth="6"] { fill: rgb(0, 255, 255); /* green */ fill-opacity: 1; stroke: rgb(127, 191, 123); stroke-width: 1pt; stroke-opacity: 1; } </style> <script type="text/javascript" src="http://**.**.**.**/arcgis_js_api/library/3.15/3.15/init.js"></script> <script> require([ "esri/map", "esri/layers/FeatureLayer", "esri/dijit/Legend", "esri/InfoTemplate", "esri/renderers/ClassBreaksRenderer", "esri/symbols/SimpleFillSymbol", "esri/symbols/SimpleLineSymbol", "dojo/_base/array", "esri/Color", "dojo/_base/fx", "dojo/_base/lang", "dojo/Deferred", "dojo/dom", "dojo/dom-construct", "dojo/dom-style", "dojo/number", "dojo/on", "dojo/parser", "dojo/string", "dojox/data/CsvStore", "dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dojo/domReady!" ], function (Map, FeatureLayer, Legend, InfoTemplate, ClassBreaksRenderer, SimpleFillSymbol, SimpleLineSymbol, arrayUtils, Color, fx, lang, Deferred, dom, domConstruct, domStyle, number, on, parser, string, CsvStore) { parser.parse(); var map, layer, currentYear = 1971, currentUSPgr, timer; map = new Map("map", { basemap: "gray", center: [120.2, 30.542], zoom: 11, slider: false }); map.on("load", function () { //加載csv數據.csv中為美國人口數據表,之后通過fip與矢量數據進行關聯 loadCSV().then(function (csvData) { //神奇的JavaScript this. 綁定setYear的上下文對象為csvData,所以,在函數中,this就是csvData setYear = lang.hitch(csvData, setYear); //年份設置為1971年 setYear(1971); //添加圖層(該方法大體上相當於將featureLayer與csv中的表進行了連接處理) layer = addCounties(csvData); }); }); // set up play/pause buttons //播放/暫停按鈕事件綁定 on(dom.byId("pause"), "click", function () { domStyle.set(this, "display", "none"); domStyle.set("play", "display", "inline-block"); pause(); }); on(dom.byId("play"), "click", function () { domStyle.set(this, "display", "none"); domStyle.set("pause", "display", "inline-block"); play(); }); function addCounties(csvData) { var content = "<b>河流名稱</b>: ${河流名稱} \ <br><b>清淤量</b>: ${清淤量} \ <br><b>FKRATE</b>: ${rate} "; // \ // <br><National Average: ${NATLAVG}"; var infoTemplate = new InfoTemplate("${河流名稱} FK河段", content); //FeatureLayer URL var url = "http://**.**.**.**/arcgis/rest/services/DQ/DQDestilingTemp/MapServer/6"; var counties = new FeatureLayer(url, { id: "counties", infoTemplate: infoTemplate, outFields: ["河流名稱", "FID", "SILTVOLUME"], styling: false }); counties.on("load", function () { on.once(counties, "update-end", function () { //設置地圖渲染器,此渲染器不用於地圖渲染,只用於生成圖例,所以"FID"字段只是寫着玩玩 var renderer = createRenderer(currentYear, "FID", csvData); counties.setRenderer(renderer); createLegend(counties); domStyle.set("pause", "display", "inline-block"); //開始動畫 play(); }); fadeOutLoading(); }); if (counties.surfaceType === "svg") { counties.on("graphic-draw", function (evt) { //下述代碼進行要素與csv表的關聯操作 var attrs = evt.graphic.attributes; var joinKey = attrs && attrs.FID; //關聯用的字段,先用FID表示了 var relgrowth = "no-data"; if (joinKey && csvData[joinKey] && csvData[joinKey][currentYear]) { //根據csv表中的數據,獲取相應年份的人口數據,計算人口增長率 var countyPgr = getGrowthRate(csvData[joinKey][currentYear - 1], csvData[joinKey][currentYear], 1); //console.log(countyPgr); //根據增長率的不同,進行分類渲染 if (countyPgr <= 0.5 && countyPgr > 0) relgrowth = "1"; else if (countyPgr > 0.5 && countyPgr <= 1) relgrowth = "2"; else if (countyPgr > 1 && countyPgr <= 1.25) relgrowth = "3"; else if (countyPgr > 1.25 && countyPgr <= 1.5) relgrowth = "4"; else if (countyPgr > -5 && countyPgr <= -0.5) relgrowth = "5"; else relgrowth = "6"; } var qyl; if (joinKey != undefined && csvData[joinKey] != undefined && csvData[joinKey][currentYear] != undefined) qyl = csvData[joinKey][currentYear]; //此處可以將某年某月的數據關聯到圖層的屬性中 attrs.清淤量 = qyl; attrs.rate = countyPgr; //此處是配色的關鍵字段!此處內容與上面配置的樣式表相對應 evt.graphic.getNode().setAttribute("data-relgrowth", relgrowth); }); } map.addLayer(counties); return counties; } function loadCSV() { //加載csv中的數據.可以略過,處理結果就是將csv中的表加載到了csvData中,其他函數可以根據FID,時間獲取某年月的數據 var dfd = new Deferred(); var csvStore = new CsvStore({ url: "DesiltingTemp.csv" }); csvStore.fetch({ onComplete: function (items, request) { //process csv data and create in memory object store. var store = request.store; var minYearPopulation = 1970; var maxYearPopulation = 2006; var counties = {}; counties.minVal = Infinity; counties.maxVal = -Infinity; arrayUtils.forEach(items, function (item) { //var countyFips = store.getValue(item, "county_fips"); //var stateFips = store.getValue(item, "state_fips"); //var fips = string.pad(stateFips, 2, "0") + string.pad(countyFips, 3, "0"); var fips = store.getValue(item, "FID"); var population = {}; population.maxVal = -Infinity; for (var year = minYearPopulation; year <= maxYearPopulation; year++) { var fieldName = "pop" + year; var popValue = parseInt(store.getValue(item, fieldName), 10); population[year] = popValue; population.maxVal = (popValue > population.maxVal) ? popValue : population.maxVal; counties.minVal = (popValue < counties.minVal) ? popValue : counties.minVal; counties.maxVal = (popValue > counties.maxVal) ? popValue : counties.maxVal; } counties[fips] = population; }); dfd.resolve(counties); }, onError: function (err) { console.log("Error loading CSV: ", err.message, err); } }); return dfd; } function getGrowthRate(pt1, pt2, t2_t1) { return ((Math.log(pt2) - Math.log(pt1)) / (t2_t1)) * 100; } function setYear(year) { //設置當前年份 //由於函數調用時有如下代碼setYear = lang.hitch(csvData, setYear); so this就是csvData var csvData = this; currentYear = year; currentUSPgr = getGrowthRate(csvData["0"][currentYear - 1], csvData["0"][currentYear], 1); dom.byId("currentYear").innerHTML = currentYear; if (layer) { layer.renderer._currentYear = year; //添加renderer分類對象,對分類渲染來說沒有實際意義 addBreaks(layer.renderer); //重繪.根據官網資料,該方法不通過服務器重繪 layer.redraw(); //恢復之前的地圖彈窗 var sel = map.infoWindow.getSelectedFeature(); if (sel && map.infoWindow.isShowing) { map.infoWindow.setFeatures([sel]); } } } function changeYear(incr) { //更改地圖的當前年份 var year; if (incr < 1) { year = (currentYear === 1971) ? 2006 : currentYear + incr; setYear(year); } else if (incr > 0) { year = (currentYear === 2006) ? 1971 : currentYear + incr; setYear(year); } } function play() { //動畫播放 if (!timer) { timer = setInterval(function () { changeYear(1); }, 1250); } } function pause() { clearInterval(timer); timer = null; } function createRenderer(startYear, joinField, data) { // renderer is used for the legend //The LLC Says:This Method is only used for the legend,actually,the breaks info of the renderer is not used for the layer to display. //so the attibuteField of the ClassBreaksRenderer is meaningless //var tColor=[0,0,0]; //該Renderer只用來生成圖例,不用以分類渲染 var renderer = new ClassBreaksRenderer(null, "FID"); renderer._currentYear = startYear; renderer._data = data; addBreaks(renderer); // console.log("renderer with breaks", renderer); return renderer; } function createLegend(layer) { //創建圖例 var legendDijit = new Legend({ map: map, layerInfos: [ { "layer": layer, "title": "Population Change" } ] }, "legend"); legendDijit.startup(); domStyle.set("feedback", "visibility", "visible"); } function addBreaks(renderer) { // console.log("addBreaks", renderer); var currentYear = renderer._currentYear, data = renderer._data, totalGrowth = getGrowthRate(data['0'][currentYear], data['0'][currentYear - 1], 1), roundedTotalGrowth = number.round(totalGrowth, 2); renderer.clearBreaks(); var negative = [175, 141, 195]; var flat = [20, 236, 231]; var positive = [127, 191, 123]; renderer.addBreak({ minValue: -Infinity, maxValue: 0, symbol: new SimpleFillSymbol().setColor(new Color(negative)) .setOutline(new SimpleLineSymbol().setColor(new Color(negative))), label: "Decrease" }); renderer.addBreak({ minValue: 0, maxValue: roundedTotalGrowth, symbol: new SimpleFillSymbol().setColor(new Color(flat)) .setOutline(new SimpleLineSymbol().setColor(new Color(flat))), label: "Flat" }); renderer.addBreak({ minValue: roundedTotalGrowth, maxValue: Infinity, symbol: new SimpleFillSymbol().setColor(new Color(positive)) .setOutline(new SimpleLineSymbol().setColor(new Color(positive))), label: "Increase" }); } function fadeOutLoading() { var fade = fx.fadeOut({ node: "loading", onEnd: function () { domConstruct.destroy(dom.byId("loading")); } }); fade.play(); } }); </script> </head> <body> <div id="loading"> <div id="loadingMessage"> 正在加載清淤量數據 <br> <img src="assets/loading_gray_circle.gif"> </div> </div> <div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="'design': 'headline', 'gutters': false"> <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="'region': 'center'"> <div id="feedback" class="shadow"> Year: <span id="currentYear"> <img src="assets/loading_gray_circle.gif"> </span> | <!--div id="play">></div--> <span id="play">Play</span> <!--div id="pause">||</div--> <span id="pause">Pause</span> <div id="legend"></div> </div> </div> <!-- end map div --> </div> <!-- end border container div --> </body> </html>