-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript.js
284 lines (268 loc) · 8.17 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
// variables prefixed with $ are global
// all others are local to their functions, or should be
// abreviated document elements that may be used a lot
var $m; // (currently empty) map object
// A -> B lat,lon points
var $A = [];
var $B = [];
// source for OD points layer
var $ODsource = new ol.source.Vector();
// source for interactive drawing layer
var $scratchSource = new ol.source.Vector();
var $load_time; // moment the map has been revealed
var $start_time; // moment finger touches the screen
var $end_time; // moment finger leaves the screen
var $od_id; // ID of OD pair presented
var $session_id = Math.random(); // ID of the user's session
// array of OD IDs that have already been returned
// initialized at non-existent value
var $completedODs = [-1];
// START button has been pressed. Do all the stuff!
function start(){
makeFullScreen();
// hide the button
var button = document.getElementById('startbutton');
button.parentNode.removeChild(button);
// DO THE MAP
// make a map with all the stuff except the stuff that changes per OD
var variableLayer = new ol.layer.VectorTile({
source: $variableTileSource,
style: $variableStyleFunction
});
// make a map with all the stuff except the stuff that changes per OD
var baseLayer = new ol.layer.VectorTile({
source: $baseTileSource,
style: $baseStyleFunction
});
$m = new ol.Map({
target:'map',
controls:[],
layers:[baseLayer,variableLayer]
});
// place for storing scribbles
var scratchLayer = new ol.layer.Vector({
source: $scratchSource
});
$m.addLayer(scratchLayer);
// add A->B features to a layer so they can be included in the map
var markers = new ol.layer.Vector({ source:$ODsource });
$m.addLayer(markers);
// create the DRAW interaction object
var draw = new ol.interaction.Draw({
source: $scratchSource,
type: 'LineString',
freehand: true
});
// add the interaction to the map
$m.addInteraction(draw);
// listen for the start of a draw motion and note the time
draw.on('drawstart',function(event){
var date = new Date();
$start_time = date.getTime();
});
// listen for the end of a draw motion
draw.on('drawend',drawend);
// call for a new OD initialization
newOD();
}
// function called at the end of a drawing event
function drawend(event){
// note the time
var date = new Date();
$end_time = date.getTime();
// get a copy of the feature geometry in two projections
var geom3857 = event.feature.getGeometry().clone();
var geom4326 = event.feature.getGeometry().clone();
geom4326.transform('EPSG:3857','EPSG:4326');
// if the line is too complex, simplify it
if(geom4326.getCoordinates().length < 30){ // is simple
mapMatch(geom4326.getCoordinates());
}else{ // is complex
// simplify in locally undistorted mercator projection
var simple = geom3857.simplify( $simplificationDistance );
// back to latlon and mapmatch
simple.transform('EPSG:3857','EPSG:4326');
mapMatch(simple.getCoordinates());
}
// send results to the DB
storeResults( geom4326.getCoordinates() );
// erase the blackboard
$scratchSource.clear();
// set a new opacity value at random for the next rendering
$opacity = $min_opacity + (Math.random()*(1-$min_opacity));
console.log('min opacity to use:'+$opacity)
}
// request a new random OD pair from the server
// store it in the global variables
// load it into the map when ready
function newOD(){
hideMap();
// request points
var r = new XMLHttpRequest();
var URL = $randomPointsURL+'?completedODs='+$completedODs;
r.open('get',URL,true);
r.onreadystatechange = function(){
if(r.readyState == 4){ // finished
if(r.status == 200){ // got good response
var data = JSON.parse(r.responseText);
// make sure we do acually have a result
if(data.id == null){
alert("You're done! Thanks for your time!");
return;
}
// store globally
$A = [data.lon1,data.lat1];
$B = [data.lon2,data.lat2];
$od_id = data.id;
$completedODs.push($od_id);
// define features
var A = new ol.Feature({geometry: new ol.geom.Point(ol.proj.fromLonLat($A))});
var B = new ol.Feature({geometry: new ol.geom.Point(ol.proj.fromLonLat($B))});
A.setStyle(Acon);
B.setStyle(Bcon);
// clear old features from the layer
$ODsource.clear();
// add the new/replacement features
$ODsource.addFeatures([A,B]);
// fit the screen to the new ODs
var view = new ol.View();
view.fit( $ODsource.getExtent(), {size: $m.getSize()} );
// zoom out a little to give a little extra space
view.setZoom( view.getZoom()-0.5 );
$tiles_requested = $tiles_loaded = 0;
$m.setView(view);
// give the map 4 seconds to load and render, then show it
setTimeout(showMap,4000);
}
}
}
r.send();
}
// hide the map from view
function hideMap(){
var map = document.getElementById('map');
map.setAttribute('style','visibility:hidden');
}
// return the map to view
function showMap(){
var map = document.getElementById('map');
map.setAttribute('style','');
var date = new Date();
$load_time = date.getTime();
}
// transform a string of lon-lat coords to WKT LINESTRING
function coordsToWKT(coordinates){
var c = coordinates;
var nc = [];
for(i=0;i<c.length;i++){
nc.push(c[i][0]+' '+c[i][1]);
}
var WKT = 'LINESTRING('+nc.join(',')+')';
return WKT;
}
// send data to be stored on the server database
function storeResults(coords){
var r = new XMLHttpRequest();
// format parameters
var params = 'od_id='+$od_id;
params += '&session_id='+$session_id;
params += '&load_time='+$load_time;
params += '&start_time='+$start_time;
params += '&end_time='+$end_time;
params += '&zoom_level='+$m.getView().getZoom();
params += '&trace='+coordsToWKT(coords);
params += '&map_extent='+extentWKT();
params += '&min_opacity='+$opacity;
r.open('POST',$storePHPURL,true);
// set headers
r.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
//r.setRequestHeader("Content-length", params.length);
//r.setRequestHeader("Connection", "close");
// and send
r.send(params);
}
// get current extent as a WKT LINESTRING in 4326
function extentWKT(){
// get the extent object
var e = $m.getView().calculateExtent( $m.getSize() );
// project to 4326
e = coords2latlon([ [ e[0],e[1] ], [ e[2],e[3] ] ]);
// format as WKT
return 'LINESTRING('+e[0][0]+' '+e[0][1]+','+e[1][0]+' '+e[1][1]+')';
}
// project linestring to EPSG:4326 [lon,lat]
function coords2latlon(coords){
var newcoords = [];
for(i=0;i<coords.length;i++){
newcoords.push(
ol.proj.toLonLat(coords[i])
);
}
return newcoords;
}
// send the coordinates to be matched on the cloud
function mapMatch(coords){
var radius = fingerRadius();
// make list into pairs of coordinate strings
var c = [];
var radii = [];
for(i=0;i<coords.length;i++){
c.push(coords[i][0]+','+coords[i][1]);
radii.push(radius);
}
var r = new XMLHttpRequest();
URL = $OSRMserver + '/match/v1/transit/';
URL += c.join(';');
URL += '?geometries=geojson&overview=full';
URL += '&radiuses='+radii.join(';');
r.open('get',URL,true);
r.onreadystatechange = function(){
if(r.readyState == 4){ // finished
if(r.status == 200){ // got good response
var data = JSON.parse(r.responseText);
var match1 = data.matchings[0];
// render match geometry
var format = new ol.format.GeoJSON();
var feature = format.readFeatures(
match1.geometry,
{
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857'
}
)[0];
feature.setStyle(
new ol.style.Style({
stroke: new ol.style.Stroke({
width:5,
color:'#ff0000'
})
})
);
$scratchSource.addFeature(feature);
// prepare a new map after the match has
// been shown for a few seconds
setTimeout(newOD,3000);
}
}
}
r.send();
}
// returns the rough radius of a fingertip
// in meters based on the current map scale
function fingerRadius(){
// TODO finish this function
return 50;
}
function makeFullScreen(){
var de = document.documentElement;
// make the page full screen (lots of campatibility BS)
if(de.requestFullscreen) {
de.requestFullscreen();
} else if(de.mozRequestFullScreen) {
de.mozRequestFullScreen();
} else if(de.webkitRequestFullscreen) {
de.webkitRequestFullscreen();
} else if(de.msRequestFullscreen) {
de.msRequestFullscreen();
}
}