ember install ember-cli-amd
- configure as per https://github.com/Esri/ember-cli-amd#usage
- add config/dojo-config.js with:
window.dojoConfig = {
async: true
};
- open ember-cli-build.js and replace
var app = new EmberApp...
with:
var app = new EmberApp(defaults, {
amd : {
// only need basic mapping capabilities, so use compact
loader: 'https://js.arcgis.com/3.19compact/',
// user defined AMD packages to search for in application
packages: [
'esri','dojo','dojox','dijit',
'put-selector','xstyle','dgrid'
],
configPath: 'config/dojo-config.js'
}
});
- in app/styes/app.css
- add the following between the bootstrap and app styles:
/* esri styles */
@import url('https://js.arcgis.com/3.19/esri/css/esri.css');
- and add the following at the end:
/* map */
.extents-map {
height: 300px;
margin-bottom: 20px;
}
ember serve
ember generate service map-service
ember generate component extents-map
rm app/components/extents-map/template.hbs
- replace contents of app/map-service/service.js with
import Ember from 'ember';
import Map from 'esri/map';
export default Ember.Service.extend({
// create a new map object at an element
newMap(element, options) {
// hold on to the reference for later operations
this._map = new Map(element, options);
},
// destroy the map if it was already created
destroyMap() {
if (this._map) {
this._map.destroy();
delete this._map;
}
}
});
- replace contents of app/components/extents-map/component.js with:
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['extents-map'],
mapService: Ember.inject.service('map-service'),
// wait until after the component is added to the DOM before creating the map
didInsertElement () {
this._super(...arguments);
// create a map at this element's DOM node
const mapService = this.get('mapService');
mapService.newMap(this.elementId, { basemap: 'gray' });
},
// destroy the map before this component is removed from the DOM
willDestroyElement () {
this._super(...arguments);
const mapService = this.get('mapService');
mapService.destroyMap();
}
});
-
in app/items/template.hbs add
{{extents-map}}
above the table -
go to the items route, you should see a map
Goal: stub the map service so we don't create a map when testing
ember install ember-sinon-qunit
- run
ember test - s
and filter for "integration" - open network tab of test browser and filter for "arcgisonline.com"
- in tests/integration/component/extents-map/component-test.js replace
import { moduleForComponent, test } from 'ember-qunit';
with:
import { moduleForComponent } from 'ember-qunit';
import test from 'ember-sinon-qunit/test-support/test';
- replace the contents of the 'it renders' test with:
// stub the newMap() function so that a map is not constructed
const mapService = this.container.lookup('service:map-service');
const stub = this.stub(mapService, 'newMap');
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
this.render(hbs`{{extents-map}}`);
// assert.equal(this.$().text().trim(), '');
assert.ok(stub.calledOnce, 'newMap was called once');
- network tab should no longer show "arcgisonline.com" requests
Once the map has loaded, and whenever map component's items are updated:
- clear map graphics
- loop through items, and for each
- create a
new Graphic()
from the item - add the graphic to the map
2 sets of async state: Application (Ember) and map:
- each has own lifecyle (event)
- up to developer to keep 2 sets of state in sync.
Converting item to a Graphic:
- get
geometry
by converting itemextent
from coordinate array to extent JSON - get
attributes
from itemtitle
andsnippet
- get
infoTemplate
andsymbol
from config
- stop app (
cmd+C
) - in config/environment.js add this to
APP
:
map: {
options: {
basemap: 'gray',
smartNavigation: false
},
itemExtents: {
symbol: {
color: [51, 122, 183, 64],
outline: {
color: [51, 122, 183, 255],
width: 1,
type: 'esriSLS',
style: 'esriSLSSolid'
},
type: 'esriSFS',
style: 'esriSFSSolid'
},
infoTemplate: {
title: '${title}',
content: '${snippet}'
}
}
}
-
ember generate util map/coords-to-extent
-
run tests w/
ember test -s
-
in tests/unit/utils/map/coords-to-extent.js replace
test
with:
test('it works', function(assert) {
const coords = [[-53.2316, -79.8433], [180, 79.8433]];
let result = mapCoordsToExtent(coords);
assert.deepEqual(result, {
xmin: -53.2316,
ymin: -79.8433,
xmax: 180,
ymax: 79.8433,
spatialReference:{
wkid:4326
}
});
});
test('it handles invalid coords', function(assert) {
let result = mapCoordsToExtent([]);
assert.equal(result, undefined);
});
- replace app/utils/map/coords-to-extent.js content with:
// expect [[-53.2316, -79.8433], [180, 79.8433]] or []
export default function mapCoordsToExtent (coords) {
if (coords && coords.length === 2) {
return {
xmin: coords[0][0],
ymin: coords[0][1],
xmax: coords[1][0],
ymax: coords[1][1],
spatialReference:{
wkid:4326
}
};
}
}
- stop tests and run
ember s
- in app/map-service/service.js add:
import Graphic from 'esri/graphic';
// NOTE: using Evented mixin to relay map events
export default Ember.Service.extend(Ember.Evented, {
- then to the bottom of
newMap
add:
// and relay the map's load event to caller
const loadHandler = this._map.on('load', () => {
loadHandler.remove();
// not a full-screen map, let user scroll down the page
this._map.disableScrollWheelZoom();
// let the rest of the app know that the map is available
this.trigger('load');
});
- then add this method:
// clear and add graphics to the map
refreshGraphics (jsonGraphics) {
const map = this._map;
if (!map || !map.loaded) {
return;
}
// clear any existing graphics
map.graphics.clear();
// convert json to graphics and add to map's graphic layer
if (!jsonGraphics || jsonGraphics.length === 0) {
return;
}
jsonGraphics.forEach(jsonGraphic => {
map.graphics.add(new Graphic(jsonGraphic));
});
},
- in app/components/extents-map/component.js add these
import
statements
import config from '../../config/environment';
import coordsToExtent from '../../utils/map/coords-to-extent';
- then add this method:
// show new item extents on map
showItemsOnMap () {
const { symbol, infoTemplate } = config.APP.map.itemExtents;
const jsonGraphics = this.get('items').map(item => {
const geometry = coordsToExtent(item.extent);
return { geometry, symbol, attributes: item, infoTemplate };
});
this.get('mapService').refreshGraphics(jsonGraphics);
},
- then update contents of
didInsertElement()
to:
this._super(...arguments);
const mapService = this.get('mapService');
// create a map at this element's DOM node
mapService.newMap(this.elementId, config.APP.map.options);
// show item extents once map loads
mapService.on('load', this, this.showItemsOnMap);
-
in app/items/template.hbs update the
extents-map
invocation to{{extents-map items=model.results}}
-
visit the items route and see the extents on the map
-
but they don't update when you change the query, or page, so
-
back in app/components/extents-map/component.js add this method:
// whenever items change, update the map
didUpdateAttrs () {
this.showItemsOnMap();
},
- see the extents on the map change when you change query/page