diff --git a/src/animate.js b/src/animate.js new file mode 100644 index 0000000..30dcf2a --- /dev/null +++ b/src/animate.js @@ -0,0 +1,213 @@ +// import CoCreateMap from './map' + +/* global CoCreateMap google */ +var CoCreateMapAnimate = function() { + // variables + this.animators = []; + this.icon = {"path":"M29.395,0H17.636c-3.117,0-5.643,3.467-5.643,6.584v34.804c0,3.116,2.526,5.644,5.643,5.644h11.759 c3.116,0,5.644-2.527,5.644-5.644V6.584C35.037,3.467,32.511,0,29.395,0z M34.05,14.188v11.665l-2.729,0.351v-4.806L34.05,14.188z M32.618,10.773c-1.016,3.9-2.219,8.51-2.219,8.51H16.631l-2.222-8.51C14.41,10.773,23.293,7.755,32.618,10.773z M15.741,21.713 v4.492l-2.73-0.349V14.502L15.741,21.713z M13.011,37.938V27.579l2.73,0.343v8.196L13.011,37.938z M14.568,40.882l2.218-3.336 h13.771l2.219,3.336H14.568z M31.321,35.805v-7.872l2.729-0.355v10.048L31.321,35.805","color":"#e50202"}; + + // selectors + this.mapDivSelector = ".google_map"; + // initialize + + this.init(); + + // functions + this.__proto__.init = function() { + let maps = document.querySelectorAll(".google_map[data-map_id]"); + for (let map of maps) { + this.animators[map.dataset.map_id] = {}; + } + }; + + // this.errHandler = function(err, _this) { + // _this.__proto__.errHandler(err); + // }; + + this.__proto__.showPosition = function(){ + console.log("showing Position") + let option = {timeout:5000}; + if (navigator.geolocation) this.watchID = navigator.geolocation.watchPosition( + position=>{ + this.showLocation(position) + }, + err=>{ + this.errHandler(err) + }, option); + else alert("Sorry, your browser does not support HTML5 geolocation."); + }; + + this.__proto__.showLocation = function(position) { + if (!this.checkAnimator('simon')) { + this.__proto__.showLocation(position); + } + this.addAnimator('simon',{'lat':position.coords.latitude,'lng':position.coords.longitude}) + } + + + this.errorCallback=function(error){ + if(error.code == 1) console.log("You've decided not to share your position, but it's OK. We won't ask you again."); + else if(error.code == 2) console.log("The network is down or the positioning service can't be reached."); + else if(error.code == 3) console.log("The attempt timed out before it could get the location data."); + else console.log("Geolocation failed due to unknown error."); + }; + + this.checkAnimator = function(key, map_id = 0) { + return this.animators[map_id][key] !== undefined; + }; + + this.removeAnimator = function(key, map_id = 0) { + this.animators[map_id][key]['marker'].setMap(null); + }; + + this.addAnimator = function(key, location, icon_obj, map_id = 0) { + icon_obj = icon_obj === undefined ? this.icon : icon_obj; + let angle = 0; + if (this.checkAnimator(key)) { + let icon = { // animator icon + path: icon_obj.path, + scale: 0.5, + fillColor: icon_obj.color, //<-- Animator Color, you can change it + fillOpacity: 1, + strokeWeight: 1, + anchor: new google.maps.Point(0, 5), + rotation: angle//<-- Animator angle + }; + console.log(icon); + this.animators[map_id][key]['marker'].setIcon(icon); + this.animatedMove(key, location); + } + else { + let icon = { // animator icon + path: icon_obj.path, + scale: 0.5, + fillColor: icon_obj.color, //<-- Animator Color, you can change it + fillOpacity: 1, + strokeWeight: 1, + anchor: new google.maps.Point(0, 5), + rotation: angle//<-- Animator angle + }; + // var curLocation = { lat: location.lat, lng: location.lng }; + + let marker_id = this.setMarker(map_id, { + position: location, + icon: icon, + title : key + }); + //if(key == getCookie('user_email')){ + this.maps[map_id].setCenter(this.markers[map_id][marker_id].getPosition()); + //} + this.animators[map_id][key] = {}; + this.animators[map_id][key]['loc'] = location; + this.animators[map_id][key]['angle'] = angle; + this.animators[map_id][key]['timestamp'] = new Date(); + this.animators[map_id][key]['marker'] = this.markers[map_id][marker_id]; + this.animators[map_id][key]['icon'] = icon_obj; + } + }; + + this.animatedMove = function(key, locMoveto, map_id = 0) { + //this.removeAnimator(key); + let animator = this.animators[map_id][key]; + let marker = animator['marker']; + let icon = animator['icon']; + let current = marker.position; + let angle = this.bearingBetweenLocations(animator['loc'],locMoveto); + if(!locMoveto.timestamp) locMoveto['timestamp'] = new Date(); + + let deltalat = (locMoveto.lat - current.lat()) / 100; + let deltalng = (locMoveto.lng - current.lng()) / 100; + let deltaangle = this.deltaAngle(angle, animator.angle) / 100; + let deltatime = (locMoveto["timestamp"].getSeconds() - animator.timestamp.getSeconds()); + let pangle = animator.angle; + pangle = this.currentAngle(pangle, deltaangle); + let delay = deltatime; + // let d = new Date(); + // let p = d.getTime(); + for (let i = 0; i < 100; i++) { + (function(ind) { + setTimeout( + function() { + let latlng = null; + let myicon = null; + let lat = marker.position.lat(); + let lng = marker.position.lng(); + lat += deltalat; + lng += deltalng; + + // pangle += deltaangle; + myicon = { // animator icon + path: icon['path'], + scale: 0.5, + fillColor: icon['color'], //<-- Animator Color, you can change it + fillOpacity: 1, + strokeWeight: 1, + anchor: new google.maps.Point(0, 5), + rotation: pangle //<-- Animator angle + }; + + latlng = new google.maps.LatLng(lat, lng); + marker.setPosition(latlng); + marker.setIcon(myicon); + // d = new Date(); + }, ind*delay*10 ); + })(i); + } + + this.animators[map_id][key]['loc'] = locMoveto; + this.animators[map_id][key]['angle'] = angle; + this.animators[map_id][key]['timestamp'] = locMoveto['timestamp']; + this.animators[map_id][key]['marker'] = marker; + }; + + this.bearingBetweenLocations = function(loc1, loc2) { + let RADTODEG = 180 / Math.PI; + let lat1 = loc1.lat / RADTODEG; + let long1 = loc1.lng / RADTODEG; + let lat2 = loc2.lat / RADTODEG; + let long2 = loc2.lng / RADTODEG; + let dLon = (long2 - long1); + let y = Math.sin(dLon) * Math.cos(lat2); + let x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon); + let brng = Math.atan2(y, x); + brng = brng * RADTODEG; + brng = (brng + 360) % 360; + return brng; + }; + + this.deltaAngle = function(CurrentAngle, PreviousAngle){ + let delta = CurrentAngle - PreviousAngle; + return delta; + }; + + this.currentAngle = function(current , delta){ + if (current+delta<0 ) { + return 360+(current+delta); + } else if (current+delta>360) { + return (current+delta)%360; + } else{ + return current+delta; + } + }; + + // this.simulate = function(){ + // cocreateLocation.addAnimator('jean',{'lat':20.9182675,'lng':-100.7446703}) + // // entre 0 y 9 + // for(var i=0;i<=100;i++){ + // setTimeout(function(){ + // var lat = parseFloat('20.918'+Math.floor(Math.random() * 10)+'675'); + // var lng = parseFloat('-100.744'+Math.floor(Math.random() * 10)+'703'); + // cocreateLocation.addAnimator('jean',{'lat':lat,'lng':lng}) + // },5000); + // } + // }; + + CoCreateMap.call(this); +}; + +CoCreateMapAnimate.prototype = Object.create(CoCreateMap.prototype); +CoCreateMapAnimate.prototype.constructor = CoCreateMapAnimate; + +// functions for prototype + +// declaration diff --git a/src/archive/autocomplete.1.js b/src/archive/autocomplete.1.js new file mode 100644 index 0000000..d171301 --- /dev/null +++ b/src/archive/autocomplete.1.js @@ -0,0 +1,141 @@ +import CoCreateMap from './map' + +/* global CoCreateMap onlyUnique, google, stripHtml */ +var CoCreateMapAutocomplete = function() { + // variables + // this.depth = 1; + this.componentForm = { + location: '', + street_number: '', + route: '', + locality: '', + administrative_area_level_1: '', + administrative_area_level_2: '', + administrative_area_level_3: '', + city: '', + country: '', + country_code: '', + postal_code: '', + new_param1: '', + new_param2: '' + }; + // selectors + this.mapDivSelector = ".google_map"; + this.autocompleteSelector = '[data-map_autocomplete="true"]'; + this.searchSelector = ".main-search"; + + // initialize + // this.__proto__.init(); + this.init(); + + // functions + this.init = function() { + this.initComponentForm(); + this.initAutoComplete(); + }; + this.initComponentForm = function() { + for (var key in this.componentForm) { + var input_item = document.querySelector("input[data-place=" + key + "]"); + if (input_item) this.componentForm[key] = input_item.dataset.place_value_type ? input_item.dataset.place_value_type : "long_name"; + else this.componentForm[key] = "long_name"; + } + }; + this.initAutoComplete = function() { + let _this = this; + let places = document.querySelectorAll("[data-place]"); + let ids = []; + for (let item of places) { + ids.push(item.dataset.place_id); + } + let place_type_json = {'address':'address','administrative_area_level_2':'(cities)','region_country':'(regions)','establishment':'establishment'}; + ids = ids.filter(onlyUnique); + ids.forEach(function(element, index){ + let place_id = element; + let autocomplete_item = document.querySelectorAll(`${_this.autocompleteSelector}[data-place_id='${place_id}']`); + // let fieldSetting = ['address_components', 'geometry', 'icon', 'name']; + autocomplete_item.forEach(function(element, j){ + let autocomplete; + let place_type = element.dataset.place; + // if(Object.keys(place_type_json).indexOf(place_type)!=-1) + if (place_type_json[place_type] !== undefined) autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:[place_type_json[place_type]]}); + /*if (place_type == "address") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['address']}); + if (place_type == "administrative_area_level_2") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['(cities)']}); + if (place_type == "region_country") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['(regions)']}); + if (place_type == "establishment") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['establishment']});*/ + // else autocomplete.setFields(fieldSetting); // omit for all fields + if (element.matches(_this.searchSelector)) + autocomplete.addListener('place_changed', function() { + let place = autocomplete.getPlace(); + let placeInfo = {}; + placeInfo["place_id"] = element.dataset.place_id; + placeInfo["google_place_id"] = place.place_id; + placeInfo["address_components"] = place.address_components; + if (place.adr_address) placeInfo["adr_address"] = stripHtml(place.adr_address); + placeInfo["longitude"] = place.geometry.location.lng(); + placeInfo["latitude"] = place.geometry.location.lat(); + placeInfo["show_map"] = element.dataset.direction != "destination" || element.dataset.autodirection == "false"; + _this.renderAutoComplete(placeInfo); + }); + }); + }); + }; + + this.objToAtt = function(object, attributeName, addInfo = "", parentInfo = "") { + let result = {}; + for (let key in object) { + if (key == "address_components") { + for (let data of object[key]) { + let type = data.types[0]; + result[type] = data.long_name; + if (type == "country") { + result["country_code"] = data.short_name; + result["region_country"] = data.long_name; + } + if (type == "administrative_area_level_1" && !result["administrative_area_level_2"]) result["administrative_area_level_2"] = data.long_name; + } + } + else if (key == "adr_address") result["address"] = object[key]; + else if (key == "place_id") continue; + else if (key == "google_place_id") result["place_id"] = object[key]; + else result[key] = object[key]; + } + this.__proto__.objToAtt(result, attributeName, addInfo, parentInfo); + }; + + this.renderAutoComplete = function(place) { + let place_id = place.place_id; + this.objToAtt(place, "place", `[data-place_id='${place_id}']`); + let longitude = document.querySelector(`[data-place='longitude'][data-place_id='${place_id}']`); + let latitude = document.querySelector(`[data-place='latitude'][data-place_id='${place_id}']`); + if (longitude && latitude) { + if ("createEvent" in document) { + var evt = document.createEvent("HTMLEvents"); + evt.initEvent("change", false, true); + longitude.dispatchEvent(evt); + latitude.dispatchEvent(evt); + } + else { + longitude.fireEvent("onchange"); + latitude.fireEvent("onchange"); + } + } + if (place.show_map) { + var map_id = document.querySelector(`[data-place_id='${place_id}']`).dataset.map_id; + var mapDiv = document.querySelector(`${this.mapDivSelector}[data-map_id='${map_id}']`); + if (mapDiv) { + mapDiv.dataset.map_lng = place.longitude; + mapDiv.dataset.map_lat = place.latitude; + } + } + }; + + CoCreateMap.call(this); +}; + +CoCreateMapAutocomplete.prototype = Object.create(CoCreateMap.prototype); +CoCreateMapAutocomplete.prototype.constructor = CoCreateMapAutocomplete; + +export default CoCreateMapAutocomplete; +// functions for prototype + +// declaration \ No newline at end of file diff --git a/src/autocomplete.js b/src/autocomplete.js new file mode 100644 index 0000000..96eae7c --- /dev/null +++ b/src/autocomplete.js @@ -0,0 +1,141 @@ +// import CoCreateMap from './map' + +/* global CoCreateMap onlyUnique, google, stripHtml */ +var CoCreateMapAutocomplete = function() { + // variables + // this.depth = 1; + this.componentForm = { + location: '', + street_number: '', + route: '', + locality: '', + administrative_area_level_1: '', + administrative_area_level_2: '', + administrative_area_level_3: '', + city: '', + country: '', + country_code: '', + postal_code: '', + new_param1: '', + new_param2: '' + }; + // selectors + this.mapDivSelector = ".google_map"; + this.autocompleteSelector = '[data-map_autocomplete="true"]'; + this.searchSelector = ".main-search"; + + // initialize + // this.__proto__.init(); + this.init(); + + // functions + this.init = function() { + this.initComponentForm(); + this.initAutoComplete(); + }; + this.initComponentForm = function() { + for (var key in this.componentForm) { + var input_item = document.querySelector("input[data-place=" + key + "]"); + if (input_item) this.componentForm[key] = input_item.dataset.place_value_type ? input_item.dataset.place_value_type : "long_name"; + else this.componentForm[key] = "long_name"; + } + }; + this.initAutoComplete = function() { + let _this = this; + let places = document.querySelectorAll("[data-place]"); + let ids = []; + for (let item of places) { + ids.push(item.dataset.place_id); + } + let place_type_json = {'address':'address','administrative_area_level_2':'(cities)','region_country':'(regions)','establishment':'establishment'}; + ids = ids.filter(onlyUnique); + ids.forEach(function(element, index){ + let place_id = element; + let autocomplete_item = document.querySelectorAll(`${_this.autocompleteSelector}[data-place_id='${place_id}']`); + // let fieldSetting = ['address_components', 'geometry', 'icon', 'name']; + autocomplete_item.forEach(function(element, j){ + let autocomplete; + let place_type = element.dataset.place; + // if(Object.keys(place_type_json).indexOf(place_type)!=-1) + if (place_type_json[place_type] !== undefined) autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:[place_type_json[place_type]]}); + /*if (place_type == "address") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['address']}); + if (place_type == "administrative_area_level_2") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['(cities)']}); + if (place_type == "region_country") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['(regions)']}); + if (place_type == "establishment") autocomplete = new google.maps.places.Autocomplete(autocomplete_item.item(j), {types:['establishment']});*/ + // else autocomplete.setFields(fieldSetting); // omit for all fields + if (element.matches(_this.searchSelector)) + autocomplete.addListener('place_changed', function() { + let place = autocomplete.getPlace(); + let placeInfo = {}; + placeInfo["place_id"] = element.dataset.place_id; + placeInfo["google_place_id"] = place.place_id; + placeInfo["address_components"] = place.address_components; + if (place.adr_address) placeInfo["adr_address"] = stripHtml(place.adr_address); + placeInfo["longitude"] = place.geometry.location.lng(); + placeInfo["latitude"] = place.geometry.location.lat(); + placeInfo["show_map"] = element.dataset.direction != "destination" || element.dataset.autodirection == "false"; + _this.renderAutoComplete(placeInfo); + }); + }); + }); + }; + + this.objToAtt = function(object, attributeName, addInfo = "", parentInfo = "") { + let result = {}; + for (let key in object) { + if (key == "address_components") { + for (let data of object[key]) { + let type = data.types[0]; + result[type] = data.long_name; + if (type == "country") { + result["country_code"] = data.short_name; + result["region_country"] = data.long_name; + } + if (type == "administrative_area_level_1" && !result["administrative_area_level_2"]) result["administrative_area_level_2"] = data.long_name; + } + } + else if (key == "adr_address") result["address"] = object[key]; + else if (key == "place_id") continue; + else if (key == "google_place_id") result["place_id"] = object[key]; + else result[key] = object[key]; + } + this.__proto__.objToAtt(result, attributeName, addInfo, parentInfo); + }; + + this.renderAutoComplete = function(place) { + let place_id = place.place_id; + this.objToAtt(place, "place", `[data-place_id='${place_id}']`); + let longitude = document.querySelector(`[data-place='longitude'][data-place_id='${place_id}']`); + let latitude = document.querySelector(`[data-place='latitude'][data-place_id='${place_id}']`); + if (longitude && latitude) { + if ("createEvent" in document) { + var evt = document.createEvent("HTMLEvents"); + evt.initEvent("change", false, true); + longitude.dispatchEvent(evt); + latitude.dispatchEvent(evt); + } + else { + longitude.fireEvent("onchange"); + latitude.fireEvent("onchange"); + } + } + if (place.show_map) { + var map_id = document.querySelector(`[data-place_id='${place_id}']`).dataset.map_id; + var mapDiv = document.querySelector(`${this.mapDivSelector}[data-map_id='${map_id}']`); + if (mapDiv) { + mapDiv.dataset.map_lng = place.longitude; + mapDiv.dataset.map_lat = place.latitude; + } + } + }; + + CoCreateMap.call(this); +}; + +CoCreateMapAutocomplete.prototype = Object.create(CoCreateMap.prototype); +CoCreateMapAutocomplete.prototype.constructor = CoCreateMapAutocomplete; + +/*export default CoCreateMapAutocomplete;*/ +// functions for prototype + +// declaration \ No newline at end of file diff --git a/src/direction.js b/src/direction.js new file mode 100644 index 0000000..a3c9bab --- /dev/null +++ b/src/direction.js @@ -0,0 +1,201 @@ +// import CoCreateMap from './map' + +var CoCreateMapDirection = function() { + // variables + // this.depth = 1; + this.isDirectionShowing = false; + + // functions + this.init(); + + this.init = function() { + let _this = this; + + let dstElements = document.querySelectorAll("[data-direction='destination'][data-map_id][data-place='longitude'], [data-direction='destination'][data-map_id][data-place='latitude']"); + dstElements.forEach(function(element, index){ + element.addEventListener("change", function(event){ + let map_id = element.dataset.map_id; + _this.prepareDirection(map_id); + }); + }); + + let options = document.querySelectorAll(".direction_option:not([data-autodirection='false']) input[data-direction]"); + options.forEach(function(element, index){ + element.addEventListener("change", function(event){ + let map_id = element.dataset.map_id; + _this.prepareDirection(map_id); + }); + }); + + let elementsForClear = document.querySelectorAll("input[data-direction='waypoint']"); + elementsForClear.forEach(function(element, index){ + element.addEventListener("change", function(event){ + let map_id = element.dataset.map_id; + let place_id = element.dataset.place_id; + if (_this.isDirectionShowing) { + _this.clearAll.clearAll(`input[data-direction='waypoint'][data-map_id='${map_id}']:not([data-place_id='${place_id}'])`); + _this.isDirectionShowing = false; + } + }); + }); + }; + + this.attToObj = function(attributeName, addInfo, parentInfo) { + let obj = this.__proto__.attToObj(attributeName, addInfo, parentInfo); + let result = {}; + for (let key in obj) { + if (key == "arrivalTime" || key == "routingPreference") { + result["transitOptions"] = result["transitOptions"] || {}; + result["transitOptions"][key] = obj[key]; + } + else if (key == "t_departureTime") { + result["transitOptions"] = result["transitOptions"] || {}; + result["transitOptions"]["departureTime"] = obj[key]; + } + else if (key == "transit_modes") { + result["transitOptions"] = result["transitOptions"] || {}; + result["transitOptions"]["modes"] = obj[key]; + } + else if (key == "d_departureTime") { + result["drivingOptions"] = result["drivingOptions"] || {}; + result["drivingOptions"]["departureTime"] = obj[key]; + } + else if (key == "trafficModel") { + result["drivingOptions"] = result["drivingOptions"] || {}; + result["drivingOptions"][key] = obj[key]; + } + else result[key] = obj[key]; + } + return result; + }; + + this.prepareDirection = function(map_id) { + const _this = this; + const waypointElements = document.querySelectorAll(`[data-direction='waypoint'][data-map_id='${map_id}'][data-place='longitude'], [data-direction='waypoint'][data-map_id='${map_id}'][data-place='latitude']`); + var latlngs = []; + var points = []; + for (var wpElement of waypointElements) { + if (!wpElement.value) continue; + var place_id = wpElement.dataset.place_id; + if (latlngs[place_id]) { + if (wpElement.dataset.place == "latitude") { + points.push({lat:wpElement.value, lng:latlngs[place_id]}); + } + else + points.push({lat:latlngs[place_id], lng:wpElement.value}); + delete latlngs[place_id]; + } + else { + latlngs[place_id] = wpElement.value; + } + } + console.log(waypointElements); + var srcLng = document.querySelector(`[data-direction='origin'][data-place='longitude'][data-map_id='${map_id}']`).value; + var srcLat = document.querySelector(`[data-direction='origin'][data-place='latitude'][data-map_id='${map_id}']`).value; + var dstLng = document.querySelector(`[data-direction='destination'][data-place='longitude'][data-map_id='${map_id}']`).value; + var dstLat = document.querySelector(`[data-direction='destination'][data-place='latitude'][data-map_id='${map_id}']`).value; + if (srcLng && srcLat && dstLng && dstLat) { + // Redraw Map + const center = this.maps[map_id].getCenter(); + const zoom = this.maps[map_id].getZoom(); + this.maps[map_id] = new google.maps.Map( + document.querySelector(`.google_map[data-map_id='${map_id}']`), {center: center, zoom: zoom}); + + let object = this.attToObj("direction", `[data-map_id='${map_id}']`, ".direction_option"); + let request = { + ...{ + map_id: map_id, + origin: {lat:srcLat, lng:srcLng}, + destination: {lat:dstLat, lng:dstLng}, + waypoints: points, + travelMode: "DRIVING" + }, + ...object + }; + _this.renderDirection(request); + } + }; + /* + directionInfo = { + map_id: "0", + origin:{lng:"", lat:""}, + destination:{lng:"", lat:""}, + waypoints:[ + {lng:"", lat:""}, + {lng:"", lat:""}, + ... + ], + travelMode:"DRIVING" | "BICYCLING" | "TRANSIT" | "WALKING", + transitOptions:{ + arrivalTime: Date, + departureTime: Date, + modes:["BUS", "RAIL", "SUBWAY", "TRAIN", "TRAM"], + routingPreference: "FEWER_TRANSFERS" | "LESS_WALKING" + }, + drivingOptions:{ + departureTime: Date, + trafficModel: "bestguess" | "pessimistic" | "optimistic" + }, + unitSystem: "METRIC" | "IMPERIAL", + optimizeWaypoints: true | false, + provideRouteAlternatives: true | false, + avoidFerries: true | false, + avoidHighways: true | false, + avoidTolls: true | false + } + */ + this.renderDirection = function(directionInfo) { + let directionsService = new google.maps.DirectionsService(); + let directionsRenderer = new google.maps.DirectionsRenderer({draggable:true}); + let request = {}; + for (let key in directionInfo) { + let element = directionInfo[key]; + if (key == "map_id") continue; + else if (key == "origin" || key == "destination") { + request[key] = {}; + request[key] = new google.maps.LatLng(element.lat, element.lng); + } + else if (key == "waypoints") { + request[key] = []; + for (let waypoint of element) request[key].push({location: new google.maps.LatLng(waypoint.lat, waypoint.lng)}); + } + else if (key == "transitOptions") { + let to = {}; + if (element.arrivalTime) to["arrivalTime"] = new Date(element.arrivalTime); + if (element.departureTime) to["departureTime"] = new Date(element.departureTime); + if (element.modes) to["modes"] = element.modes; + if (element.routingPreference) to["routingPreference"] = element.routingPreference; + request[key] = to; + } + else if (key == "drivingOptions") { + let to = {}; + if (element.departureTime) to["departureTime"] = new Date(element.departureTime); + to["trafficModel"] = element.trafficModel; + request[key] = to; + } + else if (key == "unitSystem") request[key] = element.unitSystem == "METRIC" ? google.maps.UnitSystem.METRIC : google.maps.UnitSystem.IMPERIAL; + else request[key] = element; + } + directionsRenderer.setMap(this.maps[directionInfo.map_id]); + console.log(request); + directionsService.route(request, function(result, status) { + if (status == 'OK') { + directionsRenderer.setDirections(result); + this.isDirectionShowing = true; + } + else { + alert("No result!"); + } + }); + }; + + CoCreateMap.call(this); +}; + +CoCreateMapDirection.prototype = Object.create(CoCreateMap.prototype); +CoCreateMapDirection.prototype.constructor = CoCreateMapDirection; + +// functions for prototype + + +// declaration \ No newline at end of file diff --git a/src/location.js b/src/location.js new file mode 100644 index 0000000..d49688d --- /dev/null +++ b/src/location.js @@ -0,0 +1,115 @@ +// import CoCreateMap from './map' + +/*Class Custom*/ + +var CoCreateMapGetLocation = function() { + //init custom + /*query mongo + > use mydb + > db.getCollection("users").find({"_id": ObjectId("5de03b9cc745412976891133")})*/ + this.attr = 'data-geolocation'; + this.geolocation_html = null; + + this.init = ()=>{ + if(!this.ccMapAnimate){ + this.ccMapAnimate = new CoCreateMapAnimate(); + } + this.geolocation_html = document.querySelector("["+this.attr+"]"); + if(this.geolocation_html && this.geolocation_html.getAttribute(this.attr)=='true'){ + console.log("initialite map"); + this.showPosition(); + } + // CoCreateSocket.listen('updateDocument', (data) =>{ + // console.log(data); + // if (data) + // this.createAnimator(data.data.currentLocation, data.document_id, data.data.icon); + // }); + } + + this.createAnimator = (position, document_id, icon)=>{ + this.ccMapAnimate.addAnimator(document_id,{'lat':position.coords.latitude,'lng':position.coords.longitude}, icon) // sending data + } + + this.saveData =(position)=>{ + try { + CoCreate.validateKeysJson(this.geolocation_html.dataset,['collection','document_id']); + let collection = this.geolocation_html.dataset['collection'] || ''; + let document_id = this.geolocation_html.dataset['document_id'] || ''; + // textinput to object + let icon = document.querySelector("input[data-animator='icon']").value; + console.log(icon); + if (icon) { + icon = JSON.parse(icon); + } else { + icon = this.icon; + } + if(collection != '') + if (document_id != ''){ + console.log("Saved location in db", document_id); + let obj = { + collection: collection, + document_id: document_id, + data:{ + currentLocation: this.getPositionAsJSon(position), + icon:icon + } + }; + console.log(obj); + CoCreate.crud.updateDocument(obj); + } else { + document_id = CoCreate.crud.createDocument({ + collection:collection, + data:{ + currentLocation: this.getPositionAsJSon(position), + icon:icon + } + }); + console.log(document_id); + this.geolocation_html.setAttribute("data-document_id", document_id); + } + } + catch (e) { + console.error(e); + } + } + + this.getPositionAsJSon=(position)=>{ + return { + coords: { + accuracy: position.coords.accuracy, + altitude: position.coords.altitude, + altitudeAccuracy: position.coords.altitudeAccuracy, + heading: position.coords.heading, + latitude: position.coords.latitude, + longitude: position.coords.longitude, + speed: position.coords.speed, + }, + timestamp: position.timestamp, + geoLocation: { + latitude: position.coords.latitude, + longitude: position.coords.longitude, + } + }; + } + + this.showLocation=(position) =>{ + // console.log(this); + // Check position has been changed or not before doing anything + if(this.prevLat != position.coords.latitude || this.prevLong != position.coords.longitude){ + // Set previous location + this.prevLat = position.coords.latitude; + this.prevLong = position.coords.longitude; + // console.log(position); + this.saveData(position); + var positionInfo = "Your position is (" + "Latitude: " + position.coords.latitude + ", " + "Longitude: " + position.coords.longitude + ")"; + // document.getElementById("result").innerHTML = positionInfo; + + } + } + + CoCreateMapAnimate.call(this); +}; + +CoCreateMapGetLocation.prototype = Object.create(CoCreateMapAnimate.prototype); +CoCreateMapGetLocation.prototype.constructor = CoCreateMapGetLocation; +// var CoCreateMapGetLocation = new CoCreateMapGetLocation(); diff --git a/src/map.js b/src/map.js new file mode 100644 index 0000000..a863cb3 --- /dev/null +++ b/src/map.js @@ -0,0 +1,214 @@ +var CoCreateMap = function(object) { + + // variables + // this.depth = 0; + + // selectors + this.mapDivSelector = ".google_map"; + + // functions + this.init(object); + + this.requireLocationSelector = "data-geolocation"; +}; + +/* global navigator, MutationObserver, google */ +CoCreateMap.prototype = { + mapDivs:[], + maps:[], + services:[], + markers:[], // MultiMarker & control + constructor: CoCreateMap, + init: function(object){ + let _this = this; + this.__proto__.mapDivs = document.querySelectorAll(this.mapDivSelector); + if (object !== undefined) { + this.renderMap(object.mapInfo, object.markerInfo); + } + else { + let curLocation = document.querySelector(`[${this.requireLocationSelector}]`); + let isCurLocation = curLocation ? curLocation.getAttribute(this.requireLocationSelector) : false; + if (navigator.geolocation && isCurLocation == "true") { + let options = {timeout:5000}; + navigator.geolocation.getCurrentPosition(this.showLocation, this.errHandler, options); + } + else this.errHandler({code:1}); + } + + let observer = new MutationObserver( + function (mutationList, observer) { + mutationList.forEach(mutation => { + if (mutation.type == "attributes" && (mutation.attributeName == "data-map_lng" || mutation.attributeName == "data-map_lat" || mutation.attributeName == "data-map_zoom") && mutation.target.matches(_this.mapDivSelector) && mutation.target.attributes["data-map_id"]) + cbObserver(mutation, _this); + }); + }); + let config = { attributes: true, subtree: true }; + observer.observe(document.body, config); + + function cbObserver(mutation, _this) { + let lat = mutation.target.dataset.map_lat; + let lng = mutation.target.dataset.map_lng; + if (lat && lng) { + let zoom = mutation.target.dataset.map_zoom; + if (!zoom) zoom = undefined; + let mapInfo = new MapInfo(mutation.target.dataset.map_id, lng, lat, zoom); + _this.renderMap(mapInfo); + } + } + }, + showLocation: function(position) { + let latitude = position.coords.latitude; + let longitude = position.coords.longitude; + for (let map of this.mapDivs) { + let mapInfo = new MapInfo(map.dataset.map_id, longitude, latitude); + this.renderMap(mapInfo); + } + }, + errHandler: function(err) { + if(err.code == 1) + for (let map of this.mapDivs) { + let mapInfo = new MapInfo(map.dataset.map_id); + this.renderMap(mapInfo); + } + else if(err.code == 2) + alert("Error: Position is unavailable!"); + }, + renderMap: function(mapInfo, markerInfo) { + let latitude = parseFloat(mapInfo.lat); + let longitude = parseFloat(mapInfo.lng); + let zoom = mapInfo.zoom; + let map_id = mapInfo.map_id; + let map_center = new google.maps.LatLng(latitude, longitude); + this.__proto__.maps[map_id] = new google.maps.Map( + document.querySelector(`.google_map[data-map_id='${map_id}']`), {center: map_center, zoom: zoom}); + // console.log(this.__proto__.maps[map_id].__proto__.getBounds()); + this.__proto__.maps[map_id].__proto__.bounds_changed = () => { + console.log([this.maps[map_id].getCenter().lng(), this.maps[map_id].getCenter().lat()]); + console.log([[this.maps[map_id].getBounds().Ua.i, this.maps[map_id].getBounds().Za.i], [this.maps[map_id].getBounds().Ua.j, this.maps[map_id].getBounds().Za.j]]); + }; + this.__proto__.markers[map_id] = []; + this.__proto__.services[map_id] = new google.maps.places.PlacesService(this.maps[map_id]); + if (markerInfo === undefined) { + // this.createMarker({lat:latitude, lng:longitude}, map_id, true); + // this.setMarker(map_id, {draggable: true, position: {lat:latitude, lng:longitude}}); + } + else { + if (markerInfo.option.position == undefined) markerInfo.option.position = {lat:latitude, lng:longitude}; + this.setMarker(map_id, markerInfo.option, markerInfo.marker_id); + } + }, + /** + * @param map_id : map_id + * @param option : MarkerOptions => option.position : exist - add & update, undefined - delete + * @param marker_id : marker_id : not exist - add, exist - update & delete + * @return marker_id : success - marker_id, failure - -1; + */ + setMarker: function(map_id, option, marker_id) { + option.map = this.maps[map_id]; + if (option.position !== undefined) { // add & update + if (marker_id === undefined) { // add + this.markers[map_id].push(new google.maps.Marker(option)); + return this.markers[map_id].length - 1; + } + else { + this.markers[map_id][marker_id] = new google.maps.Marker(option); + return marker_id; + } + } + else // delete + if (marker_id === undefined) return -1; // error + else { + delete this.markers[map_id][marker_id]; // delete + return marker_id; + } + }, + // createMarker: function(place, map_id, draggable = false) { + // let _this = this; + // // this.__proto__.markers[map_id].push( + // new google.maps.Marker({ + // map: _this.maps[map_id], + // draggable:draggable, + // position: place + // }); + // // ); + // }, + /** + * @param attributeName : data attribute name of input -> object key + * @param addInfo : additional selector of input + * @param parentInfo : parent selector of input + * @return object from attributes + */ + attToObj: function(attributeName, addInfo = "", parentInfo = "") { + let inputs = document.querySelectorAll(`${parentInfo} input[data-${attributeName}]${addInfo}, ${parentInfo} input[name]${addInfo}, ${parentInfo} textarea[data-${attributeName}]${addInfo}, ${parentInfo} textarea[name]${addInfo}`); + let result = {}; + for (let input of inputs) { + let key; + if (input.dataset) key = input.dataset[attributeName]; + if (!key) key = input.getAttribute("name"); + let value; + let type = input.getAttribute("type"); + if (type == "button" || type == "submit" || type == "reset") continue; + if (type == "radio") value = input.checked ? input.value : false; + else if (type == "checkbox") value = input.checked ? (input.getAttribute("value") || true) : false; // checked value = on + else if (input.value) value = input.value; + if (!value) continue; + if (key in result && type != "radio") { + let temp = result[key]; + if (Array.isArray(temp)) result[key].push(value); + else { + result[key] = [temp]; + result[key].push(value); + } + } + else if (value) result[key] = value; + } + return result; + }, + /** + * @param object : data object + * @param attributeName : data attribute name of input <- object key + * @param addInfo : additional selector of input + * @param parentInfo : parent selector of input + */ + objToAtt: function(object, attributeName, addInfo = "", parentInfo = "") { + let inputs = document.querySelectorAll(`${parentInfo} input[data-${attributeName}]${addInfo}, ${parentInfo} input[name]${addInfo}, ${parentInfo} textarea[data-${attributeName}]${addInfo}, ${parentInfo} textarea[name]${addInfo}`); + for (let input of inputs) { + let key; + key = input.dataset[attributeName]; + if (!key) key = input.getAttribute("name"); + let type = input.getAttribute("type"); + if (type == "button" || type == "submit" || type == "reset") continue; + if (type == "radio" && key in object) input.checked = object[key] == input.getAttribute("value") ? true : false; + else if (type == "checkbox" && key in object) input.checked = (object[key] == input.getAttribute("value")) || (Array.isArray(object[key]) && object[key].includes(input.getAttribute("value"))) ? true : false; // checked value = on + else if (key in object) input.value = object[key]; + } + } +}; + +function MapInfo(map_id, lng, lat, zoom) { + this.lat; + this.lng; + this.zoom; + this.map_id; + this.init(map_id, lng, lat, zoom); +} + +MapInfo.prototype = { + constructor: MapInfo, + init: function(map_id = 0, lng = -74.0060, lat = 40.7128, zoom = 15) { + this.lat = parseFloat(lat); + this.lng = parseFloat(lng); + this.zoom = parseInt(zoom, 10); + this.map_id = map_id; + } +}; + +function stripHtml(html) { + var tmp = document.createElement("div"); + tmp.innerHTML = html; + return tmp.textContent || tmp.innerText || ""; +} + +function onlyUnique(value, index, self) { + return self.indexOf(value) === index; +} \ No newline at end of file diff --git a/src/search.js b/src/search.js new file mode 100644 index 0000000..7509e20 --- /dev/null +++ b/src/search.js @@ -0,0 +1,212 @@ +// import CoCreateMap from './map' + +var CoCreateMapSearch = function() { + // variables + // this.depth = 1; + + // functions + this.init(); + + this.init = function() { + var _this = this; + document.querySelectorAll(".search").forEach(element => { + element.addEventListener("click", function(){ + let map_id = this.dataset.map_id; + _this.search(_this, map_id); + }); + }); + }; + + this.search = function(_this, map_id) { + let searchType = document.querySelector(`[data-map_id='${map_id}'][name='searchType']:checked`).value; + let locationBias = document.querySelector(`[data-map_id='${map_id}'][name='locationBias']:checked`).value; + let input = this.attToObj("option_attribute", `[data-map_id='${map_id}']`); + let object = {}; + if (searchType == "searchFromQuery" || searchType == "searchFromPhoneNumber") { + object = { + fields:['All'] + }; + if (locationBias == "LatLng" && input.latitude && input.longitude) // only one location, maybe nearest. + object.locationBias = { + lat:parseFloat(input.latitude), + lng:parseFloat(input.longitude) + }; + else if (locationBias == "LatLngBounds") + object.locationBias = _this.maps[map_id].getBounds(); + else if (locationBias == "Radius") + object.locationBias = { + radius:parseInt(input.radius, 10), + center:{ + lat:parseFloat(input.latitude), + lng:parseFloat(input.longitude) + } + }; + if (searchType == "searchFromQuery"){ + object.query = input.query; + _this.searchFromQuery(object, map_id); + } + else { + object.phoneNumber = input.query; + _this.searchFromPhoneNumber(object, map_id); + } + console.log(object); + } + else if (searchType == "searchNearBy") { + object = { + keyword:input.query + }; + if (locationBias == "LatLngBounds") + object.bounds = _this.maps[map_id].getBounds(); + else if (locationBias == "Radius") { + object.location = { + lat:parseFloat(input.latitude), + lng:parseFloat(input.longitude) + }; + object.radius = parseInt(input.radius, 10); + } + if (input.keyword) object.keyword = input.keyword; + if (input.minPriceLevel) object.minPriceLevel = input.minPriceLevel; + if (input.maxPriceLevel) object.maxPriceLevel = input.maxPriceLevel; + if (input.name) object.name = input.name; + if (input.openNow) object.openNow = input.openNow; + if (input.rankBy) object.rankBy = google.maps.places.RankBy.DISTANCE; + console.log(object); + _this.searchNearBy(object, map_id); + } + else if (searchType == "searchText") { + object = { + query:input.query + }; + if (locationBias == "LatLngBounds") + object.bounds = _this.maps[map_id].getBounds(); + else if (locationBias == "Radius") { + object.location = new google.maps.LatLng( + { + lat:parseFloat(input.latitude), + lng:parseFloat(input.longitude) + }); + object.radius = parseInt(input.radius); + } + if (input.openNow) object.openNow = input.openNow; + if (input.minPriceLevel) object.minPriceLevel = input.minPriceLevel; + if (input.maxPriceLevel) object.maxPriceLevel = input.maxPriceLevel; + _this.searchText(object, map_id); + } + }; + /* + object = { + query*: "", + fields*: ['All'], + locationBias: {lat: 37.402105, lng: -122.081974}, || {north: 37.41, south: 37.40, east: -122.08, west: -122.09} || {radius: 100, center: {lat: 37.402105, lng: -122.081974}} + + } + */ + this.searchFromQuery = function(object, map_id) { + let _this = this; + this.services[map_id].findPlaceFromQuery(object, function(results, status) { + if (status === google.maps.places.PlacesServiceStatus.OK) { + let request = { + placeId: results[0].place_id + } + _this.findDetails(request, map_id); + } + }); + }; + /* + object = { + query*: "", + fields*: ['All'], + locationBias: {lat: 37.402105, lng: -122.081974}, || {north: 37.41, south: 37.40, east: -122.08, west: -122.09} || {radius: 100, center: {lat: 37.402105, lng: -122.081974}} + } + */ + this.searchFromPhoneNumber = function(object, map_id) { + let _this = this; + this.services[map_id].findPlaceFromPhoneNumber(object, function(results, status) { + if (status === google.maps.places.PlacesServiceStatus.OK) { + let request = { + placeId: results[0].place_id + }; + _this.findDetails(request, map_id); + } + }); + }; + /* + object = { + (bounds*: google.maps.LatLngBounds(), || + (location*: google.maps.LatLng(), + radius*: "500", // at most 50000)) + keyword: "", + minPriceLevel: "", + maxPriceLevel: "", + name: "", + openNow: true || false, + rankBy: google.maps.places.RankBy.PROMINENCE (default) || google.maps.places.RankBy.DISTANCE, + type: [] // all types following the first entry are ignored + } + */ + this.searchNearBy = function(object, map_id) { + let _this = this; + this.services[map_id].nearbySearch(object, function(results, status) { + if (status === google.maps.places.PlacesServiceStatus.OK) { + console.log(results); + for (let result of results) { + let request = { + placeId: result.place_id + }; + _this.findDetails(request, map_id); + } + } + }); + }; + /* + object = { + query*: "", + openNow: true || false, + minPriceLevel: "", + maxPriceLevel: "", + (bounds*: google.maps.LatLngBounds(), || + (location*: google.maps.LatLng(), + radius*: "500", // at most 50000)) + type: [] // all types following the first entry are ignored + } + */ + this.searchText = function(object, map_id) { + let _this = this; + this.services[map_id].textSearch(object, function(results, status) { + if (status === google.maps.places.PlacesServiceStatus.OK) { + console.log(results); + for (let result of results) { + let request = { + placeId: result.place_id + }; + _this.findDetails(request, map_id); + } + } + }); + }; + /* + object = { + placeId: "", + fields: [] + } + */ + this.findDetails = function(object, map_id) { + let _this = this; + console.log(object); + this.services[map_id].getDetails(object, function(place, status){ + if (status === google.maps.places.PlacesServiceStatus.OK) { + let position = place.geometry.location; + _this.createMarker(position, map_id); + } + }); + }; + + CoCreateMap.call(this); +}; + +CoCreateMapSearch.prototype = Object.create(CoCreateMap.prototype); +CoCreateMapSearch.prototype.constructor = CoCreateMapSearch; + +// functions for prototype + +// declaration \ No newline at end of file