<\/HEAD>
<\/P>
Een tijdje geleden schreef ik een artikel over hoe je je AMD-modules kunt omarmen<\/A>. Er kwamen een paar vragen op toen men voorbeelden zag van hoe dit te doen, met gebruik van best practices en aanbevolen manieren om met modules te werken. Dus dacht ik dat ik daar vandaag mee zou helpen.<\/P><\/P>
Wat ik deed was een
voorbeeld uit de documentatie<\/A> nemen dat ik een tijd geleden had bijgewerkt om wat functies toe te voegen<\/A>.<\/P><\/P>
Ik wilde nadenken over hoe ik dit kon opsplitsen in een meer modulaire app met AMD.<\/P>
<\/P>
Laten we eerst eens naar de code kijken, zonder nu naar de HTML te kijken.<\/P>
require([
"esri\/Color", "esri\/dijit\/PopupTemplate", "esri\/layers\/FeatureLayer", "esri\/map", "esri\/renderers\/BlendRenderer",
"esri\/symbols\/SimpleFillSymbol", "esri\/symbols\/SimpleLineSymbol", "dojo\/on", "dojo\/domReady!"
], function (Color, PopupTemplate, FeatureLayer, Map, BlendRenderer, SimpleFillSymbol, SimpleLineSymbol, on){
map = new Map("map", {
basemap: "topo",
center: [-118.40, 34.06],
zoom: 15
});
\/\/_Stel de parameters van de blendRenderer in
var blendRendererParams = {
\/\/_blendMode:"overlay" \/\/_Standaard gebruikt het "source-over", haal de commentaar weg om een andere modus te tonen
\/\/_Zie: <\/SPAN>
https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/CanvasRenderingContext2D\/globalCompositeOperation<\/A>
symbol: new SimpleFillSymbol().setOutline(new SimpleLineSymbol().setWidth(0)),
fields: [
{
field: "OWNER_CY",
label: "Eigenaar Bewoond",
color: new Color([0, 0, 255])
}, {
field: "RENTER_CY",
label: "Huurder Bewoond",
color: new Color([255, 0, 0])
}, {
field: "VACANT_CY",
label: "Leegstaand",
color: new Color([0, 255, 0])
}
],
opacityStops: [
{
 :& nbsp; value: 0.1,
opacity: 0
},
{
value: 1,
opacity: 0.7
}
],
normalizationField: "TOTHU_CY"
};
//Maak de PopupTemplate die gebruikt wordt om demografische info weer te geven
var template = new PopupTemplate({
"title": "Woonstatus per Censusblok",
"fieldInfos": [
{
"fieldName": "OWNER_CY",
"label": "Aantal door eigenaar bewoonde huizen",
"visible": true,
"format": {
"places": 0,
"digitSeparator": true
}
}, {
"fieldName": "RENTER_CY",
: "label": "Aantal door huurder bewoonde huizen",
: "visible": true,
: "format": {
: "places": 0,
: "digitSeparator": true
: }
: }, {
: "fieldName": "VACANT_CY",
: "label": "Aantal leegstaande huizen",
: "visible": true,
: "format": {
: "places": 0,
: "digitSeparator": true
: }
: }, {
: "fieldName": "TOTHU_CY",
: "label": "Totaal aantal wooneenheden",
: "visible": true,
: "format": {
: "places": 0,
: "digitSeparator": true
: }
: }]
});
var layerUrl = "<\/ topic.subscribe('blend-select-update', hitch(this, 'updateBlendMode'))
);
},
updateBlendMode: function(mode) {
console.log('update blend mode with dojo/topic');
var layer = this.get('layer');
var renderer = this.get('renderer');
renderer.blendMode = mode;
layer.setRenderer(renderer);
layer.refresh();
}
});
});</PRE>
Dit is een vrij eenvoudige widget. We gebruiken een postCreate-methode om dingen op te zetten. Ik praat over de dijit levenscyclus in deze video. In deze methode stel ik mijn laag in en wijs ik de renderer toe die in de opties werd doorgegeven. Er is een eenvoudige HTML-sjabloon die gewoon een kopie is van de HTML uit het voorbeeld met een beschrijving van de data. Ik gebruik ook dojo/topic, waarover ik hier sprak. Ik ga een paar verschillende methoden van widget-communicatie demonstreren, één met dojo/topic en één met dojo/Evented.
Deze module heeft ook een updateBlendMode-methode die simpelweg de dojo/topic subscribe afhandelt en de blendMode bijwerkt. Dit betekent dat elk module in je applicatie een update kan publiceren naar de blendMode of om welke reden dan ook. Naar mijn mening is dit een ideale methode voor widget-communicatie, omdat de individuele widgets niet van elkaar op de hoogte hoeven te zijn.
Het andere wat het voorbeeld had was een selectiemenu waarmee je de blendMode kon bijwerken. Nogmaals, ik denk dat dit de perfecte kandidaat is voor een andere widget. De code voor deze widget zou er ongeveer zo uit kunnen zien:
define([
'dojo/_base/declare',
'dojo/Evented',
'dojo/topic',
'dijit/_WidgetBase',
'dijit/_TemplatedMixin',
'dojo/text!./widget.html'
], function(
declare, Evented, topic,
_WidgetBase, _TemplatedMixin,
templateString
) {
return declare([_WidgetBase, _TemplatedMixin, Evented], {
templateString: templateString,
baseClass: 'blend-select',
onChange: function(e) {
var val = e.target.value;
if (this.cboxNode.checked) {
topic.publish('blend-select-update', val);
} else {
this.emit('blend-select-update', val);
}
}
});
})
Deze widget gebruikt dojo/Evented en dojo/topic. Je zult merken dat de widget zelf dojo/Evented uitbreidt met behulp van dojo/_base/declare. Dit stelt je in staat om this.emit() te gebruiken om events vanuit je widget uit te zenden. Deze widget heeft het selectiemenu voor blendModes en ook een checkbox om in te stellen of je een event wilt uitzenden met de nieuwe blendMode of de blendMode wilt publiceren via dojo/topic.
De sjabloon hiervoor ziet er als volgt uit:
<div>
<div>
<input type="checkbox" data-dojo-attach-point="cboxNode"> Gebruik dojo/topic
</div>
<select data-dojo-attach-event="change:onChange">
<option value="source-over">source-over</option>
<option value="source-in">source-in</option>
<option value="source-out">source-out</option>
<option value="source-atop">source-atop</option>
<option value="destination-over">destination-over</option>
<option value="destination-in">destination-in</option>
<option value="destination-out">destination-out</option>
<option value="destination-atop">destination-atop</option>
<option value="lighter">lichter</option>
<option value="copy">kopieer</option>
<option value="xor">xor</option>
<option value="overlay">>overlay</option>
  < option value= "normal"> normaal< /optie> ;
