response = client.send(request, HttpResponse.BodyHandlers.ofString());
45 |
46 | if (response.statusCode() == 200) {
47 | parseAndPrintResponse(response.body());
48 | } else {
49 | System.out.println("Error: " + response.statusCode());
50 | }
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | }
54 | }
55 |
56 | private static void parseAndPrintResponse(String responseBody) {
57 | try {
58 | ObjectMapper objectMapper = new ObjectMapper();
59 | JsonNode rootNode = objectMapper.readTree(responseBody);
60 | String status = rootNode.path("status").asText();
61 |
62 | if (!"OK".equals(status)) {
63 | System.out.println("Error: " + responseBody);
64 | return;
65 | }
66 |
67 | JsonNode rows = rootNode.path("rows");
68 |
69 | for (int i = 0; i < rows.size(); i++) {
70 | JsonNode row = rows.get(i);
71 | JsonNode elements = row.path("elements");
72 | System.out.println("Origin " + (i + 1) + ":");
73 | for (int j = 0; j < elements.size(); j++) {
74 | JsonNode element = elements.get(j);
75 | String elementStatus = element.path("status").asText();
76 | if ("OK".equals(elementStatus)) {
77 | double distance = element.path("distance").path("value").asDouble();
78 | String distanceText = element.path("distance").path("text").asText();
79 | double duration = element.path("duration").path("value").asDouble();
80 | String durationText = element.path("duration").path("text").asText();
81 | System.out.println(" Destination " + (j + 1) + ":");
82 | System.out.println(" Distance: " + distance + " meters (" + distanceText + ")");
83 | System.out.println(" Duration: " + duration + " seconds (" + durationText + ")");
84 | } else {
85 | System.out.println(" Destination " + (j + 1) + " Error: " + elementStatus);
86 | }
87 | }
88 | }
89 | } catch (Exception e) {
90 | e.printStackTrace();
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/driving-directions/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/driving-directions/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/driving-directions/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 500px;
3 | }
4 |
5 | * {
6 | -webkit-box-sizing: border-box;
7 | -moz-box-sizing: border-box;
8 | box-sizing: border-box;
9 | }
10 |
11 | input {
12 | font-size: inherit;
13 | line-height: normal;
14 | }
15 |
16 | #directions-box {
17 | position: absolute;
18 | max-height: 100%;
19 | top: 10px;
20 | left: 10px;
21 | max-width: 350px;
22 | min-width: 250px;
23 | width: 40%;
24 | }
25 |
26 | #inputs,
27 | #errors,
28 | #directions {
29 | width: 100%
30 | }
31 |
32 | #inputs {
33 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
34 | display: none;
35 | background-color: white;
36 | }
37 |
38 | #directions {
39 | display: none;
40 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
41 | background-color: white;
42 | margin-top: 4px;
43 | max-height: 470px;
44 | }
45 |
46 | #directions-travel-mode-selector {
47 | position: relative;
48 | height: 40px;
49 | }
50 |
51 | #directions-travel-mode-selector .woosmap-form-label {
52 | background-color: #F7F7F7;
53 | }
54 |
55 | #errors {
56 | z-index: 8;
57 | opacity: 0;
58 | padding: 10px;
59 | border-radius: 0 0 3px 3px;
60 | background: rgba(0, 0, 0, .25);
61 | top: 90px;
62 | left: 10px;
63 | }
64 |
65 | /* Basics */
66 |
67 | .woosmap-directions-inputs,
68 | .woosmap-directions-errors,
69 | .woosmap-directions-routes,
70 | .woosmap-directions-instructions {
71 | font: 300 15px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
72 | }
73 |
74 | /* Inputs */
75 |
76 | .woosmap-directions-origin,
77 | .woosmap-directions-destination {
78 | /*background-color: white;*/
79 | position: relative;
80 | }
81 |
82 | .woosmap-form-label {
83 | cursor: pointer;
84 | position: absolute;
85 | left: 0;
86 | top: 0;
87 | background: #444;
88 | color: rgba(0, 0, 0, .75);
89 | font-weight: bold;
90 | text-align: center;
91 | padding: 10px;
92 | line-height: 20px;
93 | }
94 |
95 | .woosmap-directions-origin .woosmap-form-label {
96 | background-color: #1badee;
97 | }
98 |
99 | .woosmap-travel-mode-option {
100 | cursor: pointer;
101 | top: 0;
102 | color: rgba(0, 0, 0, .75);
103 | text-align: center;
104 | padding: 10px;
105 | line-height: 20px;
106 | }
107 |
108 | .woosmap-directions-inputs input {
109 | width: 100%;
110 | border: 0;
111 | background-color: transparent;
112 | height: 40px;
113 | margin: 0;
114 | color: rgba(0, 0, 0, .5);
115 | padding: 10px 10px 10px 50px;
116 | font-weight: 300;
117 | }
118 |
119 | .woosmap-directions-inputs input:focus {
120 | color: rgba(0, 0, 0, .75);
121 | outline: 0;
122 | box-shadow: none;
123 | outline: thin dotted;
124 | }
125 |
126 | .woosmap-directions-origin input {
127 | border-top: 1px solid rgba(0, 0, 0, .1);
128 | }
129 |
130 | .woosmap-directions-destination input {
131 | border-top: 1px solid rgba(0, 0, 0, .1);
132 | }
133 |
134 | .woosmap-directions-reverse-input {
135 | position: absolute;
136 | background: white;
137 | left: 50px;
138 | top: 70px;
139 | cursor: pointer;
140 | }
141 |
142 | .woosmap-directions-inputs .woosmap-close-icon {
143 | opacity: .5;
144 | position: absolute;
145 | right: 5px;
146 | top: 10px;
147 | cursor: pointer;
148 | }
149 |
150 | input:not(:valid) + .woosmap-close-icon {
151 | display: none;
152 | }
153 |
154 | .woosmap-close-icon:hover {
155 | opacity: .75;
156 | }
157 |
158 | /* Errors */
159 |
160 | .woosmap-directions-error {
161 | color: white;
162 | display: inline-block;
163 | padding: 0 5px;
164 | }
165 |
166 | /* Routes */
167 |
168 | .woosmap-route-container {
169 | padding: 6px;
170 | box-shadow: -1px 5px 10px -4px #aaa6a0;
171 | }
172 |
173 | .woosmap-route-info-container {
174 | border-bottom: 1px solid rgb(230, 230, 230);
175 | }
176 |
177 | .woosmap-route-info-container.hide {
178 | border-bottom: none;
179 | }
180 |
181 | .woosmap-route-short-duration {
182 | color: rgb(152, 152, 152);
183 | font-size: small
184 | }
185 |
186 | .woosmap-route-traffic-duration {
187 | color: #1badee;
188 | }
189 |
190 | .woosmap-route-details {
191 | font-size: small;
192 | color: #3b8bba;
193 | margin-bottom: 10px;
194 | }
195 |
196 | .woosmap-route-details:hover {
197 | text-decoration: underline;
198 | cursor: pointer;
199 | }
200 |
201 | .route-summary-upper-panel.hide {
202 | cursor: pointer;
203 | }
204 |
205 | /* Mail View */
206 |
207 | .woosmap-mail-container {
208 | padding: 6px;
209 | box-shadow: -1px 5px 10px -4px #aaa6a0;
210 | }
211 |
212 | .woosmap-mobile-form-menu {
213 | cursor: pointer;
214 | margin: 2px 0px 3px -3px;
215 | }
216 |
217 | .woosmap-mobile-icon {
218 | background-image: url('https://developers.woosmap.com/img/mobile-icon.png');
219 | -webkit-background-size: 20px 20px;
220 | background-size: 20px 20px;
221 | background-repeat: no-repeat;
222 | content: '';
223 | display: inline-block;
224 | vertical-align: top;
225 | width: 20px;
226 | height: 20px;
227 | cursor: pointer;
228 | margin-top: 1px;
229 | background-color: white;
230 | }
231 |
232 | .woosmap-mobile-link-container {
233 | float: right;
234 | margin: 3px;
235 | }
236 |
237 | /* Instructions */
238 |
239 | .instructions-header {
240 | background-color: #1badee;
241 | }
242 |
243 | #instructions-steps {
244 | overflow-y: scroll;
245 | overflow-x: hidden;
246 | max-height: 445px;
247 | padding-left: 5px;
248 | padding-right: 5px;
249 | font-size: 13px;
250 | }
251 |
252 | .woosmap-instructions-title {
253 | vertical-align: middle;
254 | padding-left: 10px;
255 | color: white;
256 | }
257 |
258 | .close-instructions-button {
259 | background-image: url('https://developers.woosmap.com/img/close-x.png');
260 | cursor: pointer;
261 | background-color: #1badee;
262 | width: 24px;
263 | height: 24px;
264 | float: right;
265 | }
266 |
267 | .woosmap-directions-steps {
268 | position: relative;
269 | list-style: none;
270 | margin: 0;
271 | padding: 0;
272 | }
273 |
274 | .woosmap-directions-step {
275 | position: relative;
276 | color: rgba(255, 255, 255, .75);
277 | cursor: pointer;
278 | padding: 20px 20px 20px 40px;
279 | font-size: 20px;
280 | line-height: 25px;
281 | }
282 |
283 | .woosmap-directions-step-distance {
284 | color: rgba(255, 255, 255, .5);
285 | position: absolute;
286 | padding: 5px 10px;
287 | font-size: 12px;
288 | left: 30px;
289 | bottom: -15px;
290 | }
291 |
292 | .woosmap-directions-step:hover {
293 | color: white;
294 | }
295 |
296 | .woosmap-directions-step:after {
297 | content: "";
298 | position: absolute;
299 | top: 50px;
300 | bottom: -20px;
301 | border-left: 2px dotted rgba(255, 255, 255, .2);
302 | left: 20px;
303 | }
304 |
305 | .woosmap-directions-step:last-child:after,
306 | .woosmap-directions-step:last-child .woosmap-directions-step-distance {
307 | display: none;
308 | }
309 |
310 | /* icons */
311 |
312 | .woosmap-geolocation-icon {
313 | background-image: url('https://developers.woosmap.com/img/location.png');
314 | -webkit-background-size: 280px 20px;
315 | background-size: 20px 20px;
316 | background-repeat: no-repeat;
317 | margin: 0;
318 | content: '';
319 | display: inline-block;
320 | vertical-align: top;
321 | width: 20px;
322 | height: 20px;
323 | }
324 |
325 | .woosmap-travel-mode {
326 | padding: 0 0 0 40px;
327 | background: white;
328 | text-align: center;
329 | }
330 |
331 | .woosmap-directions-icon {
332 | background-image: url('https://developers.woosmap.com/img/woosmap.directions.png');
333 | -webkit-background-size: 280px 20px;
334 | background-size: 280px 20px;
335 | background-repeat: no-repeat;
336 | margin: 0;
337 | content: '';
338 | display: inline-block;
339 | vertical-align: top;
340 | width: 20px;
341 | height: 20px;
342 | }
343 |
344 | .woosmap-directions-instructions .woosmap-directions-icon {
345 | position: absolute;
346 | left: 10px;
347 | top: 25px;
348 | margin: auto;
349 | }
350 |
351 | .woosmap-depart-icon {
352 | background-position: -160px 0;
353 | }
354 |
355 | .woosmap-arrive-icon {
356 | background-position: -200px 0;
357 | }
358 |
359 | .woosmap-close-icon {
360 | background-position: -220px 0;
361 | }
362 |
363 | .woosmap-reverse-icon {
364 | background-position: -240px 0;
365 | }
366 |
367 | .woosmap-travel-mode-option {
368 | background-color: white;
369 | }
370 |
371 | .woosmap-travel-mode-icon {
372 | background-image: url('https://developers.woosmap.com/img/driving-sprite.png');
373 | -webkit-background-size: 20px 276px;
374 | background-size: 20px 276px;
375 | background-repeat: no-repeat;
376 | margin: 0;
377 | content: '';
378 | display: inline-block;
379 | vertical-align: top;
380 | width: 20px;
381 | height: 20px;
382 | }
383 |
384 | .woosmap-driving-icon {
385 | background-position: 0 -40px;
386 | }
387 |
388 | .woosmap-walking-icon {
389 | background-position: 0 -120px;
390 | }
391 |
392 | .woosmap-bicycling-icon {
393 | background-position: 0 -160px;
394 | }
395 |
396 | .selected .woosmap-driving-icon {
397 | background-position: 0 -60px;
398 | }
399 |
400 | .selected .woosmap-walking-icon {
401 | background-position: 0 -140px;
402 | }
403 |
404 | .selected .woosmap-bicycling-icon {
405 | background-position: 0 -180px;
406 | }
407 |
408 | .woosmap-travel-mode-option.selected {
409 | box-shadow: inset 0 -2px 0px 0px #3983de;
410 | }
411 |
412 | /*------------override google maps style----------*/
413 | .adp-warnbox {
414 | display: none;
415 | }
416 |
417 | .adp-placemark {
418 | border: none;
419 | background: #FFF;
420 | }
421 |
422 | #adp-placemark, .adp-placemark {
423 | font-weight: bold !important;
424 | }
425 |
426 | .adp-substep {
427 | max-width: 153px;
428 | }
429 |
430 | #directions .adp-placemark img {
431 | width: 30px;
432 | height: 44px;
433 | margin-right: 5px;
434 | }
435 |
436 | #directions #adp-placemark img {
437 | content: url('https://developers.woosmap.com/img/markers/start.png') !important;
438 | }
439 |
440 | #directions .adp-placemark:last-child img {
441 | content: url('https://developers.woosmap.com/img/markers/end.png') !important;
442 | }
443 |
444 | #map-container {
445 | position: relative;
446 | }
447 |
448 | /*grids*/
449 | .pure-g {
450 | letter-spacing: -.31em;
451 | text-rendering: optimizespeed;
452 | display: -webkit-flex;
453 | -webkit-flex-flow: row wrap;
454 | display: -ms-flexbox;
455 | -ms-flex-flow: row wrap;
456 | -ms-align-content: flex-start;
457 | -webkit-align-content: flex-start;
458 | align-content: flex-start;
459 | }
460 |
461 | .pure-g [class *="pure-u"] {
462 | font-family: "Open Sans", "Helvetica Neue", Arial, Helvetica, Verdana, sans-serif;
463 | font-weight: normal;
464 | letter-spacing: 0.01em;
465 | }
466 |
467 | .pure-u-1, .pure-u-1-3 {
468 | display: inline-block;
469 | zoom: 1;
470 | letter-spacing: normal;
471 | word-spacing: normal;
472 | vertical-align: top;
473 | text-rendering: auto;
474 | }
475 |
476 | .pure-u-1 {
477 | width: 100%;
478 | }
479 |
480 | .pure-u-1-3 {
481 | width: 33.3333%;
482 | *width: 33.3023%
483 | }
484 |
485 | .pure-form input[type=text], .pure-form input[type=email] {
486 | padding: .5em .6em;
487 | display: inline-block;
488 | border: 1px solid #ccc;
489 | box-shadow: inset 0 1px 3px #ddd;
490 | border-radius: 4px;
491 | vertical-align: middle;
492 | -webkit-box-sizing: border-box;
493 | -moz-box-sizing: border-box;
494 | box-sizing: border-box
495 | }
496 |
497 | .pure-form input:not([type]) {
498 | padding: .5em .6em;
499 | display: inline-block;
500 | border: 1px solid #ccc;
501 | box-shadow: inset 0 1px 3px #ddd;
502 | border-radius: 4px;
503 | -webkit-box-sizing: border-box;
504 | -moz-box-sizing: border-box;
505 | box-sizing: border-box
506 | }
507 |
508 | .pure-form input[type=text]:focus, .pure-form input[type=email]:focus {
509 | outline: 0;
510 | border-color: #129FEA
511 | }
512 |
513 | .pure-form input:not([type]):focus {
514 | outline: 0;
515 | border-color: #129FEA
516 | }
517 |
518 | .pure-form input[type=text][disabled], .pure-form input[type=email][disabled] {
519 | cursor: not-allowed;
520 | background-color: #eaeded;
521 | color: #cad2d3
522 | }
523 |
524 | .pure-form input:not([type])[disabled] {
525 | cursor: not-allowed;
526 | background-color: #eaeded;
527 | color: #cad2d3
528 | }
529 |
530 | .pure-form input[readonly] {
531 | background-color: #eee;
532 | color: #777;
533 | border-color: #ccc
534 | }
535 |
536 | .pure-form input:focus:invalid {
537 | color: #b94a48;
538 | border-color: #e9322d
539 | }
540 |
541 | .pure-form label {
542 | margin: .5em 0 .2em
543 | }
544 |
545 | @media only screen and (max-width: 480px) {
546 | .pure-form button[type=submit] {
547 | margin: .7em 0 0
548 | }
549 |
550 | .pure-form input:not([type]), .pure-form input[type=text], .pure-form input[type=email], .pure-form label {
551 | margin-bottom: .3em;
552 | display: block
553 | }
554 |
555 | .pure-group input:not([type]), .pure-group input[type=text], .pure-group input[type=email] {
556 | margin-bottom: 0
557 | }
558 | }
559 |
560 | ::-webkit-scrollbar {
561 | width: 5px;
562 | height: 5px;
563 | }
564 |
565 | ::-webkit-scrollbar-thumb {
566 | background-color: #d1d1d1;
567 | }
568 |
569 | ::-webkit-scrollbar-track {
570 | background-color: #F7F7F7;
571 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/driving-directions/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: DrivingDirections - Woosmap Javascript API Driving Directions Demo
3 | description: jsFiddle demo that allow the use of Google maps Driving Directions using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/driving-directions/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
51 |
102 |
119 |
120 |
--------------------------------------------------------------------------------
/jsfiddle-samples/driving-directions/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://images.woosmap.com/marker_drive.svg', scaledSize: {width: 36, height: 48}},
7 | selectedIcon: {url: 'https://images.woosmap.com/marker_drive_selected.svg', scaledSize: {width: 46, height: 60}}
8 | }
9 | ],
10 | default: {
11 | icon: {url: 'https://images.woosmap.com/marker_default.svg', scaledSize: {width: 36, height: 48}},
12 | selectedIcon: {url: 'https://images.woosmap.com/marker_selected.svg', scaledSize: {width: 46, height: 60}}
13 | }
14 | };
15 | var tilesStyle = {
16 | color: '#383838',
17 | size: 11,
18 | minSize: 6,
19 | typeRules: [{
20 | type: 'drive',
21 | color: '#82a859'
22 | }]
23 | };
24 |
25 | //this function is called when loader finished the API loading
26 | function woosmap_main() {
27 | var loader = new woosmap.MapsLoader();
28 | var dataSource = new woosmap.DataSource();
29 | loader.load(function () {
30 |
31 | /******** usefull function ********/
32 | function closeRouteContainer() {
33 | woosmap.$('.route-summary-upper-panel').addClass('hide');
34 | woosmap.$('.route-summary-lower-panel').hide();
35 | woosmap.$('.woosmap-route-details').hide();
36 | woosmap.$('.woosmap-route-info-container').addClass('hide');
37 | }
38 |
39 | function displayRouteContainer(container) {
40 | var $container = woosmap.$(container);
41 | $container.find('.route-summary-lower-panel').show();
42 | $container.find('.woosmap-route-details').show();
43 | $container.find('.woosmap-route-info-container').removeClass('hide');
44 | $container.find('.route-summary-upper-panel').removeClass('hide');
45 | }
46 |
47 | function makeMarker(position, icon, title) {
48 | directionsMarkers.push(new google.maps.Marker({
49 | position: position,
50 | map: map,
51 | icon: icon,
52 | title: title
53 | }));
54 | }
55 |
56 | function cleanMarker() {
57 | woosmap.$.each(directionsMarkers, function (index, marker) {
58 | marker.setMap(null);
59 | });
60 | directionsMarkers = [];
61 | }
62 |
63 | /*********************************/
64 |
65 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
66 | center: {
67 | lat: 45,
68 | lng: 2
69 | },
70 | zoom: 5,
71 | disableDefaultUI: true
72 | });
73 |
74 | var mapView = new woosmap.TiledView(map, {
75 | style: markersStyle,
76 | tileStyle: tilesStyle
77 | });
78 |
79 |
80 | /**** directions renderers options ****/
81 | var newPolylineOption = {
82 | strokeColor: '#1badee',
83 | strokeOpacity: 1.0,
84 | strokeWeight: 4,
85 | icons: ['https://developers.woosmap.com/img/markers/marker.png']
86 | };
87 |
88 | // Start/Finish icons
89 | var icons = {
90 | start: 'https://developers.woosmap.com/img/markers/start.png',
91 | end: 'https://developers.woosmap.com/img/markers/end.png'
92 | };
93 | var directionRendererOptions = {
94 | suppressMarkers: true,
95 | suppressInfoWindows: true,
96 | polylineOptions: newPolylineOption
97 | };
98 |
99 | var googleDirectionsRequestOptions = {
100 | provideRouteAlternatives: true,
101 | durationInTraffic: true
102 | };
103 | /***************************************/
104 |
105 | var directionsMarkers = [];
106 | var navigatorGeolocation = new woosmap.location.LocationProvider();
107 | var travelModeSelector = new woosmap.ui.TravelModeSelector(woosmap.$('#travel-mode-selector-template').html());
108 | var originDestinationInput = new woosmap.ui.OriginDestinationInput(woosmap.$('#directions-origin-destination-template').html(), {
109 | 'geolocText': 'Ma Position'
110 | });
111 | var directionsProvider = new woosmap.location.DirectionsProvider(directionRendererOptions, googleDirectionsRequestOptions);
112 | var mailView = new woosmap.ui.MailView(woosmap.$('#directions-mail-input-template').html());
113 | var locationProvider = new woosmap.location.LocationProvider();
114 | var store_id = '';
115 | var directionsRestorer = new woosmap.utils.MVCObject();
116 | directionsRestorer.location = null;
117 | directionsRestorer.location_changed = function () {
118 | var self = this;
119 | if (store_id) {
120 | dataSource.getStoreById(store_id, function (data) {
121 | originDestinationInput.set('selectedStore', data);
122 | originDestinationInput.set('location', self.get('location'));
123 | });
124 | }
125 | };
126 |
127 | var directionsResultsDisplayer = new woosmap.ui.DirectionsResultsDisplayer(map, woosmap.$('#directions-summary-template').html(),
128 | function () {
129 | //this function is called when directionResultsDisplayer finished to display renderers
130 | directionsResultsDisplayer.displayRouteOnMap(0);
131 | directionsResultsDisplayer.displayRouteSteps(0);
132 | woosmap.$("#directions").show();
133 | var computedDirections = directionsResultsDisplayer.get("directionsRenderers")[0].getDirections();
134 | var leg = computedDirections.routes[0].legs[0];
135 | cleanMarker();
136 | makeMarker(leg.start_location, icons.start, "Start");
137 | makeMarker(leg.end_location, icons.end, 'End');
138 |
139 | closeRouteContainer();
140 | displayRouteContainer(woosmap.$('.woosmap-route-container')[0]);
141 |
142 | woosmap.$('.woosmap-route-container').click(function () {
143 | closeRouteContainer();
144 | displayRouteContainer(this);
145 | directionsResultsDisplayer.cleanMapFromRoutes();
146 | directionsResultsDisplayer.cleanRouteSteps();
147 | directionsResultsDisplayer.displayRouteOnMap(woosmap.$(this).find('.woosmap-show-steps').data('renderer-index'));
148 | directionsResultsDisplayer.displayRouteSteps(woosmap.$(this).find('.woosmap-show-steps').data('renderer-index'));
149 | });
150 |
151 | woosmap.$('.woosmap-route-details').click(function () {
152 | woosmap.$('#instructions').show();
153 | woosmap.$('#routes').hide();
154 | woosmap.$('#inputs').hide();
155 | woosmap.$('#instructions-mail').hide();
156 | woosmap.$('#directions').css('top', '5px');
157 | woosmap.$('#directions').css('bottom', '5px');
158 | });
159 |
160 | woosmap.$('#close-instructions-button').click(function () {
161 | woosmap.$('#instructions').hide();
162 | woosmap.$('#routes').show();
163 | woosmap.$('#inputs').show();
164 | woosmap.$('#instructions-mail').show();
165 | woosmap.$('#directions').css('top', '135px');
166 | woosmap.$('#directions').css('bottom', '');
167 | });
168 | }
169 | );
170 |
171 | originDestinationInput.bindTo('selectedStore', mapView);
172 | directionsProvider.bindTo('selectedTravelMode', travelModeSelector);
173 | directionsProvider.bindTo('originDestination', originDestinationInput);
174 | directionsResultsDisplayer.bindTo('directionsSummaries', directionsProvider);
175 | directionsResultsDisplayer.bindTo('directionsRenderers', directionsProvider);
176 | directionsResultsDisplayer.bindTo('directionsLink', directionsProvider);
177 | originDestinationInput.bindTo('location', navigatorGeolocation);
178 | mailView.bindTo('selectedStore', mapView);
179 | directionsRestorer.bindTo('location', locationProvider);
180 |
181 | function _update_mail_status(text, color) {
182 | var $mailStatusDiv = woosmap.$('#mail-status');
183 | $mailStatusDiv.html(text).css('color', color);
184 | $mailStatusDiv.show();
185 | setTimeout(function () {
186 | $mailStatusDiv.hide(1000);
187 | }, 3000);
188 | }
189 |
190 | mailView.delegate = {
191 | mailSent: function () {
192 | _update_mail_status('Email envoyé', 'green');
193 | woosmap.$('.woosmap-mail-input').val("");
194 | },
195 | mailError: function () {
196 | _update_mail_status('Erreur', 'red');
197 | },
198 | mailSending: function () {
199 | _update_mail_status('Envoi en cours', '#1badee');
200 | }
201 | };
202 |
203 | woosmap.$('#map-container').append(originDestinationInput.getODContainer());
204 | woosmap.$('#routes').append(directionsResultsDisplayer.getRoutesContainer());
205 | woosmap.$('#instructions-steps').append(directionsResultsDisplayer.getStepsContainer());
206 | woosmap.$('#directions-travel-mode-selector').append(travelModeSelector.getSelectorContainer());
207 |
208 | woosmap.$('#instructions-mail').empty().append(mailView.getContainer());
209 |
210 | if (new woosmap.DeviceDetector().getDeviceType() == 'mobile') {
211 | woosmap.$('.woosmap-mail-container').hide();
212 | } else {
213 | woosmap.$('.woosmap-mobile-form-menu').click(function () {
214 | woosmap.$('.woosmap-mobile-form').toggle();
215 | });
216 | }
217 |
218 | woosmap.$(".woosmap-directions-origin .woosmap-close-icon").click(function () {
219 | woosmap.$("#woosmap-directions-origin-input").val('');
220 | });
221 |
222 | woosmap.$(".woosmap-directions-destination .woosmap-close-icon").click(function () {
223 | woosmap.$("#woosmap-directions-destination-input").val('');
224 | });
225 |
226 | woosmap.$('#directions-travel-mode-selector .woosmap-travel-mode-option').click(function () {
227 | woosmap.$('#directions-travel-mode-selector .woosmap-travel-mode-option').removeClass('selected');
228 | woosmap.$(this).addClass('selected');
229 | });
230 |
231 | woosmap.$('.geolocation-button').click(function () {
232 | navigatorGeolocation.askForLocation(navigator.geolocation);
233 | });
234 |
235 | google.maps.event.addListener(map, 'click', function (event) {
236 | originDestinationInput.set('location', {
237 | 'lat': event.latLng.lat(),
238 | 'lng': event.latLng.lng()
239 | });
240 | });
241 | window.setTimeout(function () {
242 | store_id = top.location.search.split('store_id=')[1] ? top.location.search.split('store_id=')[1].replace('&', '') : '';
243 | if (store_id) {
244 | dataSource.getStoreById(store_id, function (data) {
245 | originDestinationInput.set('selectedStore', data);
246 | originDestinationInput.set('location', self.get('location'));
247 | });
248 | locationProvider.askForLocation(navigator.geolocation);
249 | }
250 | }, 1000);
251 | woosmap.$("#inputs").show();
252 | });
253 | }
254 |
255 | document.addEventListener("DOMContentLoaded", function (event) {
256 | WoosmapLoader.load('latest', projectKey, woosmap_main);
257 | });
258 |
--------------------------------------------------------------------------------
/jsfiddle-samples/geolocation/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/geolocation/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/geolocation/demo.css:
--------------------------------------------------------------------------------
1 | .bg {
2 | background: white;
3 | padding: 5px;
4 | }
5 |
6 | .nearest-store-map {
7 | height: 250px;
8 | width: 76%;
9 | float: left
10 | }
11 |
12 | .nearest-store-button {
13 | width: 100%;
14 | }
15 |
16 | .nearest-store-button-div {
17 | float: right;
18 | width: 23%;
19 | }
20 |
21 | #closest-store-info {
22 | border: 1px solid grey;
23 | display: none;
24 | width: 50%;
25 | }
26 |
27 | #html5-geolocation-button {
28 | width: 100%;
29 | margin-top: 10px;
30 | }
31 |
32 | #store-info {
33 | margin-top: 52px;
34 | }
35 |
36 | ::-webkit-scrollbar {
37 | width: 5px;
38 | height: 5px;
39 | }
40 |
41 | ::-webkit-scrollbar-thumb {
42 | background-color: #d1d1d1;
43 | }
44 |
45 | ::-webkit-scrollbar-track {
46 | background-color: #F7F7F7;
47 | }
48 |
49 | /*pure-css*/
50 |
51 | .pure-button {
52 | /* Structure */
53 | display: inline-block;
54 | zoom: 1;
55 | line-height: normal;
56 | white-space: nowrap;
57 | vertical-align: middle;
58 | text-align: center;
59 | cursor: pointer;
60 | -webkit-user-drag: none;
61 | -webkit-user-select: none;
62 | -moz-user-select: none;
63 | -ms-user-select: none;
64 | user-select: none;
65 | -webkit-box-sizing: border-box;
66 | -moz-box-sizing: border-box;
67 | box-sizing: border-box;
68 | }
69 |
70 | .pure-button {
71 | font-family: inherit;
72 | font-size: 100%;
73 | padding: 0.5em 1em;
74 | color: #444; /* rgba not supported (IE 8) */
75 | color: rgba(0, 0, 0, 0.80); /* rgba supported */
76 | border: 1px solid #999; /*IE 6/7/8*/
77 | border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
78 | background-color: #E6E6E6;
79 | text-decoration: none;
80 | border-radius: 2px;
81 | }
82 |
83 | .pure-button-hover,
84 | .pure-button:hover,
85 | .pure-button:focus {
86 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);
87 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0, 0, 0, 0.05)), to(rgba(0, 0, 0, 0.10)));
88 | background-image: -webkit-linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.10));
89 | background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.10));
90 | background-image: -o-linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.10));
91 | background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.05) 40%, rgba(0, 0, 0, 0.10));
92 | }
93 |
94 | .pure-button:focus {
95 | outline: 0;
96 | }
97 |
98 | .pure-button-active,
99 | .pure-button:active {
100 | box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15) inset, 0 0 6px rgba(0, 0, 0, 0.20) inset;
101 | border-color: #000 \9;
102 | }
103 |
104 | hr {
105 | border: 0;
106 | height: 0;
107 | border-top: 1px solid rgba(0, 0, 0, 0.1);
108 | border-bottom: 1px solid rgba(255, 255, 255, 0.3);
109 | }
110 |
--------------------------------------------------------------------------------
/jsfiddle-samples/geolocation/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: Geolocation - Woosmap Javascript API Geolocation Demo
3 | description: jsFiddle demo that allow the geolocation of a user using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/geolocation/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
20 |
21 |
25 |
29 | ...
30 |
31 |
32 |
33 |
34 |
35 |
43 |
44 |
--------------------------------------------------------------------------------
/jsfiddle-samples/geolocation/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://images.woosmap.com/marker_drive.svg', scaledSize: {width: 36, height: 48}},
7 | selectedIcon: {url: 'https://images.woosmap.com/marker_drive_selected.svg', scaledSize: {width: 46, height: 60}}
8 | }
9 | ],
10 | default: {
11 | icon: {url: 'https://images.woosmap.com/marker_default.svg', scaledSize: {width: 36, height: 48}},
12 | selectedIcon: {url: 'https://images.woosmap.com/marker_selected.svg', scaledSize: {width: 46, height: 60}}
13 | }
14 | };
15 | var tilesStyle = {
16 | color: '#383838',
17 | size: 11,
18 | minSize: 6,
19 | typeRules: [{
20 | type: 'drive',
21 | color: '#82a859'
22 | }]
23 | };
24 |
25 | //this function is called when loader finished the API loading
26 | function woosmap_main() {
27 | var loader = new woosmap.MapsLoader();
28 | var dataSource = new woosmap.DataSource();
29 | loader.load(function () {
30 | var map = new google.maps.Map(woosmap.$('#nearest-store-map')[0], {
31 | center: {lat: 46, lng: 3},
32 | zoom: 5
33 | });
34 | var mapView = new woosmap.TiledView(map, {style: markersStyle, tileStyle: tilesStyle});
35 |
36 | var locationProvider = new woosmap.location.LocationProvider();
37 | var locationProviderMap = new woosmap.location.LocationProvider();
38 | var zipCodeProvider = new woosmap.ZipCodeProvider();
39 | var zipCodeWatcher = new woosmap.utils.MVCObject();
40 |
41 | var template = "{{name}}
{{address.zipcode}} {{address.city}}
{{contact.phone}}
{{distance}} km";
42 | var storesInformationTemplateRenderer = new woosmap.TemplateRenderer(template);
43 | var storesInformationDisplayer = new woosmap.utils.MVCObject();
44 | storesInformationDisplayer.stores = null;
45 | storesInformationDisplayer.stores_changed = function () {
46 | var properties = this.get('stores')[0].properties;
47 | properties.distance = Math.round(properties.distance / 1000);
48 | woosmap.$('#store-info').html(storesInformationTemplateRenderer.render(properties));
49 | };
50 | storesInformationDisplayer.bindTo('stores', mapView);
51 |
52 | var nearbyStoresSource = new woosmap.location.NearbyStoresSource(dataSource, 1);
53 | nearbyStoresSource.bindTo('stores', mapView);
54 | mapView.bindTo('location', locationProviderMap);
55 |
56 | mapView.marker.setOptions({
57 | draggable: true,
58 | icon: {url: 'https://developers.woosmap.com/img/markers/geolocated.png'}
59 | });
60 |
61 | nearbyStoresSource.bindTo('location', locationProviderMap);
62 | zipCodeProvider.bindTo('location', locationProvider);
63 | zipCodeWatcher.bindTo('zipcode', zipCodeProvider);
64 |
65 | zipCodeWatcher.zipcode_changed = function () {
66 | woosmap.$('#geoloc-zipcode-result').html(zipCodeProvider.getZipCode());
67 | };
68 |
69 | woosmap.$("#geoloc-zipcode-ip").click(function () {
70 | woosmap.$('#geoloc-zipcode-result').html('looking for ...');
71 | woosmap.$('#geoloc-zipcode-result').html(zipCodeProvider.getZipCode());
72 | });
73 | woosmap.$("#geoloc-zipcode-optin").click(function () {
74 | locationProvider.askForLocation(navigator.geolocation);
75 | });
76 |
77 | woosmap.$("#ip-geolocation-button").click(function () {
78 | locationProviderMap.askForLocation();
79 | });
80 |
81 | woosmap.$("#html5-geolocation-button").click(function () {
82 | locationProviderMap.askForLocation(navigator.geolocation);
83 | });
84 |
85 | /*---------- DistanceProvider --------------*/
86 | var template = woosmap.$('#closest-store-template').html();
87 | var anotherLocationProvider = new woosmap.location.LocationProvider();
88 | var anotherNearbyStoresSource = new woosmap.location.NearbyStoresSource(dataSource, 10);
89 | var distanceProvider = new woosmap.location.DistanceProvider();
90 | var closestStoreTemplateRenderer = new woosmap.TemplateRenderer(template);
91 | var closestStoreDisplayer = new woosmap.utils.MVCObject();
92 | closestStoreDisplayer.stores = null;
93 | closestStoreDisplayer.stores_changed = function () {
94 | distanceProvider.updateStoresDistanceWithGoogle(this.get('stores'), function (updated_stores) {
95 | var $storesDiv = woosmap.$('#closest-store-info');
96 | var store_properties = updated_stores[0].properties;
97 | store_properties.distance = store_properties.distance / 1000;
98 | store_properties.duration = Math.round(store_properties.duration / 60);
99 | $storesDiv.html(closestStoreTemplateRenderer.render(store_properties));
100 | $storesDiv.show();
101 | }, 'duration');
102 | };
103 |
104 |
105 | closestStoreDisplayer.bindTo('stores', anotherNearbyStoresSource);
106 | anotherNearbyStoresSource.bindTo('location', anotherLocationProvider);
107 | distanceProvider.bindTo('location', anotherLocationProvider);
108 | woosmap.$('#update-stores-distance').click(function () {
109 | anotherLocationProvider.askForLocation(navigator.geolocation);
110 | });
111 |
112 |
113 | });
114 | }
115 |
116 | document.addEventListener("DOMContentLoaded", function (event) {
117 | WoosmapLoader.load('latest', projectKey, woosmap_main);
118 | });
119 |
--------------------------------------------------------------------------------
/jsfiddle-samples/locator-map/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/locator-map/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/locator-map/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 500px;
3 | }
4 |
5 | .locator-container {
6 | font-size: 15px;
7 | line-height: 1.5em;
8 | color: #555;
9 | }
10 |
11 | .sidebar {
12 | height: 500px;
13 | overflow: hidden;
14 | border: 1px solid #EEE;
15 | border-right: none;
16 | }
17 |
18 | .locator-heading {
19 | background: #fff;
20 | border-bottom: 1px solid #eee;
21 | height: 36px;
22 | line-height: 36px;
23 | padding: 0 10px;
24 | }
25 |
26 | .locator-heading h2 {
27 | font-size: 20px;
28 | margin: 0;
29 | font-weight: 400;
30 | color: #333;
31 | }
32 |
33 | .listings {
34 | height: 460px;
35 | padding-bottom: 36px;
36 | background-color: #FFF;
37 | color:#555;
38 | }
39 |
40 | .woosmap-tableview-container, .card_container {
41 | max-height: 100%;
42 | overflow-y: scroll;
43 | overflow-x: hidden;
44 | }
45 |
46 | .item {
47 | display: block;
48 | border-bottom: 1px solid #eee;
49 | padding: 10px;
50 | text-decoration: none;
51 | cursor: pointer;
52 | }
53 |
54 | .item .title {
55 | display: block;
56 | color: #4d9da9;
57 | font-weight: 500;
58 | }
59 |
60 | .item .title small {
61 | font-weight: 300;
62 | }
63 |
64 | .quiet {
65 | color: #888;
66 | }
67 | small {
68 | font-size: 80%;
69 | }
70 |
71 | .selected_card .item .title,
72 | .item .title:hover {
73 | color: #1badee;
74 | }
75 |
76 | .item.active {
77 | background-color: #f8f8f8;
78 | }
79 |
80 | .selected_card {
81 | background-color: #f8f8f8;
82 | }
83 |
84 | .selected_card:hover {
85 | background-color: #f8f8f8;
86 | }
87 |
88 | ::-webkit-scrollbar {
89 | width: 5px;
90 | height: 5px;
91 | }
92 |
93 | ::-webkit-scrollbar-thumb {
94 | background-color: #d1d1d1;
95 | }
96 |
97 | ::-webkit-scrollbar-track {
98 | background-color: #F7F7F7;
99 | }
100 |
101 | /*grids*/
102 | .pure-g {
103 | letter-spacing: -.31em;
104 | text-rendering: optimizespeed;
105 | display: -webkit-flex;
106 | -webkit-flex-flow: row wrap;
107 | display: -ms-flexbox;
108 | -ms-flex-flow: row wrap;
109 | -ms-align-content: flex-start;
110 | -webkit-align-content: flex-start;
111 | align-content: flex-start;
112 | }
113 |
114 | .pure-g [class *="pure-u"] {
115 | font-family: "Open Sans", "Helvetica Neue", Arial, Helvetica, Verdana, sans-serif;
116 | font-weight: normal;
117 | letter-spacing: 0.01em;
118 | }
119 |
120 | .pure-u-1, .u-sm-1-3, .u-sm-2-3 {
121 | display: inline-block;
122 | zoom: 1;
123 | letter-spacing: normal;
124 | word-spacing: normal;
125 | vertical-align: top;
126 | text-rendering: auto;
127 | }
128 |
129 | .pure-u-1 {
130 | width: 100%;
131 | }
132 |
133 | @media screen and (min-width: 35.5em) {
134 | .u-sm-1-3 {
135 | width: 33.3333%;
136 | }
137 |
138 | .u-sm-2-3 {
139 | width: 66.5%;
140 | }
141 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/locator-map/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: LocatorMap - Woosmap Javascript API Locator Map Demo
3 | description: jsFiddle demo that display a more complete store locator map using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/locator-map/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/jsfiddle-samples/locator-map/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://developers.woosmap.com/img/markers/marker_drive.png', scaledSize: {width: 46/2, height: 58/2}},
7 | selectedIcon: {url: 'https://developers.woosmap.com/img/markers/marker_selected.png', scaledSize: {width: 46, height: 58}}
8 | }
9 | ],
10 | default: {
11 | icon: {url: 'https://developers.woosmap.com/img/markers/marker_default.png', scaledSize: {width: 46/2, height: 58/2}},
12 | selectedIcon: {url: 'https://developers.woosmap.com/img/markers/marker_selected.png', scaledSize: {width: 46, height: 58}}
13 | }
14 | };
15 | var tilesStyle = {
16 | color: '#383838',
17 | size: 11,
18 | minSize: 6,
19 | typeRules: [{
20 | type: 'drive',
21 | color: '#82a859'
22 | }]
23 | };
24 |
25 |
26 | /*----- Init and display a Map with a TiledLayer-----*/
27 | function woosmap_main() {
28 | var self = this;
29 | var loader = new woosmap.MapsLoader();
30 | var dataSource = new woosmap.DataSource();
31 | loader.load(function () {
32 | var tableview = new woosmap.ui.TableView({
33 | cell: ''
36 | });
37 |
38 | var listings = woosmap.$('#listings');
39 | listings.append(tableview.getContainer());
40 | self.tableview = tableview;
41 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
42 | center: {lat: 46, lng: 3},
43 | zoom: 5
44 | });
45 | var mapView = new woosmap.TiledView(map, {style: markersStyle, tileStyle: tilesStyle});
46 | mapView.bindTo('stores', tableview, 'stores', false);
47 | mapView.bindTo('selectedStore', tableview, 'selectedStore', false);
48 |
49 | dataSource.getAllStores(function (stores) {
50 | tableview.set('stores', stores.features);
51 | });
52 | });
53 |
54 | }
55 |
56 | document.addEventListener("DOMContentLoaded", function (event) {
57 | WoosmapLoader.load('1.2', projectKey, woosmap_main);
58 | });
--------------------------------------------------------------------------------
/jsfiddle-samples/map-infowindow/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/map-infowindow/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/map-infowindow/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 400px;
3 | width: 100%;
4 | }
5 |
6 | .info-item {
7 | line-height: 2;
8 | display: block;
9 | overflow: hidden;
10 | white-space: nowrap;
11 | text-decoration: none;
12 | color: #555;
13 | }
14 |
15 | .info-item .title {
16 | display: block;
17 | color: #4d9da9;
18 | font-weight: 500;
19 | background: url('https://developers.woosmap.com/img/Punaise_WGS_V3.png') no-repeat top left;
20 | background-size: auto 58px;
21 | padding-left: 70px;
22 | }
23 |
24 | .quiet {
25 | color: #888;
26 | }
27 |
28 | small {
29 | font-size: 80%;
30 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/map-infowindow/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: MapInfowindow - Woosmap Javascript API MapInfowindow Demo
3 | description: jsFiddle demo that display a TiledView of a sample datasource using Woosmap Javascript API and allow to click location to open InfoWindow.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/map-infowindow/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/jsfiddle-samples/map-infowindow/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://images.woosmap.com/marker_drive.svg', scaledSize: {width: 36, height: 48}},
7 | selectedIcon: {url: 'https://images.woosmap.com/marker_drive_selected.svg', scaledSize: {width: 46, height: 60}}
8 | }
9 | ],
10 | default: {
11 | icon: {url: 'https://images.woosmap.com/marker_default.svg', scaledSize: {width: 36, height: 48}},
12 | selectedIcon: {url: 'https://images.woosmap.com/marker_selected.svg', scaledSize: {width: 46, height: 60}}
13 | }
14 | };
15 | var tilesStyle = {
16 | color: '#383838',
17 | size: 11,
18 | minSize: 6,
19 | typeRules: [{
20 | type: 'drive',
21 | color: '#82a859'
22 | }]
23 | };
24 |
25 | /*----- Init and display a Map with a TiledLayer-----*/
26 | function woosmap_main() {
27 | var loader = new woosmap.MapsLoader();
28 | var dataSource = new woosmap.DataSource();
29 | loader.load(function () {
30 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
31 | center: {lat: 46, lng: 3},
32 | zoom: 5
33 | });
34 | var template = '';
38 |
39 | var renderer = new woosmap.TemplateRenderer(template);
40 | var win = new woosmap.LocatorWindow(map, renderer);
41 |
42 | var mapView = new woosmap.TiledView(map, {style: markersStyle, tileStyle: tilesStyle});
43 | win.bindTo('selectedStore', mapView);
44 | });
45 |
46 | }
47 |
48 | document.addEventListener("DOMContentLoaded", function (event) {
49 | WoosmapLoader.load('1.2', projectKey, woosmap_main);
50 | });
51 |
--------------------------------------------------------------------------------
/jsfiddle-samples/map-tiled-view/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/map-tiled-view/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/map-tiled-view/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 400px;
3 | width: 100%;
4 | }
5 |
6 | #go-to-paris {
7 | padding: 8px;
8 | border-style: none;
9 | border-radius: 2px;
10 | box-shadow: rgba(0, 0, 0, 0.298039) 0 1px 4px -1px;
11 | background-color: rgb(255, 255, 255);
12 | cursor: pointer;
13 | }
14 |
15 | .btn-container {
16 | margin: 18px;
17 | z-index: 0;
18 | position: absolute;
19 | right: 0;
20 | top: 0;
21 | }
22 |
--------------------------------------------------------------------------------
/jsfiddle-samples/map-tiled-view/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: BasicTiledView - Woosmap Javascript API TiledView Demo
3 | description: jsFiddle demo that display a TiledView of a sample datasource using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/map-tiled-view/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/jsfiddle-samples/map-tiled-view/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://developers.woosmap.com/img/markers/marker_drive.png', scaledSize: {width: 36, height: 48}},
7 | selectedIcon: {url: 'https://developers.woosmap.com/img/markers/marker_selected.png', scaledSize: {width: 46, height: 60}}
8 | }
9 | ],
10 | default: {
11 | icon: {url: 'https://developers.woosmap.com/img/markers/marker_default.png', scaledSize: {width: 36, height: 48}},
12 | selectedIcon: {url: 'https://developers.woosmap.com/img/markers/marker_selected.png', scaledSize: {width: 46, height: 60}}
13 | }
14 | };
15 | var tilesStyle = {
16 | color: '#383838',
17 | size: 11,
18 | minSize: 6,
19 | typeRules: [{
20 | type: 'drive',
21 | color: '#82a859'
22 | }]
23 | };
24 |
25 | /*----- Handle store selection -----*/
26 | function registerLocationClickEvent(mapView) {
27 | var selectedStoreObserver = new woosmap.utils.MVCObject();
28 | selectedStoreObserver.selectedStore = null;
29 | selectedStoreObserver.selectedStore_changed = function () {
30 | var selectedStore = this.get('selectedStore');
31 | alert(selectedStore.properties.name);
32 | };
33 | selectedStoreObserver.bindTo('selectedStore', mapView);
34 | }
35 |
36 | /*----- Store by Location, with distance -----*/
37 | function registerNearbyClickEvent(mapView, dataSource) {
38 | var MAX_STORE = 10;
39 | var MAX_DISTANCE_FROM_LOCATION = 150000; //150km
40 | var nearbyStoreSource = new woosmap.location.NearbyStoresSource(dataSource, MAX_STORE, MAX_DISTANCE_FROM_LOCATION);
41 | nearbyStoreSource.bindTo('location', mapView);
42 | nearbyStoreSource.bindTo('stores', mapView);
43 |
44 | woosmap.$('#go-to-paris').on('click', function () {
45 | mapView.set('location', {
46 | lat: 48.85,
47 | lng: 2.27
48 | });
49 | });
50 | }
51 |
52 | function registerDraggableMarker(mapView) {
53 | mapView.marker.setOptions({
54 | draggable: true,
55 | icon: {url: 'https://developers.woosmap.com/img/markers/geolocated.png'}
56 | });
57 | }
58 | /*----- Init and display a Map with a TiledLayer-----*/
59 | function woosmap_main() {
60 | var loader = new woosmap.MapsLoader();
61 | var dataSource = new woosmap.DataSource();
62 | loader.load(function () {
63 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
64 | center: {lat: 46, lng: 3},
65 | zoom: 5
66 | });
67 | var mapView = new woosmap.TiledView(map, {style: markersStyle, tileStyle: tilesStyle});
68 | registerNearbyClickEvent(mapView, dataSource);
69 | registerLocationClickEvent(mapView);
70 | registerDraggableMarker(mapView);
71 | });
72 |
73 | }
74 |
75 | document.addEventListener("DOMContentLoaded", function (event) {
76 | WoosmapLoader.load('1.2', projectKey, woosmap_main);
77 | });
78 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-location/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/search-location/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-location/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 500px;
3 | }
4 |
5 | .locator-container {
6 | font-size: 15px;
7 | line-height: 1.5em;
8 | color: #555;
9 | background: #FFF;
10 | }
11 |
12 | .sidebar {
13 | height: 500px;
14 | overflow: hidden;
15 | border: 1px solid #EEE;
16 | border-right: none;
17 | }
18 |
19 | .listings {
20 | height: 460px;
21 | padding-bottom: 36px;
22 | background-color: #FFF;
23 | color: #555;
24 | }
25 |
26 | .woosmap-tableview-container, .card_container {
27 | max-height: 100%;
28 | overflow-y: scroll;
29 | overflow-x: hidden;
30 | }
31 |
32 | .item {
33 | display: block;
34 | border-bottom: 1px solid #eee;
35 | padding: 10px;
36 | text-decoration: none;
37 | cursor: pointer;
38 | }
39 |
40 | .item .title {
41 | display: block;
42 | color: #4d9da9;
43 | font-weight: 500;
44 | }
45 |
46 | .item .title small {
47 | font-weight: 300;
48 | }
49 |
50 | .quiet {
51 | color: #888;
52 | }
53 |
54 | small {
55 | font-size: 80%;
56 | }
57 |
58 | .selected_card .item .title,
59 | .item .title:hover {
60 | color: #1badee;
61 | }
62 |
63 | .item.active {
64 | background-color: #f8f8f8;
65 | }
66 |
67 | .selected_card {
68 | background-color: #f8f8f8;
69 | }
70 |
71 | .selected_card:hover {
72 | background-color: #f8f8f8;
73 | }
74 |
75 | .search_container {
76 | margin: 5px;
77 | border: 1px solid #1badee;
78 | border-radius: 2px;
79 | box-sizing: border-box;
80 | -moz-box-sizing: border-box;
81 | height: 32px;
82 | outline: none;
83 | padding: 0 7px;
84 | width: 96%;
85 | vertical-align: top;
86 | position: relative;
87 | }
88 |
89 | .search_input {
90 | border: none;
91 | padding: 0;
92 | height: 1.25em;
93 | width: 100%;
94 | z-index: 6;
95 | outline: none;
96 | background: #FFF;
97 | margin-top: 7px;
98 | float: left;
99 | font-size: 1em;
100 | color: #555;
101 | }
102 |
103 | .search_clear {
104 | float: right;
105 | background: white url('https://developers.woosmap.com/img/close.png') no-repeat left top;
106 | position: absolute;
107 | right: 5px;
108 | top: 8px;
109 | padding: 7px;
110 | font-size: 14px;
111 | cursor: pointer;
112 | display: none;
113 | }
114 |
115 | .search_clear:hover {
116 | background: white url('https://developers.woosmap.com/img/close-hover.png') no-repeat left top;
117 | }
118 |
119 | .woosmap-tableview-highlighted-cell {
120 | background-color: #f8f8f8;
121 | }
122 |
123 | ::-webkit-scrollbar {
124 | width: 5px;
125 | height: 5px;
126 | }
127 |
128 | ::-webkit-scrollbar-thumb {
129 | background-color: #d1d1d1;
130 | }
131 |
132 | ::-webkit-scrollbar-track {
133 | background-color: #F7F7F7;
134 | }
135 |
136 | /*grids*/
137 | .pure-g {
138 | letter-spacing: -.31em;
139 | text-rendering: optimizespeed;
140 | display: -webkit-flex;
141 | -webkit-flex-flow: row wrap;
142 | display: -ms-flexbox;
143 | -ms-flex-flow: row wrap;
144 | -ms-align-content: flex-start;
145 | -webkit-align-content: flex-start;
146 | align-content: flex-start;
147 | }
148 |
149 | .pure-g [class *="pure-u"] {
150 | font-family: "Open Sans", "Helvetica Neue", Arial, Helvetica, Verdana, sans-serif;
151 | font-weight: normal;
152 | letter-spacing: 0.01em;
153 | }
154 |
155 | .pure-u-1, .u-sm-1-3, .u-sm-2-3 {
156 | display: inline-block;
157 | zoom: 1;
158 | letter-spacing: normal;
159 | word-spacing: normal;
160 | vertical-align: top;
161 | text-rendering: auto;
162 | }
163 |
164 | .pure-u-1 {
165 | width: 100%;
166 | }
167 |
168 | @media screen and (min-width: 35.5em) {
169 | .u-sm-1-3 {
170 | width: 33.3333%;
171 | }
172 |
173 | .u-sm-2-3 {
174 | width: 66.5%;
175 | }
176 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/search-location/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: SearchLocation - Woosmap Javascript API Search Location Demo
3 | description: jsFiddle demo that allow the use of Google maps basic geocoding using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/search-location/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
14 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-location/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://images.woosmap.com/marker_drive.svg', scaledSize: {width: 36, height: 48}},
7 | selectedIcon: {url: 'https://images.woosmap.com/marker_drive_selected.svg', scaledSize: {width: 46, height: 60}},
8 | numberedIcon: {url: 'https://images.woosmap.com/marker_drive_selected.svg', scaledSize: {width: 46, height: 60}}
9 | }
10 | ],
11 | default: {
12 | icon: {url: 'https://images.woosmap.com/marker_default.svg', scaledSize: {width: 36, height: 48}},
13 | selectedIcon: {url: 'https://images.woosmap.com/marker_selected.svg', scaledSize: {width: 46, height: 60}}
14 | }
15 | };
16 | var tilesStyle = {
17 | color: '#383838',
18 | size: 11,
19 | minSize: 6,
20 | typeRules: [{
21 | type: 'drive',
22 | color: '#82a859'
23 | }]
24 | };
25 |
26 | function registerDraggableMarker(mapView) {
27 | mapView.marker.setOptions({
28 | draggable: true,
29 | icon: {url: 'https://developers.woosmap.com/img/markers/geolocated.png'}
30 | });
31 | }
32 |
33 | /*----- Init and display a Map with a TiledLayer-----*/
34 | function woosmap_main() {
35 | var self = this;
36 | var loader = new woosmap.MapsLoader();
37 | var dataSource = new woosmap.DataSource();
38 | loader.load(function () {
39 | var tableview = new woosmap.ui.TableView({
40 | cell_store: '',
43 | cell_place: ''
44 | });
45 | var geocoder = new woosmap.location.GeocoderSearchSource();
46 | var searchview = new woosmap.ui.SearchView(woosmap.$('#search_template').text());
47 | var nearbyStoresSource = new woosmap.location.NearbyStoresSource(dataSource, 5);
48 |
49 | nearbyStoresSource.bindTo('location', geocoder, 'location', false);
50 | tableview.bindTo('stores', nearbyStoresSource);
51 | geocoder.bindTo('query', searchview, 'query', false);
52 |
53 | var listings = woosmap.$('#listings');
54 | var sidebar = woosmap.$('.sidebar');
55 |
56 | sidebar.prepend(searchview.getContainer());
57 | listings.append(tableview.getContainer());
58 |
59 | self.tableview = tableview;
60 | var defaultStores = null;
61 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
62 | center: {lat: 46, lng: 3},
63 | zoom: 5
64 | });
65 |
66 | var mapView = new woosmap.TiledView(map, {style: markersStyle, tileStyle: tilesStyle});
67 | mapView.bindTo('stores', tableview, 'stores', false);
68 | mapView.bindTo('selectedStore', tableview, 'selectedStore', false);
69 | mapView.bindTo('location', geocoder);
70 | mapView.delegate = {
71 | 'didLocationMarkerDragEnd': function () {
72 | searchview.$searchInput.val('');
73 | }
74 | };
75 |
76 | registerDraggableMarker(mapView);
77 |
78 | searchview.delegate = {
79 | didClearSearch: function () {
80 | tableview.set('stores', defaultStores);
81 | mapView.set('selectedStore', null);
82 | mapView.set('location', {})
83 | }
84 | };
85 |
86 | });
87 |
88 | }
89 |
90 | document.addEventListener("DOMContentLoaded", function (event) {
91 | WoosmapLoader.load('latest', projectKey, woosmap_main);
92 | });
--------------------------------------------------------------------------------
/jsfiddle-samples/search-places/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/search-places/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-places/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 500px;
3 | }
4 |
5 | .locator-container {
6 | font-size: 15px;
7 | line-height: 1.5em;
8 | color: #555;
9 | background: #FFF;
10 | }
11 |
12 | .sidebar {
13 | height: 500px;
14 | overflow: hidden;
15 | border: 1px solid #EEE;
16 | border-right: none;
17 | }
18 |
19 | .listings {
20 | height: 460px;
21 | padding-bottom: 36px;
22 | background-color: #FFF;
23 | color: #555;
24 | }
25 |
26 | .woosmap-tableview-container, .card_container {
27 | max-height: 100%;
28 | overflow-y: scroll;
29 | overflow-x: hidden;
30 | }
31 |
32 | .item {
33 | display: block;
34 | border-bottom: 1px solid #eee;
35 | padding: 10px;
36 | text-decoration: none;
37 | cursor: pointer;
38 | }
39 |
40 | .item .title {
41 | display: block;
42 | color: #4d9da9;
43 | font-weight: 500;
44 | }
45 |
46 | .item .title small {
47 | font-weight: 300;
48 | }
49 |
50 | .quiet {
51 | color: #888;
52 | }
53 |
54 | small {
55 | font-size: 80%;
56 | }
57 |
58 | .selected_card .item .title,
59 | .item .title:hover {
60 | color: #1badee;
61 | }
62 |
63 | .item.active {
64 | background-color: #f8f8f8;
65 | }
66 |
67 | .selected_card {
68 | background-color: #f8f8f8;
69 | }
70 |
71 | .selected_card:hover {
72 | background-color: #f8f8f8;
73 | }
74 |
75 | .search_container {
76 | margin: 5px;
77 | border: 1px solid #1badee;
78 | border-radius: 2px;
79 | box-sizing: border-box;
80 | -moz-box-sizing: border-box;
81 | height: 32px;
82 | outline: none;
83 | padding: 0 7px;
84 | width: 96%;
85 | vertical-align: top;
86 | position: relative;
87 | }
88 |
89 | .search_input {
90 | border: none;
91 | padding: 0;
92 | height: 1.25em;
93 | width: 100%;
94 | z-index: 6;
95 | outline: none;
96 | background: #FFF;
97 | margin-top: 7px;
98 | float: left;
99 | font-size: 1em;
100 | color: #555;
101 | }
102 |
103 | .search_clear {
104 | float: right;
105 | background: white url('https://developers.woosmap.com/img/close.png') no-repeat left top;
106 | position: absolute;
107 | right: 5px;
108 | top: 8px;
109 | padding: 7px;
110 | font-size: 14px;
111 | cursor: pointer;
112 | display: none;
113 | }
114 |
115 | .search_clear:hover {
116 | background: white url('https://developers.woosmap.com/img/close-hover.png') no-repeat left top;
117 | }
118 |
119 | .woosmap-tableview-highlighted-cell {
120 | background-color: #f8f8f8;
121 | }
122 |
123 | ::-webkit-scrollbar {
124 | width: 5px;
125 | height: 5px;
126 | }
127 |
128 | ::-webkit-scrollbar-thumb {
129 | background-color: #d1d1d1;
130 | }
131 |
132 | ::-webkit-scrollbar-track {
133 | background-color: #F7F7F7;
134 | }
135 |
136 | /*grids*/
137 | .pure-g {
138 | letter-spacing: -.31em;
139 | text-rendering: optimizespeed;
140 | display: -webkit-flex;
141 | -webkit-flex-flow: row wrap;
142 | display: -ms-flexbox;
143 | -ms-flex-flow: row wrap;
144 | -ms-align-content: flex-start;
145 | -webkit-align-content: flex-start;
146 | align-content: flex-start;
147 | }
148 |
149 | .pure-g [class *="pure-u"] {
150 | font-family: "Open Sans", "Helvetica Neue", Arial, Helvetica, Verdana, sans-serif;
151 | font-weight: normal;
152 | letter-spacing: 0.01em;
153 | }
154 |
155 | .pure-u-1, .u-sm-1-3, .u-sm-2-3 {
156 | display: inline-block;
157 | zoom: 1;
158 | letter-spacing: normal;
159 | word-spacing: normal;
160 | vertical-align: top;
161 | text-rendering: auto;
162 | }
163 |
164 | .pure-u-1 {
165 | width: 100%;
166 | }
167 |
168 | @media screen and (min-width: 35.5em) {
169 | .u-sm-1-3 {
170 | width: 33.3333%;
171 | }
172 |
173 | .u-sm-2-3 {
174 | width: 66.5%;
175 | }
176 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/search-places/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: SearchPlaces - Woosmap Javascript API Search Places Demo
3 | description: jsFiddle demo that allow the use of Google maps Autocomplete using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/search-places/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-places/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [{
4 | type: 'drive',
5 | icon: {
6 | url: 'https://images.woosmap.com/marker_drive.svg',
7 | scaledSize: {
8 | width: 36,
9 | height: 48
10 | }
11 | },
12 | selectedIcon: {
13 | url: 'https://images.woosmap.com/marker_drive_selected.svg',
14 | scaledSize: {
15 | width: 46,
16 | height: 60
17 | }
18 | }
19 | }],
20 | default: {
21 | icon: {
22 | url: 'https://images.woosmap.com/marker_default.svg',
23 | scaledSize: {
24 | width: 36,
25 | height: 48
26 | }
27 | },
28 | selectedIcon: {
29 | url: 'https://images.woosmap.com/marker_selected.svg',
30 | scaledSize: {
31 | width: 46,
32 | height: 60
33 | }
34 | }
35 | }
36 | };
37 | var tilesStyle = {
38 | color: '#383838',
39 | size: 11,
40 | minSize: 6,
41 | typeRules: [{
42 | type: 'drive',
43 | color: '#82a859'
44 | }]
45 | };
46 |
47 | function registerDraggableMarker(mapView) {
48 | mapView.marker.setOptions({
49 | draggable: true,
50 | icon: {url: 'https://developers.woosmap.com/img/markers/geolocated.png'}
51 | });
52 | }
53 |
54 | /*----- Init and display a Map with a TiledLayer-----*/
55 | function woosmap_main() {
56 | var self = this;
57 | var loader = new woosmap.MapsLoader("", ['places']);
58 | var dataSource = new woosmap.DataSource();
59 | loader.load(function () {
60 |
61 | var searchBounds = new google.maps.LatLngBounds(
62 | new google.maps.LatLng(-5, 42),
63 | new google.maps.LatLng(9, 52)
64 | );
65 | var googlePlaceAutocompleteOptions = {
66 | bounds: searchBounds,
67 | types: ['geocode'],
68 | componentRestrictions: {country: 'fr'}
69 | };
70 | var tableview = new woosmap.ui.TableView({
71 | cell_store: '',
74 | cell_place: ''
75 | });
76 | var searchview = new woosmap.ui.SearchView(woosmap.$('#search_template').text());
77 | var nearbyStoresSource = new woosmap.location.NearbyStoresSource(dataSource, 5);
78 | var placesSearchSource = new woosmap.location.PlacesSearchSource(googlePlaceAutocompleteOptions);
79 |
80 | tableview.bindTo('stores', nearbyStoresSource);
81 | tableview.bindTo('predictions', placesSearchSource);
82 |
83 | placesSearchSource.bindTo('autocomplete_query', searchview, false);
84 |
85 | var listings = woosmap.$('#listings');
86 | var sidebar = woosmap.$('.sidebar');
87 |
88 | sidebar.prepend(searchview.getContainer());
89 | listings.append(tableview.getContainer());
90 |
91 | self.tableview = tableview;
92 |
93 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
94 | center: {lat: 46, lng: 3},
95 | zoom: 5
96 | });
97 |
98 | var mapView = new woosmap.TiledView(map, {style: markersStyle, tileStyle: tilesStyle});
99 | tableview.bindTo('location', mapView);
100 | nearbyStoresSource.bindTo('location', mapView);
101 | mapView.bindTo('stores', tableview, 'stores', false);
102 | mapView.bindTo('selectedStore', tableview, 'selectedStore', false);
103 |
104 | mapView.marker.setOptions({
105 | draggable: true
106 | });
107 | searchview.delegate = {
108 | didClearSearch: function () {
109 | tableview.set('stores', []);
110 | tableview.set('predictions', []);
111 | mapView.set('selectedStore', null);
112 | mapView.set('location', {})
113 | }
114 | };
115 |
116 | registerDraggableMarker(mapView);
117 | });
118 |
119 | }
120 |
121 | document.addEventListener("DOMContentLoaded", function (event) {
122 | WoosmapLoader.load('1.2', projectKey, woosmap_main);
123 | });
--------------------------------------------------------------------------------
/jsfiddle-samples/search-query/README.MD:
--------------------------------------------------------------------------------
1 |
2 | In order to view this demo on JSFiddle, open this URL:
3 | https://fiddle.jshell.net/gh/get/library/pure/woosmap/samples/tree/master/jsfiddle-samples/search-query/
4 |
5 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-query/demo.css:
--------------------------------------------------------------------------------
1 | #my-map {
2 | height: 600px;
3 | }
4 |
5 | .locator-container {
6 | font-size: 15px;
7 | line-height: 1.5em;
8 | color: #555;
9 | background: #FFF;
10 | }
11 |
12 | .sidebar {
13 | height: 600px;
14 | overflow: hidden;
15 | border: 1px solid #EEE;
16 | border-right: none;
17 | }
18 |
19 | .listings {
20 |
21 | padding-bottom: 36px;
22 | background-color: #FFF;
23 | color: #555;
24 | }
25 |
26 | .woosmap-tableview-container, .card_container {
27 | max-height: 100%;
28 | overflow-y: scroll;
29 | overflow-x: hidden;
30 | }
31 |
32 | .item {
33 | display: block;
34 | border-bottom: 1px solid #eee;
35 | padding: 10px;
36 | text-decoration: none;
37 | cursor: pointer;
38 | }
39 |
40 | .item .title {
41 | display: block;
42 | color: #4d9da9;
43 | font-weight: 500;
44 | }
45 |
46 | .item .title small {
47 | font-weight: 300;
48 | }
49 |
50 | .quiet {
51 | color: #888;
52 | }
53 |
54 | small {
55 | font-size: 80%;
56 | }
57 |
58 | .selected_card .item .title,
59 | .item .title:hover {
60 | color: #1badee;
61 | }
62 |
63 | .item.active {
64 | background-color: #f8f8f8;
65 | }
66 |
67 | .selected_card {
68 | background-color: #f8f8f8;
69 | }
70 |
71 | .selected_card:hover {
72 | background-color: #f8f8f8;
73 | }
74 |
75 | .search_container {
76 | margin: 5px;
77 | border: 1px solid #1badee;
78 | border-radius: 2px;
79 | box-sizing: border-box;
80 | -moz-box-sizing: border-box;
81 | height: 32px;
82 | outline: none;
83 | padding: 0 7px;
84 | width: 96%;
85 | vertical-align: top;
86 | position: relative;
87 | }
88 |
89 | .search_input {
90 | border: none;
91 | padding: 0;
92 | height: 1.25em;
93 | width: 100%;
94 | z-index: 6;
95 | outline: none;
96 | background: #FFF;
97 | margin-top: 7px;
98 | float: left;
99 | font-size: 1em;
100 | color: #555;
101 | }
102 |
103 | .search_clear {
104 | float: right;
105 | background: white url('https://developers.woosmap.com/img/close.png') no-repeat left top;
106 | position: absolute;
107 | right: 5px;
108 | top: 8px;
109 | padding: 7px;
110 | font-size: 14px;
111 | cursor: pointer;
112 | display: none;
113 | }
114 |
115 | .search_clear:hover {
116 | background: white url('https://developers.woosmap.com/img/close-hover.png') no-repeat left top;
117 | }
118 |
119 | .woosmap-tableview-highlighted-cell {
120 | background-color: #f8f8f8;
121 | }
122 |
123 | ::-webkit-scrollbar {
124 | width: 5px;
125 | height: 5px;
126 | }
127 |
128 | ::-webkit-scrollbar-thumb {
129 | background-color: #d1d1d1;
130 | }
131 |
132 | ::-webkit-scrollbar-track {
133 | background-color: #F7F7F7;
134 | }
135 |
136 | /* attribute search page */
137 |
138 | .attributes-search-container {
139 | border-bottom: solid 1px #eee;
140 |
141 | }
142 |
143 | .attribute-filter-container {
144 | margin: 5px;
145 | border: 1px solid rgba(27, 173, 238, 0.29);
146 | }
147 |
148 | .attribute-filter-container:hover {
149 | margin: 5px;
150 | border: 1px solid #1badee;
151 | }
152 |
153 | .attribute-filter-title {
154 | cursor: pointer;
155 | text-align: center;
156 | }
157 |
158 | .attribute-filter-title.active {
159 | border-bottom: solid 1px #eee;
160 | }
161 |
162 | .attribute-filter-body {
163 | margin-left: 5px;
164 | }
165 |
166 | .checkbox-input-attribute {
167 | margin-right: 5px;
168 | }
169 |
170 | .search-attributes-listings {
171 | height: 320px;
172 | padding-bottom: 36px;
173 | }
174 |
175 | .woosmap-tableview-highlighted-cell .title {
176 | color: #1badee;
177 | }
178 |
179 | .woosmap-tableview-selected-cell {
180 | color: #1badee;
181 | background-color: rgba(235, 235, 235, 0.29);
182 | }
183 |
184 | /*grids*/
185 | .pure-g {
186 | letter-spacing: -.31em;
187 | text-rendering: optimizespeed;
188 | display: -webkit-flex;
189 | -webkit-flex-flow: row wrap;
190 | display: -ms-flexbox;
191 | -ms-flex-flow: row wrap;
192 | -ms-align-content: flex-start;
193 | -webkit-align-content: flex-start;
194 | align-content: flex-start;
195 | }
196 |
197 | .pure-g [class *="pure-u"] {
198 | font-family: "Open Sans", "Helvetica Neue", Arial, Helvetica, Verdana, sans-serif;
199 | font-weight: normal;
200 | letter-spacing: 0.01em;
201 | }
202 |
203 | .pure-u-1, .u-sm-1-3, .u-sm-2-3 {
204 | display: inline-block;
205 | zoom: 1;
206 | letter-spacing: normal;
207 | word-spacing: normal;
208 | vertical-align: top;
209 | text-rendering: auto;
210 | }
211 |
212 | .pure-u-1 {
213 | width: 100%;
214 | }
215 |
216 | @media screen and (min-width: 35.5em) {
217 | .u-sm-1-3 {
218 | width: 33.3333%;
219 | }
220 |
221 | .u-sm-2-3 {
222 | width: 66.5%;
223 | }
224 | }
--------------------------------------------------------------------------------
/jsfiddle-samples/search-query/demo.details:
--------------------------------------------------------------------------------
1 | ---
2 | name: SearchAttributes - Woosmap Javascript API Search Attributes Demo
3 | description: jsFiddle demo that allow you to search the data attributes using Woosmap Javascript API.
4 | authors:
5 | - Woosmap DevTeam
6 | ...
--------------------------------------------------------------------------------
/jsfiddle-samples/search-query/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
26 |
41 |
53 |
54 |
60 |
61 |
--------------------------------------------------------------------------------
/jsfiddle-samples/search-query/demo.js:
--------------------------------------------------------------------------------
1 | var projectKey = '12345678';
2 | var markersStyle = {
3 | rules: [
4 | {
5 | type: 'drive',
6 | icon: {url: 'https://images.woosmap.com/marker_drive.svg', scaledSize: {width: 36, height: 48}},
7 | selectedIcon: {url: 'https://images.woosmap.com/marker_drive_selected.svg', scaledSize: {width: 46, height: 60}}
8 | }
9 | ],
10 | default: {
11 | icon: {url: 'https://dimages.woosmap.com/marker_default.svg', scaledSize: {width: 36, height: 48}},
12 | selectedIcon: {url: 'https://images.woosmap.com/marker_selected.svg', scaledSize: {width: 46, height: 60}}
13 | }
14 | };
15 | var tilesStyle = {
16 | color: '#383838',
17 | size: 11,
18 | minSize: 6,
19 | typeRules: [{
20 | type: 'drive',
21 | color: '#82a859'
22 | }]
23 | };
24 |
25 | function registerDraggableMarker(mapView) {
26 | mapView.marker.setOptions({
27 | draggable: true,
28 | icon: {
29 | url: 'https://developers.woosmap.com/img/markers/geolocated.png'
30 | }
31 | });
32 | }
33 |
34 | /*----- Init and display a Map with a TiledLayer-----*/
35 | function woosmap_main() {
36 | var self = this;
37 | var loader = new woosmap.MapsLoader("", ['places']);
38 | var dataSource = new woosmap.DataSource();
39 | loader.load(function () {
40 |
41 | var map = new google.maps.Map(woosmap.$('#my-map')[0], {
42 | center: {
43 | lat: 46,
44 | lng: 3
45 | },
46 | zoom: 5
47 | });
48 |
49 | var mapView = new woosmap.TiledView(map, {
50 | style: markersStyle,
51 | tileStyle: tilesStyle
52 | });
53 |
54 | var searchview = new woosmap.ui.SearchView(woosmap.$('#search_template').text());
55 |
56 | var initialSearchTextOptions = {
57 | name: woosmap.search.SearchQuery.OR,
58 | city: woosmap.search.SearchQuery.OR
59 | };
60 | var searchQuery = new woosmap.search.SearchQuery(initialSearchTextOptions);
61 |
62 | var searchTextOptionsRenderer = new woosmap.TemplateRenderer(woosmap.$("#text-search-options-template").html());
63 | var tagsRenderer = new woosmap.TemplateRenderer(woosmap.$("#tags-selector-template").html());
64 | var typesRenderer = new woosmap.TemplateRenderer(woosmap.$("#types-selector-template").html());
65 | var attributeSearchContainer = woosmap.$('');
66 | attributeSearchContainer.append(searchview.getContainer());
67 | attributeSearchContainer.append(searchTextOptionsRenderer.render());
68 | attributeSearchContainer.append(tagsRenderer.render());
69 | attributeSearchContainer.append(typesRenderer.render());
70 | var sidebar = woosmap.$('.sidebar');
71 | sidebar.prepend(attributeSearchContainer);
72 |
73 | function typeChanged() {
74 | searchQuery.types = [];
75 | woosmap.$.each(woosmap.$('.woosmap-available-type:checked'), function (index, object) {
76 | searchQuery.addTypeFilter(woosmap.$(object).val(), woosmap.search.SearchQuery.AND);
77 | });
78 | mapView.setSearchQuery(searchQuery);
79 | }
80 |
81 | function tagChanged() {
82 | searchQuery.tags = [];
83 | woosmap.$.each(woosmap.$('.woosmap-available-tag:checked'), function (index, object) {
84 | searchQuery.addTagFilter(woosmap.$(object).val(), woosmap.search.SearchQuery.AND);
85 | });
86 | mapView.setSearchQuery(searchQuery);
87 | }
88 |
89 | woosmap.$('.woosmap-available-tag').click(function () {
90 | tagChanged();
91 | });
92 |
93 | woosmap.$('.woosmap-available-type').click(function () {
94 | typeChanged();
95 | });
96 |
97 | woosmap.$('.woosmap-text-search-param').click(function () {
98 | if (this.checked) {
99 | searchQuery.addQueryOption(woosmap.$(this).val(), woosmap.search.SearchQuery.OR)
100 | } else {
101 | searchQuery.removeQueryOption(woosmap.$(this).val())
102 | }
103 | mapView.setSearchQuery(searchQuery);
104 | });
105 |
106 | woosmap.$('.search_input').on("change paste keyup", function () {
107 | searchQuery.setQuery(woosmap.$(this).val());
108 | mapView.setSearchQuery(searchQuery);
109 | });
110 |
111 | searchview.delegate = {
112 | didClearSearch: function () {
113 | searchQuery.setQuery('');
114 | mapView.setSearchQuery(searchQuery);
115 | }
116 | };
117 | });
118 |
119 | }
120 |
121 | document.addEventListener("DOMContentLoaded", function (event) {
122 | WoosmapLoader.load('1.2', projectKey, woosmap_main);
123 | });
124 |
125 |
--------------------------------------------------------------------------------
/python-samples/batchgeocoding/README.md:
--------------------------------------------------------------------------------
1 | **[UPDATE 31/01/2020]**
2 | The script has moved to a dedicated repository, [woosmap/geopy-googlemaps-batchgeocoder](https://github.com/woosmap/geopy-googlemaps-batchgeocoder), and updated to be compatible with Python3.
3 | ---
4 |
5 | # Python Script to batch geocode your csv address file using geopy and GoogleV3 Geocoding service
6 |
7 | **input** : csv file with addresses you need to geocode
8 |
9 | **output** : same csv with appended following fields
10 |
11 | - Latitude
12 | - Longitude
13 | - Location_Type
14 | - Formatted_Address
15 | - Error (if needded, for failed geocoded addresses)
16 |
17 | sample usage:
18 |
19 | python google_batch_geocoder.py
20 |
21 |
22 | **Mandatory parameters you have to set inside the python file**
23 |
24 | - ADDRESS_COLUMNS_NAME = ["name", "addressline1", "town"]
25 | *used to set a google geocoding query by merging this value into one string with comma separated. it depends on your CSV Input File*
26 |
27 | - NEW_COLUMNS_NAME = ["Lat", "Long", "Error", "formatted_address", "location_type"]
28 | *appended columns name to processed data csv*
29 |
30 | - DELIMITER = ";"
31 | *delimiter for input csv file*
32 |
33 | - INPUT_CSV_FILE = "./hairdresser_sample_addresses_sample.csv"
34 | *path and name for output csv file*
35 |
36 | - OUTPUT_CSV_FILE = "./processed.csv"
37 | *path and name for output csv file*
38 |
39 | **optional parameters**
40 |
41 | - COMPONENTS_RESTRICTIONS_COLUMNS_NAME = {"country": "IsoCode"}
42 | *used to define component restrictions for google geocoding*
43 | *see [Google componentRestrictions doc](https://developers.google.com/maps/documentation/javascript/reference?hl=FR#GeocoderComponentRestrictions) for details*
44 |
45 | - GOOGLE_SECRET_KEY = "1Asfgsdf5vR12XE1A6sfRd7="
46 | *google secret key that allow you to geocode for Google API Premium accounts*
47 |
48 | - GOOGLE_CLIENT_ID = "gme-webgeoservicessa1"
49 | *google client ID, used to track and analyse your requests for Google API Premium accounts*
50 |
51 |
52 |
53 | **useful links**
54 |
55 | - [geopy](https://github.com/geopy/geopy) : Geocoding library for Python.
56 | - [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/start)
57 | - [Google Maps Geocoding API Usage Limits](https://developers.google.com/maps/documentation/geocoding/usage-limits)
58 |
--------------------------------------------------------------------------------
/python-samples/batchgeocoding/google_batch_geocoder.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import os
3 | import time
4 | from _csv import QUOTE_MINIMAL
5 | from csv import Dialect
6 | from geopy.geocoders import GoogleV3
7 | from geopy.exc import (
8 | GeocoderQueryError,
9 | GeocoderQuotaExceeded,
10 | ConfigurationError,
11 | GeocoderParseError,
12 | GeocoderTimedOut
13 | )
14 |
15 | # used to set a google geocoding query by merging this value into one string with comma separated
16 | ADDRESS_COLUMNS_NAME = ["name", "addressline1", "town"]
17 |
18 | # used to define component restrictions for google geocoding
19 | COMPONENT_RESTRICTIONS_COLUMNS_NAME = {"country": "IsoCode"}
20 |
21 | # appended columns name to processed data csv
22 | NEW_COLUMNS_NAME = ["Lat", "Long", "Error", "formatted_address", "location_type"]
23 |
24 | # delimiter for input csv file
25 | DELIMITER = ";"
26 |
27 | # Automatically retry X times when GeocoderErrors occur (sometimes the API Service return intermittent failures).
28 | RETRY_COUNTER_CONST = 5
29 |
30 | dir = os.path.dirname(__file__)
31 |
32 | # path and name for output csv file
33 | INPUT_CSV_FILE = os.path.join(dir, "hairdresser_sample_addresses.csv")
34 |
35 | # path and name for output csv file
36 | OUTPUT_CSV_FILE = os.path.join(dir, "processed.csv")
37 |
38 | # google keys - see https://blog.woosmap.com for more details
39 | GOOGLE_SECRET_KEY = "" # important !! this key must stay private. TODO : pass this variable as a parameter to script
40 | GOOGLE_CLIENT_ID = "" # Only for Premium users so if used, you must also provide secret_key
41 | GOOGLE_API_KEY = "" # it will become a mandatory parameter soon
42 |
43 |
44 | # dialect to manage different format of CSV
45 | class CustomDialect(Dialect):
46 | delimiter = DELIMITER
47 | quotechar = '"'
48 | doublequote = True
49 | skipinitialspace = False
50 | lineterminator = '\n'
51 | quoting = QUOTE_MINIMAL
52 |
53 |
54 | csv.register_dialect('ga', CustomDialect)
55 |
56 |
57 | def process_addresses_from_csv():
58 | geo_locator = GoogleV3(api_key=GOOGLE_API_KEY,
59 | client_id=GOOGLE_CLIENT_ID,
60 | secret_key=GOOGLE_SECRET_KEY)
61 |
62 | with open(INPUT_CSV_FILE, 'r') as csvinput:
63 | with open(OUTPUT_CSV_FILE, 'w') as csvoutput:
64 |
65 | # new csv based on same dialect as input csv
66 | writer = csv.writer(csvoutput, dialect="ga")
67 |
68 | reader = csv.DictReader(csvinput, dialect="ga")
69 |
70 | # 2-dimensional data variable used to write the new CSV
71 | processed_data = []
72 |
73 | # append new columns, to receive geocoded information, to the header of the new CSV
74 | header = list(reader.fieldnames)
75 | for column_name in NEW_COLUMNS_NAME:
76 | header.append(column_name.strip())
77 | processed_data.append(header)
78 |
79 | # iterate through each row of input CSV
80 | for record in reader:
81 | # build a line address based on the merge of multiple field values to pass to Google Geocoder
82 | line_address = ','.join(
83 | str(val) for val in (record[column_name] for column_name in ADDRESS_COLUMNS_NAME))
84 |
85 | # if you want to use componentRestrictions feature,
86 | # build a matching dict {'googleComponentRestrictionField' : 'yourCSVFieldValue'}
87 | # to pass to Google Geocoder
88 | component_restrictions = {}
89 | if COMPONENT_RESTRICTIONS_COLUMNS_NAME:
90 | for key, value in COMPONENT_RESTRICTIONS_COLUMNS_NAME.items():
91 | component_restrictions[key] = record[value]
92 |
93 | # geocode the built line_address and passing optional componentRestrictions
94 | location = geocode_address(geo_locator, line_address, component_restrictions)
95 |
96 | # build a new temp_row for each csv entry to append to process_data Array
97 | # first, append existing fieldnames value to this temp_row
98 | temp_row = [record[column_name] for column_name in reader.fieldnames]
99 |
100 | # then, append geocoded field value to this temp_row
101 | for column_name in NEW_COLUMNS_NAME:
102 | try:
103 | if isinstance(location[column_name], str):
104 | temp_row.append(location[column_name].encode('utf-8'))
105 | else:
106 | temp_row.append(location[column_name])
107 | except BaseException as error:
108 | print(error)
109 | temp_row.append('')
110 |
111 | # to manage more precisely errors, you could use csvwriter.writerow(item)
112 | # instead of build the processed_data array
113 | processed_data.append(temp_row)
114 |
115 | try:
116 | # finally write all rows once a time to the output CSV.
117 | writer.writerows(processed_data)
118 | except BaseException as error:
119 | print(error)
120 |
121 |
122 | def geocode_address(geo_locator, line_address, component_restrictions=None, retry_counter=0):
123 | try:
124 | # if not using Google Map API For Work (Standard instead of Premium) you will raise an OVER_QUERY_LIMIT
125 | # due to the quotas request per seconds. So we have to sleep 500 ms between each request to Geocoding Service.
126 | if not GOOGLE_SECRET_KEY:
127 | time.sleep(0.5)
128 |
129 | # the geopy GoogleV3 geocoding call
130 | location = geo_locator.geocode(line_address, components=component_restrictions)
131 |
132 | if location is not None:
133 | # build a dict to append to output CSV
134 | location_result = {"Lat": location.latitude, "Long": location.longitude, "Error": "",
135 | "formatted_address": location.raw['formatted_address'],
136 | "location_type": location.raw['geometry']['location_type']}
137 | else:
138 | raise ValueError("None location found, please verify your address line")
139 |
140 | # To catch generic geocoder errors. TODO : Handle finer-grained exceptions
141 | except (ValueError, GeocoderQuotaExceeded, ConfigurationError, GeocoderParseError) as error:
142 | location_result = {"Lat": 0, "Long": 0, "Error": error.message, "formatted_address": "", "location_type": ""}
143 |
144 | # To retry because intermittent failures sometimes occurs
145 | except (GeocoderQueryError, GeocoderTimedOut) as error:
146 | if retry_counter < RETRY_COUNTER_CONST:
147 | return geocode_address(geo_locator, line_address, component_restrictions, retry_counter + 1)
148 | else:
149 | location_result = {"Lat": 0, "Long": 0, "Error": error.message, "formatted_address": "",
150 | "location_type": ""}
151 |
152 | print("address line : %s" % line_address)
153 | print("geocoded address : %s" % location_result["formatted_address"])
154 | print("location type : %s" % location_result["location_type"])
155 |
156 | return location_result
157 |
158 |
159 | if __name__ == '__main__':
160 | process_addresses_from_csv()
161 |
--------------------------------------------------------------------------------
/python-samples/batchgeocoding/hairdresser_sample_addresses.csv:
--------------------------------------------------------------------------------
1 | country;name;enabled;addressline1;town;postalcode;IsoCode
2 | "AU";"Hairhouse Warehouse - Ipswich";"1";"Shop 28 Riverlink Shopping centre";"Ipswich";"4305";"AU"
3 | "AU";"Room For Hair";"0";"20 Jull Street";"ARMADALE";"6112";"AU"
4 | "AU";"D'luxe Hair & Beauty";"0";"Shop 4 Lot 6 Burra PlaceShellharbour City Plaza";"Shellharbour";"2529";"AU"
5 | "AU";"Complete Hair & Passion";"1";"Shop 10";"Cabramatta";"2166";"AU"
6 | "AU";"Kink The Art Of Hair - Orange - Closed";"0";"167 Summer Street";"Orange";"2800";"AU"
7 | "AU";"Bernadette Missen NLU - Closed";"0";"2B Raymond Street";"APPLECROSS";"6153";"AU"
8 | "AU";"Hairess - Closed";"0";"Murdoch University";"MURDOCH";"6150";"AU"
9 | "AU";"Rubi Hair Richmond - Closed";"0";"234 Swan St";"Richmond";"3121";"AU"
10 | "AU";"Hon Hair Studio";"0";"Shop 21/101-103 John street";"Cabramatta";"2166";"AU"
11 | "AU";"Kepnock Hair";"1";"Shop 7";"Bundaberg";"4670";"AU"
12 | "AU";"Nova Hair & Body";"1";"7 Walker Street";"MOUNT BARKER";"5251";"AU"
13 | "AU";"One Hair & Beauty";"1";"29 Wharf Street";"Forster";"2428";"AU"
14 | "AU";"Hairhouse Warehouse - Rosny - Closed";"0";"Shop U002";"Rosny";"7018";"AU"
15 | "AU";"Bliss Hair and Beauty";"0";"298 Bayliss Rd";"Heritage Park";"4118";"AU"
16 | "AU";"Volona & Associates - Ocean Keys";"0";"Shop 46 Ocean Keys Shopping Centre";"CLARKSON";"6030";"AU"
17 | "AU";"Glambox Hair Studio";"1";"Shop 5 226 Shute Harbour Road";"Cannonvale";"4802";"AU"
18 | "AU";"To Dye For Hair and Beauty";"0";"322 Brookfield Ave";"Broken Hill";"2880";"AU"
19 | "AU";"EV Hair & Beauty - Marrickville";"1";"Shop 82";"Marrickville";"2204";"AU"
20 | "ZA";"Nicci Phillips Hairdressing cc";"1";"23 Long Street";"Knysna";"6571";"ZA"
21 |
--------------------------------------------------------------------------------
/python-samples/batchgeocoding_woosmap_localities/woosmap_localities_batch_geocoder.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import os
3 | import requests
4 | from _csv import QUOTE_MINIMAL
5 | from csv import Dialect
6 |
7 | # used to set a google geocoding query by merging this value into one string with comma separated
8 | ADDRESS_COLUMNS_NAME = ["name", "AddressLine1", "AddressLine2", "AddressLine3", "City", "Postcode"]
9 |
10 | # used to define component restrictions for google geocoding
11 | COMPONENT_RESTRICTIONS_COLUMNS_NAME = {}
12 |
13 | # appended columns name to processed data csv
14 | NEW_COLUMNS_NAME = ["Lat", "Long", "Error", "formatted_address", "location_type"]
15 |
16 | # delimiter for input csv file
17 | DELIMITER = ","
18 |
19 | # Automatically retry X times when GeocoderErrors occur (sometimes the API Service return intermittent failures).
20 | RETRY_COUNTER_CONST = 5
21 |
22 | dir = os.path.dirname(__file__)
23 |
24 | # path and name for output csv file
25 | INPUT_CSV_FILE = os.path.join(dir, "input1.csv")
26 |
27 | # path and name for output csv file
28 | OUTPUT_CSV_FILE = os.path.join(dir, "processed_test.csv")
29 |
30 | # Add your Woosmap Private Key here
31 | WOOSMAP_PRIVATE_API_KEY = "XXXX"
32 |
33 |
34 | # dialect to manage different format of CSV
35 | class CustomDialect(Dialect):
36 | delimiter = DELIMITER
37 | quotechar = '"'
38 | doublequote = True
39 | skipinitialspace = False
40 | lineterminator = '\n'
41 | quoting = QUOTE_MINIMAL
42 |
43 |
44 | csv.register_dialect('ga', CustomDialect)
45 |
46 |
47 | class WoosmapLocalities:
48 | """A wrapper around the Woosmap Localities API."""
49 |
50 | WOOSMAP_API_HOSTNAME = 'api.woosmap.com'
51 |
52 | def __init__(self):
53 | self.session = requests.Session()
54 |
55 | def get_details(self, public_id):
56 | return self.session.get(
57 | 'https://{hostname}/localities/details/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
58 | params={'private_key': WOOSMAP_PRIVATE_API_KEY,
59 | 'public_id': public_id}).json()
60 |
61 | def autocomplete(self, text_input):
62 | return self.session.get(
63 | 'https://{hostname}/localities/autocomplete/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
64 | params={'private_key': WOOSMAP_PRIVATE_API_KEY,
65 | 'input': text_input,
66 | 'types': 'address'}).json()
67 |
68 | def end(self):
69 | self.session.close()
70 |
71 |
72 | def process_addresses_from_csv():
73 | woosmap_localities = WoosmapLocalities()
74 | with open(INPUT_CSV_FILE, 'r') as csvinput:
75 | with open(OUTPUT_CSV_FILE, 'w') as csvoutput:
76 |
77 | # new csv based on same dialect as input csv
78 | writer = csv.writer(csvoutput, dialect="ga")
79 |
80 | # create a proper header with stripped fieldnames for new CSV
81 | # header = [h.strip() for h in next(csvinput).split(DELIMITER)]
82 |
83 | # read Input CSV as Dict of Dict
84 | reader = csv.DictReader(csvinput, dialect="ga")
85 |
86 | # 2-dimensional data variable used to write the new CSV
87 | processed_data = []
88 |
89 | # append new columns, to receive geocoded information, to the header of the new CSV
90 | header = list(reader.fieldnames)
91 | for column_name in NEW_COLUMNS_NAME:
92 | header.append(column_name.strip())
93 | processed_data.append(header)
94 |
95 | # iterate through each row of input CSV
96 | for record in reader:
97 | # build a line address based on the merge of multiple field values to pass to Google Geocoder
98 | line_address = ','.join(
99 | str(val) for val in (record[column_name] for column_name in ADDRESS_COLUMNS_NAME))
100 |
101 | # if you want to use componentRestrictions feature,
102 | # build a matching dict {'googleComponentRestrictionField' : 'yourCSVFieldValue'}
103 | # to pass to Google Geocoder
104 | component_restrictions = {}
105 | if COMPONENT_RESTRICTIONS_COLUMNS_NAME:
106 | for key, value in COMPONENT_RESTRICTIONS_COLUMNS_NAME.items():
107 | component_restrictions[key] = record[value]
108 |
109 | # geocode the built line_address and passing optional componentRestrictions
110 | location = geocode_address(woosmap_localities, line_address, component_restrictions)
111 |
112 | # build a new temp_row for each csv entry to append to process_data Array
113 | # first, append existing fieldnames value to this temp_row
114 | temp_row = [record[column_name] for column_name in reader.fieldnames]
115 |
116 | # then, append geocoded field value to this temp_row
117 | for column_name in NEW_COLUMNS_NAME:
118 | try:
119 | temp_row.append(location[column_name])
120 | except BaseException as error:
121 | print(error)
122 | temp_row.append('')
123 |
124 | # to manage more precisely errors, you could use csvwriter.writerow(item)
125 | # instead of build the processed_data array
126 | processed_data.append(temp_row)
127 |
128 | woosmap_localities.end()
129 |
130 | try:
131 | # finally write all rows once a time to the output CSV.
132 | writer.writerows(processed_data)
133 | except BaseException as error:
134 | print(error)
135 |
136 |
137 | def geocode_address(woosmap_localities, line_address, component_restrictions=None, retry_counter=0):
138 | try:
139 | suggestions = woosmap_localities.autocomplete(line_address)
140 | if suggestions is not None:
141 | location = woosmap_localities.get_details(suggestions['localities'][0].get('public_id', ''))['result']
142 | if location is not None:
143 | location_geom = location.get('geometry')
144 | # build a dict to append to output CSV
145 | location_result = {"Lat": location['geometry']['location']['lat'],
146 | "Long": location['geometry']['location']['lng'],
147 | "Error": "",
148 | "formatted_address": location['formatted_address'],
149 | "location_type": location['geometry']['accuracy']}
150 | else:
151 | raise ValueError("None location found, please verify your address line")
152 |
153 | # To catch generic geocoder errors. TODO : Handle finer-grained exceptions
154 | except (ValueError) as error:
155 | location_result = {"Lat": 0, "Long": 0, "Error": error.message, "formatted_address": "", "location_type": ""}
156 |
157 | print("address line : %s" % line_address)
158 | print("geocoded address : %s" % location_result["formatted_address"])
159 | print("location type : %s" % location_result["location_type"])
160 | print("--------------------------------------------------------")
161 |
162 | return location_result
163 |
164 |
165 | if __name__ == '__main__':
166 | process_addresses_from_csv()
167 |
--------------------------------------------------------------------------------
/python-samples/batchimport/README.md:
--------------------------------------------------------------------------------
1 | # Python Script to batch import your location to Woosmap Database.
2 |
3 | sample usage:
4 |
5 | python batch_import_locations.py
6 |
7 | The sample CSV File represent all the bars in Paris extracted from OpenStreetMap
--------------------------------------------------------------------------------
/python-samples/batchimport/batch_import_locations.py:
--------------------------------------------------------------------------------
1 | import csv
2 | from _csv import QUOTE_ALL
3 | from csv import Dialect
4 | import requests
5 |
6 | endpoint_csv = 'france_museum_geocoded.csv'
7 | private_key = '' #your private key here
8 | endpoint_api = 'http://api.woosmap.com/stores'
9 | stores_batch_size = 100
10 | update_location = False
11 |
12 |
13 | class InvalidGeometry(Exception):
14 | pass
15 |
16 |
17 | def get_geometry(store):
18 | return {
19 | 'lat': store['latitude'],
20 | 'lng': store['longitude']
21 | }
22 |
23 |
24 | def get_contact(store):
25 | return {
26 | 'website': store['SITWEB']
27 | }
28 |
29 |
30 | def get_address(store):
31 | return {
32 | 'lines': [store['ADR']],
33 | 'city': store['VILLE'],
34 | 'zipcode': store['CP'],
35 | }
36 |
37 |
38 | def datagov2woosmap(store, id):
39 | geometry = get_geometry(store)
40 | address = get_address(store)
41 | contact = get_contact(store)
42 | return {
43 | 'storeId': id,
44 | 'name': store['NOM DU MUSEE'],
45 | 'address': address,
46 | 'contact': contact,
47 | 'location': geometry
48 | }
49 |
50 |
51 | class data_gov_dialect(Dialect):
52 | delimiter = ','
53 | quotechar = '"'
54 | doublequote = True
55 | skipinitialspace = False
56 | lineterminator = '\n'
57 | quoting = QUOTE_ALL
58 |
59 |
60 | csv.register_dialect('dg', data_gov_dialect)
61 |
62 |
63 | def import_batch(batch, use_put=False):
64 | print('--> Importing batch (%d) locations' % len(batch))
65 | if use_put:
66 | response = session.put(endpoint_api,
67 | params={'private_key': private_key},
68 | json={'stores': batch})
69 | else:
70 | response = session.post(endpoint_api,
71 | params={'private_key': private_key},
72 | json={'stores': batch})
73 |
74 | print('<-- Total time:', response.elapsed.total_seconds())
75 | if response.status_code >= 400:
76 | print('Failed batch')
77 | print(response.text)
78 | return False
79 |
80 | return True
81 |
82 |
83 | if __name__ == '__main__':
84 | with open(endpoint_csv, 'r') as f:
85 | reader = csv.DictReader(f, dialect="dg")
86 |
87 | failed = []
88 | session = requests.Session()
89 | if not update_location:
90 | response = session.delete(endpoint_api, params={'private_key': private_key})
91 |
92 | if response.status_code >= 400:
93 | print(response.text)
94 | exit(-1)
95 |
96 | batch = []
97 | batch_size = stores_batch_size
98 | id = 0
99 | for location in reader:
100 | id += 1
101 | try:
102 | woosmap_location = datagov2woosmap(location, "ID" + str(id))
103 |
104 | if len(batch) == batch_size:
105 | batch_result = import_batch(batch, use_put=update_location)
106 | batch = []
107 | else:
108 | batch.append(woosmap_location)
109 |
110 | except InvalidGeometry:
111 | pass
112 |
113 | if batch:
114 | batch_result = import_batch(batch, use_put=update_location)
115 | batch = []
116 |
--------------------------------------------------------------------------------
/python-samples/csv_to_woosmap/csv_to_woosmap.py:
--------------------------------------------------------------------------------
1 | import unicodecsv as csv
2 | import json
3 | import os
4 | import time
5 | import requests
6 | from hashlib import sha1
7 |
8 | YOUR_INPUT_CSV_FILE = 'foodmarkets.csv'
9 | WOOSMAP_PRIVATE_API_KEY = '23713926-1af5-4321-ba54-032966f6e95d'
10 | BATCH_SIZE = 5
11 |
12 |
13 | class MyCSVDialect(csv.Dialect):
14 | delimiter = ','
15 | quotechar = '"'
16 | doublequote = True
17 | skipinitialspace = False
18 | lineterminator = '\n'
19 | quoting = csv.QUOTE_ALL
20 |
21 |
22 | class Woosmap:
23 | """A wrapper around the Woosmap Data API."""
24 |
25 | WOOSMAP_API_HOSTNAME = 'api.woosmap.com'
26 |
27 | def __init__(self):
28 | self.session = requests.Session()
29 |
30 | def delete(self):
31 | self.session.delete('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
32 | params={'private_key': WOOSMAP_PRIVATE_API_KEY})
33 |
34 | def post(self, payload):
35 | return self.session.post('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
36 | params={'private_key': WOOSMAP_PRIVATE_API_KEY},
37 | json={'stores': payload})
38 |
39 | def end(self):
40 | self.session.close()
41 |
42 |
43 | def get_name(asset):
44 | name = asset.get('Name', '')
45 | if name:
46 | return name
47 | else:
48 | raise ValueError('Unable to get the Name')
49 |
50 |
51 | def generate_id(asset):
52 | asset_id = sha1(get_name(asset).encode('utf-8')).hexdigest()
53 | return asset_id
54 |
55 |
56 | def get_contact(asset):
57 | return {
58 | 'website': asset.get('Website', ''),
59 | 'phone': asset.get('Contact Phone', ''),
60 | 'email': asset.get('Contact Email', '')
61 | }
62 |
63 |
64 | def get_geometry(asset):
65 | latitude = asset.get('Latitude', None)
66 | longitude = asset.get('Longitude', None)
67 | if latitude is not None and longitude is not None:
68 | return {
69 | 'lat': float(latitude),
70 | 'lng': float(longitude)
71 | }
72 | else:
73 | raise ValueError('Unable to get the location')
74 |
75 |
76 | def get_address(asset):
77 | return {
78 | 'lines': [asset.get('Address Line', '')],
79 | 'city': asset.get('City', ''),
80 | 'zipcode': asset.get('Zipcode', '')
81 | }
82 |
83 |
84 | def convert_to_woosmap(asset):
85 | converted_asset = {}
86 | try:
87 | converted_asset.update({
88 | 'storeId': generate_id(asset),
89 | 'name': get_name(asset),
90 | 'address': get_address(asset),
91 | 'contact': get_contact(asset),
92 | 'location': get_geometry(asset)
93 | })
94 | except ValueError as ve:
95 | print('ValueError Raised {0} for Asset {1}'.format(ve, json.dumps(asset, indent=2)))
96 |
97 | return converted_asset
98 |
99 |
100 | def import_assets(assets_data, woosmap_api_helper):
101 | try:
102 | print('Batch import {count} Assets...'.format(count=len(assets_data)))
103 | response = woosmap_api_helper.post(assets_data)
104 | if response.status_code >= 400:
105 | response.raise_for_status()
106 |
107 | except requests.exceptions.HTTPError as http_exception:
108 | if http_exception.response.status_code >= 400:
109 | print('Woosmap API Import Error: {0}'.format(http_exception.response.text))
110 | else:
111 | print('Error requesting the API: {0}'.format(http_exception))
112 | return False
113 | except Exception as exception:
114 | print('Failed importing Assets! {0}'.format(exception))
115 | return False
116 |
117 | print('Successfully imported in {0} seconds'.format(response.elapsed.total_seconds()))
118 | return True
119 |
120 |
121 | def batch(assets_data, n=1):
122 | l = len(assets_data)
123 | for ndx in range(0, l, n):
124 | yield assets_data[ndx:min(ndx + n, l)]
125 |
126 |
127 | def main():
128 | start = time.time()
129 | print('Start parsing and importing your data...')
130 | with open(file_path, 'rb') as csv_file:
131 | try:
132 | reader = csv.DictReader(csv_file, dialect=MyCSVDialect())
133 | woosmap_assets = []
134 | for asset in reader:
135 | converted_asset = convert_to_woosmap(asset)
136 | if bool(converted_asset):
137 | woosmap_assets.append(converted_asset)
138 |
139 | print('{0} Assets converted from source file'.format(len(woosmap_assets)))
140 |
141 | woosmap_api_helper = Woosmap()
142 | # /!\ deleting existing assets before posting new ones /!\
143 | woosmap_api_helper.delete()
144 |
145 | count_imported_assets = 0
146 | for chunk in batch(woosmap_assets, BATCH_SIZE):
147 | imported_success = import_assets(chunk, woosmap_api_helper)
148 | if imported_success:
149 | count_imported_assets += len(chunk)
150 |
151 | woosmap_api_helper.end()
152 | print("{0} Assets successfully imported".format(count_imported_assets))
153 |
154 | except csv.Error as csv_error:
155 | print('Error in CSV file found: {0}'.format(csv_error))
156 | except Exception as exception:
157 | print("Script Failed! {0}".format(exception))
158 | finally:
159 | end = time.time()
160 | print('...Script ended in {0} seconds'.format(end - start))
161 |
162 |
163 | if __name__ == '__main__':
164 | file_path = os.path.join(os.getcwd(), YOUR_INPUT_CSV_FILE)
165 | if os.path.exists(file_path):
166 | main()
167 | else:
168 | print('File not found: {0} '.format(file_path))
169 |
--------------------------------------------------------------------------------
/python-samples/csv_to_woosmap/foodmarkets.csv:
--------------------------------------------------------------------------------
1 | Type,Latitude,Longitude,Name,Address Line,City,Zipcode,Website,Contact Phone,Contact Email
2 | covered,51.919948,4.486843,Markthal Rotterdam,Dominee Jan Scharpstraat 298,Rotterdam,3011 GZ,http://markthalrotterdam.nl/,+31 (0)30 234 64 64,info@markthalrotterdam.nl
3 | covered,41.877657,12.473909,Testaccio Market,Via Galvani/Via Alessandro Volta,Roma,00118,http://www.mercatotestaccio.com/,+39 06 578 0638,info@mercatotestaccio.ocm
4 | covered,48.199044,16.364234,Naschmarkt Vienna,Via Galvani/Via Alessandro Volta,Vienna,1060,http://www.naschmarkt-vienna.com/,+43 1 240555,contact@naschmarkt-vienna.com
5 | covered,40.415261,-3.708944,Mercado de San Miguel,Plaza de San Miguel,Madrid,28005,http://www.mercadodesanmiguel.es/en,(+34) 915 42 49 36,administracion@mercadodesanmiguel.es
6 | covered,41.381635,2.171596,Mercado de La Boqueria,"La Rambla, 91",Barcelona,08001,http://www.boqueria.info/,+34 933 18 25 84,administracion@mercadodesanmiguel.es
7 | covered,43.695530,7.275492,Cours Saleya,Place Charles Félix,Nice,06300,http://leblogduvieuxnice.nicematin.com/.services/blog/6a0120a864ed46970b0162fd89fc17970d/search?filter.q=marché,,
8 | covered,48.849021,2.377700,Marché d’Aligre,Place d’Aligre,Paris,75012,http://equipement.paris.fr/marche-couvert-beauvau-marche-d-aligre-5480,01 45 11 71 11,
9 | covered,43.776540,11.253133,Mercato Centrale di San Lorenzo,Piazza del Mercato Centrale,Firenze,50123,http://www.mercatocentrale.it,+39 0552399798,info@mercatocentrale.it
10 | covered,55.684025,12.569469,Torvehallerne,Frederiksborggade 21,Copenhagen,1360,http://torvehallernekbh.dk,+39 0552399798,info@torvehallernekbh.dk
11 | covered,51.505046,-0.090679,Borough Market,8 Southwark St,London,SE1 1TL,http://boroughmarket.org.uk,020 7407 1002,
12 | covered,48.135105,11.576246,Victuals Market,Viktualienmarkt 3,München,80881,http://www.muenchen.de/int/en/shopping/markets/viktualienmarkt.html,+49 89 89068205,
13 | covered,43.40214,3.69545,Halles de Sète,Rue Gambetta,Sète,34200,http://www.halles-sete.com/,04 99 04 70 00,commerce-artisanat@ville-sete.fr
14 | outside,44.011821,4.418889,Marché d'Uzès,Place aux Herbes,Uzès,30700,http://www.uzes.fr/Calendrier-des-marches-brocantes-et-foires_a126.html,+33 (0)4 66 22 68 88,
15 | outside,43.876503,5.393588,Le Grand Marché d'Apt,Place de la Bouquerie,Apt,84400,http://www.luberon-apt.fr/index.php/fr/sortir/les-marches,+33 (0)4 90 74 03 18,oti@paysapt-luberon.fr
16 | outside,46.187465,-1.327086,Le Marché de la Flotte,Rue du Marché,La Flotte,17630,http://laflotte.fr/index.php/Vie-quotidienne/les-marches.html,05.46.09.15.00,annie@laflotte.fr
17 | outside,55.947817,-3.203562,Edimburgh Farmers' Market,Castle Terrace,Edimburgh,EH1 UK,http://www.edinburghfarmersmarket.co.uk/,0131 220 8580,
18 | covered,54.596073,-5.921654,St George's Market,12 - 20 East Bridge Street,Belfast,BT1 3NQ,http://www.belfastcity.gov.uk/tourism-venues/stgeorgesmarket/stgeorgesmarket-index.aspx,028 9043 5704,markets@belfastcity.gov.uk
19 | covered,50.626710,3.049325,Halles de Wazemmes,Place de la nouvelle aventure,Lille,59000,http://www.halles-wazemmes.com/,,
20 |
--------------------------------------------------------------------------------
/python-samples/excel_to_woosmap/excel_to_woosmap.py:
--------------------------------------------------------------------------------
1 | from openpyxl import load_workbook
2 | import json
3 | import os
4 | import time
5 | import requests
6 | from hashlib import sha1
7 |
8 | INPUT_EXCEL_FILE = 'foodmarkets.xlsx'
9 | WORKSHEET_NAME = 'foodmarkets'
10 | WOOSMAP_PRIVATE_API_KEY = '23713926-1af5-4321-ba54-032966f6e95d'
11 | BATCH_SIZE = 5
12 |
13 |
14 | class Woosmap:
15 | """A wrapper around the Woosmap Data API."""
16 |
17 | WOOSMAP_API_HOSTNAME = 'api.woosmap.com'
18 |
19 | def __init__(self):
20 | self.session = requests.Session()
21 |
22 | def delete(self):
23 | self.session.delete('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
24 | params={'private_key': WOOSMAP_PRIVATE_API_KEY})
25 |
26 | def post(self, payload):
27 | return self.session.post('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
28 | params={'private_key': WOOSMAP_PRIVATE_API_KEY},
29 | json={'stores': payload})
30 |
31 | def end(self):
32 | self.session.close()
33 |
34 |
35 | class ExcelFile:
36 | """A simple wrapper around the needed openpyxl functions for this script"""
37 |
38 | def __init__(self, filename, worksheet_name=''):
39 | self.filename = filename
40 | self.workbook = load_workbook(self.filename)
41 | self.worksheet_name = worksheet_name if worksheet_name else self.get_first_worksheet_name()
42 | self.worksheet = self.workbook.get_sheet_by_name(self.worksheet_name)
43 |
44 | def get_first_worksheet_name(self):
45 | return self.workbook.get_sheet_names()[0]
46 |
47 | def iter_rows(self):
48 | for row in self.worksheet.iter_rows():
49 | yield [cell.value for cell in row]
50 |
51 |
52 | def get_name(asset):
53 | name = asset.get('Name', '')
54 | if name:
55 | return name
56 | else:
57 | raise ValueError('Unable to get the Name')
58 |
59 |
60 | def generate_id(asset):
61 | asset_id = sha1(get_name(asset).encode('utf-8')).hexdigest()
62 | return asset_id
63 |
64 |
65 | def get_contact(asset):
66 | return {
67 | 'website': asset.get('Website', ''),
68 | 'phone': asset.get('Contact Phone', ''),
69 | 'email': asset.get('Contact Email', '')
70 | }
71 |
72 |
73 | def get_geometry(asset):
74 | latitude = asset.get('Latitude', None)
75 | longitude = asset.get('Longitude', None)
76 | if latitude is not None and longitude is not None:
77 | return {
78 | 'lat': float(latitude),
79 | 'lng': float(longitude)
80 | }
81 | else:
82 | raise ValueError('Unable to get the location')
83 |
84 |
85 | def get_address(asset):
86 | return {
87 | 'lines': [asset.get('Address Line', '')],
88 | 'city': asset.get('City', ''),
89 | 'zipcode': asset.get('Zipcode', '')
90 | }
91 |
92 |
93 | def convert_to_woosmap(asset):
94 | converted_asset = {}
95 | try:
96 | converted_asset.update({
97 | 'storeId': generate_id(asset),
98 | 'name': get_name(asset),
99 | 'address': get_address(asset),
100 | 'contact': get_contact(asset),
101 | 'location': get_geometry(asset)
102 | })
103 | except ValueError as ve:
104 | print('ValueError Raised {0} for Asset {1}'.format(ve, json.dumps(asset, indent=2)))
105 |
106 | return converted_asset
107 |
108 |
109 | def import_assets(assets_data, woosmap_api_helper):
110 | try:
111 | print('Batch import {count} Assets...'.format(count=len(assets_data)))
112 | response = woosmap_api_helper.post(assets_data)
113 | if response.status_code >= 400:
114 | response.raise_for_status()
115 |
116 | except requests.exceptions.HTTPError as http_exception:
117 | if http_exception.response.status_code >= 400:
118 | print('Woosmap API Import Error: {0}'.format(http_exception.response.text))
119 | else:
120 | print('Error requesting the API: {0}'.format(http_exception))
121 | return False
122 | except Exception as exception:
123 | print('Failed importing Assets! {0}'.format(exception))
124 | return False
125 |
126 | print('Successfully imported in {0} seconds'.format(response.elapsed.total_seconds()))
127 | return True
128 |
129 |
130 | def batch(assets_data, n=1):
131 | l = len(assets_data)
132 | for ndx in range(0, l, n):
133 | yield assets_data[ndx:min(ndx + n, l)]
134 |
135 |
136 | def main():
137 | start = time.time()
138 | print('Start parsing and importing your data...')
139 | excel_file = ExcelFile(INPUT_EXCEL_FILE, WORKSHEET_NAME)
140 | sheet_data = list(excel_file.iter_rows())
141 | header = sheet_data.pop(0)
142 | assets_as_dict = [dict(zip(header, item)) for item in sheet_data]
143 |
144 | woosmap_assets = []
145 | for asset in assets_as_dict:
146 | converted_asset = convert_to_woosmap(asset)
147 | if bool(converted_asset):
148 | woosmap_assets.append(converted_asset)
149 |
150 | print('{0} Assets converted from source file'.format(len(woosmap_assets)))
151 |
152 | woosmap_api_helper = Woosmap()
153 | # /!\ deleting existing assets before posting new ones /!\
154 | woosmap_api_helper.delete()
155 |
156 | count_imported_assets = 0
157 | for chunk in batch(woosmap_assets):
158 | imported_success = import_assets(chunk, woosmap_api_helper)
159 | if imported_success:
160 | count_imported_assets += len(chunk)
161 |
162 | woosmap_api_helper.end()
163 |
164 | end = time.time()
165 | print('...Script ended in {0} seconds'.format(end - start))
166 |
167 |
168 | if __name__ == '__main__':
169 | file_path = os.path.join(os.getcwd(), INPUT_EXCEL_FILE)
170 | if os.path.exists(file_path):
171 | main()
172 | else:
173 | print('File not found: {0} '.format(file_path))
174 |
--------------------------------------------------------------------------------
/python-samples/excel_to_woosmap/foodmarkets.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Woosmap/woosmap-samples/dad13508d36ecd85204c9027c4c9848c3b4ed087/python-samples/excel_to_woosmap/foodmarkets.xlsx
--------------------------------------------------------------------------------
/python-samples/googlemybusiness_to_woosmap/googlemybusiness_to_woosmap.py:
--------------------------------------------------------------------------------
1 | import httplib2
2 | import json
3 | import os
4 | import requests
5 |
6 | from apiclient import discovery
7 | from oauth2client.client import flow_from_clientsecrets
8 | from oauth2client.file import Storage
9 | from oauth2client import tools
10 |
11 | from timezonefinder import TimezoneFinder
12 |
13 | tf = TimezoneFinder()
14 |
15 | WOOSMAP_PRIVATE_API_KEY = 'eafb8805-3743-4cb9-abff-xxxxxxxxxxxx'
16 |
17 | GOOGLE_ACCOUNT_NAME = "accounts/123456789101112131415" # The Account Manager
18 | GOOGLE_CREDENTIALS_PATH = "client_secret_xxxxxxx-xxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com.json"
19 |
20 |
21 | class GoogleMyBusiness(object):
22 | """A wrapper around the Google My Business API."""
23 |
24 | API_NAME = 'mybusiness'
25 | API_VERSION = 'v3'
26 | DISCOVERY_URI = 'https://developers.google.com/my-business/samples/{api}_google_rest_{apiVersion}.json'
27 | SCOPE = "https://www.googleapis.com/auth/plus.business.manage"
28 | REDIRECT_URI = 'http://localshot:8080'
29 |
30 | def __init__(self, credentials_path, account_name=''):
31 | self.credentials_path = credentials_path
32 | self.account_name = account_name
33 | self.credentials = self.get_credentials()
34 | self.http = self.credentials.authorize(httplib2.Http())
35 | if self.credentials is not None and self.credentials.access_token_expired:
36 | self.credentials.refresh(self.http)
37 |
38 | self.service = self.build_service()
39 | if not self.account_name:
40 | # If GOOGLE_ACCOUNT_NAME constant is not set, we pick the first in account listing
41 | self.account_name = self.list_accounts()['accounts'][0]['name']
42 |
43 | def build_service(self):
44 | return discovery.build(self.API_NAME, self.API_VERSION, http=self.http,
45 | discoveryServiceUrl=self.DISCOVERY_URI)
46 |
47 | def get_credentials(self):
48 | storage_path = '.' + os.path.splitext(os.path.basename(__file__))[0] + '.credentials'
49 | storage = Storage(storage_path)
50 |
51 | credentials = storage.get() if os.path.exists(storage_path) else None
52 |
53 | if credentials is None or credentials.invalid:
54 | flow = flow_from_clientsecrets(self.credentials_path,
55 | scope=self.SCOPE,
56 | redirect_uri=self.REDIRECT_URI)
57 |
58 | flow.params['access_type'] = 'offline'
59 | flow.params['approval_prompt'] = 'force'
60 | credentials = tools.run_flow(flow, storage)
61 |
62 | return credentials
63 |
64 | def list_accounts(self):
65 | return self.service.accounts().list().execute()
66 |
67 | def list_locations(self):
68 | return self.service.accounts().locations().list(name=self.account_name).execute()
69 |
70 |
71 | class Woosmap:
72 | """A wrapper around the Woosmap Data API."""
73 |
74 | WOOSMAP_API_HOSTNAME = 'api.woosmap.com'
75 |
76 | def __init__(self):
77 | self.session = requests.Session()
78 |
79 | def delete(self):
80 | self.session.delete('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
81 | params={'private_key': WOOSMAP_PRIVATE_API_KEY})
82 |
83 | def post(self, payload):
84 | return self.session.post('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
85 | params={'private_key': WOOSMAP_PRIVATE_API_KEY},
86 | json={'stores': payload})
87 |
88 | def end(self):
89 | self.session.close()
90 |
91 |
92 | def get_name(asset):
93 | return asset.get('locationName')
94 |
95 |
96 | def get_id(asset):
97 | return asset.get('name').rsplit('/', 1)[1]
98 |
99 |
100 | def get_contact(asset):
101 | return {
102 | 'website': asset.get('websiteUrl', ''),
103 | 'phone': asset.get('primaryPhone', '')
104 | }
105 |
106 |
107 | def get_tags(asset):
108 | return asset.get('labels', [])
109 |
110 |
111 | def get_primary_category(asset):
112 | primary_type = []
113 | primary_category = asset.get('primaryCategory', {})
114 | if primary_category:
115 | primary_type.append(primary_category.get('name', ''))
116 |
117 | return primary_type
118 |
119 |
120 | def get_additional_categories(asset):
121 | additional_types = []
122 | additional_categories = asset.get('additionalCategories', [])
123 | if additional_categories:
124 | for category in additional_categories:
125 | additional_types.append(category.get('name', ''))
126 |
127 | return additional_types
128 |
129 |
130 | def get_types(asset):
131 | types = []
132 | types.extend(get_primary_category(asset))
133 | types.extend(get_additional_categories(asset))
134 | return types
135 |
136 |
137 | def get_user_properties(asset):
138 | # return all other useful attributes to store in "userProperties" property
139 | return {
140 | 'photos': asset.get('photos', {}),
141 | 'metadata': asset.get('metadata', {}),
142 | 'storeCode': asset.get('storeCode', ''),
143 | 'languageCode': asset.get('languageCode', ''),
144 | 'attributes': asset.get('attributes', []),
145 | 'serviceArea': asset.get('serviceArea', {}),
146 | 'locationKey': asset.get('locationKey', {}),
147 | 'priceLists': asset.get('priceLists', []),
148 | 'locationState': asset.get('locationState', {}),
149 | 'additionalPhones': asset.get('locationState', []),
150 | 'adWordsLocationExtensions': asset.get('adWordsLocationExtensions', {}),
151 | }
152 |
153 |
154 | def get_geometry(asset):
155 | # latlng can be empty {} if you did'nt moved the pushpin location was created on Google
156 | # Thus you need to geocode address location to get lat/lng
157 | latlng = asset.get('latlng', {})
158 | if latlng:
159 | return {
160 | 'lat': latlng.get('latitude'),
161 | 'lng': latlng.get('longitude')
162 | }
163 | else:
164 | # TODO: geocode address
165 | raise ValueError('Unable to get the latlng')
166 |
167 |
168 | def get_address(asset):
169 | address = asset.get('address', {})
170 | if address:
171 | return {
172 | 'lines': address.get('addressLines', []),
173 | 'city': address.get('locality', ''),
174 | 'zipcode': address.get('postalCode', ''),
175 | 'countryCode': address.get('country', '')
176 | }
177 | else:
178 | raise ValueError('Unable to get the Address')
179 |
180 |
181 | def find_timezone(asset):
182 | latlng = get_geometry(asset)
183 | timezone_name = ''
184 | try:
185 | lat = float(latlng['lat'])
186 | lng = float(latlng['lng'])
187 | timezone_name = tf.timezone_at(lng=lng, lat=lat)
188 | if timezone_name is None:
189 | timezone_name = tf.closest_timezone_at(lng=lng, lat=lat)
190 | return timezone_name
191 |
192 | except ValueError:
193 | print('Unable to Get the timezone for {latlng}'.format(latlng=latlng))
194 | timezone_name = 'Europe/Paris'
195 |
196 | finally:
197 | return {'timezone': timezone_name}
198 |
199 |
200 | def get_regular_hours(asset):
201 | # TODO: manage regular hours that take longer than 24hours (e.g. open monday 9am and close Tuesday 9pm)
202 | regular_hours = asset.get('regularHours', {})
203 | periods = regular_hours.get('periods', [])
204 |
205 | usual = {}
206 | week_days = [{'MONDAY': '1'}, {'TUESDAY': '2'}, {'WEDNESDAY': '3'}, {'THURSDAY': '4'}, {'FRIDAY': '5'},
207 | {'SATURDAY': '6'},
208 | {'SUNDAY': '7'}]
209 | if periods:
210 | for period in periods:
211 | for day in week_days:
212 | for key in day:
213 | if period['openDay'] == key:
214 | usual.setdefault(day[key], []).append({'start': period['openTime'], 'end': period['closeTime']})
215 |
216 | return {'usual': usual}
217 |
218 |
219 | def get_special_hours(asset):
220 | # TODO: manage special hours that take longer than 24hours (e.g. open monday 9am and close Tuesday 9pm)
221 | special_hours = asset.get('specialHours', {})
222 | periods = special_hours.get('specialHourPeriods', [])
223 |
224 | special = {}
225 | if periods:
226 | for period in periods:
227 | start_date = period.get('startDate', '')
228 | if start_date:
229 | key = str(start_date.get('year')) + '-' + str(start_date.get('month')) + '-' + str(
230 | start_date.get('day'))
231 | if period.get('isClosed', False):
232 | special.setdefault(key, [])
233 | else:
234 | special.setdefault(key, []).append({'start': period['openTime'], 'end': period['closeTime']})
235 |
236 | return {'special': special}
237 |
238 |
239 | def get_hours(asset):
240 | return dict(find_timezone(asset).items() + get_regular_hours(asset).items() + get_special_hours(asset).items())
241 |
242 |
243 | def convert_mybusiness_to_woosmap(data):
244 | converted_asset = {}
245 | try:
246 | converted_asset.update({
247 | 'storeId': get_id(data),
248 | 'name': get_name(data),
249 | 'address': get_address(data),
250 | 'contact': get_contact(data),
251 | 'location': get_geometry(data),
252 | 'openingHours': get_hours(data),
253 | 'tags': get_tags(data),
254 | 'types': get_types(data),
255 | 'userProperties': get_user_properties(data)
256 | })
257 | except ValueError as ve:
258 | print('ValueError Raised {0} for MyBusiness location {1}'.format(ve, json.dumps(data, indent=2)))
259 |
260 | return converted_asset
261 |
262 |
263 | def import_assets(assets_data, woosmap_api):
264 | try:
265 | print('Batch import {count} Assets to Woosmap...'.format(count=len(assets_data)))
266 | response = woosmap_api.post(assets_data)
267 | if response.status_code >= 400:
268 | response.raise_for_status()
269 |
270 | except requests.exceptions.HTTPError as http_exception:
271 | if http_exception.response.status_code >= 400:
272 | print('Woosmap API Import Error: {0}'.format(http_exception.response.text))
273 | else:
274 | print('Error requesting the API: {0}'.format(http_exception))
275 | return False
276 | except Exception as exception:
277 | print('Failed importing Assets! {0}'.format(exception))
278 | return False
279 |
280 | print('Successfully imported in {0} seconds'.format(response.elapsed.total_seconds()))
281 | return True
282 |
283 |
284 | def batch(assets_data, n=1):
285 | l = len(assets_data)
286 | for ndx in range(0, l, n):
287 | yield assets_data[ndx:min(ndx + n, l)]
288 |
289 |
290 | def main():
291 | google_my_business = GoogleMyBusiness(GOOGLE_CREDENTIALS_PATH, GOOGLE_ACCOUNT_NAME)
292 | extracted_my_business = google_my_business.list_locations()
293 | woosmap_assets = []
294 | for location in extracted_my_business["locations"]:
295 | converted_asset = convert_mybusiness_to_woosmap(location)
296 | if bool(converted_asset):
297 | woosmap_assets.append(converted_asset)
298 |
299 | woosmap_api = Woosmap()
300 | woosmap_api.delete()
301 |
302 | for chunk in batch(woosmap_assets):
303 | import_assets(chunk, woosmap_api)
304 |
305 |
306 | if __name__ == '__main__':
307 | main()
308 |
--------------------------------------------------------------------------------
/python-samples/googleplaces_to_woosmap/googleplaces_to_woosmap.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | import time
3 | from hashlib import sha1
4 |
5 | import simplejson as json # useful to deal with Decimal(x.x) potential errors
6 | from googleplaces import GooglePlaces, GooglePlacesAttributeError, GooglePlacesError
7 | from timezonefinder import TimezoneFinder
8 |
9 | GOOGLE_API_KEY = 'AIzaSyDRcaVMH1F_H3pIbm1T-XXXXXXXXXXX'
10 | WOOSMAP_OUTPUT_JSON = 'woosmap_output.json'
11 | SEARCH_DATA_PATH = 'search_data.json'
12 |
13 | tf = TimezoneFinder()
14 |
15 |
16 | def get_location(places_location):
17 | return {
18 | 'lat': float(places_location['geometry']['location']['lat']),
19 | 'lng': float(places_location['geometry']['location']['lng'])
20 | }
21 |
22 |
23 | def get_id(places_location):
24 | return sha1(places_location.get('place_id')).hexdigest()
25 |
26 |
27 | def find_timezone(places_location):
28 | latlng = get_location(places_location)
29 | timezone_name = ''
30 | try:
31 | lat = latlng['lat']
32 | lng = latlng['lng']
33 | timezone_name = tf.timezone_at(lng=lng, lat=lat)
34 | if timezone_name is None:
35 | timezone_name = tf.closest_timezone_at(lng=lng, lat=lat)
36 | return timezone_name
37 |
38 | except ValueError:
39 | print('Unable to Get the timezone for {latlng}'.format(latlng=latlng))
40 | timezone_name = 'Europe/Paris'
41 |
42 | finally:
43 | return {'timezone': timezone_name}
44 |
45 |
46 | # TODO : Update for multi opening and closing in a day
47 | def get_regular_hours(places_location):
48 | weekdays = [1, 2, 3, 4, 5, 6, 0]
49 | day_index = 1
50 | usual = {}
51 | day_hours = places_location.get('opening_hours', {})
52 |
53 | if bool(day_hours):
54 | try:
55 | for day in weekdays:
56 | hours = []
57 | start_hour = ''
58 | end_hour = ''
59 | if len(day_hours['periods']) == 1:
60 | hours.append({'all-day': True})
61 | else:
62 | for period in day_hours['periods']:
63 | if period['open']['day'] and period['open']['day'] == day:
64 | start_hour = period['open']['time'][:2] + ':' + period['open']['time'][-2:]
65 | if period['close']:
66 | end_hour = period['close']['time'][:2] + ':' + period['close']['time'][-2:]
67 | break
68 | if start_hour and end_hour:
69 | hours.append({'start': start_hour, 'end': end_hour})
70 |
71 | usual[day_index] = hours
72 | day_index += 1
73 |
74 | except Exception as error:
75 | raise ValueError('Unable to get the OpeningHours: {0}'.format(error))
76 |
77 | return {'usual': usual}
78 |
79 |
80 | def get_contact(places_location):
81 | website = places_location.get('website', '') if places_location.get('website', '') else places_location.get('url')
82 | return {
83 | 'website': website,
84 | 'phone': places_location.get('formatted_phone_number')
85 | }
86 |
87 |
88 | def get_address(places_location):
89 | return {
90 | 'lines': [places_location.get('formatted_address')]
91 | }
92 |
93 |
94 | def get_name(places_location):
95 | return places_location.get('name')
96 |
97 |
98 | def get_types(places_location):
99 | return places_location.get('types', [])
100 |
101 |
102 | def get_hours(places_location):
103 | return dict(find_timezone(places_location).items() + get_regular_hours(places_location).items())
104 |
105 |
106 | def google_places_to_woosmap(places_location):
107 | converted_asset = {}
108 | try:
109 | converted_asset.update({
110 | 'storeId': get_id(places_location),
111 | 'name': get_name(places_location),
112 | 'address': get_address(places_location),
113 | 'contact': get_contact(places_location),
114 | 'location': get_location(places_location),
115 | 'openingHours': get_hours(places_location),
116 | 'types': get_types(places_location)
117 | })
118 | except ValueError as ve:
119 | print('ValueError Raised {0} for Places Location {1}'.format(ve, json.dumps(places_location, indent=2)))
120 |
121 | return converted_asset
122 |
123 |
124 | def export_to_woosmap_json(input_json):
125 | data_places = {'stores': input_json}
126 | with codecs.open(WOOSMAP_OUTPUT_JSON, 'w', encoding='utf8') as outfile:
127 | json.dump(data_places, outfile, indent=2, ensure_ascii=False)
128 |
129 |
130 | def main():
131 | woosmap_converted_asset = []
132 | with codecs.open(SEARCH_DATA_PATH, 'rb', encoding='utf8') as search_data_file:
133 | search_data = json.loads(search_data_file.read())
134 | google_places = GooglePlaces(GOOGLE_API_KEY)
135 | for place_id in search_data['places_ids']:
136 | try:
137 | place = google_places.get_place(place_id)
138 | converted_asset = google_places_to_woosmap(place.details)
139 | if bool(converted_asset):
140 | print("... {place_name} ...converted to Wosmap OK".format(place_name=place.name.encode('utf-8')))
141 | woosmap_converted_asset.append(converted_asset)
142 |
143 | except (GooglePlacesError, GooglePlacesAttributeError) as error_detail:
144 | print('Google Returned an Error : {0} for Place ID : {1}'.format(error_detail, place_id))
145 | pass
146 |
147 | except Exception as exception:
148 | print('Exception Returned {0} for Place ID : {1}'.format(exception, place_id))
149 | time.sleep(1)
150 | pass
151 |
152 | export_to_woosmap_json(woosmap_converted_asset)
153 | print('{0} google places extracted for {1} places_ids found '.format(len(woosmap_converted_asset),
154 | len(search_data['places_ids'])))
155 |
156 |
157 | if __name__ == '__main__':
158 | main()
159 |
--------------------------------------------------------------------------------
/python-samples/googleplaces_to_woosmap/search_data.json:
--------------------------------------------------------------------------------
1 | {
2 | "places_ids": [
3 | "ChIJC4Wu9QmvthIRDmojjnJB6rA",
4 | "ChIJuRFUv33Ew0cRk0JQb2xQOfs",
5 | "ChIJ9yGYrIwd9kcRlV-tE8ixHpw",
6 | "ChIJJ9NzTOW83UcRh3KE1nh9bno",
7 | "ChIJNx8atyPbEEgRXZQc7nPAKpQ",
8 | "ChIJWRTTPgJl5kcROB_8Pwj9BeI"
9 | ]
10 | }
--------------------------------------------------------------------------------
/python-samples/googlesheet_to_woosmap/googlesheet_to_woosmap.py:
--------------------------------------------------------------------------------
1 | import httplib2
2 | import os
3 | import json
4 | import requests
5 | from hashlib import sha1
6 |
7 | from apiclient import discovery
8 | from oauth2client.client import flow_from_clientsecrets
9 | from oauth2client import tools
10 | from oauth2client.file import Storage
11 |
12 | GOOGLE_CREDENTIALS_PATH = 'client_secret_xxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com.json'
13 | GOOGLE_SPREADSHEET_ID = '1bRQubfDVmFg53ohzY_SLSJRahf04kDtV2O0Ql28hP7U'
14 | GOOGLE_RANGE_NAME = 'foodmarkets'
15 |
16 | WOOSMAP_PRIVATE_API_KEY = 'eafb8805-3743-4cb9-abff-xxxxxxxxxxx'
17 |
18 |
19 | class GoogleSheets(object):
20 | """A wrapper around the Google Sheets API."""
21 |
22 | API_NAME = 'sheets'
23 | API_VERSION = 'v4'
24 | DISCOVERY_URI = 'https://sheets.googleapis.com/$discovery/rest?version={apiVersion}'
25 | SCOPES = 'https://www.googleapis.com/auth/spreadsheets.readonly'
26 | APPLICATION_NAME = 'Google Sheets To Woosmap'
27 | REDIRECT_URI = 'http://localhost:8080'
28 |
29 | def __init__(self, credentials_path, spreadsheet_id, range_name=''):
30 | self.credentials_path = credentials_path
31 | self.spreadsheet_id = spreadsheet_id
32 | self.credentials = self.get_credentials()
33 | self.http = self.credentials.authorize(httplib2.Http())
34 | if self.credentials is not None and self.credentials.access_token_expired:
35 | self.credentials.refresh(self.http)
36 |
37 | self.service = self.build_service()
38 | self.range_name = range_name if range_name else self.get_first_sheetname()
39 |
40 | def build_service(self):
41 | return discovery.build(self.API_NAME, self.API_VERSION, http=self.http,
42 | discoveryServiceUrl=self.DISCOVERY_URI)
43 |
44 | def get_credentials(self):
45 | storage_path = '.' + os.path.splitext(os.path.basename(__file__))[0] + '.credentials'
46 | storage = Storage(storage_path)
47 | credentials = storage.get() if os.path.exists(storage_path) else None
48 | if credentials is None or credentials.invalid:
49 | flow = flow_from_clientsecrets(self.credentials_path, self.SCOPES, redirect_uri=self.REDIRECT_URI)
50 | flow.user_agent = self.APPLICATION_NAME
51 | credentials = tools.run_flow(flow, storage)
52 |
53 | return credentials
54 |
55 | def get_values(self):
56 | return self.service.spreadsheets().values().get(spreadsheetId=self.spreadsheet_id,
57 | range=self.range_name).execute()
58 |
59 | def get_first_sheetname(self):
60 | sheet_metadata = self.service.spreadsheets().get(spreadsheetId=self.spreadsheet_id).execute()
61 | return sheet_metadata.get('sheets', '')[0].get("properties", {}).get("title", "Sheet1")
62 |
63 |
64 | class Woosmap:
65 | """A wrapper around the Woosmap Data API."""
66 |
67 | WOOSMAP_API_HOSTNAME = 'api.woosmap.com'
68 |
69 | def __init__(self):
70 | self.session = requests.Session()
71 |
72 | def delete(self):
73 | self.session.delete('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
74 | params={'private_key': WOOSMAP_PRIVATE_API_KEY})
75 |
76 | def post(self, payload):
77 | return self.session.post('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
78 | params={'private_key': WOOSMAP_PRIVATE_API_KEY},
79 | json={'stores': payload})
80 |
81 | def end(self):
82 | self.session.close()
83 |
84 |
85 | def get_name(asset):
86 | name = asset.get('Name', '')
87 | if name:
88 | return name
89 | else:
90 | raise ValueError('Unable to get the Name')
91 |
92 |
93 | def generate_id(asset):
94 | asset_id = sha1(get_name(asset).encode('utf-8')).hexdigest()
95 | return asset_id
96 |
97 |
98 | def get_contact(asset):
99 | return {
100 | 'website': asset.get('Website', ''),
101 | 'phone': asset.get('Contact Phone', ''),
102 | 'email': asset.get('Contact Email', '')
103 | }
104 |
105 |
106 | def get_geometry(asset):
107 | latitude = asset.get('Latitude', None)
108 | longitude = asset.get('Longitude', None)
109 | if latitude is not None and longitude is not None:
110 | return {
111 | 'lat': float(latitude),
112 | 'lng': float(longitude)
113 | }
114 | else:
115 | raise ValueError('Unable to get the location')
116 |
117 |
118 | def get_address(asset):
119 | return {
120 | 'lines': [asset.get('Address Line', '')],
121 | 'city': asset.get('City', ''),
122 | 'zipcode': asset.get('Zipcode', '')
123 | }
124 |
125 |
126 | def convert_to_woosmap(asset):
127 | converted_asset = {}
128 | try:
129 | converted_asset.update({
130 | 'storeId': generate_id(asset),
131 | 'name': get_name(asset),
132 | 'address': get_address(asset),
133 | 'contact': get_contact(asset),
134 | 'location': get_geometry(asset)
135 | })
136 | except ValueError as ve:
137 | print('ValueError Raised {0} for Asset {1}'.format(ve, json.dumps(asset, indent=2)))
138 |
139 | return converted_asset
140 |
141 |
142 | def import_assets(assets_data, woosmap_api_helper):
143 | try:
144 | print('Batch import {count} Assets...'.format(count=len(assets_data)))
145 | response = woosmap_api_helper.post(assets_data)
146 | if response.status_code >= 400:
147 | response.raise_for_status()
148 |
149 | except requests.exceptions.HTTPError as http_exception:
150 | if http_exception.response.status_code >= 400:
151 | print('Woosmap API Import Error: {0}'.format(http_exception.response.text))
152 | else:
153 | print('Error requesting the API: {0}'.format(http_exception))
154 | return False
155 | except Exception as exception:
156 | print('Failed importing Assets! {0}'.format(exception))
157 | return False
158 |
159 | print('Successfully imported in {0} seconds'.format(response.elapsed.total_seconds()))
160 | return True
161 |
162 |
163 | def batch(assets_data, n=1):
164 | l = len(assets_data)
165 | for ndx in range(0, l, n):
166 | yield assets_data[ndx:min(ndx + n, l)]
167 |
168 |
169 | def main():
170 | google_sheets = GoogleSheets(GOOGLE_CREDENTIALS_PATH, GOOGLE_SPREADSHEET_ID)
171 |
172 | sheet_data = google_sheets.get_values().get('values', [])
173 | header = sheet_data.pop(0)
174 | assets_as_dict = [dict(zip(header, item)) for item in sheet_data]
175 |
176 | woosmap_assets = []
177 | for asset in assets_as_dict:
178 | converted_asset = convert_to_woosmap(asset)
179 | if bool(converted_asset):
180 | woosmap_assets.append(converted_asset)
181 |
182 | print('{0} Assets converted from source file'.format(len(woosmap_assets)))
183 |
184 | woosmap_api_helper = Woosmap()
185 | # /!\ deleting existing assets before posting new ones /!\
186 | woosmap_api_helper.delete()
187 |
188 | count_imported_assets = 0
189 | for chunk in batch(woosmap_assets):
190 | imported_success = import_assets(chunk, woosmap_api_helper)
191 | if imported_success:
192 | count_imported_assets += len(chunk)
193 |
194 | woosmap_api_helper.end()
195 |
196 |
197 | if __name__ == '__main__':
198 | main()
199 |
--------------------------------------------------------------------------------
/python-samples/woosmap_jsonschema_validation/foodmarkets.json:
--------------------------------------------------------------------------------
1 | {
2 | "stores": [
3 | {
4 | "address": {
5 | "city": "Rotterdam",
6 | "lines": [
7 | "Dominee Jan Scharpstraat 298"
8 | ],
9 | "zipcode": "3011 GZ"
10 | },
11 | "storeId": "d3911140d1fbadb82b83e74486af99142623a0dc",
12 | "location": {
13 | "lat": 51.919948,
14 | "lng": 4.486843
15 | },
16 | "name": "Markthal Rotterdam",
17 | "contact": {
18 | "website": "http://markthalrotterdam.nl/",
19 | "phone": "+31 (0)30 234 64 64",
20 | "email": "info@markthalrotterdam.nl"
21 | }
22 | },
23 | {
24 | "address": {
25 | "city": "Roma",
26 | "lines": [
27 | "Via Galvani/Via Alessandro Volta"
28 | ],
29 | "zipcode": "00118"
30 | },
31 | "storeId": "6f4c75c5e74336d99ab73bd715ce1ce0a3850970",
32 | "location": {
33 | "lat": 41.877657,
34 | "lng": 12.473909
35 | },
36 | "name": "Testaccio Market",
37 | "contact": {
38 | "website": "http://www.mercatotestaccio.com/",
39 | "phone": "+39 06 578 0638",
40 | "email": "info@mercatotestaccio.ocm"
41 | }
42 | },
43 | {
44 | "address": {
45 | "city": "Vienna",
46 | "lines": [
47 | "Via Galvani/Via Alessandro Volta"
48 | ],
49 | "zipcode": "1060"
50 | },
51 | "storeId": "72adb1b1419c16f4d28f90d4ac4394de25f2f555",
52 | "location": {
53 | "lat": 48.199044,
54 | "lng": 16.364234
55 | },
56 | "name": "Naschmarkt Vienna",
57 | "contact": {
58 | "website": "http://www.naschmarkt-vienna.com/",
59 | "phone": "+43 1 240555",
60 | "email": "contact@naschmarkt-vienna.com"
61 | }
62 | },
63 | {
64 | "address": {
65 | "city": "Madrid",
66 | "lines": [
67 | "Plaza de San Miguel"
68 | ],
69 | "zipcode": "28005"
70 | },
71 | "storeId": "8af852d45a9059090b5225a96cf424ae0ddcefc5",
72 | "location": {
73 | "lat": 40.415261,
74 | "lng": -3.708944
75 | },
76 | "name": "Mercado de San Miguel",
77 | "contact": {
78 | "website": "http://www.mercadodesanmiguel.es/en",
79 | "phone": "(+34) 915 42 49 36",
80 | "email": "administracion@mercadodesanmiguel.es"
81 | }
82 | },
83 | {
84 | "address": {
85 | "city": "Barcelona",
86 | "lines": [
87 | "La Rambla, 91"
88 | ],
89 | "zipcode": "08001"
90 | },
91 | "storeId": "ba3599fcc23989456c146997e68b1a7816fcf5fc",
92 | "location": {
93 | "lat": 41.381635,
94 | "lng": 2.171596
95 | },
96 | "name": "Mercado de La Boqueria",
97 | "contact": {
98 | "website": "http://www.boqueria.info/",
99 | "phone": "+34 933 18 25 84",
100 | "email": "administracion@mercadodesanmiguel.es"
101 | }
102 | },
103 | {
104 | "address": {
105 | "city": "Nice",
106 | "lines": [
107 | "Place Charles F\u00e9lix"
108 | ],
109 | "zipcode": "06300"
110 | },
111 | "storeId": "e49e1fcf75bd3b509bf5b5201903ca5270930977",
112 | "location": {
113 | "lat": 43.69553,
114 | "lng": 7.275492
115 | },
116 | "name": "Cours Saleya",
117 | "contact": {
118 | "website": "http://leblogduvieuxnice.nicematin.com/.services/blog/6a0120a864ed46970b0162fd89fc17970d/search?filter.q=march\u00e9",
119 | "phone": "",
120 | "email": ""
121 | }
122 | },
123 | {
124 | "address": {
125 | "city": "Paris",
126 | "lines": [
127 | "Place d\u2019Aligre"
128 | ],
129 | "zipcode": "75012"
130 | },
131 | "storeId": "7fe6cfa7b39dbae2eec8fdd7faed315561619cff",
132 | "location": {
133 | "lat": 48.849021,
134 | "lng": 2.3777
135 | },
136 | "name": "March\u00e9 d\u2019Aligre",
137 | "contact": {
138 | "website": "http://equipement.paris.fr/marche-couvert-beauvau-marche-d-aligre-5480",
139 | "phone": "01 45 11 71 11",
140 | "email": ""
141 | }
142 | },
143 | {
144 | "address": {
145 | "city": "Firenze",
146 | "lines": [
147 | "Piazza del Mercato Centrale"
148 | ],
149 | "zipcode": "50123"
150 | },
151 | "storeId": "6080ed9f535dcb2e925c334068abe0a4431bb08d",
152 | "location": {
153 | "lat": 43.77654,
154 | "lng": 11.253133
155 | },
156 | "name": "Mercato Centrale di San Lorenzo",
157 | "contact": {
158 | "website": "http://www.mercatocentrale.it",
159 | "phone": "+39 0552399798",
160 | "email": "info@mercatocentrale.it"
161 | }
162 | },
163 | {
164 | "address": {
165 | "city": "Copenhagen",
166 | "lines": [
167 | "Frederiksborggade 21"
168 | ],
169 | "zipcode": "1360"
170 | },
171 | "storeId": "56eb5f571b8c083d384658a95a929ea997d69f9f",
172 | "location": {
173 | "lat": 55.684025,
174 | "lng": 12.569469
175 | },
176 | "name": "Torvehallerne",
177 | "contact": {
178 | "website": "http://torvehallernekbh.dk",
179 | "phone": "+39 0552399798",
180 | "email": "info@torvehallernekbh.dk"
181 | }
182 | },
183 | {
184 | "address": {
185 | "city": "London",
186 | "lines": [
187 | "8 Southwark St"
188 | ],
189 | "zipcode": "SE1 1TL"
190 | },
191 | "storeId": "74cf59f30119a3672647ef0c4bd9f0587cfcfba4",
192 | "location": {
193 | "lat": 51.505046,
194 | "lng": -0.090679
195 | },
196 | "name": "Borough Market",
197 | "contact": {
198 | "website": "http://boroughmarket.org.uk",
199 | "phone": "020 7407 1002",
200 | "email": ""
201 | }
202 | },
203 | {
204 | "address": {
205 | "city": "M\u00fcnchen",
206 | "lines": [
207 | "Viktualienmarkt 3"
208 | ],
209 | "zipcode": "80881"
210 | },
211 | "storeId": "71504c368f415a820795c254d852cadfd711651c",
212 | "location": {
213 | "lat": 48.135105,
214 | "lng": 11.576246
215 | },
216 | "name": "Victuals Market",
217 | "contact": {
218 | "website": "http://www.muenchen.de/int/en/shopping/markets/viktualienmarkt.html",
219 | "phone": "+49 89 89068205",
220 | "email": ""
221 | }
222 | },
223 | {
224 | "address": {
225 | "city": "S\u00e8te",
226 | "lines": [
227 | "Rue Gambetta"
228 | ],
229 | "zipcode": "34200"
230 | },
231 | "storeId": "e5bac7b59e5f6a2d4260b412904e09052f6df12c",
232 | "location": {
233 | "lat": 43.40214,
234 | "lng": 3.69545
235 | },
236 | "name": "Halles de S\u00e8te",
237 | "contact": {
238 | "website": "http://www.halles-sete.com/",
239 | "phone": "04 99 04 70 00",
240 | "email": "commerce-artisanat@ville-sete.fr"
241 | }
242 | },
243 | {
244 | "address": {
245 | "city": "Uz\u00e8s",
246 | "lines": [
247 | "Place aux Herbes"
248 | ],
249 | "zipcode": "30700"
250 | },
251 | "storeId": "e50bcf462a9fa23cedb6ef2fe57b81472f3477ba",
252 | "location": {
253 | "lat": 44.011821,
254 | "lng": 4.418889
255 | },
256 | "name": "March\u00e9 d'Uz\u00e8s",
257 | "contact": {
258 | "website": "http://www.uzes.fr/Calendrier-des-marches-brocantes-et-foires_a126.html",
259 | "phone": "+33 (0)4 66 22 68 88",
260 | "email": ""
261 | }
262 | },
263 | {
264 | "address": {
265 | "city": "Apt",
266 | "lines": [
267 | "Place de la Bouquerie"
268 | ],
269 | "zipcode": "84400"
270 | },
271 | "storeId": "8b685237005769cf1b85a6eb07ccc156b820ec9b",
272 | "location": {
273 | "lat": 43.876503,
274 | "lng": 5.393588
275 | },
276 | "name": "Le Grand March\u00e9 d'Apt",
277 | "contact": {
278 | "website": "http://www.luberon-apt.fr/index.php/fr/sortir/les-marches",
279 | "phone": "+33 (0)4 90 74 03 18",
280 | "email": "oti@paysapt-luberon.fr"
281 | }
282 | },
283 | {
284 | "address": {
285 | "city": "La Flotte",
286 | "lines": [
287 | "Rue du March\u00e9"
288 | ],
289 | "zipcode": 17630
290 | },
291 | "storeId": "846c55afb649f6c5715fd0d04700fbac8c369611",
292 | "location": {
293 | "lat": 46.187465,
294 | "lng": -1.327086
295 | },
296 | "name": "Le March\u00e9 de la Flotte",
297 | "contact": {
298 | "website": "http://laflotte.fr/index.php/Vie-quotidienne/les-marches.html",
299 | "phone": "05.46.09.15.00",
300 | "email": "annie@laflotte.fr"
301 | }
302 | },
303 | {
304 | "address": {
305 | "city": "Edimburgh",
306 | "lines": [
307 | "Castle Terrace"
308 | ],
309 | "zipcode": "EH1 UK"
310 | },
311 | "storeId": "01d822835de61e34be80dc747fe0e73773aef015",
312 | "location": {
313 | "lat": 55.947817,
314 | "lng": -3.203562
315 | },
316 | "name": "Edimburgh Farmers' Market",
317 | "contact": {
318 | "website": "http://www.edinburghfarmersmarket.co.uk/",
319 | "phone": "0131 220 8580",
320 | "email": ""
321 | }
322 | },
323 | {
324 | "address": {
325 | "city": "Belfast",
326 | "lines": [
327 | "12 - 20 East Bridge Street"
328 | ],
329 | "zipcode": "BT1 3NQ"
330 | },
331 | "storeId": "7fc2088804d1700be543f85eb44392134a1e3b4b",
332 | "location": {
333 | "lat": 54.596073,
334 | "lng": -5.921654
335 | },
336 | "name": "St George's Market",
337 | "contact": {
338 | "website": "http://www.belfastcity.gov.uk/tourism-venues/stgeorgesmarket/stgeorgesmarket-index.aspx",
339 | "phone": "028 9043 5704",
340 | "email": "markets@belfastcity.gov.uk"
341 | }
342 | },
343 | {
344 | "address": {
345 | "city": "Lille",
346 | "lines": [
347 | "Place de la nouvelle aventure"
348 | ],
349 | "zipcode": "59000"
350 | },
351 | "storeId": "b61c2fca4f713cb9b6136150a9459f5be59a5eed",
352 | "location": {
353 | "lat": 50.62671,
354 | "lng": 3.049325
355 | },
356 | "name": "Halles de Wazemmes",
357 | "contact": {
358 | "website": "http://www.halles-wazemmes.com/",
359 | "phone": "",
360 | "email": "",
361 | "ErrorKey":2
362 | }
363 |
364 | }
365 | ]
366 | }
--------------------------------------------------------------------------------
/python-samples/woosmap_jsonschema_validation/woosmap_jsonschema_validation.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 | from jsonschema import ValidationError, validate
4 |
5 | JSON_TO_VALIDATE = os.path.join(os.getcwd(), 'foodmarkets.json')
6 |
7 | WOOSMAP_SCHEMA = {
8 | '$ref': 'https://raw.githubusercontent.com/woosmap/woosmap-json-schema/master/asset.json#'
9 | }
10 | WOOSMAP_COLLECTION_SCHEMA = {
11 | '$ref': 'https://raw.githubusercontent.com/woosmap/woosmap-json-schema/master/assetCollection.json#'
12 | }
13 |
14 |
15 | def load_json(file_path):
16 | with open(file_path, 'r') as f:
17 | return json.load(f)
18 |
19 |
20 | def validate_collection(assets):
21 | """ Validate an array of Assets expected as {"stores":[{asset},{asset},...]}
22 | Less time consuming but will raise ValidationError at first error """
23 | try:
24 | print("Validating Collection of Assets...")
25 | validate(assets, WOOSMAP_COLLECTION_SCHEMA)
26 | except ValidationError as error:
27 | print Exception("Asset not Matching: {0}".format(error.message))
28 | else:
29 | print("...Validated Collection Successful!")
30 |
31 |
32 | def validate_one_by_one(assets):
33 | """ Validate individually each Asset that could be useful to identify
34 | all Asset which could be in wrong schema. A little slower """
35 | print("Validating assets individually..")
36 | for item in assets["stores"]:
37 | try:
38 | validate(item, WOOSMAP_SCHEMA)
39 | except ValidationError as error:
40 | print Exception(
41 | "Asset not Matching: {0}".format(error.message))
42 | else:
43 | print("...Validated Asset {id} Successful!".format(id=item["storeId"]))
44 |
45 |
46 | def main():
47 | assets_to_validate = load_json(JSON_TO_VALIDATE)
48 | validate_collection(assets_to_validate)
49 | validate_one_by_one(assets_to_validate)
50 |
51 |
52 | if __name__ == '__main__':
53 | if os.path.exists(os.path.join(os.getcwd(), JSON_TO_VALIDATE)):
54 | main()
55 | else:
56 | print('File not found: {0} '.format(JSON_TO_VALIDATE))
57 |
--------------------------------------------------------------------------------
/python-samples/woosmap_to_geojson/woosmap_to_geojson.py:
--------------------------------------------------------------------------------
1 | import codecs
2 | import json
3 |
4 | import requests
5 |
6 | origin_public_key = 'woos-3886aa76-xxxxxxxxxx'
7 | output_file = origin_public_key + '.json'
8 | allowed_referer = 'http://localhost/'
9 | api_server_host = 'api.woosmap.com'
10 | geojson_features = []
11 |
12 |
13 | def get_all_stores(page=1):
14 | params = dict(key=origin_public_key, page=page)
15 | ref_header = {'referer': allowed_referer}
16 |
17 | response = session.get(url='http://{api_server_host}/stores'.format(
18 | api_server_host=api_server_host),
19 | params=params,
20 | headers=ref_header)
21 |
22 | temp_json = response.json()
23 | for feature in temp_json['features']:
24 | geojson_features.append(feature)
25 |
26 | if temp_json['pagination']['page'] != temp_json['pagination']['pageCount']:
27 | get_all_stores(temp_json['pagination']['page'] + 1)
28 |
29 | return geojson_features
30 |
31 |
32 | def export_input_geojson(inputjson):
33 | with codecs.open(output_file, 'w', encoding='utf8') as outfile:
34 | woosmap_geojson = {'type': 'FeatureCollection', 'features': inputjson}
35 | json.dump(woosmap_geojson, outfile, indent=2, ensure_ascii=False)
36 |
37 |
38 | if __name__ == '__main__':
39 | session = requests.Session()
40 | batch = []
41 | try:
42 | stores_geojson = get_all_stores()
43 | export_input_geojson(stores_geojson)
44 |
45 | except BaseException as error: # bad bad way!
46 | print('An exception occurred: {}'.format(error))
47 |
--------------------------------------------------------------------------------
/python-samples/woosmap_to_woosmap/README.md:
--------------------------------------------------------------------------------
1 | # Python Script to export data from a Woosmap Customer as a JSON file and eventually import them to another customer.
2 |
3 | You need to define parameter for **public_key** (origin data).
4 | You could define parameter for **private key** (destination project) if you want to re-import them.
5 |
6 | sample usage:
7 |
8 | python woosmap_to_woosmap.py
9 |
10 | The exported data is saved in the file `data.json`
--------------------------------------------------------------------------------
/python-samples/woosmap_to_woosmap/woosmap_to_woosmap.py:
--------------------------------------------------------------------------------
1 | import json
2 | import requests
3 | import codecs
4 |
5 | origin_public_key = 'woos-54e9fe79-5c35-3641-ace8-215e5610278d'
6 | private_key = ''
7 | output_file = 'woos-54e9fe79-5c35-3641-ace8-215e5610278d.json'
8 | allowed_referer = 'http://localhost/'
9 | api_server_host = 'api.woosmap.com'
10 | geojson_features = []
11 | stores_batch_size = 500
12 |
13 |
14 | def get_geometry(store):
15 | return {
16 | 'lat': store['geometry']['coordinates'][1],
17 | 'lng': store['geometry']['coordinates'][0]
18 | }
19 |
20 |
21 | def transform_geojson_woosmap(extracted_geojson):
22 | stores = []
23 | for feature in extracted_geojson:
24 | try:
25 | prop = feature["properties"]
26 | stores.append({"location": get_geometry(feature),
27 | "storeId": prop.get("store_id"),
28 | "openingHours": prop.get("opening_hours", {}),
29 | "userProperties": prop.get("user_properties", {}),
30 | "types": prop.get("types", []),
31 | "address": prop.get("address", {}),
32 | "name": prop.get("name", ""),
33 | "tags": prop.get("tags", []),
34 | "contact": prop.get("contact", {})})
35 | except BaseException as error:
36 | print('An exception occurred: {}'.format(error))
37 |
38 | return stores
39 |
40 |
41 | def get_all_stores(page=1):
42 | params = dict(key=origin_public_key, page=page)
43 | ref_header = {'referer': allowed_referer}
44 |
45 | response = session.get(url='http://{api_server_host}/stores'.format(
46 | api_server_host=api_server_host),
47 | params=params,
48 | headers=ref_header)
49 |
50 | temp_json = response.json()
51 | for feature in temp_json['features']:
52 | geojson_features.append(feature)
53 |
54 | if temp_json['pagination']['page'] != temp_json['pagination']['pageCount']:
55 | get_all_stores(temp_json['pagination']['page'] + 1)
56 |
57 | return geojson_features
58 |
59 |
60 | def export_input_json(inputjson):
61 | with codecs.open(output_file, 'w', encoding='utf8') as outfile:
62 | woosmap_data = {'stores': inputjson}
63 | json.dump(woosmap_data, outfile, indent=2, ensure_ascii=False)
64 |
65 |
66 | def import_location(locations):
67 | print('Importing locations (%d) ...' % len(locations))
68 | response = session.post(
69 | 'http://{api_server_host}/stores'.format(
70 | api_server_host=api_server_host),
71 | params={'private_key': private_key},
72 | json={'stores': locations})
73 |
74 | print('Import time:', response.elapsed.total_seconds())
75 | if response.status_code >= 400:
76 | print('Import Failed')
77 | print(response.text)
78 | return False
79 |
80 | return True
81 |
82 |
83 | if __name__ == '__main__':
84 | session = requests.Session()
85 | batch = []
86 | try:
87 | stores_geojson = get_all_stores()
88 | stores_woosmap = transform_geojson_woosmap(stores_geojson)
89 | if output_file:
90 | export_input_json(stores_woosmap)
91 | if private_key:
92 | for store in stores_woosmap:
93 | if len(batch) == stores_batch_size:
94 | batch_result = import_location(batch)
95 | batch = []
96 | else:
97 | batch.append(store)
98 |
99 | if batch:
100 | batch_result = import_location(batch)
101 | batch = []
102 |
103 | except BaseException as error: # bad bad way!
104 | print('An exception occurred: {}'.format(error))
105 |
--------------------------------------------------------------------------------
/python-samples/woosmapjson_import/README.md:
--------------------------------------------------------------------------------
1 | # Python Script to import a simple dataset to Woosmap Database.
2 |
3 | sample usage:
4 |
5 | python woosmapjson_import.py
6 |
7 | This python script may only be used for small data (less than 1000 locations).
8 |
9 | The sample JSON File (foodmarkets.json) represent a list of some of the best Food Markets in Europe.
--------------------------------------------------------------------------------
/python-samples/woosmapjson_import/foodmarkets.json:
--------------------------------------------------------------------------------
1 | {
2 | "stores": [
3 | {
4 | "types": [
5 | "covered"
6 | ],
7 | "location": {
8 | "lat": 51.919948,
9 | "lng": 4.486843
10 | },
11 | "storeId": "markthalrotterdam",
12 | "name": "Markthal Rotterdam",
13 | "address": {
14 | "lines": [
15 | "Dominee Jan Scharpstraat 298"
16 | ],
17 | "country": "Netherlands",
18 | "city": "Rotterdam",
19 | "zipcode": "3011 GZ"
20 | },
21 | "contact": {
22 | "website": "http://markthalrotterdam.nl/",
23 | "phone": "+31 (0)30 234 64 64",
24 | "email": "info@markthalrotterdam.nl"
25 | },
26 | "openingHours": {
27 | "timezone": "Europe/Amsterdam",
28 | "usual": {
29 | "default": [
30 | {
31 | "start": "10:00",
32 | "end": "20:00"
33 | }
34 | ],
35 | "1": []
36 | }
37 | }
38 | },
39 | {
40 | "types": [
41 | "covered"
42 | ],
43 | "location": {
44 | "lat": 41.877657,
45 | "lng": 12.473909
46 | },
47 | "storeId": "testacciomarket",
48 | "name": "Testaccio Market",
49 | "address": {
50 | "lines": [
51 | "Via Galvani/Via Alessandro Volta"
52 | ],
53 | "country": "Italy",
54 | "city": "Roma",
55 | "zipcode": "00118"
56 | },
57 | "contact": {
58 | "website": "http://www.mercatotestaccio.com/",
59 | "phone": "+39 06 578 0638",
60 | "email": "info@mercatotestaccio.ocm"
61 | },
62 | "openingHours": {
63 | "timezone": "Europe/Rome",
64 | "usual": {
65 | "default": [
66 | {
67 | "all-day": true
68 | }
69 | ]
70 | }
71 | }
72 | },
73 | {
74 | "types": [
75 | "covered"
76 | ],
77 | "location": {
78 | "lat": 48.199044,
79 | "lng": 16.364234
80 | },
81 | "storeId": "naschmarktvienna",
82 | "name": "Naschmarkt Vienna",
83 | "address": {
84 | "lines": [
85 | "Via Galvani/Via Alessandro Volta"
86 | ],
87 | "country": "Austria",
88 | "city": "Vienna",
89 | "zipcode": "1060"
90 | },
91 | "contact": {
92 | "website": "http://www.naschmarkt-vienna.com/",
93 | "tel": "+43 1 240555",
94 | "email": "contact@naschmarkt-vienna.com"
95 | },
96 | "openingHours": {
97 | "timezone": "Europe/Vienna",
98 | "usual": {
99 | "default": [
100 | {
101 | "start": "6:00",
102 | "end": "19:30"
103 | }
104 | ],
105 | "6": [
106 | {
107 | "start": "6:00",
108 | "end": "17:00"
109 | }
110 | ],
111 | "7": []
112 | }
113 | }
114 | },
115 | {
116 | "types": [
117 | "covered"
118 | ],
119 | "location": {
120 | "lat": 40.415261,
121 | "lng": -3.708944
122 | },
123 | "storeId": "mercadodesanmiguel",
124 | "name": "Mercado de San Miguel",
125 | "address": {
126 | "lines": [
127 | "Plaza de San Miguel"
128 | ],
129 | "country": "Spain",
130 | "city": "Madrid",
131 | "zipcode": "28005"
132 | },
133 | "contact": {
134 | "website": "http://www.mercadodesanmiguel.es/en",
135 | "phone": "(+34) 915 42 49 36",
136 | "email": "administracion@mercadodesanmiguel.es"
137 | },
138 | "openingHours": {
139 | "timezone": "Europe/Madrid",
140 | "usual": {
141 | "default": [
142 | {
143 | "start": "10:00",
144 | "end": "23:59"
145 | }
146 | ],
147 | "4": [
148 | {
149 | "start": "10:00",
150 | "end": "23:59"
151 | }
152 | ],
153 | "5": [
154 | {
155 | "start": "10:00",
156 | "end": "23:59"
157 | }
158 | ],
159 | "6": [
160 | {
161 | "start": "10:00",
162 | "end": "23:59"
163 | }
164 | ]
165 | }
166 | }
167 | },
168 | {
169 | "types": [
170 | "covered"
171 | ],
172 | "location": {
173 | "lat": 41.381635,
174 | "lng": 2.171596
175 | },
176 | "storeId": "mercadodelaboqueria",
177 | "name": "Mercado de La Boqueria",
178 | "address": {
179 | "lines": [
180 | "La Rambla, 91"
181 | ],
182 | "country": "Spain",
183 | "city": "Barcelona",
184 | "zipcode": "08001"
185 | },
186 | "contact": {
187 | "website": "http://www.boqueria.info/",
188 | "phone": "+34 933 18 25 84",
189 | "email": "administracion@mercadodesanmiguel.es"
190 | },
191 | "openingHours": {
192 | "timezone": "Europe/Madrid",
193 | "usual": {
194 | "default": [
195 | {
196 | "start": "08:00",
197 | "end": "20:30"
198 | }
199 | ],
200 | "7": []
201 | }
202 | }
203 | },
204 | {
205 | "types": [
206 | "covered"
207 | ],
208 | "location": {
209 | "lat": 43.695530,
210 | "lng": 7.275492
211 | },
212 | "storeId": "courssaleya",
213 | "name": "Cours Saleya",
214 | "address": {
215 | "lines": [
216 | "Place Charles Félix"
217 | ],
218 | "country": "France",
219 | "city": "Nice",
220 | "zipcode": "06300"
221 | },
222 | "contact": {
223 | "website": "http://leblogduvieuxnice.nicematin.com/.services/blog/6a0120a864ed46970b0162fd89fc17970d/search?filter.q=marché"
224 | },
225 | "openingHours": {
226 | "timezone": "Europe/Paris",
227 | "usual": {
228 | "default": [
229 | {
230 | "start": "06:00",
231 | "end": "17:30"
232 | }
233 | ],
234 | "1": [],
235 | "7": [
236 | {
237 | "start": "06:00",
238 | "end": "13:30"
239 | }
240 | ]
241 | }
242 | }
243 | },
244 | {
245 | "types": [
246 | "covered"
247 | ],
248 | "location": {
249 | "lat": 48.849021,
250 | "lng": 2.377700
251 | },
252 | "storeId": "marchedaligre",
253 | "name": "Marché d’Aligre",
254 | "address": {
255 | "lines": [
256 | "Place d’Aligre"
257 | ],
258 | "country": "France",
259 | "city": "Paris",
260 | "zipcode": "75012"
261 | },
262 | "contact": {
263 | "website": "http://equipement.paris.fr/marche-couvert-beauvau-marche-d-aligre-5480",
264 | "phone": "01 45 11 71 11"
265 | },
266 | "openingHours": {
267 | "timezone": "Europe/Paris",
268 | "usual": {
269 | "default": [
270 | {
271 | "start": "09:00",
272 | "end": "13:00"
273 | },
274 | {
275 | "start": "16:00",
276 | "end": "19:30"
277 | }
278 | ],
279 | "6": [
280 | {
281 | "start": "09:00",
282 | "end": "13:00"
283 | },
284 | {
285 | "start": "15:30",
286 | "end": "19:30"
287 | }
288 | ],
289 | "7": [
290 | {
291 | "start": "09:00",
292 | "end": "13:00"
293 | }
294 | ]
295 | }
296 | }
297 | },
298 | {
299 | "types": [
300 | "covered"
301 | ],
302 | "location": {
303 | "lat": 43.776540,
304 | "lng": 11.253133
305 | },
306 | "storeId": "mercatocentraledisanlorenzo",
307 | "name": "Mercato Centrale di San Lorenzo",
308 | "address": {
309 | "lines": [
310 | "Piazza del Mercato Centrale",
311 | "Via dell'Ariento"
312 | ],
313 | "country": "Italy",
314 | "city": "Firenze",
315 | "zipcode": "50123"
316 | },
317 | "contact": {
318 | "website": "http://www.mercatocentrale.it",
319 | "phone": "+39 0552399798",
320 | "email": "info@mercatocentrale.it"
321 | },
322 | "openingHours": {
323 | "timezone": "Europe/Madrid",
324 | "usual": {
325 | "default": [
326 | {
327 | "start": "10:00",
328 | "end": "23:59"
329 | }
330 | ]
331 | }
332 | }
333 | },
334 | {
335 | "types": [
336 | "covered"
337 | ],
338 | "location": {
339 | "lat": 55.684025,
340 | "lng": 12.569469
341 | },
342 | "storeId": "torvehallerne",
343 | "name": "Torvehallerne",
344 | "address": {
345 | "lines": [
346 | "Frederiksborggade 21"
347 | ],
348 | "country": "Denmark",
349 | "city": "Copenhagen",
350 | "zipcode": "1360"
351 | },
352 | "contact": {
353 | "website": "http://torvehallernekbh.dk",
354 | "phone": "+39 0552399798",
355 | "email": "info@torvehallernekbh.dk"
356 | },
357 | "openingHours": {
358 | "timezone": "Europe/Copenhagen",
359 | "usual": {
360 | "default": [
361 | {
362 | "start": "10:00",
363 | "end": "19:00"
364 | }
365 | ],
366 | "5": [
367 | {
368 | "start": "10:00",
369 | "end": "20:00"
370 | }
371 | ],
372 | "6": [
373 | {
374 | "start": "10:00",
375 | "end": "18:00"
376 | }
377 | ],
378 | "7": [
379 | {
380 | "start": "11:00",
381 | "end": "17:00"
382 | }
383 | ]
384 | }
385 | }
386 | },
387 | {
388 | "types": [
389 | "covered"
390 | ],
391 | "location": {
392 | "lat": 51.505046,
393 | "lng": -0.090679
394 | },
395 | "storeId": "boroughmarket",
396 | "name": "Borough Market",
397 | "address": {
398 | "lines": [
399 | "8 Southwark St"
400 | ],
401 | "country": "United Kingdom",
402 | "city": "London",
403 | "zipcode": "SE1 1TL"
404 | },
405 | "contact": {
406 | "website": "http://boroughmarket.org.uk",
407 | "phone": "020 7407 1002"
408 | },
409 | "openingHours": {
410 | "timezone": "Europe/London",
411 | "usual": {
412 | "default": [
413 | {
414 | "start": "10:00",
415 | "end": "17:00"
416 | }
417 | ],
418 | "5": [
419 | {
420 | "start": "10:00",
421 | "end": "18:00"
422 | }
423 | ],
424 | "7": []
425 | }
426 | }
427 | },
428 | {
429 | "types": [
430 | "covered"
431 | ],
432 | "location": {
433 | "lat": 48.135105,
434 | "lng": 11.576246
435 | },
436 | "storeId": "victualsmarket",
437 | "name": "Victuals Market",
438 | "address": {
439 | "lines": [
440 | "Viktualienmarkt 3"
441 | ],
442 | "country": "Germany",
443 | "city": "München",
444 | "zipcode": "80881"
445 | },
446 | "contact": {
447 | "website": "http://www.muenchen.de/int/en/shopping/markets/viktualienmarkt.html",
448 | "phone": "+49 89 89068205"
449 | },
450 | "openingHours": {
451 | "timezone": "Europe/Berlin",
452 | "usual": {
453 | "default": [
454 | {
455 | "start": "10:00",
456 | "end": "18:00"
457 | }
458 | ],
459 | "6": [
460 | {
461 | "start": "10:00",
462 | "end": "15:00"
463 | }
464 | ],
465 | "7": []
466 | }
467 | }
468 | },
469 | {
470 | "types": [
471 | "covered"
472 | ],
473 | "location": {
474 | "lat": 43.40214,
475 | "lng": 3.69545
476 | },
477 | "storeId": "hallesdesete",
478 | "name": "Halles de Sète",
479 | "address": {
480 | "lines": [
481 | "Rue Gambetta"
482 | ],
483 | "country": "France",
484 | "city": "Sète",
485 | "zipcode": "34200"
486 | },
487 | "contact": {
488 | "website": "http://www.halles-sete.com/",
489 | "phone": "04 99 04 70 00",
490 | "email": "commerce-artisanat@ville-sete.fr"
491 | },
492 | "openingHours": {
493 | "timezone": "Europe/Paris",
494 | "usual": {
495 | "default": [
496 | {
497 | "start": "08:00",
498 | "end": "13:00"
499 | }
500 | ]
501 | }
502 | }
503 | },
504 | {
505 | "types": [
506 | "outside"
507 | ],
508 | "location": {
509 | "lat": 44.011821,
510 | "lng": 4.418889
511 | },
512 | "storeId": "marcheduzes",
513 | "name": "Marché d'Uzès",
514 | "address": {
515 | "lines": [
516 | "Place aux Herbes"
517 | ],
518 | "country": "France",
519 | "city": "Uzès",
520 | "zipcode": "30700"
521 | },
522 | "contact": {
523 | "website": "http://www.uzes.fr/Calendrier-des-marches-brocantes-et-foires_a126.html",
524 | "phone": "+33 (0)4 66 22 68 88"
525 | },
526 | "openingHours": {
527 | "timezone": "Europe/Paris",
528 | "usual": {
529 | "default": [
530 | {
531 | "start": "07:30",
532 | "end": "13:00"
533 | }
534 | ],
535 | "1": [],
536 | "2": [],
537 | "4": [],
538 | "5": [],
539 | "7": []
540 | }
541 | }
542 | },
543 | {
544 | "types": [
545 | "outside"
546 | ],
547 | "location": {
548 | "lat": 43.876503,
549 | "lng": 5.393588
550 | },
551 | "storeId": "marchedapt",
552 | "name": "Le Grand Marché d'Apt",
553 | "address": {
554 | "lines": [
555 | "Place de la Bouquerie"
556 | ],
557 | "country": "France",
558 | "city": "Apt",
559 | "zipcode": "84400"
560 | },
561 | "contact": {
562 | "website": "http://www.luberon-apt.fr/index.php/fr/sortir/les-marches",
563 | "phone": "+33 (0)4 90 74 03 18",
564 | "email": "oti@paysapt-luberon.fr"
565 | },
566 | "openingHours": {
567 | "timezone": "Europe/Paris",
568 | "usual": {
569 | "default": [
570 | {
571 | "start": "08:00",
572 | "end": "13:00"
573 | }
574 | ],
575 | "1": [],
576 | "2": [],
577 | "3": [],
578 | "4": [],
579 | "5": [],
580 | "7": []
581 | }
582 | }
583 | },
584 | {
585 | "types": [
586 | "outside"
587 | ],
588 | "location": {
589 | "lat": 46.187465,
590 | "lng": -1.327086
591 | },
592 | "storeId": "marchedelaflotte",
593 | "name": "Le Marché de la Flotte",
594 | "address": {
595 | "lines": [
596 | "Rue du Marché"
597 | ],
598 | "country": "France",
599 | "city": "La Flotte",
600 | "zipcode": "17630"
601 | },
602 | "contact": {
603 | "website": "http://laflotte.fr/index.php/Vie-quotidienne/les-marches.html",
604 | "phone": "05.46.09.15.00",
605 | "email": "annie@laflotte.fr"
606 | },
607 | "openingHours": {
608 | "timezone": "Europe/Paris",
609 | "usual": {
610 | "default": [
611 | {
612 | "start": "08:00",
613 | "end": "13:00"
614 | }
615 | ]
616 | }
617 | }
618 | },
619 | {
620 | "types": [
621 | "outside"
622 | ],
623 | "location": {
624 | "lat": 55.947817,
625 | "lng": -3.203562
626 | },
627 | "storeId": "edimburghfarmersmarket",
628 | "name": "Edimburgh Farmers' Market",
629 | "address": {
630 | "lines": [
631 | "Castle Terrace"
632 | ],
633 | "country": "Scotland",
634 | "city": "Edimburgh",
635 | "zipcode": "EH1 UK"
636 | },
637 | "contact": {
638 | "website": "http://www.edinburghfarmersmarket.co.uk/",
639 | "phone": "0131 220 8580"
640 | },
641 | "openingHours": {
642 | "timezone": "Europe/London",
643 | "usual": {
644 | "default": [],
645 | "6": [
646 | {
647 | "start": "09:00",
648 | "end": "14:00"
649 | }
650 | ]
651 | }
652 | }
653 | },
654 | {
655 | "types": [
656 | "covered"
657 | ],
658 | "location": {
659 | "lat": 54.596073,
660 | "lng": -5.921654
661 | },
662 | "storeId": "stgeorgesmarket",
663 | "name": "St George's Market",
664 | "address": {
665 | "lines": [
666 | "12 - 20 East Bridge Street"
667 | ],
668 | "country": "Ireland",
669 | "city": "Belfast",
670 | "zipcode": "BT1 3NQ"
671 | },
672 | "contact": {
673 | "website": "http://www.belfastcity.gov.uk/tourism-venues/stgeorgesmarket/stgeorgesmarket-index.aspx",
674 | "phone": "028 9043 5704",
675 | "email": "markets@belfastcity.gov.uk"
676 | },
677 | "openingHours": {
678 | "timezone": "Europe/London",
679 | "usual": {
680 | "default": [],
681 | "5": [
682 | {
683 | "start": "06:00",
684 | "end": "14:00"
685 | }
686 | ],
687 | "6": [
688 | {
689 | "start": "09:00",
690 | "end": "15:00"
691 | }
692 | ],
693 | "7": [
694 | {
695 | "start": "10:00",
696 | "end": "16:00"
697 | }
698 | ]
699 | }
700 | }
701 | },
702 | {
703 | "types": [
704 | "covered"
705 | ],
706 | "location": {
707 | "lat": 50.626710,
708 | "lng": 3.049325
709 | },
710 | "storeId": "hallesdewazemmes",
711 | "name": "Halles de Wazemmes",
712 | "address": {
713 | "lines": [
714 | "Place de la nouvelle aventure"
715 | ],
716 | "country": "France",
717 | "city": "Lille",
718 | "zipcode": "59000"
719 | },
720 | "contact": {
721 | "website": "http://www.halles-wazemmes.com/"
722 | },
723 | "openingHours": {
724 | "timezone": "Europe/Paris",
725 | "usual": {
726 | "default": [
727 | {
728 | "start": "08:00",
729 | "end": "14:00"
730 | }
731 | ],
732 | "1":[],
733 | "5": [
734 | {
735 | "start": "08:00",
736 | "end": "20:00"
737 | }
738 | ],
739 | "6": [
740 | {
741 | "start": "08:00",
742 | "end": "20:00"
743 | }
744 | ],
745 | "7": [
746 | {
747 | "start": "08:00",
748 | "end": "15:00"
749 | }
750 | ]
751 | }
752 | }
753 | }
754 | ]
755 | }
--------------------------------------------------------------------------------
/python-samples/woosmapjson_import/woosmapjson_import.py:
--------------------------------------------------------------------------------
1 | import json
2 | import requests
3 |
4 | WOOSMAP_JSON_FILE = 'foodmarkets.json'
5 | WOOSMAP_PRIVATE_API_KEY = '23713926-1af5-4321-ba54-xxxxxxxxxxx'
6 |
7 |
8 | class Woosmap:
9 | """A wrapper around the Woosmap Data API."""
10 |
11 | WOOSMAP_API_HOSTNAME = 'api.woosmap.com'
12 |
13 | def __init__(self):
14 | self.session = requests.Session()
15 |
16 | def delete(self):
17 | self.session.delete('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
18 | params={'private_key': WOOSMAP_PRIVATE_API_KEY})
19 |
20 | def post(self, payload):
21 | return self.session.post('https://{hostname}/stores/'.format(hostname=self.WOOSMAP_API_HOSTNAME),
22 | params={'private_key': WOOSMAP_PRIVATE_API_KEY},
23 | json={'stores': payload})
24 |
25 | def end(self):
26 | self.session.close()
27 |
28 |
29 | def import_assets(assets_data, woosmap_api_helper):
30 | try:
31 | print('Batch import {count} Assets...'.format(count=len(assets_data)))
32 | response = woosmap_api_helper.post(assets_data)
33 | if response.status_code >= 400:
34 | response.raise_for_status()
35 |
36 | except requests.exceptions.HTTPError as http_exception:
37 | if http_exception.response.status_code >= 400:
38 | print('Woosmap API Import Error: {0}'.format(http_exception.response.text))
39 | else:
40 | print('Error requesting the API: {0}'.format(http_exception))
41 | return False
42 | except Exception as exception:
43 | print('Failed importing Assets! {0}'.format(exception))
44 | return False
45 |
46 | print('Successfully imported in {0} seconds'.format(response.elapsed.total_seconds()))
47 | return True
48 |
49 |
50 | def main():
51 | with open(WOOSMAP_JSON_FILE, 'rb') as f:
52 | assets = json.loads(f.read())
53 | try:
54 | woosmap_api_helper = Woosmap()
55 | # /!\ deleting existing assets before posting new ones /!\
56 | woosmap_api_helper.delete()
57 | import_assets(assets["stores"], woosmap_api_helper)
58 | woosmap_api_helper.end()
59 | except Exception as error:
60 | print("Unable to import file {0} : {1}".format(WOOSMAP_JSON_FILE, error))
61 |
62 |
63 | if __name__ == '__main__':
64 | main()
65 |
--------------------------------------------------------------------------------