Skip to content

Commit

Permalink
initial commit. all tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
Petr Kosikhin committed Mar 24, 2016
1 parent 4a99905 commit e5a7a2f
Show file tree
Hide file tree
Showing 12 changed files with 389 additions and 10 deletions.
99 changes: 95 additions & 4 deletions README.md
@@ -1,12 +1,103 @@
# Ember-leaflet-layer-control

This README outlines the details of collaborating on this Ember addon.
Provides Interface for Layer Control functionality for [Ember-Leaflet](http://ember-leaflet.com), an Ember Addon for [Leaflet](http://leafletjs.com) interactive maps.

This plugin utilizes Leaflet [Layer Groups](http://leafletjs.com/reference.html#layergroup) to create overlay layers in the Leaflet [Layer Control](http://leafletjs.com/reference.html#control-layers) and also enables to identify Leaflet [Tile Layers](http://leafletjs.com/reference.html#tilelayer) as baselayers in Layer Control.

## Installation

* `git clone` this repository
* `npm install`
* `bower install`
* `ember install ember-leaflet-layer-control`

## Using the plugin

The following example summarizes the usage of the plugin by simple example:

template.hbs
```handlebars
{{#leaflet-map lat=lat lng=lng zoom=zoom}}
{{#layer-group name="tilelayer#1" baselayer=true default=true}}
{{tile-layer url="http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"}}
{{/layer-group}}
{{#layer-group name="tilelayer#2" baselayer=true}}
{{google-tile-layer type="SATELLITE" opacity=0.9}}
{{/layer-group}}
{{#layer-group name="markerLayer#1" default=true}}
{{#each markers as |marker|}}
{{#marker-layer location=marker.location}}
<h3>{{marker.title}}</h3>
{{marker.description}}
{{/marker-layer}}
{{/each}}
{{/layer-group}}
{{#layer-group name="polylineLayer#1"}}
{{#each polylines as |polyline|}}
{{#polyline-layer locations=polyline.locations}}
<h3>{{polyline.title}}</h3>
{{polyline.description}}
{{/polyline-layer}}
{{/each}}
{{/layer-group}}
{{layer-control handler=(action "layerControlEvent")}}
{{/leaflet-map}}
```

component.js
```javascript
import Ember from 'ember';

export default Ember.Component.extend({
lat: 53.318602,
lng: 48.586415,
zoom: 15,
markers: [
{
title:"marker1",
description:"this is marker1",
location: L.LatLng(53.318602,48.586415)
}
],
polylines:[
// some polyline data here.
],
actions: {
layerControlEvent(event){

}
}
});

```

####Baselayers
Creating such component would result in a leaflet map with layer-control element. On load the tile layer `tilelayer#1` is selected in layer control and enabled on the map. Both `tilelayer#1` and `tilelayer#2` are shown in layer control as radio buttons. This happens as they both have `baselayer=true` so they are identified as baselayers. There must be just one baselayer per each `{{#layer-group}}{{/layer-group}}` block. The names of layers can be set by setting the `name` attribute on the block. This names currently only are valid during initialization and are not bound. to the values in leaflet layer control. You can use baselayer control to enable seamless support of [Google tile layers](https://github.com/miguelcobain/ember-leaflet-google-tile-layer) implemented as other ember-leaflet plugin.

####Layergroups
Layer groups with names `markerLayer#1` and `polylineLayer#1` are real leaflet Layer Groups and can hold as much different leaflet elements as needed and they can be also of different types togather in one group. The component identifies them as native Leaflet Layer groups as the `baselayer=true` is NOT set on them. Their `name` attribute also propagates to layer control on init and they are displayed as checkboxes there. The `{{#layer-group default=true}}{{/layer-group}}` would enable the layer group on the map during init as oposed to excluding the argument or providing `false` value in which case the layer group would be disabled on init.

####Layer-control
This component is only available as blockless version. It is important that this component is placed inside the `{{#leaflet-map}}{{/leaflet-map}}` and it should come last, after all `{{#layer-group}}{{/layer-group}}` declarations.

####Handling events
You can set the action on the `layer-control` component like in the example: `{{layer-control handler=(action "layerControlEvent")}}`. Then this action would be fired on any change in Leaflet control (if we change the baselayer or tick layer group on or off). The handler would recieve the Leaflet object of the following form:
```
{
layer: ##the layer which was triggered##,
name: ##layer name as set on layer group##,
overlay: ##true/false##,
target: ##Leaflet map object##,
type: ##"overlayadd"/"overlayremove"/"baselayerchange"##
}
```
The important parts here would be `type` which corresponds for event type:
`overlayadd` - stands for overlay layer has been ticked to the on position
`overlayremove` - stands for overlay layer has been ticked to the off position
`baselayerchange` - stands for the tile layer (baselayer) change

## Running

Expand Down
49 changes: 49 additions & 0 deletions addon/components/layer-control.js
@@ -0,0 +1,49 @@
import Ember from 'ember';
import BaseLayer from 'ember-leaflet/components/base-layer';

const {get,isEmpty,isBlank,isEqual} = Ember;

export default BaseLayer.extend({
layerSetup() {
this._layer = this.createLayer();
this._addObservers();
this._addEventListeners();
if (get(this,'containerLayer')) {
this._layer.addTo(get(this,'containerLayer')._layer);
}
this.didCreateLayer();
},
createLayer(){
return L.control.layers();
},
didCreateLayer(){
let layerGroups = get(this,'containerLayer._layerGroups');
if (!isBlank(layerGroups)){
layerGroups.forEach(layerGroup=>{
if (layerGroup.default){
let containerLayer = get(this,'containerLayer._layer');
layerGroup.layer.addTo(containerLayer);
}
this._layer.addOverlay(layerGroup.layer,layerGroup.name);
});
}
let baseLayers = get(this,'containerLayer._baseLayers');
if (!isBlank(baseLayers)){
baseLayers.forEach(baseLayer=>{
if (baseLayer.default){
let containerLayer = get(this,'containerLayer._layer');
baseLayer.layer.addTo(containerLayer);
}
this._layer.addBaseLayer(baseLayer.layer,baseLayer.name);
});
}

let handler = get(this,'handler') || null;
if (!isEmpty(handler)){
let map = get(this,'containerLayer')._layer;
map.on('overlayadd', this.attrs.handler);
map.on('overlayremove', this.attrs.handler);
map.on('baselayerchange', this.attrs.handler);
}
}
});
77 changes: 77 additions & 0 deletions addon/components/layer-group.js
@@ -0,0 +1,77 @@
import Ember from 'ember';
import BaseLayer from 'ember-leaflet/components/base-layer';
import ContainerMixin from 'ember-leaflet/mixins/container';

const {get, getProperties, isEmpty, set, isNone} = Ember;

export default BaseLayer.extend(ContainerMixin,{
baselayer: false,
blockLayer: false,
default: false,
createLayer(){
return this.L.layerGroup();
},
didInsertElement() {
this._super(...arguments);
this.layerSetup();
this.get('_childLayers').invoke('layerSetup');
this.registerNameOnParent();
},
registerNameOnParent(){
let name = get(this,'name');
let container = this.get('containerLayer');
let defaultState = get(this,'default');
if (!get(this,'baselayer')){
let layerGroups = get(container,'_layerGroups');
if (isEmpty(layerGroups)){
layerGroups = Ember.A();
set(container,'_layerGroups',layerGroups);
}
layerGroups.addObject({
name:name,
layer:get(this,'_layer'),
default: defaultState
});
} else {
let baseLayers = get(container,'_baseLayers');
if (isEmpty(baseLayers)){
baseLayers = Ember.A();
set(container,'_baseLayers',baseLayers);
}
baseLayers.addObject({
name:name,
layer:get(this,'_layer._layer'),
default: defaultState
});
}
},
willDestroyLayer() {
this.get('_childLayers').invoke('layerTeardown');
this.get('_childLayers').clear();
},
layerSetup() {
if (isNone(get(this,'_layer'))) {
if (!get(this,'baselayer')){
set(this,'blockLayer',true);
this._layer = this.createLayer();
this.didCreateLayer();
if (get(this,'containerLayer')) {
if (!isNone(get(this,'containerLayer')._layer)) {
get(this,'containerLayer')._layer.addLayer(this._layer);
}
}
} else {
this._layer = {
_layer: null,
addLayer(layer){
this._layer = layer;
},
removeLayer(){
this._layer = null;
}
};
}
}

}
});
1 change: 1 addition & 0 deletions addon/templates/components/layer-control.hbs
@@ -0,0 +1 @@
{{yield}}
3 changes: 3 additions & 0 deletions addon/templates/components/layer-group.hbs
@@ -0,0 +1,3 @@
{{#if blockLayer}}
{{yield}}
{{/if}}
1 change: 1 addition & 0 deletions app/components/layer-control.js
@@ -0,0 +1 @@
export { default } from 'ember-leaflet-layer-control/components/layer-control';
1 change: 1 addition & 0 deletions app/components/layer-group.js
@@ -0,0 +1 @@
export { default } from 'ember-leaflet-layer-control/components/layer-group';
3 changes: 2 additions & 1 deletion bower.json
Expand Up @@ -4,6 +4,7 @@
"ember": "~2.4.1",
"ember-cli-shims": "0.1.0",
"ember-cli-test-loader": "0.2.2",
"ember-qunit-notifications": "0.1.0"
"ember-qunit-notifications": "0.1.0",
"leaflet": "~0.7.7"
}
}
16 changes: 11 additions & 5 deletions package.json
@@ -1,7 +1,7 @@
{
"name": "ember-leaflet-layer-control",
"version": "0.0.0",
"description": "The default blueprint for ember-cli addons.",
"version": "0.0.1",
"description": "Addon for Ember-Leaflet which adds Layer Control interface",
"directories": {
"doc": "doc",
"test": "tests"
Expand Down Expand Up @@ -37,13 +37,19 @@
"ember-load-initializers": "^0.5.0",
"ember-resolver": "^2.0.3",
"ember-try": "^0.1.2",
"loader.js": "^4.0.0"
"loader.js": "^4.0.0",
"ember-leaflet": "2.2.0"
},
"keywords": [
"ember-addon"
"ember-addon",
"ember-leaflet",
"ember-leaflet-layer-control",
"ember",
"leaflet"
],
"dependencies": {
"ember-cli-babel": "^5.1.5"
"ember-cli-babel": "^5.1.5",
"ember-cli-htmlbars": "^1.0.1"
},
"ember-addon": {
"configPath": "tests/dummy/config"
Expand Down
9 changes: 9 additions & 0 deletions tests/helpers/locations.js
@@ -0,0 +1,9 @@
/* global L */
export default {
nyc: L.latLng(40.713282, -74.006978),
sf: L.latLng(37.77493, -122.419415),
chicago: L.latLng(41.878114, -87.629798),
paris: L.latLng(48.856614, 2.352222),
london: L.latLng(51.511214, -0.119824),
newdelhi: L.latLng(28.635308, 77.22496)
};
56 changes: 56 additions & 0 deletions tests/integration/components/layer-control-test.js
@@ -0,0 +1,56 @@
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import LayerControlComponent from 'ember-leaflet-layer-control/components/layer-control';
import locations from '../../helpers/locations';
import Ember from 'ember';
const {get} = Ember;
/* global L */

//Needed to silence leaflet autodetection error
L.Icon.Default.imagePath = 'some-path';

let layerControl;

moduleForComponent('layer-control', 'Integration | Component | layer control', {
integration: true,
beforeEach() {

this.register('component:layer-control', LayerControlComponent.extend({
init() {
this._super(...arguments);
layerControl = this;
}
}));

this.set('center', locations.nyc);
this.set('zoom', 13);
},
afterEach() {
}
});

test('it works as expected', function(assert) {
this.set('locations',locations);
this.set('layerControl',layerControl);
this.set('tileLayerName',"tilelayer#1");
this.set('layerGroupName',"markerLayer#1");
this.render(hbs`
{{#leaflet-map center=center zoom=zoom}}
{{#layer-group name=tileLayerName baselayer=true default=true}}
{{tile-layer url="http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png"}}
{{/layer-group}}
{{#layer-group name=layerGroupName default=true}}
{{marker-layer location=locations.nyc}}
{{/layer-group}}
{{layer-control}}
{{/leaflet-map}}
`);
assert.ok(layerControl._layer._baseLayersList.innerText.indexOf(get(this,'tileLayerName')));
assert.ok(layerControl._layer._overlaysList.innerText.indexOf(get(this,'layerGroupName')));
});

0 comments on commit e5a7a2f

Please sign in to comment.