11const photosSource = new ol . source . Vector ( ) ;
2+ const clusterSource = new ol . source . Cluster ( {
3+ distance : 30 ,
4+ minDistance : 10 ,
5+ source : photosSource
6+ } ) ;
27
38// Configure map layers: bottom - OpenStreetMap map, top - photo thumbnails
49const layerOSM = new ol . layer . Tile ( {
510 source : new ol . source . OSM ( )
611} ) ;
7- const layerThumbs = new ol . layer . Vector ( {
8- source : photosSource ,
9- style : thumbStyle ,
12+ const layerClusters = new ol . layer . Vector ( {
13+ source : clusterSource ,
14+ style : clusterStyle ,
1015 updateWhileAnimating : true ,
1116 updateWhileInteracting : true ,
1217} ) ;
1318const map = new ol . Map ( {
1419 target : 'map' ,
15- layers : [ layerOSM , layerThumbs ] ,
20+ layers : [ layerOSM , layerClusters ] ,
1621 view : new ol . View ( {
1722 center : ol . proj . transform ( [ 20 , 47 ] , 'EPSG:4326' , 'EPSG:3857' ) ,
18- zoom : 4
23+ zoom : 4 ,
24+ maxZoom : 20
1925 } )
2026} ) ;
2127
22- // Configure thumbnail selector
23- const thumbSelector = new ol . interaction . Select ( {
24- layers : [ layerThumbs ] ,
25- style : selectedStyle
26- } ) ;
27- map . addInteraction ( thumbSelector ) ;
28-
29- const selectedFeatures = thumbSelector . getFeatures ( ) ;
30- selectedFeatures . on ( 'add' , event => {
31- const feature = event . target . item ( 0 ) ;
32- const details = photoDetails ( feature ) ;
33- document . getElementById ( 'photo-details' ) . innerHTML = details ;
34- } ) ;
35- selectedFeatures . on ( 'remove' , ( ) => {
36- document . getElementById ( 'photo-details' ) . innerHTML = '' ;
28+ map . on ( 'click' , event => {
29+ layerClusters . getFeatures ( event . pixel ) . then ( clickedFeatures => {
30+ if ( ! clickedFeatures . length ) return ;
31+ const features = clickedFeatures [ 0 ] . get ( 'features' ) ;
32+ // Show photo details
33+ const details = features . map ( f => photoDetails ( f ) ) ;
34+ document . getElementById ( 'photo-details' ) . innerHTML = details . join ( ) ;
35+ } ) ;
3736} ) ;
3837
3938const handleMapDataLoaded = items => {
@@ -55,6 +54,15 @@ handleMapDataLoaded([{
5554 "make" : "Sony Ericsson" ,
5655 "model" : "MK16i" ,
5756 "date" : "2017-06-02 19:30:08"
57+ } , {
58+ "name" : "dsc03425_1211.jpg" ,
59+ "path" : "https://annimon.com/albums/files/dsc03425_1211.jpg" ,
60+ "preview" : "https://annimon.com/albums/screens/dsc03425_1211.jpg.250.png" ,
61+ "lat" : 47.8 ,
62+ "lon" : 37.27 ,
63+ "make" : "Sony Ericsson" ,
64+ "model" : "C510i" ,
65+ "date" : "2011-06-03 16:55:23"
5866} ] ) ;
5967
6068// -- photo details --
@@ -71,6 +79,27 @@ function photoDetails(feature) {
7179// -- icon styles --
7280const cache = { } ;
7381
82+ function clusterStyle ( feature , resolution ) {
83+ const features = feature . get ( 'features' ) ;
84+ const size = features . length ;
85+ const key = `cl-${ size } ` ;
86+ if ( ! cache [ key ] ) {
87+ cache [ key ] = new ol . style . Style ( {
88+ zIndex : 110 ,
89+ image : new ol . style . Circle ( {
90+ radius : 12 ,
91+ stroke : new ol . style . Stroke ( { color : '#8AFFD9' } ) ,
92+ fill : new ol . style . Fill ( { color : '#229D75' } )
93+ } ) ,
94+ text : new ol . style . Text ( {
95+ text : `${ size } ` ,
96+ fill : new ol . style . Fill ( { color : '#fff' } )
97+ } ) ,
98+ } ) ;
99+ }
100+ return cache [ key ] ;
101+ }
102+
74103function photoStyle ( feature , scale ) {
75104 const url = feature . get ( 'url' ) ;
76105 const key = `${ scale } ${ url } ` ;
@@ -86,10 +115,6 @@ function thumbStyle(feature, resolution) {
86115 return [ photoStyle ( feature , clamp ( 0.2 , 0.1 / resolution , 1 ) ) ] ;
87116}
88117
89- function selectedStyle ( feature , resolution ) {
90- return [ photoStyle ( feature , clamp ( 0.4 , 0.14 / resolution , 1.2 ) ) ] ;
91- }
92-
93118function clamp ( min , value , max ) {
94119 if ( value < min ) return min ;
95120 if ( value > max ) return max ;
0 commit comments