地图要素动画应用场景:动态显示地图上的要素的属性随着时间的改变而改变,并根据其属性的变化设置其渲染.比如:某水域项目中,随着时间的变化,动态展现水域的清淤进度
本文目的:对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>