app.js 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262
  1. // file:///Users/francoisbeaufils/Downloads/geocoder-demo-master/index.html
  2. var app = angular.module('application', ['ngMaterial', 'adaptive.detection']);
  3. app.directive('skrollr', function() {
  4. var directiveDefinitionObject = {
  5. link: function() {
  6. skrollr.init();
  7. }
  8. };
  9. return directiveDefinitionObject;
  10. });
  11. app.controller('mainController', function($scope, $detection, $http, $mdSidenav, $timeout, $sce, $mdToast) {
  12. $scope.title = "Manche Numerique";
  13. var nbJoursFTTH = 300,
  14. siteName = 'Eligibilité Manche Numérique',
  15. siteUrl = 'http://eligibilite.manchenumerique.fr',
  16. siteEmail = 'ftth@manchenumerique.fr',
  17. siteAddresse= '235, rue Joseph Cugnot Zone Delta, 50000 SAINT LÔ';
  18. var catTypeVoie = [
  19. {
  20. "name": "Allée",
  21. "id" : "allee"
  22. },
  23. {
  24. "name": "Avenue",
  25. "id" : "avenue"
  26. },
  27. {
  28. "name": "Boulevard",
  29. "id" : "boulevard"
  30. },
  31. {
  32. "name": "Carrefour",
  33. "id" : "carrefour"
  34. },
  35. {
  36. "name": "Chemin",
  37. "id" : "chemin"
  38. },
  39. {
  40. "name": "Cité",
  41. "id" : "cite"
  42. },
  43. {
  44. "name": "Hammeau",
  45. "id" : "hammeau"
  46. },
  47. {
  48. "name": "Impasse",
  49. "id" : "impasse"
  50. },
  51. {
  52. "name": "Lieu-dit",
  53. "id" : "lieu_dit"
  54. },
  55. {
  56. "name": "Lotissement",
  57. "id" : "lotissement"
  58. },
  59. {
  60. "name": "Place",
  61. "id" : "place"
  62. },
  63. {
  64. "name": "Résidence",
  65. "id" : "residence"
  66. },
  67. {
  68. "name": "Route",
  69. "id" : "route"
  70. },
  71. {
  72. "name": "Rue",
  73. "id" : "rue"
  74. },
  75. {
  76. "name": "Villa",
  77. "id" : "villa"
  78. },
  79. {
  80. "name": "Village",
  81. "id" : "village"
  82. }
  83. ];
  84. var catVousEtes = [
  85. {
  86. "name": "Locataire de ce logement",
  87. "id" : "locataire"
  88. },
  89. {
  90. "name": "Occupant à titre gratuit de ce logement",
  91. "id" : "occupant_gratuit"
  92. },
  93. {
  94. "name": "Propriétaire de ce logement",
  95. "id" : "proprietaire"
  96. }
  97. ];
  98. var catCeLogementEst = [
  99. {
  100. "name": "Votre résidence principale",
  101. "id" : "residence_principale"
  102. },
  103. {
  104. "name": "Votre résidence secondaire",
  105. "id" : "residence_secondaire"
  106. }
  107. ];
  108. $scope.formulaires = {
  109. "eligibilite": {
  110. "sections": [
  111. {
  112. "name": "Générale",
  113. "visible": false,
  114. "lines": [
  115. {
  116. "ctrls": [
  117. {
  118. "name" : "Prénom",
  119. "id" : "prenom",
  120. "type" : "text",
  121. "width" : "50%",
  122. "require": true,
  123. "isValid": function(value) {
  124. return !!value && value.length > 2;
  125. },
  126. "msg" : 'Prénom invalide'
  127. },
  128. {
  129. "name" : "Nom",
  130. "id" : "nom",
  131. "type" : "text",
  132. "width" : "50%",
  133. "require": true,
  134. "isValid": function(value) {
  135. return !!value && value.length > 2;
  136. },
  137. "msg" : 'Nom invalide'
  138. }
  139. ]
  140. },
  141. {
  142. "ctrls": [
  143. {
  144. "name" : "Email",
  145. "id" : "email",
  146. "type" : "text",
  147. "width" : null,
  148. "require": true,
  149. "isValid": function(value) {
  150. function validateEmail(email) {
  151. var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
  152. return re.test(email);
  153. }
  154. return validateEmail(value);
  155. },
  156. "msg" : 'Email invalide.'
  157. }
  158. ]
  159. },
  160. {
  161. "ctrls": [
  162. {
  163. "name" : "Téléphone fixe",
  164. "id" : "telephone_fixe",
  165. "type" : "text",
  166. "width" : "50%",
  167. "require": false
  168. },
  169. {
  170. "name" : "Téléphone portable",
  171. "id" : "telephone_portable",
  172. "type" : "text",
  173. "width" : "50%",
  174. "require": false
  175. }
  176. ]
  177. }
  178. ]
  179. },
  180. {
  181. "name": "Adresse",
  182. "visible": true,
  183. "lines": [
  184. {
  185. "ctrls": [
  186. {
  187. "name" : "Numero",
  188. "id" : "numero_voie",
  189. "type" : "text",
  190. "width" : "80px",
  191. "require": false
  192. },
  193. {
  194. "name" : "Type voie",
  195. "id" : "type_voie",
  196. "type" : "select",
  197. "width" : "106px",
  198. "require": false,
  199. "options": {
  200. "categories": catTypeVoie
  201. }
  202. },
  203. {
  204. "name" : "Nom voie",
  205. "id" : "nom_voie",
  206. "type" : "text",
  207. "width" : "378px",
  208. "require": true,
  209. "isValid": function(value) {
  210. return !!value;
  211. },
  212. "msg" : 'Nom de voie invalide.'
  213. }
  214. ]
  215. },
  216. {
  217. "ctrls": [
  218. {
  219. "name" : "Complément Adresse",
  220. "id" : "complement_addresse",
  221. "type" : "textarea",
  222. "width" : null,
  223. "require": false
  224. }
  225. ]
  226. },
  227. {
  228. "ctrls": [
  229. {
  230. "name" : "Bâtiment",
  231. "id" : "batiment",
  232. "type" : "text",
  233. "width" : "50%",
  234. "require": false
  235. },
  236. {
  237. "name" : "Cage escalier",
  238. "id" : "cage_escalier",
  239. "type" : "text",
  240. "width" : "50%",
  241. "require": false
  242. }
  243. ]
  244. },
  245. {
  246. "ctrls": [
  247. {
  248. "name" : "Etage / Niveau",
  249. "id" : "etage",
  250. "type" : "text",
  251. "width" : "50%",
  252. "require": false
  253. },
  254. {
  255. "name" : "Numero appartement / porte",
  256. "id" : "numero_appartement",
  257. "type" : "text",
  258. "width" : "50%",
  259. "require": false
  260. }
  261. ]
  262. },
  263. {
  264. "ctrls": [
  265. {
  266. "name" : "Code postal",
  267. "id" : "code_postal",
  268. "type" : "text",
  269. "width" : "50%",
  270. "require": true,
  271. "isValid": function(value) {
  272. if(!value || value.length !== 5 || isNaN(parseInt(value, 10))) {
  273. return false;
  274. }
  275. return true;
  276. },
  277. "msg" : 'Non valide'
  278. },
  279. {
  280. "name" : "Ville",
  281. "id" : "ville",
  282. "type" : "text",
  283. "width" : "50%",
  284. "require": true,
  285. "isValid": function(value) {
  286. return !!value && value.length > 2;
  287. },
  288. "msg" : 'Ville invalide.'
  289. }
  290. ]
  291. }
  292. ]
  293. },
  294. {
  295. "name": "Logement",
  296. "visible": true,
  297. "lines": [
  298. {
  299. "ctrls": [
  300. {
  301. "name" : "Vous êtes",
  302. "id" : "vous_etes",
  303. "type" : "radio",
  304. "width" : null,
  305. "require": true,
  306. "options": {
  307. "categories": catVousEtes,
  308. "alertes": {
  309. "locataire": "Si vous êtes locataire, vous devez impérativement avertir votre propriétaire que vous souhaitez bénéficier du pré-raccordement à la fibre optique."
  310. }
  311. },
  312. "isValid": function(value) {
  313. return !!value;
  314. },
  315. "msg" : 'Vous devez sélectionner une entrée.'
  316. }
  317. ]
  318. },
  319. {
  320. "ctrls": [
  321. {
  322. "name" : "Ce logement est",
  323. "id" : "ce_logement_est",
  324. "type" : "radio",
  325. "width" : null,
  326. "require": true,
  327. "options": {
  328. "categories": catCeLogementEst
  329. },
  330. "isValid": function(value) {
  331. return !!value;
  332. },
  333. "msg" : 'Vous devez sélectionner une entrée.'
  334. }
  335. ]
  336. }
  337. ]
  338. },
  339. {
  340. "name": "Conditions pour le raccordement final d’abonné dans un immeuble individuel",
  341. "visible": true,
  342. "lines": [
  343. {
  344. "text": "Le Syndicat Mixte Manche Numérique, composé du Département de la Manche et des Etablissements Publics de Coopération Intercommunale (EPCI) du département, a pour mission l'aménagement numérique du territoire manchois, du point de vue tant des réseaux que du développement des usages du numérique.\r\nDans ce cadre, Manche Numérique a élaboré un Schéma Directeur Territorial d'Aménagement Numérique (SDTAN), qui vise une couverture FTTH (fibre optique jusqu’à l’abonné) universelle du département. Le SDTAN prévoit ainsi le déploiement d’un réseau de communications électroniques à très haut débit FTTH sur le territoire de la Manche.\r\nManche Numérique assurera le déploiement de ce réseau public sous sa maîtrise d’ouvrage. S’agissant de l’exploitation du réseau, celle-ci sera confiée à un délégataire de service public désigné par Manche Numérique à l’issue d’une procédure de mise en concurrence. Le futur gestionnaire du réseau aura en charge notamment sa commercialisation auprès des opérateurs de communications électroniques (les fournisseurs d’accès à internet), qui eux-mêmes délivreront des services de communications électroniques aux utilisateurs finals (les abonnés).\r\nDans le cadre du déploiement de ce réseau, Manche Numérique réalise sous sa maîtrise d’ouvrage des raccordements finals d’abonnés au futur réseau, qui seront ensuite remis au futur délégataire de service public en vue de leur gestion.\r\nC’est dans ce contexte que Manche Numérique propose aux intéressés qui le souhaitent, de faire d’ores et déjà raccorder leur logement ou local à usage professionnel, au futur réseau de communications électroniques à très haut débit FTTH.",
  345. "ctrls": [
  346. {
  347. "name" : "Accord",
  348. "id" : "accord",
  349. "libelle": "Je souhaite être pré-raccordé au réseau de fibre optique et accepte les conditions de paiement de 50€. IMPORTANT : le règlement ne vous sera demandé qu’après travaux effectués",
  350. "type" : "checkbox",
  351. "width" : null,
  352. "require": true,
  353. "isValid": function(value) {
  354. return !!value;
  355. },
  356. "msg" : 'Vous devez doner votre accord.'
  357. }
  358. ]
  359. }
  360. ]
  361. },
  362. {
  363. "name": "Informatique et libertés",
  364. "visible": false,
  365. "lines": [
  366. {
  367. "ctrls": [
  368. {
  369. "name" : "Informatique et libertés",
  370. "id" : "info_et_libertes",
  371. "libelle": 'La personne responsable du traitement de la présente demande de pré-raccordement est le représentant du Syndicat Mixte Manche Numérique, le Président, Monsieur Serge DESLANDES. Les informations portées sur ce formulaire sont obligatoires. Elles font l’objet d’un traitement informatisé destiné au raccordement final de l’usager à la fibre optique (FTTH) ainsi qu’à l’exploitation du réseau optique. Les destinataires des données sont : le Syndicat Mixte Manche Numérique, les entreprises en charge de réaliser les travaux de raccordement, ainsi que l’exploitant du réseau optique. Conformément à la loi "informatique et libertés" du 6 janvier 1978 modifiée, vous bénéficiez d’un droit d’accès, de rectification aux informations qui vous concernent, d’opposition au traitement de vos données personnelles. Si vous souhaitez exercer ce droit et obtenir communication des informations vous concernant, veuillez-vous adresser au Syndicat Mixte Manche Numérique ftth@manchenumerique.fr. Dans l’hypothèse où le présent formulaire est incomplet et/ou illisible, la présente demande de raccordement ne sera pas traitée.',
  372. "type" : "checkbox",
  373. "width" : null,
  374. "require": true,
  375. "isValid": function(value) {
  376. return !!value;
  377. },
  378. "msg" : 'Vous devez accepter.'
  379. }
  380. ]
  381. }
  382. ]
  383. }
  384. ]
  385. }
  386. };
  387. var computeDateFTTH = function() {
  388. if(!$scope.results.ftth) {return;}
  389. // A date already exists
  390. if($scope.results.ftth.DATE_OUV_SERVICE_REEL || $scope.results.ftth.DATE_OUV_SERVICE_PREV) {
  391. $scope.results.ftth.date = $scope.results.ftth.DATE_OUV_SERVICE_REEL || $scope.results.ftth.DATE_OUV_SERVICE_PREV;
  392. return;
  393. }
  394. // Compute Date
  395. var momentDate = moment($scope.results.ftth.DATE_FIN_TRAV_PREV, 'DD/MM/YY');
  396. momentDate.add(nbJoursFTTH, 'days');
  397. $scope.results.ftth.date = momentDate.format('DD/MM/YYYY');
  398. };
  399. $scope.closeRight = function() {
  400. $mdSidenav('right').close().then(function(){});
  401. };
  402. $scope.toggleRight = function() {
  403. $mdSidenav('right').toggle()
  404. .then(function(){});
  405. };
  406. var stlo = [49.1154686, -1.0828136000000086];
  407. var map = L.map('map', {zoomControl:false}).setView(stlo, 9);
  408. map.on('dblclick', function(e) {
  409. var p = e.latlng;
  410. //console.log('click', e.latlng); // e is an event object (MouseEvent in this case)
  411. $scope.geoCode = {
  412. x: p.lng,
  413. y: p.lat
  414. };
  415. addCurrentMarker();
  416. $scope.showResultPane();
  417. getResults();
  418. });
  419. //http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
  420. //http://{s}.api.cartocdn.com/base-light/{z}/{x}/{y}.png
  421. //http://{s}.api.cartocdn.com/base-flatblue/{z}/{x}/{y}.png
  422. //http://{s}.api.cartocdn.com/base-dark/{z}/{x}/{y}.png
  423. //http://{s}.tile.osm.org/{z}/{x}/{y}.png
  424. //http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/14/5616/8137
  425. var maps = {
  426. "carte" : 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}',
  427. "satellite" : 'http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
  428. };
  429. var cLayer = L.tileLayer(maps.carte, {
  430. attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
  431. maxZoom: 18
  432. }).addTo(map);
  433. var styleOpts = {
  434. color : 'red',
  435. fillColor: 'red',
  436. weight : 8
  437. };
  438. $scope.data = {};
  439. var parseData = function(identifier, data, style, properties) {
  440. var getPolygonsCoord = function(type, coord) {
  441. var result = [];
  442. if(type === 'Polygon') {
  443. result.push(_.map(coord[0], function(r) {return [r[1], r[0]];}));
  444. }
  445. if(type === 'MultiPolygon') {
  446. var p = [];
  447. _.each(coord, function(c) {
  448. result.push(_.map(c[0], function(r) {return [r[1], r[0]];}));
  449. });
  450. }
  451. return result;
  452. };
  453. var records = [];
  454. _.each(data.features, function(r) {
  455. var record = r.properties;
  456. var polygons = getPolygonsCoord(r.geometry.type, r.geometry.coordinates);
  457. record._coordinates = r.geometry.coordinates;
  458. record._type = r.geometry.type;
  459. record._polygons = polygons;
  460. record._style = style;
  461. record._properties = properties;
  462. records.push(record);
  463. });
  464. $scope.data[identifier] = records;
  465. };
  466. var isDate = function(value) {
  467. return (value.toString().length === 14 && value.toString().substring(0,2) === "20");
  468. };
  469. var formatDate = function(value) {
  470. return moment(value.toString().substr(0,4) + '-' + value.toString().substr(4,2) + '-' + value.toString().substr(6,2)).locale("fr");
  471. };
  472. $scope.getHtmlContent = function(identifier, record) {
  473. var title = record._properties.name.string ? record._properties.name.string : record[record._properties.name.key];
  474. // Tooltip content
  475. var tooltip = '<div class="popup-line"><span class="popup-title">' + title +'</span></div>' +
  476. '<hr>';
  477. _.each(record, function(value, property) {
  478. if(property.charAt(0) === '_' ||
  479. (record._properties.hidden && record._properties.hidden.indexOf(property) !== -1) ||
  480. record._properties.name.key === property ||
  481. value === null |
  482. typeof value === 'undefined') {
  483. return;
  484. }
  485. var label = $scope.dictionary[property] || property;
  486. value = $scope.dictionary[value] || value;
  487. var date;
  488. if(property.substring(0, 5) === 'DATE_' && !$scope.dictionary[value] && isDate(value)) {
  489. date = formatDate(value);
  490. }
  491. tooltip += '<div class="popup-line"><div class="popup-label">' + label + '</div><div class="popup-value">' + (date ? date.locale("fr").format('ddd, LL') : value) + '</div><div class="popup-small-date">' + (date ? date.locale("fr").fromNow() : '') + '</div></div>';
  492. });
  493. return tooltip;
  494. };
  495. $scope.formatResults = function(identifier, results) {
  496. return $sce.trustAsHtml($scope.getHtmlContent(identifier, results));
  497. };
  498. $scope.formatDateFTTH = function(date) {
  499. if(!date) {return;}
  500. var momentDate = moment(date, 'DD/MM/YYYY');
  501. var result = '<div class="popup-line"><div class="box-eligibilite-title">Date prévisionnelle abonnement FTTH</div><div style="font-weight: bold;" class="popup-value">' + momentDate.locale("fr").format('ddd, LL') + '</div><div class="popup-small-date">' + momentDate.locale("fr").fromNow() + '</div></div>';
  502. return $sce.trustAsHtml(result);
  503. };
  504. var layer = {};
  505. $scope.computeLayer = function(identifier) {
  506. var Lpolygons = [];
  507. _.each($scope.data[identifier], function(record) {
  508. _.each(record._polygons, function(polygon) {
  509. Lpolygons.push(L.polygon(polygon, record._style).bindPopup($scope.getHtmlContent(identifier, record)));
  510. });
  511. });
  512. layer[identifier] = L.layerGroup(Lpolygons);
  513. };
  514. $scope.showLayer = function(identifier) {
  515. map.addLayer(layer[identifier]);
  516. };
  517. $scope.hideLayer = function(identifier) {
  518. map.removeLayer(layer[identifier]);
  519. };
  520. $scope.colors = {
  521. "ftth": "#8cc474", // green
  522. "mimo": "#f9b256", // orange
  523. "adsl": "#76a7fa" // blue
  524. };
  525. $http({method: 'POST', url: 'data/dictionary.json'}).success(function(data) {
  526. $scope.dictionary = data;
  527. });
  528. $http({method: 'POST', url: 'data/Contour_Manche.json'}).success(function(data) {
  529. var style = {
  530. color : 'blue',
  531. fillColor: 'blue',
  532. weight : 2
  533. };
  534. $scope.data.manche = [{
  535. _polygons : [data.features[0].geometry.coordinates[0]],
  536. _style : style,
  537. _properties : {
  538. name : {string: 'Manche'}
  539. }
  540. }];
  541. var mancheCoordinates = data && data.features && data.features[0] && data.features[0].geometry && data.features[0].geometry.coordinates && data.features[0].geometry.coordinates[0]; // response data
  542. _.each(mancheCoordinates, function(c, i) {
  543. mancheCoordinates[i] = [c[1], c[0]];
  544. });
  545. // Rectangle coordinates around Manche
  546. //var mancheCoordinates = [[49.732307856286, -1.97117692088061],[48.4, -1.75],[48.4, -0.5],[49.732307856286, -1.2]];
  547. // Debug: show manche limits
  548. //L.polygon(mancheCoordinates, {color: 'blue', fillColor: 'blue',weight: 8}).addTo(map);
  549. var searchExtent = {
  550. "xmin" : _.max(_.map(mancheCoordinates, function(c) {return c[1];})),
  551. "ymin" : _.max(_.map(mancheCoordinates, function(c) {return c[0];})),
  552. "xmax" : _.min(_.map(mancheCoordinates, function(c) {return c[1];})),
  553. "ymax" : _.min(_.map(mancheCoordinates, function(c) {return c[0];})),
  554. "spatialReference" : {"wkid" : 84}
  555. };
  556. var suggestURL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/suggest?f=pjson&searchExtent=' + JSON.stringify(searchExtent);
  557. var findURL = 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find?f=pjson&searchExtent=' + JSON.stringify(searchExtent);
  558. $('.address-bar input').typeahead({
  559. onSelect: function(item) {
  560. $scope.address = item.text;
  561. var suggestion = _.find($scope.suggestions, {text: item.text});
  562. $scope.magicKey = suggestion && suggestion.magicKey;
  563. $scope.$evalAsync();
  564. $scope.onSubmitAddress();
  565. },
  566. ajax: {
  567. url: suggestURL,
  568. timeout: 500,
  569. displayField: "text",
  570. triggerLength: 1,
  571. method: "get",
  572. loadingClass: "loading-circle",
  573. preDispatch: function (query) {
  574. var q = query;
  575. $('.typeahead.dropdown-menu').hide();
  576. $scope.suggestions = null;
  577. return {
  578. text: q
  579. };
  580. },
  581. valueField: 'suggestions',
  582. preProcess: function (data) {
  583. //console.log('suggestions', data && data.suggestions);
  584. $scope.suggestions = data.suggestions;
  585. $scope.magicKey = null;
  586. return data.suggestions;
  587. }
  588. }
  589. });
  590. $scope.getGeoCode = function(address, magicKey, callback) {
  591. //console.log('address, magicKey', address, magicKey);
  592. getGeoCodeInProgress = true;
  593. var url = findURL + "&text=" + address + ((magicKey) ? ("&magicKey=" + magicKey) : ', Basse-Normandie, France');
  594. //console.log('url', url);
  595. $.get(
  596. url,
  597. function(data, status) {
  598. data = JSON.parse(data);
  599. if (status === 'success' && data.locations[0]) {
  600. if(data.locations[0].extent.xmax < searchExtent.xmin &&
  601. data.locations[0].extent.xmax > searchExtent.xmax &&
  602. data.locations[0].extent.xmin > searchExtent.xmax&&
  603. data.locations[0].extent.xmin > searchExtent.xmax) {
  604. getGeoCodeInProgress = false;
  605. return callback(null, data);
  606. }
  607. getGeoCodeInProgress = false;
  608. callback('No result for ' + address);
  609. } else {
  610. getGeoCodeInProgress = false;
  611. callback(status !== 'success' ? status : 'No result for ' + address);
  612. }
  613. });
  614. };
  615. });
  616. //console.time('FTTH data');
  617. $http({method: 'POST', url: 'data/FTTH_zapm_partielle.json'}).success(function(data) {
  618. var style = {
  619. color : $scope.colors.ftth,
  620. fillColor: $scope.colors.ftth,
  621. weight : 2
  622. };
  623. var properties = {
  624. name : {key: 'ATD'},
  625. hidden: ['ID_PM', 'MARCHE', 'ID_FT_ADSL', 'ID_FTTH_MN_ZAPM_PARTIELLE', 'ID_ZAPM_PARTIELLE', 'ID_ZAPM'],
  626. position: ['DATE_DEB_TRAV_PREV']
  627. };
  628. parseData('ftth', data, style, properties);
  629. //console.timeEnd('FTTH data');
  630. //console.debug('Data for FTTH are ready', data);
  631. if($scope.data.mimo && $scope.data.adsl && $scope.data.ftth) {
  632. $scope.loaded = true;
  633. }
  634. $scope.$evalAsync();
  635. });
  636. //console.time('ADSL data');
  637. $http({method: 'POST', url: 'data/TEL_FT_ADSL.json'}).success(function(data) {
  638. var style = {
  639. color : $scope.colors.adsl,
  640. fillColor: $scope.colors.adsl,
  641. weight : 2
  642. };
  643. var properties = {
  644. name : {key: 'LEGENDE'},
  645. hidden: ['NATURE', 'NRA_CETE', 'NRA_TMP', 'NRA_DPT', 'ID_FT_ADSL']
  646. };
  647. parseData('adsl', data, style, properties);
  648. //console.timeEnd('ADSL data');
  649. //console.debug('Data for ADSL are ready', data);
  650. if($scope.data.mimo && $scope.data.adsl && $scope.data.ftth) {
  651. $scope.loaded = true;
  652. }
  653. $scope.$evalAsync();
  654. });
  655. //console.time('MiMo data');
  656. $http({method: 'POST', url: 'data/Couverture_mimo.json'}).success(function(data) {
  657. var style = {
  658. color : $scope.colors.mimo,
  659. fillColor: $scope.colors.mimo,
  660. weight : 2
  661. };
  662. var properties = {
  663. name : {string: 'Couverture MiMo'},
  664. hidden: ['ID_MIMO_COUVERTURE']
  665. };
  666. parseData('mimo', data, style, properties);
  667. //console.timeEnd('MiMo data');
  668. //console.debug('Data for MIMO are ready', data);
  669. if($scope.data.mimo && $scope.data.adsl && $scope.data.ftth) {
  670. $scope.loaded = true;
  671. }
  672. $scope.$evalAsync();
  673. });
  674. window.map = map;
  675. var getGeoCodeInProgress = false;
  676. var isInside = function(polygon, point) {
  677. // ray-casting algorithm based on
  678. // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
  679. var y = point.x ? point.x : point[0],
  680. x = point.y ? point.y : point[1];
  681. var inside = false;
  682. for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
  683. var xi = polygon[i][0], yi = polygon[i][1];
  684. var xj = polygon[j][0], yj = polygon[j][1];
  685. var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
  686. if (intersect) {
  687. inside = !inside;
  688. }
  689. }
  690. return inside;
  691. };
  692. var getRecordsFor = function(identifier, coordinates) {
  693. var records = [];
  694. _.each($scope.data[identifier], function(record) {
  695. _.some(record._polygons, function(polygon) {
  696. if(isInside(polygon, coordinates)) {
  697. records.push(record);
  698. return true;
  699. }
  700. });
  701. });
  702. // Debug
  703. var debug = false;
  704. if (debug) {
  705. var colors = ['red', 'green', 'blue', 'black', 'silver', 'yellow'];
  706. var marker = L.marker([coordinates.y, coordinates.x]).addTo(map);
  707. var Lpolygons = [];
  708. _.each(records, function(record, i) {
  709. var style = {
  710. color : colors[i],
  711. fillColor: colors[i],
  712. weight : 4
  713. };
  714. _.each(record._polygons, function(polygon) {
  715. Lpolygons.push(L.polygon(polygon, style).bindPopup($scope.getHtmlContent(identifier, record)));
  716. });
  717. });
  718. L.layerGroup(Lpolygons).addTo(map);
  719. }
  720. return records;
  721. };
  722. $scope.showResultPane = function() {
  723. $('#result').animate({height: ($('body').height() / 2) + 'px'}, 1000);
  724. $('#map').animate({
  725. height: ($('body').height() / 2) + 'px',
  726. }, 1000, function() {
  727. // Animation complete.
  728. map.invalidateSize();
  729. map.setView(new L.LatLng($scope.geoCode.y, $scope.geoCode.x), 14);
  730. });
  731. };
  732. $scope.isFormValid = function() {
  733. if(!$scope.result || !$scope.result.eligibilite) {return;}
  734. var isValid = true;
  735. _.each($scope.formulaires.eligibilite.sections, function(section) {
  736. _.each(section.lines, function(line) {
  737. _.each(line.ctrls, function(ctrl) {
  738. ctrl.invalid = false;
  739. if(ctrl.require && !ctrl.isValid($scope.result.eligibilite[ctrl.id])) {
  740. isValid = false;
  741. ctrl.invalid = true;
  742. }
  743. });
  744. });
  745. });
  746. return isValid;
  747. };
  748. $scope.hideResultPane = function() {
  749. if(!$('#result').height()) {return;}
  750. $('#result').animate({height: 0}, 1000);
  751. $('#map').animate({
  752. height: $('body').height(),
  753. }, 1000, function() {
  754. // Animation complete.
  755. map.invalidateSize();
  756. var centerPoint = $scope.geoCode ? new L.LatLng($scope.geoCode.y, $scope.geoCode.x) : stlo;
  757. map.setView(centerPoint, 14);
  758. });
  759. };
  760. var computeFullAdress = function() {
  761. return $scope.result.eligibilite.complement_addresse;
  762. };
  763. var reverseLocation = function(geoCode, address, callback) {
  764. var reverseGeo = 'http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/reverseGeocode?f=pjson&distance=300';
  765. var url = reverseGeo + '&location=' + (geoCode ? $scope.geoCode.x + ',' + $scope.geoCode.y : address) ;
  766. $.get(
  767. url,
  768. function(data, status) {
  769. data = JSON.parse(data);
  770. var adresse = data && data.address && data.address.Match_addr;
  771. if(data && data.address && data.address.Address) {
  772. var i = 0;
  773. var num = '';
  774. while(!isNaN(parseInt(data.address.Address[i], 10))) {
  775. num += data.address.Address[i];
  776. i++;
  777. }
  778. data.address.StreetNumber = num;
  779. data.address.Address = data.address.Address.substr(num.length).trim();
  780. var typeVoie = data.address.Address.substring(0, data.address.Address.indexOf(' ')).toLowerCase();
  781. type = _.find(catTypeVoie, function(c){
  782. if(c.id === typeVoie || c.name.toLowerCase() === typeVoie) {
  783. return true;
  784. }
  785. });
  786. if(type) {
  787. data.address.StreetType = type.id;
  788. data.address.Address = data.address.Address.substr(typeVoie.length).trim();
  789. }
  790. }
  791. if(adresse)
  792. //console.log('Reverse', data, '=>', data && data.address);
  793. callback(adresse, data.address);
  794. $scope.$evalAsync();
  795. });
  796. };
  797. $scope.initPopup = function() {
  798. //console.log('initPopup', $scope.geoCode);
  799. $scope.postForm = null;
  800. reverseLocation($scope.geoCode, null, function(string, address) {
  801. //console.log('add', address);
  802. $scope.result = {eligibilite: {}};
  803. // Debug
  804. // $scope.result.eligibilite.prenom = 'Francois';
  805. // $scope.result.eligibilite.nom = 'Beaufils';
  806. // $scope.result.eligibilite.email = 'francoisbeaufils@zeno-labs.com';
  807. // $scope.result.eligibilite.vous_etes = 'locataire';
  808. // $scope.result.eligibilite.ce_logement_est = 'residence_principale';
  809. // $scope.result.eligibilite.info_et_libertes = true;
  810. // $scope.result.eligibilite.accord = true;
  811. $scope.result.eligibilite.geo_code = JSON.stringify($scope.geoCode);
  812. $scope.result.eligibilite.code_postal = address.Postal;
  813. $scope.result.eligibilite.complement_addresse = address.Match_addr;
  814. $scope.result.eligibilite.nom_voie = address.Address;
  815. $scope.result.eligibilite.numero_voie = address.StreetNumber;
  816. $scope.result.eligibilite.type_voie = address.StreetType;
  817. $scope.result.eligibilite.ville = address.City;
  818. });
  819. };
  820. $scope.postFormEl = function() {
  821. $scope.postForm = {inProgress: true};
  822. //console.log('postForm', $scope.result.eligibilite);
  823. $scope.$evalAsync();
  824. function mysql_real_escape_string (str) {
  825. if(typeof str !== 'string') {return str;}
  826. return str.replace(/[\0\x08\x09\x1a\n\r"'\\\%]/g, function (char) {
  827. switch (char) {
  828. case "\0":
  829. return "\\0";
  830. case "\x08":
  831. return "\\b";
  832. case "\x09":
  833. return "\\t";
  834. case "\x1a":
  835. return "\\z";
  836. case "\n":
  837. return "\\n";
  838. case "\r":
  839. return "\\r";
  840. case "\"":
  841. case "'":
  842. case "\\":
  843. case "%":
  844. return "\\"+char; // prepends a backslash to backslash, percent,
  845. // and double/single quotes
  846. }
  847. });
  848. }
  849. var keys = '';
  850. var values = '';
  851. _.each($scope.result.eligibilite, function(value, key) {
  852. keys += '`' + key + '`, ';
  853. values += "'" + mysql_real_escape_string(value) + "', ";
  854. });
  855. var query = "INSERT INTO `eligibilite`.`demandes` (" + keys.substring(0, keys.length -2) + ") VALUES (" + values.substring(0, values.length -2) + ");";
  856. //console.log('query', query);
  857. $.ajax({
  858. method : "POST",
  859. url : "ajax/datastores.php",
  860. data : {query: query}
  861. })
  862. .done(function( msg ) {
  863. if(!isNaN(msg)) {
  864. $scope.postForm = {ok: true};
  865. var numDemande = moment().format('YYYYMMDD') + msg;
  866. var body = 'Bonjour ' + $scope.result.eligibilite.prenom + ' ' + $scope.result.eligibilite.nom + ', <br>' +
  867. 'Nous vous confirmons votre demande de pré-raccordement FTTH. <br><br>' +
  868. 'Cette demande porte le numéro: ' +
  869. '<span style="color: #31708f;font-size:17px; font-weight:bold;">' + numDemande + '</span><br><br>' +
  870. 'Voici le détail de votre demande:' +
  871. '<div style="color: #31708f;background-color: #d9edf7;border-color: #bce8f1;padding: 10px;margin: 1em;font-size:14px;">' +
  872. '<table style="line-height: 40px;">';
  873. // _.each($scope.result.eligibilite, function(value, key) {
  874. // body += '<tr>';
  875. // body += '<th style="text-align:left;">' + key + '</th>';
  876. // body += '<td>' + value + '</td>';
  877. // body += '</tr>';
  878. // });
  879. // Numero demande
  880. body += '<tr>';
  881. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Numéro demande</th>';
  882. body += '<td>' + numDemande + '</td>';
  883. body += '</tr>';
  884. // Date demande
  885. body += '<tr>';
  886. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Date</th>';
  887. body += '<td>' + moment().lang('fr').format('LLLL') + '</td>';
  888. body += '</tr>';
  889. // Demandeur
  890. body += '<tr>';
  891. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Demandeur</th>';
  892. body += '<td>' + $scope.result.eligibilite.prenom + ' ' + $scope.result.eligibilite.nom + '</td>';
  893. body += '</tr>';
  894. // Email
  895. body += '<tr>';
  896. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Email</th>';
  897. body += '<td>' + $scope.result.eligibilite.email + '</td>';
  898. body += '</tr>';
  899. // Adresse
  900. body += '<tr>';
  901. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Adresse</th>';
  902. body += '<td>' + computeFullAdress() + '</td>';
  903. body += '</tr>';
  904. // Vous etes
  905. var cat = _.find(catVousEtes, {id: $scope.result.eligibilite.vous_etes});
  906. var res = cat && cat.name ? cat.name : $scope.result.eligibilite.vous_etes;
  907. body += '<tr>';
  908. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Vous êtes</th>';
  909. body += '<td>' + res + '</td>';
  910. body += '</tr>';
  911. // Ce logement est
  912. var cat2 = _.find(catCeLogementEst, {id: $scope.result.eligibilite.ce_logement_est});
  913. var res2 = cat2 && cat2.name ? cat2.name : $scope.result.eligibilite.ce_logement_est;
  914. body += '<tr>';
  915. body += '<th style="text-align: left;white-space: nowrap;height: 40px;color: #666;">Ce logement est</th>';
  916. body += '<td>' + res2 + '</td>';
  917. body += '</tr>';
  918. //console.log('$scope.result', $scope.result);
  919. body += '</table></div><br>';
  920. body += 'Conformément à la loi "informatique et libertés" du 6 janvier 1978 modifiée, vous bénéficiez d’un droit d’accès, de rectification aux informations qui vous concernent, d’opposition au traitement de vos données personnelles. Si vous souhaitez exercer ce droit et obtenir communication des informations vous concernant, merci de nous contacter :' + '<br>' +
  921. '<div style="">' +
  922. ' Email: ' + siteEmail + '<br>' +
  923. ' Adresse: ' + siteAddresse + '<br>' +
  924. '</div><br><br>';
  925. body += 'A bientôt sur: <a href="' + siteUrl + '">' + siteName + '</a>';
  926. var mail = {
  927. to : $scope.result.eligibilite.email,
  928. sujet : 'Votre demande de pré-raccordement FTTH n° ' + numDemande,
  929. message: body
  930. };
  931. $.ajax({
  932. method : "POST",
  933. url : "ajax/datastores.php",
  934. data : {mail: mail}
  935. })
  936. .done(function( msg ) {
  937. console.log('Mail result', msg);
  938. });
  939. $scope.result.eligibilite = {};
  940. }
  941. else {
  942. $scope.postForm = {error: msg};
  943. }
  944. $scope.$apply();
  945. });
  946. };
  947. $scope.toggleResultPane = function() {
  948. if($('#result').height()) {
  949. return $scope.hideResultPane();
  950. }
  951. if($scope.results && $scope.results.ftth) {
  952. return $scope.showResultPane();
  953. }
  954. };
  955. var parseResults = function(records) {
  956. if(!records || !records.length) {
  957. return null;
  958. }
  959. if(records.length === 1) {
  960. return records[0];
  961. }
  962. var result = records[0];
  963. return result;
  964. };
  965. var currentMarker;
  966. var ariaz = function(address, callback) {
  967. var url = 'http://www.eligibilite-adsl.com/testXmlAriase.php?ip=80.13.25.43&insee=35238&rivoli=8993&numeroVoie=2&complementNumeroVoie=';
  968. $.get(
  969. url,
  970. function(data, status) {
  971. callback(data);
  972. });
  973. };
  974. var addCurrentMarker = function() {
  975. if(currentMarker) {
  976. map.removeLayer(currentMarker);
  977. }
  978. currentMarker = L.marker([$scope.geoCode.y, $scope.geoCode.x], {draggable: true}).addTo(map); //.bindPopup(data.locations[0].name).openPopup();
  979. reverseLocation($scope.geoCode, null, function(address) {
  980. $scope.address = address;
  981. });
  982. currentMarker.on('dragend', function(event) {
  983. var p = currentMarker.getLatLng();
  984. //console.log('dragend', p);
  985. $scope.geoCode = {
  986. x: p.lng,
  987. y: p.lat
  988. };
  989. reverseLocation($scope.geoCode, null, function(address) {
  990. $scope.address = address;
  991. ariaz(address, function(result) {
  992. //console.log('ariaz', result);
  993. });
  994. getResults();
  995. });
  996. });
  997. };
  998. var getResults = function() {
  999. $scope.results = {};
  1000. $.ajax({
  1001. method : "POST",
  1002. url : "ajax/oracle.php",
  1003. data : $scope.geoCode
  1004. })
  1005. .error(function(err) {
  1006. console.error('Oracle issue', err);
  1007. // Debug without Oracle access
  1008. onResults('{"x":-1.1060984089996,"y":49.119046582,"ftth":[{"ID_ZAPM_PARTIELLE":"203AP0","DATE_OUV_SERVICE_REEL":null,"DATE_OUV_SERVICE_PREV":null,"DATE_FIN_TRAV_PREV":"02\/05\/16"}],"adsl":[{"ID_FT_ADSL":"656","LEGENDE":"TV sur ADSL","NATURE":"0 - 37"}],"mimo":null}');
  1009. })
  1010. .done(function( msg ) {
  1011. onResults(msg);
  1012. });
  1013. var onResults = function(results) {
  1014. try {
  1015. $scope.results = JSON.parse(results);
  1016. $scope.results.address = $scope.address;
  1017. $scope.results.ftth = parseResults($scope.results.ftth);
  1018. $scope.results.adsl = parseResults($scope.results.adsl);
  1019. $scope.results.mimo = parseResults($scope.results.mimo);
  1020. computeDateFTTH();
  1021. }
  1022. catch(e) {
  1023. console.error(e);
  1024. }
  1025. console.log('$scope.results', $scope.results);
  1026. };
  1027. $scope.$evalAsync();
  1028. };
  1029. $scope.onSubmitAddress = function() {
  1030. $scope.results = null;
  1031. $scope.getGeoCode($scope.address, $scope.magicKey, function(err, data) {
  1032. $scope.geoCode = data && data.locations && data.locations[0] && data.locations[0].feature.geometry;
  1033. if(err) {console.error('Geocode error', err);}
  1034. var toast = toast || {
  1035. template: '<md-toast><i class = " md-error"></i> Oups! Aucun résultat trouvé dans la Manche pour: ' + $scope.address + '</md-toast>',
  1036. hideDelay: 3000,
  1037. position: 'bottom right'
  1038. };
  1039. // $mdToast.simple()
  1040. // .template(')
  1041. // .position('bottom right')
  1042. // .hideDelay(3000);
  1043. if(err || !$scope.geoCode) {
  1044. $scope.hideResultPane();
  1045. $mdToast.show(toast);
  1046. }
  1047. //console.log('Addresses found for', $scope.address, '=>', data, '=> Geocode:', $scope.geoCode);
  1048. if($scope.geoCode) {
  1049. addCurrentMarker();
  1050. $scope.showResultPane();
  1051. getResults();
  1052. }
  1053. });
  1054. };
  1055. $scope.mapType = 'Carte';
  1056. $scope.changeMap = function(value) {
  1057. //console.log('Goto', value);
  1058. map.removeLayer(cLayer);
  1059. cLayer = L.tileLayer(maps[value], {
  1060. attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
  1061. maxZoom: 18
  1062. }).addTo(map);
  1063. };
  1064. $scope.view = {};
  1065. $scope.isShown = {};
  1066. $scope.$watch('view', function(view) {
  1067. if(_.isEmpty(view)) {return;}
  1068. $('#layer-loading').removeClass('force-hidden').find('.md-inner').show();
  1069. setTimeout(function() {
  1070. _.each(view, function(value, key) {
  1071. if($scope.isShown[key] !== value) {
  1072. if(value) {
  1073. if(typeof $scope.isShown[key] !== 'undefined') {
  1074. $scope.showLayer(key);
  1075. $('#layer-loading').find('.md-inner').hide();
  1076. }
  1077. else {
  1078. $timeout(function() {
  1079. $scope.computeLayer(key);
  1080. $scope.showLayer(key);
  1081. $('#layer-loading').find('.md-inner').hide();
  1082. }, 500);
  1083. }
  1084. }
  1085. else {
  1086. $scope.hideLayer(key);
  1087. setTimeout(function() {
  1088. $('#layer-loading').find('.md-inner').hide();
  1089. }, 1000);
  1090. }
  1091. $scope.isShown[key] = value;
  1092. }
  1093. });
  1094. });
  1095. }, true);
  1096. $(window).resize(function() {
  1097. if(!$('#result').height()) {return;}
  1098. $scope.showResultPane();
  1099. });
  1100. });