Skip to content

Commit e80ad69

Browse files
author
André Gaul
committed
move leaflet views from couchmap-example
1 parent b93feaa commit e80ad69

File tree

9 files changed

+310
-0
lines changed

9 files changed

+310
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.*.swp
3+
npm-debug.log

Gruntfile.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = function(grunt) {
2+
grunt.initConfig({
3+
pkg: grunt.file.readJSON('package.json'),
4+
// lint js files
5+
jshint: {
6+
files: ['**/*.js', '!node_modules/**/*.js']
7+
},
8+
// jasmine unit tests
9+
jasmine_node: {
10+
projectRoot: 'test',
11+
specNameMatcher: 'Spec',
12+
forceExit: true
13+
}
14+
});
15+
grunt.loadNpmTasks('grunt-contrib-jshint');
16+
grunt.loadNpmTasks('grunt-jasmine-node');
17+
18+
grunt.registerTask('test', ['jshint', 'jasmine_node']);
19+
// Default task(s).
20+
grunt.registerTask('default', ['test']);
21+
};

package.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "couchmap-backbone-leaflet",
3+
"version": "0.1.0",
4+
"description": "backbone leaflet views for couchmap",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git://github.com/libremap/couchmap-backbone-leaflet.git"
12+
},
13+
"keywords": [
14+
"couchmap",
15+
"couchdb",
16+
"geocouch",
17+
"backbone",
18+
"leaflet"
19+
],
20+
"author": "André Gaul <[email protected]>",
21+
"license": "GPLv3",
22+
"bugs": {
23+
"url": "https://github.com/libremap/couchmap-backbone-leaflet/issues"
24+
},
25+
"dependencies": {
26+
"couchmap-common": "libremap/couchmap-common",
27+
"couchmap-backbone": "libremap/couchmap-backbone",
28+
"underscore": "~1.5.2",
29+
"backbone": "~1.1.0"
30+
},
31+
"devDependencies": {
32+
"grunt": "~0.4.1",
33+
"grunt-contrib-jshint": "~0.6.4",
34+
"grunt-jasmine-node": "~0.1.0"
35+
}
36+
}

test/spec/commonSpec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
var _ = require('underscore');

views/coarse.js

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
var Backbone = require('backbone');
2+
_ = require('underscore');
3+
var L = require('leaflet');
4+
var Lmarkercluster = require('leaflet-markercluster');
5+
var common = require('couchmap-common');
6+
7+
module.exports = Backbone.View.extend({
8+
CoarseMarkerView: require('./coarseMarker'),
9+
initialize: function(options) {
10+
this.mapView = options.mapView;
11+
this.bbox = common.bbox(this.mapView.map.getBounds());
12+
this.zoom = common.validate_zoom(this.mapView.map.getZoom()+1);
13+
this.layer = L.markerClusterGroup(
14+
{
15+
showCoverageOnHover: false,
16+
zoomToBoundsOnClick: false,
17+
maxClusterRadius: 50,
18+
iconCreateFunction: function(cluster) {
19+
var count = 0;
20+
_.each(cluster.getAllChildMarkers(), function(marker) {
21+
count += marker.options.view.model.get('count');
22+
});
23+
return this.iconCreate(count);
24+
}.bind(this)
25+
})
26+
.addTo(this.mapView.map)
27+
.on('click', function(a) {
28+
var model = a.layer.options.view.model;
29+
this.mapView.map.fitBounds([
30+
[model.get('bbox_south'), model.get('bbox_west')],
31+
[model.get('bbox_north'), model.get('bbox_east')]
32+
]);
33+
}.bind(this))
34+
.on('clusterclick', function(a) {
35+
var models = _.map(a.layer.getAllChildMarkers(), function(marker) {
36+
return marker.options.view.model;
37+
});
38+
var west = _.min(_.map(models, function(model) { return model.get('bbox_west'); }));
39+
var east = _.max(_.map(models, function(model) { return model.get('bbox_east'); }));
40+
var south = _.min(_.map(models, function(model) { return model.get('bbox_south'); }));
41+
var north = _.max(_.map(models, function(model) { return model.get('bbox_north'); }));
42+
this.mapView.map.fitBounds([
43+
[south, west],
44+
[north, east]
45+
]);
46+
}.bind(this));
47+
48+
49+
this.markers = {};
50+
51+
this.listenTo(this.mapView, 'bbox', function(bbox, zoom) {
52+
this.bbox = bbox;
53+
if (this.zoom!=zoom) {
54+
this.zoom = zoom;
55+
}
56+
});
57+
this.listenTo(this.collection, 'sync', this.render);
58+
this.listenTo(this.collection, 'add', this.addModel);
59+
this.listenTo(this.collection, 'remove', this.removeModel);
60+
this.render();
61+
},
62+
render: function() {
63+
// add views for the current zoom level
64+
_.each(this.collection.where({zoom: this.zoom}), this.addModel, this);
65+
// remove views for other zoom levels
66+
var remove = this.collection.filter(function(model) {
67+
return model.get('zoom')!=this.zoom;
68+
}, this);
69+
_.each(remove, this.removeModel, this);
70+
},
71+
iconCreate: function(count) {
72+
var size = 'large';
73+
if (count<10) {
74+
size = 'small';
75+
} else if (count<100) {
76+
size = 'medium';
77+
}
78+
return new L.DivIcon({
79+
html: '<div><span>'+count+'</span></div>',
80+
className: 'marker-cluster marker-cluster-'+size,
81+
iconSize: new L.Point(40,40)
82+
});
83+
},
84+
addModel: function(model) {
85+
var id = model.get('id');
86+
if (model.get('zoom')==this.zoom && !this.markers[id]) {
87+
this.markers[id] = new this.CoarseMarkerView({
88+
layer: this.layer,
89+
model: model,
90+
iconCreate: this.iconCreate
91+
});
92+
}
93+
},
94+
removeModel: function(model) {
95+
var id = model.get('id');
96+
if (this.markers[id]) {
97+
this.markers[id].remove();
98+
delete this.markers[id];
99+
}
100+
},
101+
remove: function() {
102+
_.each(this.markers, function(marker, id) {
103+
marker.remove();
104+
});
105+
this.markers = {};
106+
this.mapView.map.removeLayer(this.layer);
107+
}
108+
});