& lt optie waarde= "vermenigvuldigen "& gt vermenigvuldigen< /optie> ;
& lt optie waarde= "scherm "& gt scherm< /optie> ;
& lt optie waarde= "verdonkeren "& gt verdonkeren< /optie> ;
& lt optie waarde= "verlichten "& gt verlichten< /optie> ;
& lt optie waarde= "kleur-dodge "& gt kleur-dodge< /optie> ;
& lt optie waarde= "kleur-verbranding "& gt kleur-verbranding< /optie> ;
& lt optie waarde= "hard-licht "& gt hard-licht< /optie> ;
& lt optie waarde= "zacht-licht "& gt zacht-licht< /optie> ;
& lt optie waarde= "verschil "& gt verschil< /optie> ;
& lt optie waarde= "uitsluiting "& gt uitsluiting< /optie> ;
& lt optie waarde= "tint "& gt tint< /optie> ;
& lt optie waarde= "verzadiging "& gt verzadiging< /optie> ;
& lt optie waarde= "kleur "& gt kleur< /optie> ;
& lt optie waarde= "helderheid "& gt helderheid< /optie> ;
& lt/selecteer>
</div>
Oke9, we hebben dus twee widgets, e9e9ne die de FeatureLayer maakt met de blendRenderer en een andere widget die de blendMode van de renderer bijwerkt.
Laten we dit aansluiten in een main.js-module om aan de slag te gaan.
define([
'esri/map',
'esri/layers/ArcGISTiledMapServiceLayer',
'app/widgets/population/widget',
'app/widgets/blendselection/widget',
'app/utils/popupUtil',
'app/utils/rendererUtil'
], function(
Map, ArcGISTiledMapServiceLayer,
PopulationWidget, BlendSelectionWidget,
popup,
renderer
) {
var map = new Map('map', {
center: [-100, 38],
zoom: 5
});
var tileLayer = new ArcGISTiledMapServiceLayer('http://tiles.arcgis.com/tiles/nzS0F0zdNLvs7nc8/arcgis/rest/services/US_Counties_basemap/MapServer');
map.addLayer(tileLayer);
map.on('load', function() {
var populationWidget = new PopulationWidget({
layerOptions: {
outFields: ['WHITE', 'POP2012', 'AMERI_ES', 'HISPANIC', 'BLACK', 'ASIAN', 'POP12_SQMI', 'NAME', 'STATE_NAME'],
opacity: 1,
infoTemplate: popup
},
renderer: renderer,
map: map,
s url: 'http://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Counties_Generalized/FeatureServer/0'
}, 'population-container');
var blendSelectionWidget = new BlendSelectionWidget({}, 'blend-selection-container');
// een manier om de blendMode bij te werken
blendSelectionWidget.on('blend-select-update', function(mode) {
console.log('update blend mode with events');
renderer.blendMode = mode;
populationWidget.get('layer').setRenderer(renderer);
populationWidget.get('layer').refresh();
});
});
});
Oke9, het doel van het main-bestand is om de kaart te maken en de widgets te laden, waarbij de vereiste opties worden doorgegeven terwijl ook gebruik wordt gemaakt van de eerder gemaakte utils. Je zult ook merken dat ik gebruik maak van blendSelectionWidget.on('blend-select-update', function(mode){}) om te luisteren wanneer er een event wordt uitgezonden en handmatig de renderer voor de laag in de population-widget bij te werken. Dit is een andere manier waarop je communicatie tussen widgets kunt doen, waarbij je het in een main-bestand kunt doen of misschien heb je een WidgetController die alle widget-communicatie van je applicatie afhandelt, het hangt echt af van wat jou aanspreekt. Normaal gesproken zou ik zelfs het maken van de kaart als eigen widget uitwerken.
Ik wil ook graag wijzen op de dojoConfig voor deze applicatie.
var dojoConfig = {
isDebug: true,
deps: ['app/main'],
packages: [{
name: 'app',
s location: location.pathname.replace(new RegExp(/\/[^\/]+$/), '') + 'app'
s }]
s};Dat is heel eenvoudig. Door het op deze manier te doen heb ik een app-pakket gedefinieerd en al mijn modules bevinden zich in dit pakket. Dit betekent dat ik geen apart widgets-pakket of utils-pakket hoef te maken, ik kan ze gewoon refereren als app/widgets en app/utils. Let ook op de eigenschap deps. Dit vertelt de Dojo-loader om deze module te laden wanneer Dojo wordt geladen. Je kunt de documentatie hier bekijken. Dit maakt mijn daadwerkelijke index.html bestand echt eenvoudig.<\/P>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no" />
<title>Modular App Demo</title>
<link rel="stylesheet" href="http://js.arcgis.com/3.14/esri/css/esri.css"><\/SPAN>
<link rel="stylesheet" href="css/main.css">
<script src="dojoConfig.js"></script>
</head>
<body>
<div id="blend-selection-container"></div>
<div id="population-container"></div>
<div id="map"></div>
<script src="http://js.arcgis.com/3.14/"></script><\/SPAN>
</body>
</html><\/PRE>Je kunt lezen over andere methoden om je applicatie te initialiseren hier.<\/P><\/P>Neem het gewoon stukje voor stukje<\/H2>Je kunt de volledige gemoduleerde applicatie vinden in deze github repo. Ik hoop dat dit wat meer inzicht geeft in hoe je een applicatie kunt opsplitsen in modules en hoe je modulariteit in je eigen ontwikkeling kunt gaan zien. Ik vind het prettig om functies van een applicatie op te splitsen in hun eigen widgets, of het nu bewerken, zoeken, geocoderen is of zelfs gewoon gedrag toevoegen.<\/P><\/P>Je kunt enkele andere voorbeelden van modulariteit zien in dingen waar ik in het verleden aan heb gewerkt in deze starter-kit, die volledig configureerbaar is, of mijn laatste experimenten in deze yeoman generator, en voorbeeldapp. Een andere app die erg modulair is, is iets als de cmv app.<\/P><\/P>Nogmaals, dit is simpelweg mijn mening over hoe ik denk dat je een app kunt opsplitsen in kleinere modules die het niet alleen gemakkelijker maken om te onderhouden na verloop van tijd, maar ook om gemakkelijk nieuwe functionaliteit toe te voegen.<\/P><\/P>Voor meer geodev tips en trucs, bekijk mijn blog.<\/P><\/BODY><\/HTML>