1
- // mapid is the id of the div where the map will appear
2
- var map = L
3
- . map ( 'mapid' )
4
- . setView ( [ 40.730610 , - 73.935242 ] , 11 ) ; // center position + zoom
5
-
6
- // Add background to map (many diff options: https://leaflet-extras.github.io/leaflet-providers/preview/)
7
- L . tileLayer (
8
- 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png' , {
9
- attribution : '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>' ,
10
- subdomains : 'abcd' ,
11
- maxZoom : 19
12
- } ) . addTo ( map ) ;
13
-
14
- // Add a svg layer to the map
15
- L . svg ( ) . addTo ( map ) ;
16
-
17
- // Create color palettes
18
- var violation = {
19
- true : "red" ,
20
- false : "green"
21
- }
1
+ makeMap ( ) ;
22
2
23
- // Plot map
24
- d3 . json ( "hs-severity.json" , function ( data ) {
25
-
26
- d3 . select ( "#mapid" )
27
- . select ( "svg" )
28
- . selectAll ( "myCircle" )
29
- . data ( data )
30
- . enter ( )
31
- . append ( "circle" )
32
- . attr ( "cx" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . x } )
33
- . attr ( "cy" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . y } )
34
- . attr ( "r" , function ( d ) {
35
- if ( d . s == 0 ) {
36
- return ( d . s / 3 ) + 5 ;
37
- }
38
- else {
39
- return ( d . s ** ( 1 / 3 ) ) * 4 ;
40
- }
41
- } ) // change this to correlate with severity
42
- . style ( "fill" , function ( d ) {
43
- return violation [ d . v ] ;
44
- } )
45
- . attr ( "stroke" , false )
46
- . attr ( "fill-opacity" , .8 )
47
-
48
- // Function that update circle position if something change
49
- function update ( ) {
50
- d3 . selectAll ( "circle" )
51
- . attr ( "cx" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . x } )
52
- . attr ( "cy" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . y } )
3
+ function makeMap ( ) {
4
+ // mapid is the id of the div where the map will appear
5
+ var map = L
6
+ . map ( 'mapid' )
7
+ . setView ( [ 40.730610 , - 73.935242 ] , 11 ) ; // center position + zoom
8
+
9
+ // Add background to map (many diff options: https://leaflet-extras.github.io/leaflet-providers/preview/)
10
+ L . tileLayer (
11
+ 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png' , {
12
+ attribution : '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>' ,
13
+ subdomains : 'abcd' ,
14
+ maxZoom : 19
15
+ } ) . addTo ( map ) ;
16
+
17
+ // Add a svg layer to the map
18
+ L . svg ( ) . addTo ( map ) ;
19
+
20
+ // Create color palettes
21
+ var violation = {
22
+ true : "red" ,
23
+ false : "green"
53
24
}
54
25
55
- //add brush to timeline, hook to callback
56
- var brush = d3 . svg . brush ( )
57
- . x ( x ) ;
58
- . on ( "brush" , function ( ) { brushCallback ( brush , data ) ; } )
59
- . extent ( [ new Date ( "7/1/2014" ) , new Date ( "8/1/2014" ) ] ) ; // initial value
26
+ // Plot map + parse data
27
+ d3 . json ( "hs-severity.json" , function ( data ) {
28
+
29
+ d3 . select ( "#mapid" )
30
+ . select ( "svg" )
31
+ . selectAll ( "myCircle" )
32
+ . data ( data )
33
+ . enter ( )
34
+ . append ( "circle" )
35
+ . attr ( "cx" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . x } )
36
+ . attr ( "cy" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . y } )
37
+ . attr ( "r" , function ( d ) {
38
+ if ( d . s == 0 ) {
39
+ return ( d . s / 3 ) + 5 ;
40
+ }
41
+ else {
42
+ return ( d . s ** ( 1 / 3 ) ) * 4 ;
43
+ }
44
+ } ) // change this to correlate with severity
45
+ . style ( "fill" , function ( d ) {
46
+ return violation [ d . v ] ;
47
+ } )
48
+ . attr ( "stroke" , false )
49
+ . attr ( "fill-opacity" , .8 )
50
+
51
+
52
+ // data parsing
53
+ var parseMonthDayYear = d3 . timeFormat ( "%d-%b" ) ; // d3.utcParse() // fix this
54
+
55
+ var dataForTimeline = [ ] ,
56
+ dateToCrimeCount = { } ;
60
57
61
- slider . append ( "g" )
58
+ data . forEach ( function ( d , idx ) {
59
+
60
+ d . a = parseMonthDayYear ( new Date ( d . a ) ) ;
61
+ // d.created_at = parseMonthDayYear(d.created_at);
62
+ if ( ! dateToCrimeCount [ d . a ] ) {
63
+ var dataCount = [ d . t , 1 ] ;
64
+ dateToCrimeCount [ d . a ] = dataCount ;
65
+ }
66
+ dateToCrimeCount [ d . a ] [ 0 ] += d . t ;
67
+ dateToCrimeCount [ d . a ] [ 1 ] += 1 ;
68
+
69
+ } ) ;
70
+
71
+ Object . keys ( dateToCrimeCount ) . forEach ( function ( time ) {
72
+ dateToCrimeCount [ time ] = dateToCrimeCount [ time ] [ 0 ] / dateToCrimeCount [ time ] [ 1 ] ;
73
+ dataForTimeline . push ( { TIME : new Date ( time ) , TEMP : dateToCrimeCount [ time ] } ) ;
74
+ } ) ;
75
+ dataForTimeline . sort ( function ( a , b ) { return a . TIME - b . TIME ; } ) ;
76
+
77
+ makeTimeline ( data , dataForTimeline ) ;
78
+ //makeLegend();
79
+
80
+ } )
81
+
82
+ // If the user change the map (zoom or drag), update circle position:
83
+ map . on ( "moveend" , update )
84
+
85
+ }
86
+
87
+ // Creates the event timeline and sets up callbacks for brush changes
88
+ function makeTimeline ( dataForMap , dataForTimeline ) {
89
+
90
+ var margin = { top : 10 , right : 10 , bottom : 20 , left : 25 } ,
91
+ width = 600 - margin . left - margin . right ,
92
+ height = 80 - margin . top - margin . bottom ;
93
+
94
+ var timelineSvg = d3 . select ( "#timeline-container" ) . append ( "svg" )
95
+ . attr ( "width" , width + margin . left + margin . right )
96
+ . attr ( "height" , height + margin . top + margin . bottom ) ;
97
+
98
+ var timeline = timelineSvg . append ( "g" )
99
+ . attr ( "class" , "timeline" )
100
+ . attr ( "transform" , "translate(" + margin . left + "," + margin . top + ")" ) ;
101
+
102
+ var x = d3 . scaleTime ( )
103
+ . domain ( d3 . extent ( dataForTimeline . map ( function ( d ) { return d . TIME ; } ) ) )
104
+ . range ( [ 0 , width ] ) ;
105
+
106
+ var y = d3 . scaleLinear ( )
107
+ . domain ( d3 . extent ( dataForTimeline . map ( function ( d ) { return d . TEMP ; } ) ) )
108
+ . range ( [ height , 0 ] ) ;
109
+
110
+ var xAxis = d3 . axisBottom ( )
111
+ . scale ( x ) ;
112
+
113
+ var yAxis = d3 . axisLeft ( )
114
+ . scale ( y ) ;
115
+
116
+ var area = d3 . area ( )
117
+ . x ( function ( d ) { return x ( d . TIME ) ; } )
118
+ . y0 ( height )
119
+ . y1 ( function ( d ) { return y ( d . TEMP ) ; } ) ;
120
+
121
+ timeline . append ( "path" )
122
+ . datum ( dataForTimeline )
123
+ . attr ( "class" , "area" )
124
+ . attr ( "d" , area ) ;
125
+
126
+ timeline . append ( "g" )
127
+ . attr ( "class" , "x axis" )
128
+ . attr ( "transform" , "translate(0," + height + ")" )
129
+ . call ( xAxis ) ;
130
+
131
+ timeline . append ( "g" )
132
+ . attr ( "class" , "y axis" )
133
+ . call ( yAxis ) ;
134
+
135
+ timeline . append ( "text" )
136
+ . attr ( "transform" , "rotate(-90)" )
137
+ . attr ( "dy" , "1em" )
138
+ . style ( "text-anchor" , "end" )
139
+ . text ( "Temperature" ) ;
140
+
141
+ // Add brush to timeline, hook up to callback
142
+ var brush = d3 . brushX ( )
143
+ . on ( "brush" , function ( ) { brushCallback ( brush , dataForMap ) ; } ) ;
144
+
145
+ timeline . append ( "g" )
62
146
. attr ( "class" , "x brush" )
63
147
. call ( brush )
64
- . selectAll ( "rect" )
65
- . attr ( "y" , "-10" )
66
- . attr ( "height" , height + 10 ) ;
67
-
68
- brush . event ( slider . select ( 'g,x.brush' ) ) ; //dispatches a single brush event
69
-
70
- } ) ;
71
-
72
- // Called whenever the timeline brush range (extent) is updated
73
- // Filters the map data to those points that fall within the selected timeline range
74
- function brushCallback ( d3 . slider ( ) . brush , data ) {
75
- if ( brush . empty ( ) ) {
76
- update ( [ ] ) ;
77
- } else {
78
- var newDateRange = brush . extent ( ) ,
79
- filteredData = [ ] ;
80
-
81
- data . forEach ( function ( d ) {
82
- if ( d . TIME >= newDateRange [ 0 ] && d . TIME <= newDateRange [ 1 ] ) {
83
- filteredData . push ( d ) ;
84
- }
85
- } ) ;
86
- update ( filteredData ) ;
87
- }
148
+ . selectAll ( "rect" )
149
+ . append ( "rect" )
150
+ . attr ( "y" , - 6 )
151
+ . attr ( "height" , height + 7 ) ;
152
+
153
+ //console.log(d3.)
154
+ //brush.event(timeline.select('g.x.brush')); // dispatches a single brush event
88
155
}
89
156
90
- // If the user change the map (zoom or drag), update circle position:
91
- map . on ( "moveend" , update )
92
- } )
157
+ // this part isn't working
158
+ function brushCallback ( brush , dataForMap ) {
159
+ if ( d3 . event . selection == null ) {
160
+ updateMapPoints ( [ ] ) ;
161
+ } else {
162
+ var newDateRange = brush . extent ( ) ,
163
+ filteredData = [ ] ;
164
+
165
+ dataForMap . forEach ( function ( d ) {
166
+ if ( d . TIME >= newDateRange [ 0 ] && d . TIME <= newDateRange [ 1 ] ) {
167
+ filteredData . push ( d ) ;
168
+ }
169
+ } ) ;
170
+ updateMapPoints ( filteredData ) ;
171
+ console . log ( filteredData ) ;
172
+ }
173
+ }
174
+
175
+ // Updates the points displayed on the map, to those in the passed data array
176
+ function updateMapPoints ( data ) {
177
+ /*
178
+ var circles = mapSvg.selectAll("circle").data(data, function(d) { return d.TIME + d.TOT; });
179
+
180
+ circles // update existing points
181
+ .on("mouseover", tipMouseover)
182
+ .on("mouseout", tipMouseout)
183
+ .attr("fill", function(d) { return colorScale(d.CR); })
184
+ .attr("cx", function(d) { return projection([+d.longitude, +d.latitude])[0]; })
185
+ .attr("cy", function(d) { return projection([+d.longitude, +d.latitude])[1]; })
186
+ .attr("r", function(d) { return radiusScale(+d.TOT); });
187
+
188
+ circles.enter().append("circle") // new entering points
189
+ .on("mouseover", tipMouseover)
190
+ .on("mouseout", tipMouseout)
191
+ .attr("fill", function(d) { return colorScale(d.CR); })
192
+ .attr("cx", function(d) { return projection([+d.longitude, +d.latitude])[0]; })
193
+ .attr("cy", function(d) { return projection([+d.longitude, +d.latitude])[1]; })
194
+ .attr("r", 0)
195
+ .transition()
196
+ .duration(500)
197
+ .attr("r", function(d) { return radiusScale(+d.TOT); });
198
+
199
+ circles.exit() // exiting points
200
+ .attr("r", function(d) { return radiusScale(+d.TOT); })
201
+ .transition()
202
+ .duration(500)
203
+ .attr("r", 0).remove();
204
+ */
205
+ } ;
206
+
207
+ function update ( ) {
208
+ d3 . selectAll ( "circle" )
209
+ . attr ( "cx" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . x } )
210
+ . attr ( "cy" , function ( d ) { return map . latLngToLayerPoint ( [ d . la , d . lo ] ) . y } )
211
+ } ;
0 commit comments