views/coarseMarker.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
var Backbone = require('backbone');
2+
var L = require('leaflet');
3+
4+
module.exports = Backbone.View.extend({
5+
initialize: function(options) {
6+
this.layer = options.layer;
7+
this.iconCreate = options.iconCreate;
8+
this.listenTo(this.model, 'change', this.render);
9+
this.render();
10+
},
11+
render: function() {
12+
this.remove();
13+
var count = this.model.get('count');
14+
this.marker = L.marker([this.model.get('lat'), this.model.get('lon')],{
15+
icon: this.iconCreate(count),
16+
view: this
17+
})
18+
.addTo(this.layer);
19+
this.marker.view = this;
20+
},
21+
remove: function() {
22+
if (this.marker) {
23+
this.layer.removeLayer(this.marker);
24+
}
25+
}
26+
});

views/couchMap.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
var Backbone = require('backbone');
2+
_ = require('underscore');
3+
var L = require('leaflet');
4+
var common = require('couchmap-common');
5+
6+
module.exports = Backbone.View.extend({
7+
initialize: function(options) {
8+
this.CoarseView = options.CoarseView || require('./coarse');
9+
this.FineView = options.FineView || require('./fine');
10+
11+
// create map and add OpenStreetMap tile layer
12+
this.map = L.map(this.el, {center: [10, 0], zoom: 2} );
13+
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
14+
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
15+
}).addTo(this.map);
16+
this.map.on('moveend', this.update_bbox, this);
17+
18+
this.listenTo(this.model, {
19+
'fine': this.render.bind(this, 'fine'),
20+
'coarse': this.render.bind(this, 'coarse')
21+
});
22+
this.update_bbox();
23+
},
24+
update_bbox: function() {
25+
var bbox = common.bbox(this.map.getBounds());
26+
var zoom = common.validate_zoom(this.map.getZoom()+1);
27+
this.trigger('bbox', bbox, zoom);
28+
this.model.update(bbox, zoom);
29+
},
30+
render: function(mode) {
31+
if (this.mode!=mode) {
32+
this.mode = mode;
33+
if (this.subview) {
34+
this.subview.remove();
35+
}
36+
if (this.mode=='coarse') {
37+
this.subview = new this.CoarseView(_.extend(this.coarse_options || {}, {
38+
mapView: this,
39+
collection: this.model.get('coarse_coll')
40+
}));
41+
} else {
42+
this.subview = new this.FineView(_.extend(this.fine_options || {}, {
43+
mapView: this,
44+
collection: this.model.get('fine_coll')
45+
}));
46+
}
47+
}
48+
},
49+
remove: function() {
50+
if (this.subview) {
51+
this.subview.remove();
52+
}
53+
}
54+
});

views/fine.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
var Backbone = require('backbone');
2+
_ = require('underscore');
3+
var L = require('leaflet');
4+
var Lmarkercluster = require('leaflet-markercluster');
5+
6+
module.exports = Backbone.View.extend({
7+
FineMarkerView: require('./fineMarker'),
8+
initialize: function(options) {
9+
this.mapView = options.mapView;
10+
this.layer = L.markerClusterGroup().addTo(this.mapView.map);
11+
this.subviews = {};
12+
this.listenTo(this.collection, 'sync', this.render);
13+
this.listenTo(this.collection, 'add', this.addModel);
14+
this.listenTo(this.collection, 'remove', this.removeModel);
15+
this.render();
16+
},
17+
addModel: function(model) {
18+
this.removeModel(model);
19+
this.subviews[model.id] = new this.FineMarkerView({
20+
layer: this.layer,
21+
model: model
22+
});
23+
},
24+
removeModel: function(model) {
25+
if (this.subviews[model.id]) {
26+
this.subviews[model.id].remove();
27+
delete this.subviews[model.id];
28+
}
29+
},
30+
render: function() {
31+
this.collection.each(this.addModel, this);
32+
},
33+
remove: function() {
34+
_.each(this.subviews, this.removeModel, this);
35+
this.mapView.map.removeLayer(this.layer);
36+
}
37+
});
38+

views/fineMarker.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
var Backbone = require('backbone');
2+
var L = require('leaflet');
3+
4+
module.exports = Backbone.View.extend({
5+
initialize: function(options) {
6+
this.layer = options.layer;
7+
this.listenTo(this.model, 'change', this.render);
8+
this.render();
9+
},
10+
render: function() {
11+
if (this.marker) {
12+
this.remove();
13+
}
14+
this.marker = L.marker([this.model.get('lat'), this.model.get('lon')],{
15+
title: this.model.id
16+
})
17+
.addTo(this.layer);
18+
},
19+
remove: function() {
20+
this.layer.removeLayer(this.marker);
21+
}
22+
});
23+

0 commit comments

Comments
 (0)