From 2fe7c1450d9d619150bfd30d1af315152667b266 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 5 Apr 2022 16:33:14 +0200 Subject: [PATCH 01/99] make geopub/leaflet a separate library --- .gitignore | 1 + .ocamlformat | 42 +++++++++++++++++++++ CHANGES.md | 1 + LICENSE.md | 8 ++++ README.md | 40 ++++++++++++++++++++ doc/dune | 3 ++ doc/index.mld | 17 +++++++++ dune-project | 33 +++++++++++++++++ example/dune | 3 ++ example/main.ml | 1 + leaflet.opam | 33 +++++++++++++++++ src/dune | 7 ++++ src/leaflet.js | 6 +++ src/leaflet.js.license | 3 ++ src/leaflet.ml | 83 ++++++++++++++++++++++++++++++++++++++++++ src/leaflet.mli | 67 ++++++++++++++++++++++++++++++++++ test/dune | 3 ++ test/test.ml | 1 + 18 files changed, 352 insertions(+) create mode 100644 .gitignore create mode 100644 .ocamlformat create mode 100644 CHANGES.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 doc/dune create mode 100644 doc/index.mld create mode 100644 dune-project create mode 100644 example/dune create mode 100644 example/main.ml create mode 100644 leaflet.opam create mode 100644 src/dune create mode 100644 src/leaflet.js create mode 100644 src/leaflet.js.license create mode 100644 src/leaflet.ml create mode 100644 src/leaflet.mli create mode 100644 test/dune create mode 100644 test/test.ml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_build diff --git a/.ocamlformat b/.ocamlformat new file mode 100644 index 0000000..1b64a37 --- /dev/null +++ b/.ocamlformat @@ -0,0 +1,42 @@ +version=0.21.0 +assignment-operator=end-line +break-cases=fit +break-fun-decl=wrap +break-fun-sig=wrap +break-infix=wrap +break-infix-before-func=false +break-separators=before +break-sequences=true +cases-exp-indent=2 +cases-matching-exp-indent=normal +doc-comments=before +doc-comments-padding=2 +doc-comments-tag-only=default +dock-collection-brackets=false +exp-grouping=preserve +field-space=loose +if-then-else=compact +indicate-multiline-delimiters=space +indicate-nested-or-patterns=unsafe-no +infix-precedence=indent +leading-nested-match-parens=false +let-and=sparse +let-binding-spacing=compact +let-module=compact +margin=80 +max-indent=68 +module-item-spacing=sparse +ocp-indent-compat=false +parens-ite=false +parens-tuple=always +parse-docstrings=true +sequence-blank-line=preserve-one +sequence-style=terminator +single-case=compact +space-around-arrays=true +space-around-lists=true +space-around-records=true +space-around-variants=true +type-decl=sparse +wrap-comments=false +wrap-fun-args=true diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..d9cd2e7 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1 @@ +## unreleased diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c0fd71b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,8 @@ +The ISC License (ISC) +===================== + +Copyright © 2022, TODO + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e628def --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# leaflet + +[leaflet] is an [OCaml] executable/library to TODO. + +## Installation + +`leaflet` can be installed with [opam]: + +```sh +opam install leaflet +``` + +If you don't have `opam`, you can install it following the [how to install opam] guide. + +If you can't or don't want to use `opam`, consult the [opam file] for build instructions. + +## Quickstart + +```ocaml +let () = Format.printf "TODO@." +``` + +For more, have a look at the [example] folder, at the [documentation] or at the [test suite]. + +## About + +- [LICENSE] +- [CHANGELOG] + +[CHANGELOG]: ./CHANGES.md +[example]: ./example +[LICENSE]: ./LICENSE.md +[opam file]: ./leaflet.opam +[test suite]: ./test + +[documentation]: TODO/leaflet +[how to install opam]: https://opam.ocaml.org/doc/Install.html +[OCaml]: https://ocaml.org +[opam]: https://opam.ocaml.org/ +[leaflet]: TODO/leaflet diff --git a/doc/dune b/doc/dune new file mode 100644 index 0000000..f03de7c --- /dev/null +++ b/doc/dune @@ -0,0 +1,3 @@ +(documentation + (package leaflet) + (mld_files index)) diff --git a/doc/index.mld b/doc/index.mld new file mode 100644 index 0000000..c248edf --- /dev/null +++ b/doc/index.mld @@ -0,0 +1,17 @@ +{0 leaflet} + +{{:https://TODO/leaflet} leaflet} is an {{:https://ocaml.org} OCaml} library/executable to TODO. + +{1:api API} + +{!modules: +Leaflet +} + +{1:private_api Private API} + +You shouldn't have to use any of these modules, they're used internally only. + +{!modules: +TODO +} diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..5220076 --- /dev/null +++ b/dune-project @@ -0,0 +1,33 @@ +(lang dune 2.9) + +(implicit_transitive_deps false) + +(name leaflet) + +(license ISC) + +(authors "TODO") + +(maintainers "TODO") + +(source + (uri TODO/leaflet)) + +(homepage TODO/leaflet) + +(bug_reports TODO/leaflet) + +(documentation TODO/leaflet) + +(generate_opam_files true) + +(package + (name leaflet) + (synopsis "OCaml library/executable to TODO") + (description + "leaflet is an OCaml library/executable to TODO.") + (tags + (leaflet TODO TODO TODO TODO)) + (depends + (ocaml + (>= 4.08)))) diff --git a/example/dune b/example/dune new file mode 100644 index 0000000..e36b142 --- /dev/null +++ b/example/dune @@ -0,0 +1,3 @@ +(executable + (name main) + (modules main)) diff --git a/example/main.ml b/example/main.ml new file mode 100644 index 0000000..16c9b9f --- /dev/null +++ b/example/main.ml @@ -0,0 +1 @@ +let () = Format.printf "TODO@." diff --git a/leaflet.opam b/leaflet.opam new file mode 100644 index 0000000..996aee0 --- /dev/null +++ b/leaflet.opam @@ -0,0 +1,33 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "OCaml library/executable to TODO" +description: "leaflet is an OCaml library/executable to TODO." +maintainer: ["TODO"] +authors: ["TODO"] +license: "ISC" +tags: ["leaflet" "TODO" "TODO" "TODO" "TODO"] +homepage: "TODO/leaflet" +doc: "TODO/leaflet" +bug-reports: "TODO/leaflet" +depends: [ + "dune" {>= "2.9"} + "ocaml" {>= "4.08"} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "--promote-install-files=false" + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["dune" "install" "-p" name "--create-install-files" name] +] +dev-repo: "TODO/leaflet" diff --git a/src/dune b/src/dune new file mode 100644 index 0000000..a2d7907 --- /dev/null +++ b/src/dune @@ -0,0 +1,7 @@ +(library + (name leaflet) + (public_name leaflet) + (modules leaflet) + (libraries brr js_of_ocaml) + (js_of_ocaml + (javascript_files leaflet.js))) diff --git a/src/leaflet.js b/src/leaflet.js new file mode 100644 index 0000000..21f499c --- /dev/null +++ b/src/leaflet.js @@ -0,0 +1,6 @@ +/* @preserve + * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com + * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";function h(t){for(var i,e,n=1,o=arguments.length;n=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt={ie:tt,ielt9:it,edge:et,webkit:nt,android:ot,android23:st,androidStock:at,opera:ht,chrome:ut,gecko:lt,safari:ct,phantom:_t,opera12:dt,win:pt,ie3d:mt,webkit3d:ft,gecko3d:gt,any3d:vt,mobile:yt,mobileWebkit:xt,mobileWebkit3d:wt,msPointer:Pt,pointer:Lt,touch:bt,mobileOpera:Tt,mobileGecko:Mt,retina:zt,passiveEvents:Ct,canvas:St,svg:Zt,vml:Et},At=Pt?"MSPointerDown":"pointerdown",It=Pt?"MSPointerMove":"pointermove",Ot=Pt?"MSPointerUp":"pointerup",Rt=Pt?"MSPointerCancel":"pointercancel",Nt={},Dt=!1;function jt(t,i,e,n){function o(t){Ut(t,r)}var s,r,a,h,u,l,c,_;function d(t){t.pointerType===(t.MSPOINTER_TYPE_MOUSE||"mouse")&&0===t.buttons||Ut(t,h)}return"touchstart"===i?(u=t,l=e,c=n,_=p(function(t){t.MSPOINTER_TYPE_TOUCH&&t.pointerType===t.MSPOINTER_TYPE_TOUCH&&Ri(t),Ut(t,l)}),u["_leaflet_touchstart"+c]=_,u.addEventListener(At,_,!1),Dt||(document.addEventListener(At,Wt,!0),document.addEventListener(It,Ht,!0),document.addEventListener(Ot,Ft,!0),document.addEventListener(Rt,Ft,!0),Dt=!0)):"touchmove"===i?(h=e,(a=t)["_leaflet_touchmove"+n]=d,a.addEventListener(It,d,!1)):"touchend"===i&&(r=e,(s=t)["_leaflet_touchend"+n]=o,s.addEventListener(Ot,o,!1),s.addEventListener(Rt,o,!1)),this}function Wt(t){Nt[t.pointerId]=t}function Ht(t){Nt[t.pointerId]&&(Nt[t.pointerId]=t)}function Ft(t){delete Nt[t.pointerId]}function Ut(t,i){for(var e in t.touches=[],Nt)t.touches.push(Nt[e]);t.changedTouches=[t],i(t)}var Vt=Pt?"MSPointerDown":Lt?"pointerdown":"touchstart",qt=Pt?"MSPointerUp":Lt?"pointerup":"touchend",Gt="_leaflet_";var Kt,Yt,Xt,Jt,$t,Qt,ti=fi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ii=fi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ei="webkitTransition"===ii||"OTransition"===ii?ii+"End":"transitionend";function ni(t){return"string"==typeof t?document.getElementById(t):t}function oi(t,i){var e,n=t.style[i]||t.currentStyle&&t.currentStyle[i];return n&&"auto"!==n||!document.defaultView||(n=(e=document.defaultView.getComputedStyle(t,null))?e[i]:null),"auto"===n?null:n}function si(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ri(t){var i=t.parentNode;i&&i.removeChild(t)}function ai(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function hi(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function ui(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function li(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=pi(t);return 0this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,N(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e,n,o=A((i=i||{}).paddingTopLeft||i.padding||[0,0]),s=A(i.paddingBottomRight||i.padding||[0,0]),r=this.getCenter(),a=this.project(r),h=this.project(t),u=this.getPixelBounds(),l=u.getSize().divideBy(2),c=O([u.min.add(o),u.max.subtract(s)]);return c.contains(h)||(this._enforcingBounds=!0,e=a.subtract(h),n=A(h.x+e.x,h.y+e.y),(h.xc.max.x)&&(n.x=a.x-e.x,0c.max.y)&&(n.y=a.y-e.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[m(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Vi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Vi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){var i;this._loaded&&!Ui(t)&&("mousedown"!==(i=t.type)&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Pi(t.target||t.srcElement),this._fireDOMEvent(t,i))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){var n;if("click"===t.type&&((n=h({},t)).type="preclick",this._fireDOMEvent(n,n.type,e)),!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Ri(t);var s,r={originalEvent:t};"keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(s=o.getLatLng&&(!o._radius||o._radius<=10),r.containerPoint=s?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s?o.getLatLng():this.layerPointToLatLng(r.layerPoint));for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,ci(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(p(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&_i(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Yi(t){return new Xi(t)}var Xi=S.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return ci(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ri(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+m(this),n),this._layerControlInputs.push(i),i.layerId=m(t.layer),zi(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),$i=Xi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=si("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=si("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Oi(s),zi(s,"click",Ni),zi(s,"click",o,this),zi(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";_i(this._zoomInButton,i),_i(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||ci(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||ci(this._zoomInButton,i)}});Ki.mergeOptions({zoomControl:!0}),Ki.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new $i,this.addControl(this.zoomControl))});var Qi=Xi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=si("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=si("div",i,e)),t.imperial&&(this._iScale=si("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=si("div","leaflet-control-attribution"),Oi(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ki.mergeOptions({attributionControl:!0}),Ki.addInitHook(function(){this.options.attributionControl&&(new te).addTo(this)});Xi.Layers=Ji,Xi.Zoom=$i,Xi.Scale=Qi,Xi.Attribution=te,Yi.layers=function(t,i,e){return new Ji(t,i,e)},Yi.zoom=function(t){return new $i(t)},Yi.scale=function(t){return new Qi(t)},Yi.attribution=function(t){return new te(t)};var ie=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});ie.addTo=function(t,i){return t.addHandler(i,this),this};var ee,ne={Events:Z},oe=bt?"touchstart mousedown":"mousedown",se={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},re={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ae=E.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){c(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(zi(this._dragStartTarget,oe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ae._dragging===this&&this.finishDrag(),Si(this._dragStartTarget,oe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var i,e;!t._simulated&&this._enabled&&(this._moved=!1,li(this._element,"leaflet-zoom-anim")||ae._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ae._dragging=this)._preventOutline&&Pi(this._element),xi(),Xt(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=bi(this._element),this._startPoint=new k(i.clientX,i.clientY),this._parentScale=Ti(e),zi(document,re[t.type],this._onMove,this),zi(document,se[t.type],this._onUp,this))))},_onMove:function(t){var i,e;!t._simulated&&this._enabled&&(t.touches&&1i&&(e.push(t[n]),o=n);oi.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function de(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||Oe.prototype._containsPoint.call(this,t,!0)}});var Ne=Ce.extend({initialize:function(t,i){c(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=g(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c]))},_onCloseButtonClick:function(t){this._close(),Ni(t)},_getAnchor:function(){return A(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ki.mergeOptions({closePopupOnClick:!0}),Ki.include({openPopup:function(t,i,e){return t instanceof tn||(t=new tn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Me.include({bindPopup:function(t,i){return t instanceof tn?(c(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new tn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Ni(t),i instanceof Be?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var en=Qe.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Qe.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Qe.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Qe.prototype.getEvents.call(this);return bt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=si("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i,e=this._map,n=this._container,o=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=n.offsetWidth,h=n.offsetHeight,u=A(this.options.offset),l=this._getAnchor(),c="top"===r?(i=a/2,h):"bottom"===r?(i=a/2,0):(i="center"===r?a/2:"right"===r?0:"left"===r?a:s.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return N(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new R(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new k(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ri(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){ci(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=a,t.onmousemove=a,it&&this.options.opacity<1&&mi(t,this.options.opacity),ot&&!st&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),p(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(p(this._tileReady,this,t,null,o)),vi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(mi(e.el,0),z(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(ci(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),it||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(p(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new k(this._wrapX?o(t.x,this._wrapX):t.x,this._wrapY?o(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new I(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var sn=on.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=c(this,i)).detectRetina&&zt&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_n={_initContainer:function(){this._container=si("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(hn.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=cn("shape");ci(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=cn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ri(i),t.removeInteractiveTarget(i),delete this._layers[m(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i=i||(t._stroke=cn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=g(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e=e||(t._fill=cn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){hi(t._container)},_bringToBack:function(t){ui(t._container)}},dn=Et?cn:J,pn=hn.extend({getEvents:function(){var t=hn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ri(this._container),Si(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){var t,i,e;this._map._animatingZoom&&this._bounds||(hn.prototype._update.call(this),i=(t=this._bounds).getSize(),e=this._container,this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),vi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update"))},_initPath:function(t){var i=t._path=dn("path");t.options.className&&ci(i,t.options.className),t.options.interactive&&ci(i,"leaflet-interactive"),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ri(t._path),t.removeInteractiveTarget(t._path),delete this._layers[m(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,$(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){hi(t._path)},_bringToBack:function(t){ui(t._path)}});function mn(t){return Zt||Et?new pn(t):null}Et&&pn.include(_n),Ki.include({getRenderer:function(t){var i=(i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&ln(t)||mn(t)}});var fn=Re.extend({initialize:function(t,i){Re.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=N(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});pn.create=dn,pn.pointsToPath=$,Ne.geometryToLayer=De,Ne.coordsToLatLng=We,Ne.coordsToLatLngs=He,Ne.latLngToCoords=Fe,Ne.latLngsToCoords=Ue,Ne.getFeature=Ve,Ne.asFeature=qe,Ki.mergeOptions({boxZoom:!0});var gn=ie.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){zi(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Si(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ri(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Xt(),xi(),this._startPoint=this._map.mouseEventToContainerPoint(t),zi(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=si("div","leaflet-zoom-box",this._container),ci(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new I(this._point,this._startPoint),e=i.getSize();vi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ri(this._box),_i(this._container,"leaflet-crosshair")),Jt(),wi(),Si(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){var i;1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(p(this._resetState,this),0),i=new R(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})))},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ki.addInitHook("addHandler","boxZoom",gn),Ki.mergeOptions({doubleClickZoom:!0});var vn=ie.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ki.addInitHook("addHandler","doubleClickZoom",vn),Ki.mergeOptions({dragging:!0,inertia:!st,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var yn=ie.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new ae(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),ci(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){_i(this._map._container,"leaflet-grab"),_i(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,i=this._map;i._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=N(this._map.options.maxBounds),this._offsetLimit=O(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,i.fire("movestart").fire("dragstart"),i.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var i,e;this._map.options.inertia&&(i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(e),this._times.push(i),this._prunePositions(i)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1 + * + * SPDX-License-Identifier: AGPL-3.0-or-later + *) +open Brr + +let leaflet = + match Jv.(find global "L") with + | Some l -> l + | None -> failwith "Could not load Leaflet" + +module LatLng = struct + type t = Jv.t + + let create lat lng = + Jv.call leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] + + let lat latlng = Jv.get latlng "lat" |> Jv.to_float + let lng latlng = Jv.get latlng "lng" |> Jv.to_float +end + +module Ev = struct + module MouseEvent = struct + type t = Jv.t + + let latlng e = Jv.get e "latlng" + end +end + +module Map = struct + type t = Jv.t + + let create ?(options = Jv.null) el = + Jv.call leaflet "map" [| El.to_jv el; options |] + + let invalidate_size map = + ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] + + let fit_world map = ignore @@ Jv.call map "fitWorld" [||] + let get_container map = Jv.call map "getContainer" [||] |> El.of_jv + + let set_view latlng ~zoom map = + ignore @@ Jv.call map "setView" [| latlng; Jv.of_int zoom |]; + map + + let as_target map = Brr.Ev.target_of_jv map + let click = Brr.Ev.Type.create (Jstr.v "click") +end + +module TileLayer = struct + type t = Jv.t + + let create_osm () = + Jv.call leaflet "tileLayer" + [| + Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; + Jv.obj + [| + ( "attribution", + Jv.of_string + "© OpenStreetMap \ + contributors" ); + |]; + |] + + let add_to tile_layer map = ignore @@ Jv.call tile_layer "addTo" [| map |] +end + +module Marker = struct + type t = Jv.t + + let create latlng = Jv.call leaflet "marker" [| latlng |] + let add_to marker map = ignore @@ Jv.call marker "addTo" [| map |] + + let bind_popup el marker = + ignore @@ Jv.call marker "bindPopup" [| El.to_jv el |]; + marker + + let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] +end + diff --git a/src/leaflet.mli b/src/leaflet.mli new file mode 100644 index 0000000..16f36fc --- /dev/null +++ b/src/leaflet.mli @@ -0,0 +1,67 @@ +(* + * SPDX-FileCopyrightText: 2021 pukkamustard + * + * SPDX-License-Identifier: AGPL-3.0-or-later + *) + +open Brr +(** {1 Leaflet} + +This module provides bindings to the Leaflet JavaScript library for +mobile-friendly interactive maps. + +See also the [Leaflet API reference](https://leafletjs.com/reference.html). +*) + +module LatLng : sig + type t + + val create : float -> float -> t + val lat : t -> float + val lng : t -> float +end + +module Ev : sig + module MouseEvent : sig + type t + + val latlng : t -> LatLng.t + end +end + +module Map : sig + type t + + val create : ?options:Jv.t -> El.t -> t + val invalidate_size : t -> unit + val set_view : LatLng.t -> zoom:int -> t -> t + val fit_world : t -> unit + val get_container : t -> El.t + + (** {1 Events} **) + + val as_target : t -> Brr.Ev.target + + (** {2 Interaction events} **) + + val click : Ev.MouseEvent.t Brr.Ev.type' +end + +module TileLayer : sig + type t + + val create_osm : unit -> t + val add_to : t -> Map.t -> unit +end + +module Marker : sig + type t + + val create : LatLng.t -> t + val add_to : t -> Map.t -> unit + + (** {2 Popup methods} *) + + val bind_popup : El.t -> t -> t + val open_popup : t -> unit +end diff --git a/test/dune b/test/dune new file mode 100644 index 0000000..f929c11 --- /dev/null +++ b/test/dune @@ -0,0 +1,3 @@ +(test + (name test) + (modules test)) diff --git a/test/test.ml b/test/test.ml new file mode 100644 index 0000000..29ef5f9 --- /dev/null +++ b/test/test.ml @@ -0,0 +1 @@ +let () = assert true (* TODO *) From 2154a10db4b63a747d32a2994cc37fc91a513fe5 Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 6 Apr 2022 19:56:13 +0200 Subject: [PATCH 02/99] add more functions --- src/leaflet.ml | 68 ++++++++++++++++++++++++++++++++++++++----------- src/leaflet.mli | 50 +++++++++++++++++++++++++++++++----- 2 files changed, 96 insertions(+), 22 deletions(-) diff --git a/src/leaflet.ml b/src/leaflet.ml index e1c5948..fca38f9 100644 --- a/src/leaflet.ml +++ b/src/leaflet.ml @@ -17,7 +17,10 @@ module LatLng = struct Jv.call leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] let lat latlng = Jv.get latlng "lat" |> Jv.to_float + let lng latlng = Jv.get latlng "lng" |> Jv.to_float + + let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool end module Ev = struct @@ -31,21 +34,36 @@ end module Map = struct type t = Jv.t - let create ?(options = Jv.null) el = - Jv.call leaflet "map" [| El.to_jv el; options |] + let create ?(options = Jv.null) container_id = + Jv.call leaflet "map" [| Jv.of_string container_id; options |] let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] let fit_world map = ignore @@ Jv.call map "fitWorld" [||] + let get_container map = Jv.call map "getContainer" [||] |> El.of_jv - let set_view latlng ~zoom map = - ignore @@ Jv.call map "setView" [| latlng; Jv.of_int zoom |]; - map + let set_view latlng ?zoom map = + ignore + @@ + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] let as_target map = Brr.Ev.target_of_jv map + let click = Brr.Ev.Type.create (Jstr.v "click") + (*?= let click = Brr.Ev.click *) + + let on ~event ~handler map = + ignore @@ Jv.call map "on" [| Jv.of_string event; Jv.repr handler |] + + let get_center map = Jv.call map "getCenter" [||] + + let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int + + let wrapped_latlng latlng map = Jv.call map "wrapLatLng" [| latlng |] end module TileLayer = struct @@ -53,25 +71,33 @@ module TileLayer = struct let create_osm () = Jv.call leaflet "tileLayer" - [| - Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; - Jv.obj - [| - ( "attribution", - Jv.of_string - "© OpenStreetMap \ - contributors" ); - |]; + [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] |] let add_to tile_layer map = ignore @@ Jv.call tile_layer "addTo" [| map |] end +module GeojsonLayer = struct + type t = Jv.t + + let create ?(options = Jv.null) geojson = + Jv.call leaflet "geoJSON" [| geojson; options |] + + let add_to layer map = ignore @@ Jv.call layer "addTo" [| map |] +end + module Marker = struct type t = Jv.t let create latlng = Jv.call leaflet "marker" [| latlng |] + let add_to marker map = ignore @@ Jv.call marker "addTo" [| map |] let bind_popup el marker = @@ -81,3 +107,15 @@ module Marker = struct let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] end +module Popup = struct + let popup = Jv.call leaflet "popup" [||] + + let set_latlng latlng = ignore @@ Jv.call popup "setLatLng" [| latlng |] + + let set_content content = + ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + + let open_on map = ignore @@ Jv.call popup "openOn" [| map |] + + let close map = ignore @@ Jv.call map "closePopup" [||] +end diff --git a/src/leaflet.mli b/src/leaflet.mli index 16f36fc..dd166cf 100644 --- a/src/leaflet.mli +++ b/src/leaflet.mli @@ -4,21 +4,24 @@ * SPDX-License-Identifier: AGPL-3.0-or-later *) -open Brr (** {1 Leaflet} -This module provides bindings to the Leaflet JavaScript library for -mobile-friendly interactive maps. + This module provides bindings to the Leaflet JavaScript library for + mobile-friendly interactive maps. -See also the [Leaflet API reference](https://leafletjs.com/reference.html). -*) + See also the [Leaflet API reference](https://leafletjs.com/reference.html). *) +open Brr module LatLng : sig type t val create : float -> float -> t + val lat : t -> float + val lng : t -> float + + val equals : t -> t -> bool end module Ev : sig @@ -32,12 +35,24 @@ end module Map : sig type t - val create : ?options:Jv.t -> El.t -> t + val create : ?options:Jv.t -> string -> t + val invalidate_size : t -> unit - val set_view : LatLng.t -> zoom:int -> t -> t + + val set_view : LatLng.t -> ?zoom:int -> t -> unit + val fit_world : t -> unit + val get_container : t -> El.t + val on : event:string -> handler:('a -> 'b) -> t -> unit + + val get_center : t -> LatLng.t + + val get_zoom : t -> int + + val wrapped_latlng : LatLng.t -> t -> LatLng.t + (** {1 Events} **) val as_target : t -> Brr.Ev.target @@ -51,6 +66,15 @@ module TileLayer : sig type t val create_osm : unit -> t + + val add_to : t -> Map.t -> unit +end + +module GeojsonLayer : sig + type t + + val create : ?options:Jv.t -> Jv.t -> t + val add_to : t -> Map.t -> unit end @@ -58,10 +82,22 @@ module Marker : sig type t val create : LatLng.t -> t + val add_to : t -> Map.t -> unit (** {2 Popup methods} *) val bind_popup : El.t -> t -> t + val open_popup : t -> unit end + +module Popup : sig + val set_latlng : LatLng.t -> unit + + val set_content : string -> unit + + val open_on : Map.t -> unit + + val close : Map.t -> unit +end From 82d74ad985b4f3591b19107c46d718a69e1d4271 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 14:45:11 +0200 Subject: [PATCH 03/99] split modules and fix Ev --- src/dune | 2 +- src/ev.ml | 12 +++++ src/ev.mli | 11 ++++ src/geojson_layer.ml | 7 +++ src/geojson_layer.mli | 5 ++ src/global.ml | 4 ++ src/latlng.ml | 14 +++++ src/latlng.mli | 13 +++++ src/leaflet.ml | 121 ------------------------------------------ src/leaflet.mli | 103 ----------------------------------- src/map.ml | 46 ++++++++++++++++ src/map.mli | 34 ++++++++++++ src/marker.ml | 11 ++++ src/marker.mli | 11 ++++ src/popup.ml | 11 ++++ src/popup.mli | 7 +++ src/tile_layer.ml | 16 ++++++ src/tile_layer.mli | 5 ++ 18 files changed, 208 insertions(+), 225 deletions(-) create mode 100644 src/ev.ml create mode 100644 src/ev.mli create mode 100644 src/geojson_layer.ml create mode 100644 src/geojson_layer.mli create mode 100644 src/global.ml create mode 100644 src/latlng.ml create mode 100644 src/latlng.mli delete mode 100644 src/leaflet.ml delete mode 100644 src/leaflet.mli create mode 100644 src/map.ml create mode 100644 src/map.mli create mode 100644 src/marker.ml create mode 100644 src/marker.mli create mode 100644 src/popup.ml create mode 100644 src/popup.mli create mode 100644 src/tile_layer.ml create mode 100644 src/tile_layer.mli diff --git a/src/dune b/src/dune index a2d7907..e7f3daf 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,7 @@ (library (name leaflet) (public_name leaflet) - (modules leaflet) + (modules ev latlng geojson_layer tile_layer popup marker map global) (libraries brr js_of_ocaml) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/ev.ml b/src/ev.ml new file mode 100644 index 0000000..d4f9aad --- /dev/null +++ b/src/ev.ml @@ -0,0 +1,12 @@ +type type' = Jv.t + +module Event = struct + (*type for simple Event *) + type t = type' +end + +module Mouse = struct + type t = type' + + let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" +end diff --git a/src/ev.mli b/src/ev.mli new file mode 100644 index 0000000..0a93bcf --- /dev/null +++ b/src/ev.mli @@ -0,0 +1,11 @@ +type type' + +module Event : sig + type t +end + +module Mouse : sig + type t + + val latlng : t -> Latlng.t +end diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml new file mode 100644 index 0000000..66ed14a --- /dev/null +++ b/src/geojson_layer.ml @@ -0,0 +1,7 @@ +(*TODO merge with TileLayer*) +type t = Jv.t + +let create ?(options = Jv.null) geojson = + Jv.call Global.leaflet "geoJSON" [| geojson; options |] + +let add_to layer map = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli new file mode 100644 index 0000000..12bb980 --- /dev/null +++ b/src/geojson_layer.mli @@ -0,0 +1,5 @@ +type t + +val create : ?options:Jv.t -> Jv.t -> t + +val add_to : t -> Map.t -> unit diff --git a/src/global.ml b/src/global.ml new file mode 100644 index 0000000..c209f3d --- /dev/null +++ b/src/global.ml @@ -0,0 +1,4 @@ +let leaflet = + match Jv.(find global "L") with + | Some l -> l + | None -> failwith "Could not load Leaflet" diff --git a/src/latlng.ml b/src/latlng.ml new file mode 100644 index 0000000..d2b4dbc --- /dev/null +++ b/src/latlng.ml @@ -0,0 +1,14 @@ +type t = Jv.t + +let create lat lng = + Jv.call Global.leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] + +let lat latlng = Jv.get latlng "lat" |> Jv.to_float + +let lng latlng = Jv.get latlng "lng" |> Jv.to_float + +let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool + +let of_jv_t = Fun.id + +let to_jv_t = Fun.id diff --git a/src/latlng.mli b/src/latlng.mli new file mode 100644 index 0000000..fb793ae --- /dev/null +++ b/src/latlng.mli @@ -0,0 +1,13 @@ +type t + +val create : float -> float -> t + +val lat : t -> float + +val lng : t -> float + +val equals : t -> t -> bool + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/leaflet.ml b/src/leaflet.ml deleted file mode 100644 index fca38f9..0000000 --- a/src/leaflet.ml +++ /dev/null @@ -1,121 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2021 pukkamustard - * - * SPDX-License-Identifier: AGPL-3.0-or-later - *) -open Brr - -let leaflet = - match Jv.(find global "L") with - | Some l -> l - | None -> failwith "Could not load Leaflet" - -module LatLng = struct - type t = Jv.t - - let create lat lng = - Jv.call leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] - - let lat latlng = Jv.get latlng "lat" |> Jv.to_float - - let lng latlng = Jv.get latlng "lng" |> Jv.to_float - - let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool -end - -module Ev = struct - module MouseEvent = struct - type t = Jv.t - - let latlng e = Jv.get e "latlng" - end -end - -module Map = struct - type t = Jv.t - - let create ?(options = Jv.null) container_id = - Jv.call leaflet "map" [| Jv.of_string container_id; options |] - - let invalidate_size map = - ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] - - let fit_world map = ignore @@ Jv.call map "fitWorld" [||] - - let get_container map = Jv.call map "getContainer" [||] |> El.of_jv - - let set_view latlng ?zoom map = - ignore - @@ - match zoom with - | None -> Jv.call map "setView" [| latlng |] - | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] - - let as_target map = Brr.Ev.target_of_jv map - - let click = Brr.Ev.Type.create (Jstr.v "click") - (*?= let click = Brr.Ev.click *) - - let on ~event ~handler map = - ignore @@ Jv.call map "on" [| Jv.of_string event; Jv.repr handler |] - - let get_center map = Jv.call map "getCenter" [||] - - let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int - - let wrapped_latlng latlng map = Jv.call map "wrapLatLng" [| latlng |] -end - -module TileLayer = struct - type t = Jv.t - - let create_osm () = - Jv.call leaflet "tileLayer" - [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - - let add_to tile_layer map = ignore @@ Jv.call tile_layer "addTo" [| map |] -end - -module GeojsonLayer = struct - type t = Jv.t - - let create ?(options = Jv.null) geojson = - Jv.call leaflet "geoJSON" [| geojson; options |] - - let add_to layer map = ignore @@ Jv.call layer "addTo" [| map |] -end - -module Marker = struct - type t = Jv.t - - let create latlng = Jv.call leaflet "marker" [| latlng |] - - let add_to marker map = ignore @@ Jv.call marker "addTo" [| map |] - - let bind_popup el marker = - ignore @@ Jv.call marker "bindPopup" [| El.to_jv el |]; - marker - - let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] -end - -module Popup = struct - let popup = Jv.call leaflet "popup" [||] - - let set_latlng latlng = ignore @@ Jv.call popup "setLatLng" [| latlng |] - - let set_content content = - ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] - - let open_on map = ignore @@ Jv.call popup "openOn" [| map |] - - let close map = ignore @@ Jv.call map "closePopup" [||] -end diff --git a/src/leaflet.mli b/src/leaflet.mli deleted file mode 100644 index dd166cf..0000000 --- a/src/leaflet.mli +++ /dev/null @@ -1,103 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2021 pukkamustard - * - * SPDX-License-Identifier: AGPL-3.0-or-later - *) - -(** {1 Leaflet} - - This module provides bindings to the Leaflet JavaScript library for - mobile-friendly interactive maps. - - See also the [Leaflet API reference](https://leafletjs.com/reference.html). *) -open Brr - -module LatLng : sig - type t - - val create : float -> float -> t - - val lat : t -> float - - val lng : t -> float - - val equals : t -> t -> bool -end - -module Ev : sig - module MouseEvent : sig - type t - - val latlng : t -> LatLng.t - end -end - -module Map : sig - type t - - val create : ?options:Jv.t -> string -> t - - val invalidate_size : t -> unit - - val set_view : LatLng.t -> ?zoom:int -> t -> unit - - val fit_world : t -> unit - - val get_container : t -> El.t - - val on : event:string -> handler:('a -> 'b) -> t -> unit - - val get_center : t -> LatLng.t - - val get_zoom : t -> int - - val wrapped_latlng : LatLng.t -> t -> LatLng.t - - (** {1 Events} **) - - val as_target : t -> Brr.Ev.target - - (** {2 Interaction events} **) - - val click : Ev.MouseEvent.t Brr.Ev.type' -end - -module TileLayer : sig - type t - - val create_osm : unit -> t - - val add_to : t -> Map.t -> unit -end - -module GeojsonLayer : sig - type t - - val create : ?options:Jv.t -> Jv.t -> t - - val add_to : t -> Map.t -> unit -end - -module Marker : sig - type t - - val create : LatLng.t -> t - - val add_to : t -> Map.t -> unit - - (** {2 Popup methods} *) - - val bind_popup : El.t -> t -> t - - val open_popup : t -> unit -end - -module Popup : sig - val set_latlng : LatLng.t -> unit - - val set_content : string -> unit - - val open_on : Map.t -> unit - - val close : Map.t -> unit -end diff --git a/src/map.ml b/src/map.ml new file mode 100644 index 0000000..3efedd7 --- /dev/null +++ b/src/map.ml @@ -0,0 +1,46 @@ +type t = Jv.t + +module Event = struct + let to_brr s = s |> Jstr.v |> Brr.Ev.Type.create + + let click = to_brr "click" + + let moveend = to_brr "moveend" + + let zoomend = to_brr "zoomend" +end + +let of_jv_t = Fun.id + +let to_jv_t = Fun.id + +let create ?(options = Jv.null) container_id = + Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] + +let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] + +let fit_world map = ignore @@ Jv.call map "fitWorld" [||] + +let get_container map = + Jv.call (to_jv_t map) "getContainer" [||] |> Brr.El.of_jv + +let set_view latlng ?zoom map = + let latlng = Latlng.to_jv_t latlng in + ignore + @@ + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] + +let as_target map = Brr.Ev.target_of_jv map + +let on ~event ~handler map = + let name = Brr.Ev.Type.name event |> Jv.of_jstr in + ignore @@ Jv.call map "on" [| name; Jv.repr handler |] + +let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] + +let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int + +let wrapped_latlng latlng map = + Latlng.of_jv_t @@ Jv.call map "wrapLatLng" [| Latlng.to_jv_t latlng |] diff --git a/src/map.mli b/src/map.mli new file mode 100644 index 0000000..c373001 --- /dev/null +++ b/src/map.mli @@ -0,0 +1,34 @@ +type t + +module Event : sig + (* TODO do this need to be wrapped in Brr.Ev.type' ?*) + val click : Ev.Mouse.t Brr.Ev.type' + + val moveend : Ev.Event.t Brr.Ev.type' + + val zoomend : Ev.Event.t Brr.Ev.type' +end + +val create : ?options:Jv.t -> string -> t + +val invalidate_size : t -> unit + +val set_view : Latlng.t -> ?zoom:int -> t -> unit + +val fit_world : t -> unit + +val get_container : t -> Brr.El.t + +val on : event:'a Brr.Ev.type' -> handler:('a -> 'b) -> t -> unit + +val get_center : t -> Latlng.t + +val get_zoom : t -> int + +val wrapped_latlng : Latlng.t -> t -> Latlng.t + +val as_target : t -> Brr.Ev.target + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml new file mode 100644 index 0000000..cfcd0b3 --- /dev/null +++ b/src/marker.ml @@ -0,0 +1,11 @@ +type t = Jv.t + +let create latlng = Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] + +let add_to marker map = ignore @@ Jv.call marker "addTo" [| Map.to_jv_t map |] + +let bind_popup el marker = + ignore @@ Jv.call marker "bindPopup" [| Brr.El.to_jv el |]; + marker + +let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] diff --git a/src/marker.mli b/src/marker.mli new file mode 100644 index 0000000..3bf1691 --- /dev/null +++ b/src/marker.mli @@ -0,0 +1,11 @@ +type t + +val create : Latlng.t -> t + +val add_to : t -> Map.t -> unit + +(** {2 Popup methods} *) + +val bind_popup : Brr.El.t -> t -> t + +val open_popup : t -> unit diff --git a/src/popup.ml b/src/popup.ml new file mode 100644 index 0000000..9a268db --- /dev/null +++ b/src/popup.ml @@ -0,0 +1,11 @@ +let popup = Jv.call Global.leaflet "popup" [||] + +let set_latlng latlng = + ignore @@ Jv.call popup "setLatLng" [| Latlng.to_jv_t latlng |] + +let set_content content = + ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + +let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] + +let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] diff --git a/src/popup.mli b/src/popup.mli new file mode 100644 index 0000000..cda85f6 --- /dev/null +++ b/src/popup.mli @@ -0,0 +1,7 @@ +val set_latlng : Latlng.t -> unit + +val set_content : string -> unit + +val open_on : Map.t -> unit + +val close : Map.t -> unit diff --git a/src/tile_layer.ml b/src/tile_layer.ml new file mode 100644 index 0000000..fe32d14 --- /dev/null +++ b/src/tile_layer.ml @@ -0,0 +1,16 @@ +type t = Jv.t + +let create_osm () = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + +let add_to tile_layer map = + ignore @@ Jv.call tile_layer "addTo" [| Map.to_jv_t map |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli new file mode 100644 index 0000000..afcd56e --- /dev/null +++ b/src/tile_layer.mli @@ -0,0 +1,5 @@ +type t + +val create_osm : unit -> t + +val add_to : t -> Map.t -> unit From 5868601fa1060ec52b8a989e08c76e1f50fbaf64 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 15:24:25 +0200 Subject: [PATCH 04/99] change type' to type t --- src/ev.ml | 6 +++--- src/ev.mli | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ev.ml b/src/ev.ml index d4f9aad..911e749 100644 --- a/src/ev.ml +++ b/src/ev.ml @@ -1,12 +1,12 @@ -type type' = Jv.t +type t = Jv.t module Event = struct (*type for simple Event *) - type t = type' + type nonrec t = t end module Mouse = struct - type t = type' + type nonrec t = t let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" end diff --git a/src/ev.mli b/src/ev.mli index 0a93bcf..fffa63d 100644 --- a/src/ev.mli +++ b/src/ev.mli @@ -1,4 +1,4 @@ -type type' +type t module Event : sig type t From 2d8301bdfd6c91317b0cb259157e674bba94f37e Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 17:58:01 +0200 Subject: [PATCH 05/99] add tile_url option --- src/tile_layer.ml | 9 +++++++-- src/tile_layer.mli | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tile_layer.ml b/src/tile_layer.ml index fe32d14..137eb64 100644 --- a/src/tile_layer.ml +++ b/src/tile_layer.ml @@ -1,8 +1,13 @@ type t = Jv.t -let create_osm () = +let create_osm ?tile_url () = + (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) + let tile_url = + Option.fold ~some:Fun.id + ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url + in Jv.call Global.leaflet "tileLayer" - [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + [| Jv.of_string tile_url ; Jv.obj [| ( "attribution" , Jv.of_string diff --git a/src/tile_layer.mli b/src/tile_layer.mli index afcd56e..4fffaa2 100644 --- a/src/tile_layer.mli +++ b/src/tile_layer.mli @@ -1,5 +1,5 @@ type t -val create_osm : unit -> t +val create_osm : ?tile_url:string -> unit -> t val add_to : t -> Map.t -> unit From d99eafccbf79c7366c83623d24abc9025250339a Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 19:04:33 +0200 Subject: [PATCH 06/99] better Ev --- src/ev.ml | 33 +++++++++++++++++++++++------- src/ev.mli | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/ev.ml b/src/ev.ml index 911e749..7823351 100644 --- a/src/ev.ml +++ b/src/ev.ml @@ -1,12 +1,31 @@ -type t = Jv.t +module Make () = struct + type t = Jv.t -module Event = struct - (*type for simple Event *) - type nonrec t = t -end + let type' e = Jv.get e "type" |> Jv.to_string -module Mouse = struct - type nonrec t = t + let target e = Jv.get e "target" |> Brr.Ev.target_of_jv + + let source_target e = Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv + + let propagated_from e = Jv.get e "propagatedFrom" let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" + + let layer_point e = Jv.get e "layerPoint" + + let container_point e = Jv.get e "containerPoint" + + let original_event e = Jv.get e "originalEvent" + + let message e = Jv.get e "message" |> Jv.to_string + + let code e = Jv.get e "code" |> Jv.to_int end + +module Event = Make () + +module Keyboard = Make () + +module Mouse = Make () + +module Error = Make () diff --git a/src/ev.mli b/src/ev.mli index fffa63d..520b5ff 100644 --- a/src/ev.mli +++ b/src/ev.mli @@ -1,11 +1,66 @@ -type t - module Event : sig type t + + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + (* TODO this should return Point *) + val propagated_from : t -> Jv.t +end + +module Keyboard : sig + type t + + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + val propagated_from : t -> Jv.t + + (* TODO this should return BrrDomEvent*) + val original_event : t -> Jv.t end module Mouse : sig type t + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + val propagated_from : t -> Jv.t + val latlng : t -> Latlng.t + + (* TODO this should return Point *) + val layer_point : t -> Jv.t + + (* TODO this should return Point *) + val container_point : t -> Jv.t + + (* TODO this should return BrrDomEvent*) + val original_event : t -> Jv.t +end + +module Error : sig + type t + + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + val propagated_from : t -> Jv.t + + val message : t -> string + + val code : t -> int end From d9f25e4d8d208f9226a4115619f23fa984e3f2ef Mon Sep 17 00:00:00 2001 From: Swrup Date: Fri, 8 Apr 2022 13:21:20 +0200 Subject: [PATCH 07/99] add layer --- src/dune | 2 +- src/geojson_layer.ml | 7 ++----- src/geojson_layer.mli | 20 +++++++++++++++++++- src/layer.ml | 23 +++++++++++++++++++++++ src/layer.mli | 21 +++++++++++++++++++++ src/marker.ml | 13 +++---------- src/marker.mli | 18 +++++++++++++++--- src/popup.ml | 4 ++++ src/popup.mli | 4 ++++ src/tile_layer.ml | 26 ++++++++++++-------------- src/tile_layer.mli | 20 +++++++++++++++++++- 11 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 src/layer.ml create mode 100644 src/layer.mli diff --git a/src/dune b/src/dune index e7f3daf..8f28969 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,7 @@ (library (name leaflet) (public_name leaflet) - (modules ev latlng geojson_layer tile_layer popup marker map global) + (modules ev latlng geojson_layer tile_layer popup marker map global layer) (libraries brr js_of_ocaml) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml index 66ed14a..c5c113d 100644 --- a/src/geojson_layer.ml +++ b/src/geojson_layer.ml @@ -1,7 +1,4 @@ -(*TODO merge with TileLayer*) -type t = Jv.t +include Layer let create ?(options = Jv.null) geojson = - Jv.call Global.leaflet "geoJSON" [| geojson; options |] - -let add_to layer map = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] + of_jv_t @@ Jv.call Global.leaflet "geoJSON" [| geojson; options |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli index 12bb980..e8c4660 100644 --- a/src/geojson_layer.mli +++ b/src/geojson_layer.mli @@ -2,4 +2,22 @@ type t val create : ?options:Jv.t -> Jv.t -> t -val add_to : t -> Map.t -> unit +val add_to : Map.t -> t -> unit + +val remove : t -> unit + +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit + +val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml new file mode 100644 index 0000000..d0c8b62 --- /dev/null +++ b/src/layer.ml @@ -0,0 +1,23 @@ +type t = Jv.t + +let add_to map layer = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] + +let remove layer = ignore @@ Jv.call layer "remove" [||] + +let remove_from map layer = + ignore @@ Jv.call layer "removeFrom" [| Map.to_jv_t map |] + +let bind_popup el layer = + ignore @@ Jv.call layer "bindPopup" [| Brr.El.to_jv el |] + +let unbind_popup layer = ignore @@ Jv.call layer "unbindPopup" [||] + +let open_popup layer = ignore @@ Jv.call layer "openPopup" [||] + +let close_popup layer = ignore @@ Jv.call layer "closePopup" [||] + +let get_popup layer = Popup.of_jv_t @@ Jv.call layer "getPopup" [||] + +let of_jv_t = Fun.id + +let to_jv_t = Fun.id diff --git a/src/layer.mli b/src/layer.mli new file mode 100644 index 0000000..98fe10c --- /dev/null +++ b/src/layer.mli @@ -0,0 +1,21 @@ +type t + +val add_to : Map.t -> t -> unit + +val remove : t -> unit + +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit + +val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml index cfcd0b3..44925a1 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -1,11 +1,4 @@ -type t = Jv.t +include Layer -let create latlng = Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] - -let add_to marker map = ignore @@ Jv.call marker "addTo" [| Map.to_jv_t map |] - -let bind_popup el marker = - ignore @@ Jv.call marker "bindPopup" [| Brr.El.to_jv el |]; - marker - -let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] +let create latlng = + of_jv_t @@ Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] diff --git a/src/marker.mli b/src/marker.mli index 3bf1691..ab77fc5 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -2,10 +2,22 @@ type t val create : Latlng.t -> t -val add_to : t -> Map.t -> unit +val add_to : Map.t -> t -> unit -(** {2 Popup methods} *) +val remove : t -> unit -val bind_popup : Brr.El.t -> t -> t +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/popup.ml b/src/popup.ml index 9a268db..bc0febf 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -1,3 +1,5 @@ +type t = Jv.t + let popup = Jv.call Global.leaflet "popup" [||] let set_latlng latlng = @@ -9,3 +11,5 @@ let set_content content = let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] + +let of_jv_t = Fun.id diff --git a/src/popup.mli b/src/popup.mli index cda85f6..5ca939b 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -1,3 +1,5 @@ +type t + val set_latlng : Latlng.t -> unit val set_content : string -> unit @@ -5,3 +7,5 @@ val set_content : string -> unit val open_on : Map.t -> unit val close : Map.t -> unit + +val of_jv_t : Jv.t -> t diff --git a/src/tile_layer.ml b/src/tile_layer.ml index 137eb64..1dae48c 100644 --- a/src/tile_layer.ml +++ b/src/tile_layer.ml @@ -1,4 +1,4 @@ -type t = Jv.t +include Layer let create_osm ?tile_url () = (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) @@ -6,16 +6,14 @@ let create_osm ?tile_url () = Option.fold ~some:Fun.id ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url in - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string tile_url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - -let add_to tile_layer map = - ignore @@ Jv.call tile_layer "addTo" [| Map.to_jv_t map |] + of_jv_t + @@ Jv.call Global.leaflet "tileLayer" + [| Jv.of_string tile_url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli index 4fffaa2..b1834b5 100644 --- a/src/tile_layer.mli +++ b/src/tile_layer.mli @@ -2,4 +2,22 @@ type t val create_osm : ?tile_url:string -> unit -> t -val add_to : t -> Map.t -> unit +val add_to : Map.t -> t -> unit + +val remove : t -> unit + +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit + +val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t From 2a760bc98d6fefff090d13afcb5b6c7cdfb8872a Mon Sep 17 00:00:00 2001 From: pena Date: Fri, 8 Apr 2022 22:43:31 +0200 Subject: [PATCH 08/99] use gadts for event, clean repo --- src/dune | 14 +++++++-- src/ev.ml | 31 -------------------- src/ev.mli | 66 ------------------------------------------ src/event.ml | 59 +++++++++++++++++++++++++++++++++++++ src/event.mli | 42 +++++++++++++++++++++++++++ src/leaflet.js.license | 3 -- src/map.ml | 18 ++++-------- src/map.mli | 11 +------ 8 files changed, 118 insertions(+), 126 deletions(-) delete mode 100644 src/ev.ml delete mode 100644 src/ev.mli create mode 100644 src/event.ml create mode 100644 src/event.mli delete mode 100644 src/leaflet.js.license diff --git a/src/dune b/src/dune index 8f28969..bce2f76 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,15 @@ (library - (name leaflet) (public_name leaflet) - (modules ev latlng geojson_layer tile_layer popup marker map global layer) - (libraries brr js_of_ocaml) + (modules + event + geojson_layer + global + latlng + layer + map + marker + popup + tile_layer) + (libraries brr) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/ev.ml b/src/ev.ml deleted file mode 100644 index 7823351..0000000 --- a/src/ev.ml +++ /dev/null @@ -1,31 +0,0 @@ -module Make () = struct - type t = Jv.t - - let type' e = Jv.get e "type" |> Jv.to_string - - let target e = Jv.get e "target" |> Brr.Ev.target_of_jv - - let source_target e = Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv - - let propagated_from e = Jv.get e "propagatedFrom" - - let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" - - let layer_point e = Jv.get e "layerPoint" - - let container_point e = Jv.get e "containerPoint" - - let original_event e = Jv.get e "originalEvent" - - let message e = Jv.get e "message" |> Jv.to_string - - let code e = Jv.get e "code" |> Jv.to_int -end - -module Event = Make () - -module Keyboard = Make () - -module Mouse = Make () - -module Error = Make () diff --git a/src/ev.mli b/src/ev.mli deleted file mode 100644 index 520b5ff..0000000 --- a/src/ev.mli +++ /dev/null @@ -1,66 +0,0 @@ -module Event : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - (* TODO this should return Point *) - val propagated_from : t -> Jv.t -end - -module Keyboard : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - (* TODO this should return BrrDomEvent*) - val original_event : t -> Jv.t -end - -module Mouse : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - val latlng : t -> Latlng.t - - (* TODO this should return Point *) - val layer_point : t -> Jv.t - - (* TODO this should return Point *) - val container_point : t -> Jv.t - - (* TODO this should return BrrDomEvent*) - val original_event : t -> Jv.t -end - -module Error : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - val message : t -> string - - val code : t -> int -end diff --git a/src/event.ml b/src/event.ml new file mode 100644 index 0000000..491f322 --- /dev/null +++ b/src/event.ml @@ -0,0 +1,59 @@ +type _ t = + | Keyboard : Jv.t -> [> `Keyboard ] t + | Mouse : Jv.t -> [> `Mouse ] t + | Error : Jv.t -> [> `Error ] t + | Basic : Jv.t -> [> `Basic ] t + +type _ sub = + | Click : [> `Mouse ] sub + | Move_end : [> `Basic ] sub + | Zoom_end : [> `Basic ] sub + +let of_jv_t : type kind. kind sub -> Jv.t -> kind t = + fun tag e -> + match tag with Click -> Mouse e | Move_end -> Basic e | Zoom_end -> Basic e + +let sub_to_string : type kind. kind sub -> string = function + | Click -> "click" + | Move_end -> "moveend" + | Zoom_end -> "zoomend" + +(** Basic events *) + +let get_type : type kind. kind t -> string = function + | Keyboard e | Mouse e | Error e | Basic e -> Jv.get e "type" |> Jv.to_string + +let target : type kind. kind t -> Brr.Ev.target = function + | Keyboard e | Mouse e | Error e | Basic e -> + Jv.get e "target" |> Brr.Ev.target_of_jv + +let source_target : type kind. kind t -> Brr.Ev.target = function + | Keyboard e | Mouse e | Error e | Basic e -> + Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv + +let propagated_from : type kind. kind t -> Jv.t = function + | Keyboard e | Mouse e | Error e | Basic e -> Jv.get e "propagatedFrom" + +(** Keyboard & Mouse events *) + +let original_event : [ `Keyboard | `Mouse ] t -> Jv.t = function + | Keyboard e | Mouse e -> Jv.get e "originalEvent" + +(** Mouse events *) + +let container_point : [ `Mouse ] t -> Jv.t = function + | Mouse e -> Jv.get e "containerPoint" + +let layer_point : [ `Mouse ] t -> Jv.t = function + | Mouse e -> Jv.get e "layerPoint" + +let latlng : [ `Mouse ] t -> Latlng.t = function + | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv_t + +(** Error events *) + +let code : [ `Error ] t -> int = function + | Error e -> Jv.get e "code" |> Jv.to_int + +let message : [ `Error ] t -> string = function + | Error e -> Jv.get e "message" |> Jv.to_string diff --git a/src/event.mli b/src/event.mli new file mode 100644 index 0000000..bf4f2d7 --- /dev/null +++ b/src/event.mli @@ -0,0 +1,42 @@ +type _ t = + | Keyboard : Jv.t -> [> `Keyboard ] t + | Mouse : Jv.t -> [> `Mouse ] t + | Error : Jv.t -> [> `Error ] t + | Basic : Jv.t -> [> `Basic ] t + +type _ sub = + | Click : [> `Mouse ] sub + | Move_end : [> `Basic ] sub + | Zoom_end : [> `Basic ] sub + +val of_jv_t : 'a sub -> Jv.t -> 'a t + +val sub_to_string : _ sub -> string + +(** Basic events *) + +val get_type : _ t -> string + +val target : _ t -> Brr.Ev.target + +val source_target : _ t -> Brr.Ev.target + +val propagated_from : _ t -> Jv.t + +(** Keyboard & Mouse events *) + +val original_event : [ `Keyboard | `Mouse ] t -> Jv.t + +(** Mouse events *) + +val container_point : [ `Mouse ] t -> Jv.t + +val layer_point : [ `Mouse ] t -> Jv.t + +val latlng : [ `Mouse ] t -> Latlng.t + +(** Error events *) + +val code : [ `Error ] t -> int + +val message : [ `Error ] t -> string diff --git a/src/leaflet.js.license b/src/leaflet.js.license deleted file mode 100644 index 8f54aad..0000000 --- a/src/leaflet.js.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2010-2021 Vladimir Agafonkin - -SPDX-License-Identifier: BSD-2-Clause \ No newline at end of file diff --git a/src/map.ml b/src/map.ml index 3efedd7..e070351 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,15 +1,5 @@ type t = Jv.t -module Event = struct - let to_brr s = s |> Jstr.v |> Brr.Ev.Type.create - - let click = to_brr "click" - - let moveend = to_brr "moveend" - - let zoomend = to_brr "zoomend" -end - let of_jv_t = Fun.id let to_jv_t = Fun.id @@ -34,9 +24,11 @@ let set_view latlng ?zoom map = let as_target map = Brr.Ev.target_of_jv map -let on ~event ~handler map = - let name = Brr.Ev.Type.name event |> Jv.of_jstr in - ignore @@ Jv.call map "on" [| name; Jv.repr handler |] +let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = + fun event handler map -> + let name = Event.sub_to_string event in + let handler v = handler @@ Event.of_jv_t event v in + ignore @@ Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] diff --git a/src/map.mli b/src/map.mli index c373001..fdbd710 100644 --- a/src/map.mli +++ b/src/map.mli @@ -1,14 +1,5 @@ type t -module Event : sig - (* TODO do this need to be wrapped in Brr.Ev.type' ?*) - val click : Ev.Mouse.t Brr.Ev.type' - - val moveend : Ev.Event.t Brr.Ev.type' - - val zoomend : Ev.Event.t Brr.Ev.type' -end - val create : ?options:Jv.t -> string -> t val invalidate_size : t -> unit @@ -19,7 +10,7 @@ val fit_world : t -> unit val get_container : t -> Brr.El.t -val on : event:'a Brr.Ev.type' -> handler:('a -> 'b) -> t -> unit +val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit val get_center : t -> Latlng.t From dbfbaeda60669962c561913a38b951c3ffcfa561 Mon Sep 17 00:00:00 2001 From: pena Date: Sat, 9 Apr 2022 22:21:22 +0200 Subject: [PATCH 09/99] use gadts for layer, clean code --- src/dune | 12 +----- src/event.ml | 4 +- src/event.mli | 2 +- src/geojson_layer.ml | 4 -- src/geojson_layer.mli | 23 ----------- src/latlng.ml | 4 +- src/latlng.mli | 4 +- src/layer.ml | 92 +++++++++++++++++++++++++++++++++++++------ src/layer.mli | 38 ++++++++++++------ src/map.ml | 39 ++++++++++-------- src/map.mli | 6 +-- src/marker.ml | 4 -- src/marker.mli | 23 ----------- src/popup.ml | 16 +++++--- src/popup.mli | 2 +- src/tile_layer.ml | 19 --------- src/tile_layer.mli | 23 ----------- 17 files changed, 152 insertions(+), 163 deletions(-) delete mode 100644 src/geojson_layer.ml delete mode 100644 src/geojson_layer.mli delete mode 100644 src/marker.ml delete mode 100644 src/marker.mli delete mode 100644 src/tile_layer.ml delete mode 100644 src/tile_layer.mli diff --git a/src/dune b/src/dune index bce2f76..ed4515f 100644 --- a/src/dune +++ b/src/dune @@ -1,15 +1,7 @@ (library (public_name leaflet) - (modules - event - geojson_layer - global - latlng - layer - map - marker - popup - tile_layer) + (modules event global latlng layer map popup) + (private_modules global) (libraries brr) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/event.ml b/src/event.ml index 491f322..6b456d2 100644 --- a/src/event.ml +++ b/src/event.ml @@ -9,7 +9,7 @@ type _ sub = | Move_end : [> `Basic ] sub | Zoom_end : [> `Basic ] sub -let of_jv_t : type kind. kind sub -> Jv.t -> kind t = +let of_jv : type kind. kind sub -> Jv.t -> kind t = fun tag e -> match tag with Click -> Mouse e | Move_end -> Basic e | Zoom_end -> Basic e @@ -48,7 +48,7 @@ let layer_point : [ `Mouse ] t -> Jv.t = function | Mouse e -> Jv.get e "layerPoint" let latlng : [ `Mouse ] t -> Latlng.t = function - | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv_t + | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv (** Error events *) diff --git a/src/event.mli b/src/event.mli index bf4f2d7..9592bfb 100644 --- a/src/event.mli +++ b/src/event.mli @@ -9,7 +9,7 @@ type _ sub = | Move_end : [> `Basic ] sub | Zoom_end : [> `Basic ] sub -val of_jv_t : 'a sub -> Jv.t -> 'a t +val of_jv : 'a sub -> Jv.t -> 'a t val sub_to_string : _ sub -> string diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml deleted file mode 100644 index c5c113d..0000000 --- a/src/geojson_layer.ml +++ /dev/null @@ -1,4 +0,0 @@ -include Layer - -let create ?(options = Jv.null) geojson = - of_jv_t @@ Jv.call Global.leaflet "geoJSON" [| geojson; options |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli deleted file mode 100644 index e8c4660..0000000 --- a/src/geojson_layer.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create : ?options:Jv.t -> Jv.t -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t diff --git a/src/latlng.ml b/src/latlng.ml index d2b4dbc..6611746 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -9,6 +9,6 @@ let lng latlng = Jv.get latlng "lng" |> Jv.to_float let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool -let of_jv_t = Fun.id +let of_jv = Fun.id -let to_jv_t = Fun.id +let to_jv = Fun.id diff --git a/src/latlng.mli b/src/latlng.mli index fb793ae..c63a970 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -8,6 +8,6 @@ val lng : t -> float val equals : t -> t -> bool -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t -val to_jv_t : t -> Jv.t +val to_jv : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml index d0c8b62..fd9b07a 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -1,23 +1,89 @@ -type t = Jv.t +type _ t = + | Basic : Jv.t -> [> `Basic ] t + | Geojson : Jv.t -> [> `Geojson ] t + | Marker : Jv.t -> [> `Marker ] t + | Tile : Jv.t -> [> `Tile ] t -let add_to map layer = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] +(** Basic layers *) -let remove layer = ignore @@ Jv.call layer "remove" [||] +let add_to : type kind. Map.t -> kind t -> unit = + fun map -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "addTo" [| Map.to_jv map |] in + () -let remove_from map layer = - ignore @@ Jv.call layer "removeFrom" [| Map.to_jv_t map |] +let remove : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "remove" [||] in + () -let bind_popup el layer = - ignore @@ Jv.call layer "bindPopup" [| Brr.El.to_jv el |] +let remove_from : type kind. Map.t -> kind t -> unit = + fun map -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in + () -let unbind_popup layer = ignore @@ Jv.call layer "unbindPopup" [||] +let bind_popup : type kind. Brr.El.t -> kind t -> unit = + fun el -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el |] in + () -let open_popup layer = ignore @@ Jv.call layer "openPopup" [||] +let unbind_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "unbindPopup" [||] in + () -let close_popup layer = ignore @@ Jv.call layer "closePopup" [||] +let open_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "openPopup" [||] in + () -let get_popup layer = Popup.of_jv_t @@ Jv.call layer "getPopup" [||] +let close_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "closePopup" [||] in + () -let of_jv_t = Fun.id +let get_popup : type kind. kind t -> Popup.t = function + | Basic l | Geojson l | Marker l | Tile l -> + Jv.call l "getPopup" [||] |> Popup.of_jv -let to_jv_t = Fun.id +let to_jv : type kind. kind t -> Jv.t = function + | Basic l | Geojson l | Marker l | Tile l -> l + +(** Geojson layers *) + +let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = + fun ?(options = Jv.null) geojson -> + let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; options |] in + Geojson jv_t + +(** Marker layers *) + +let create_marker : Latlng.t -> [ `Marker ] t = + fun latlng -> + let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng |] in + Marker jv_t + +(** Tile layers *) + +let create_tile_osm : string option -> [ `Tile ] t = + fun url -> + (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) + let url = + Option.value url + ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + in + let jv_t = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + in + Tile jv_t diff --git a/src/layer.mli b/src/layer.mli index 98fe10c..0baf3fd 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -1,21 +1,37 @@ -type t +type _ t = + | Basic : Jv.t -> [> `Basic ] t + | Geojson : Jv.t -> [> `Geojson ] t + | Marker : Jv.t -> [> `Marker ] t + | Tile : Jv.t -> [> `Tile ] t -val add_to : Map.t -> t -> unit +(** Basic layers *) -val remove : t -> unit +val add_to : Map.t -> _ t -> unit -val remove_from : Map.t -> t -> unit +val remove : _ t -> unit -val bind_popup : Brr.El.t -> t -> unit +val remove_from : Map.t -> _ t -> unit -val unbind_popup : t -> unit +val bind_popup : Brr.El.t -> _ t -> unit -val open_popup : t -> unit +val unbind_popup : _ t -> unit -val close_popup : t -> unit +val open_popup : _ t -> unit -val get_popup : t -> Popup.t +val close_popup : _ t -> unit -val of_jv_t : Jv.t -> t +val get_popup : _ t -> Popup.t -val to_jv_t : t -> Jv.t +val to_jv : _ t -> Jv.t + +(** Geojson layers *) + +val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t + +(** Marker layers *) + +val create_marker : Latlng.t -> [ `Marker ] t + +(** Tile layers *) + +val create_tile_osm : string option -> [ `Tile ] t diff --git a/src/map.ml b/src/map.ml index e070351..57598f4 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,38 +1,43 @@ type t = Jv.t -let of_jv_t = Fun.id +let of_jv = Fun.id -let to_jv_t = Fun.id +let to_jv = Fun.id let create ?(options = Jv.null) container_id = Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] -let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] +let invalidate_size map = + let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in + () -let fit_world map = ignore @@ Jv.call map "fitWorld" [||] +let fit_world map = + let (_ : Jv.t) = Jv.call map "fitWorld" [||] in + () -let get_container map = - Jv.call (to_jv_t map) "getContainer" [||] |> Brr.El.of_jv +let get_container map = Jv.call (to_jv map) "getContainer" [||] |> Brr.El.of_jv -let set_view latlng ?zoom map = - let latlng = Latlng.to_jv_t latlng in - ignore - @@ - match zoom with - | None -> Jv.call map "setView" [| latlng |] - | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] +let set_view latlng ~zoom map = + let latlng = Latlng.to_jv latlng in + let (_ : Jv.t) = + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] + in + () let as_target map = Brr.Ev.target_of_jv map let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in - let handler v = handler @@ Event.of_jv_t event v in - ignore @@ Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] + let handler v = handler @@ Event.of_jv event v in + let (_ : Jv.t) = Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] in + () -let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] +let get_center map = Latlng.of_jv @@ Jv.call map "getCenter" [||] let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int let wrapped_latlng latlng map = - Latlng.of_jv_t @@ Jv.call map "wrapLatLng" [| Latlng.to_jv_t latlng |] + Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] diff --git a/src/map.mli b/src/map.mli index fdbd710..f4f6f2b 100644 --- a/src/map.mli +++ b/src/map.mli @@ -4,7 +4,7 @@ val create : ?options:Jv.t -> string -> t val invalidate_size : t -> unit -val set_view : Latlng.t -> ?zoom:int -> t -> unit +val set_view : Latlng.t -> zoom:int option -> t -> unit val fit_world : t -> unit @@ -20,6 +20,6 @@ val wrapped_latlng : Latlng.t -> t -> Latlng.t val as_target : t -> Brr.Ev.target -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t -val to_jv_t : t -> Jv.t +val to_jv : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml deleted file mode 100644 index 44925a1..0000000 --- a/src/marker.ml +++ /dev/null @@ -1,4 +0,0 @@ -include Layer - -let create latlng = - of_jv_t @@ Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] diff --git a/src/marker.mli b/src/marker.mli deleted file mode 100644 index ab77fc5..0000000 --- a/src/marker.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create : Latlng.t -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t diff --git a/src/popup.ml b/src/popup.ml index bc0febf..fb0264c 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -3,13 +3,19 @@ type t = Jv.t let popup = Jv.call Global.leaflet "popup" [||] let set_latlng latlng = - ignore @@ Jv.call popup "setLatLng" [| Latlng.to_jv_t latlng |] + let (_ : Jv.t) = Jv.call popup "setLatLng" [| Latlng.to_jv latlng |] in + () let set_content content = - ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in + () -let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] +let open_on map = + let (_ : Jv.t) = Jv.call popup "openOn" [| Map.to_jv map |] in + () -let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] +let close map = + let (_ : Jv.t) = Jv.call (Map.to_jv map) "closePopup" [||] in + () -let of_jv_t = Fun.id +let of_jv = Fun.id diff --git a/src/popup.mli b/src/popup.mli index 5ca939b..65e5dfc 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -8,4 +8,4 @@ val open_on : Map.t -> unit val close : Map.t -> unit -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t diff --git a/src/tile_layer.ml b/src/tile_layer.ml deleted file mode 100644 index 1dae48c..0000000 --- a/src/tile_layer.ml +++ /dev/null @@ -1,19 +0,0 @@ -include Layer - -let create_osm ?tile_url () = - (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) - let tile_url = - Option.fold ~some:Fun.id - ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url - in - of_jv_t - @@ Jv.call Global.leaflet "tileLayer" - [| Jv.of_string tile_url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli deleted file mode 100644 index b1834b5..0000000 --- a/src/tile_layer.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create_osm : ?tile_url:string -> unit -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t From d6195f00e9442b869805c936ec0bf58e885c28d6 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 12 Apr 2022 13:46:37 +0200 Subject: [PATCH 10/99] license --- LICENSE.md | 11 ++++++----- README.md | 7 +++++-- dune-project | 18 +++++++++--------- leaflet.opam | 23 ++++++++++++++--------- src/event.ml | 2 ++ src/event.mli | 2 ++ src/global.ml | 2 ++ src/latlng.ml | 2 ++ src/latlng.mli | 2 ++ src/layer.ml | 2 ++ src/layer.mli | 2 ++ src/map.ml | 2 ++ src/map.mli | 2 ++ src/popup.ml | 2 ++ src/popup.mli | 2 ++ 15 files changed, 56 insertions(+), 25 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index c0fd71b..5a2b10a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,8 +1,9 @@ -The ISC License (ISC) -===================== +Copyright 2022 pukkamustard , swrup , pena -Copyright © 2022, TODO +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index e628def..4c297f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # leaflet -[leaflet] is an [OCaml] executable/library to TODO. +`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library. ## Installation @@ -24,6 +24,8 @@ For more, have a look at the [example] folder, at the [documentation] or at the ## About +leaflet's original code was taken from a [NGI0 funded project] + - [LICENSE] - [CHANGELOG] @@ -37,4 +39,5 @@ For more, have a look at the [example] folder, at the [documentation] or at the [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ -[leaflet]: TODO/leaflet +[Leaflet]: https://leafletjs.com/ +[NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ diff --git a/dune-project b/dune-project index 5220076..1613163 100644 --- a/dune-project +++ b/dune-project @@ -4,18 +4,18 @@ (name leaflet) -(license ISC) +(license BSD-2-Clause) -(authors "TODO") +(authors "pukkamustard " "swrup " "Léo Andrès ") -(maintainers "TODO") +(maintainers "swrup ") (source - (uri TODO/leaflet)) + (uri git+https://git.zapashcanon.fr/swrup/leaflet.git)) -(homepage TODO/leaflet) +(homepage https://git.zapashcanon.fr/swrup/leaflet) -(bug_reports TODO/leaflet) +(bug_reports https://git.zapashcanon.fr/swrup/leaflet/issues) (documentation TODO/leaflet) @@ -23,11 +23,11 @@ (package (name leaflet) - (synopsis "OCaml library/executable to TODO") + (synopsis "Bindings for the Leaflet JavaScript library") (description - "leaflet is an OCaml library/executable to TODO.") + "leaflet is an OCaml bindings library for the Leaflet JavaScript library.") (tags - (leaflet TODO TODO TODO TODO)) + (leaflet javascript bindings interactive map openstreetmap)) (depends (ocaml (>= 4.08)))) diff --git a/leaflet.opam b/leaflet.opam index 996aee0..deb4d45 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -1,14 +1,19 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "OCaml library/executable to TODO" -description: "leaflet is an OCaml library/executable to TODO." -maintainer: ["TODO"] -authors: ["TODO"] -license: "ISC" -tags: ["leaflet" "TODO" "TODO" "TODO" "TODO"] -homepage: "TODO/leaflet" +synopsis: "Bindings for the Leaflet JavaScript library" +description: + "leaflet is an OCaml bindings library for the Leaflet JavaScript library." +maintainer: ["swrup "] +authors: [ + "pukkamustard " + "swrup " + "Léo Andrès " +] +license: "BSD-2-Clause" +tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] +homepage: "https://git.zapashcanon.fr/swrup/leaflet" doc: "TODO/leaflet" -bug-reports: "TODO/leaflet" +bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} "ocaml" {>= "4.08"} @@ -30,4 +35,4 @@ build: [ ] ["dune" "install" "-p" name "--create-install-files" name] ] -dev-repo: "TODO/leaflet" +dev-repo: "git+https://git.zapashcanon.fr/swrup/leaflet.git" diff --git a/src/event.ml b/src/event.ml index 6b456d2..2b39417 100644 --- a/src/event.ml +++ b/src/event.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Keyboard : Jv.t -> [> `Keyboard ] t | Mouse : Jv.t -> [> `Mouse ] t diff --git a/src/event.mli b/src/event.mli index 9592bfb..8723a09 100644 --- a/src/event.mli +++ b/src/event.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Keyboard : Jv.t -> [> `Keyboard ] t | Mouse : Jv.t -> [> `Mouse ] t diff --git a/src/global.ml b/src/global.ml index c209f3d..a4ebdfa 100644 --- a/src/global.ml +++ b/src/global.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + let leaflet = match Jv.(find global "L") with | Some l -> l diff --git a/src/latlng.ml b/src/latlng.ml index 6611746..400200b 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let create lat lng = diff --git a/src/latlng.mli b/src/latlng.mli index c63a970..9097890 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val create : float -> float -> t diff --git a/src/layer.ml b/src/layer.ml index fd9b07a..9808ebb 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Basic : Jv.t -> [> `Basic ] t | Geojson : Jv.t -> [> `Geojson ] t diff --git a/src/layer.mli b/src/layer.mli index 0baf3fd..b3816e6 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Basic : Jv.t -> [> `Basic ] t | Geojson : Jv.t -> [> `Geojson ] t diff --git a/src/map.ml b/src/map.ml index 57598f4..259efeb 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let of_jv = Fun.id diff --git a/src/map.mli b/src/map.mli index f4f6f2b..96795cb 100644 --- a/src/map.mli +++ b/src/map.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val create : ?options:Jv.t -> string -> t diff --git a/src/popup.ml b/src/popup.ml index fb0264c..5447cd4 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let popup = Jv.call Global.leaflet "popup" [||] diff --git a/src/popup.mli b/src/popup.mli index 65e5dfc..ee5df35 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val set_latlng : Latlng.t -> unit From f0435c549bb95856307b227b616f21bf6a7f7468 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 12 Apr 2022 15:26:49 +0200 Subject: [PATCH 11/99] add point --- src/dune | 2 +- src/event.ml | 8 ++++---- src/event.mli | 4 ++-- src/point.ml | 11 +++++++++++ src/point.mli | 9 +++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 src/point.ml create mode 100644 src/point.mli diff --git a/src/dune b/src/dune index ed4515f..4e2d45f 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup) + (modules event global latlng layer map popup point) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/event.ml b/src/event.ml index 2b39417..2b9cb77 100644 --- a/src/event.ml +++ b/src/event.ml @@ -43,11 +43,11 @@ let original_event : [ `Keyboard | `Mouse ] t -> Jv.t = function (** Mouse events *) -let container_point : [ `Mouse ] t -> Jv.t = function - | Mouse e -> Jv.get e "containerPoint" +let container_point : [ `Mouse ] t -> Point.t = function + | Mouse e -> Jv.get e "containerPoint" |> Point.of_jv -let layer_point : [ `Mouse ] t -> Jv.t = function - | Mouse e -> Jv.get e "layerPoint" +let layer_point : [ `Mouse ] t -> Point.t = function + | Mouse e -> Jv.get e "layerPoint" |> Point.of_jv let latlng : [ `Mouse ] t -> Latlng.t = function | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv diff --git a/src/event.mli b/src/event.mli index 8723a09..5793744 100644 --- a/src/event.mli +++ b/src/event.mli @@ -31,9 +31,9 @@ val original_event : [ `Keyboard | `Mouse ] t -> Jv.t (** Mouse events *) -val container_point : [ `Mouse ] t -> Jv.t +val container_point : [ `Mouse ] t -> Point.t -val layer_point : [ `Mouse ] t -> Jv.t +val layer_point : [ `Mouse ] t -> Point.t val latlng : [ `Mouse ] t -> Latlng.t diff --git a/src/point.ml b/src/point.ml new file mode 100644 index 0000000..0191894 --- /dev/null +++ b/src/point.ml @@ -0,0 +1,11 @@ +(* BSD-2-Clause License *) + +type t = + { x : int + ; y : int + } + +let of_jv point = + let x = Jv.get point "x" |> Jv.to_int in + let y = Jv.get point "y" |> Jv.to_int in + { x; y } diff --git a/src/point.mli b/src/point.mli new file mode 100644 index 0000000..2ca4de2 --- /dev/null +++ b/src/point.mli @@ -0,0 +1,9 @@ +(* BSD-2-Clause License *) + +type t = + { x : int + ; y : int + } + +(** [of_jv jv] is [jv] as {!t} *) +val of_jv : Jv.t -> t From 0370fb97a2a33a17a49d726b1f380c51a84e54b5 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 15:46:43 +0200 Subject: [PATCH 12/99] add example --- example/dune | 6 +- example/leaflet.css | 640 ++++++++++++++++++++++++++++++++++++++++++++ example/main.ml | 15 +- example/map.html | 12 + 4 files changed, 671 insertions(+), 2 deletions(-) create mode 100644 example/leaflet.css create mode 100644 example/map.html diff --git a/example/dune b/example/dune index e36b142..80423a9 100644 --- a/example/dune +++ b/example/dune @@ -1,3 +1,7 @@ (executable (name main) - (modules main)) + (modules main) + (libraries leaflet) + (modes js) + (preprocess + (pps js_of_ocaml-ppx))) diff --git a/example/leaflet.css b/example/leaflet.css new file mode 100644 index 0000000..3385b5e --- /dev/null +++ b/example/leaflet.css @@ -0,0 +1,640 @@ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg, +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + } + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-tile { + will-change: opacity; + } +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + will-change: transform; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline: 0; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-container a.leaflet-active { + outline: 2px solid orange; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a, +.leaflet-bar a:hover { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(/assets/img/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(/assets/img/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { + background-image: url(/assets/img/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.7); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover { + text-decoration: underline; + } +.leaflet-container .leaflet-control-attribution, +.leaflet-container .leaflet-control-scale { + font-size: 11px; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + -moz-box-sizing: border-box; + box-sizing: border-box; + + background: #fff; + background: rgba(255, 255, 255, 0.5); + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 19px; + line-height: 1.4; + } +.leaflet-popup-content p { + margin: 18px 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + padding: 4px 4px 0 0; + border: none; + text-align: center; + width: 18px; + height: 14px; + font: 16px/14px Tahoma, Verdana, sans-serif; + color: #c3c3c3; + text-decoration: none; + font-weight: bold; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999; + } +.leaflet-popup-scrolled { + overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } +.leaflet-oldie .leaflet-popup-tip-container { + margin-top: -1px; + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-clickable { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } diff --git a/example/main.ml b/example/main.ml index 16c9b9f..9b8e97d 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1 +1,14 @@ -let () = Format.printf "TODO@." +(* create map *) +let map = + let container_id = "map" in + Leaflet.Map.create container_id + +(* setup map *) +let () = + (* set osm layer *) + let osm_layer = Leaflet.Layer.create_tile_osm None in + Leaflet.Layer.add_to map osm_layer; + + (* set view *) + let latlng = Leaflet.Latlng.create 40.71 (-74.0) in + ignore @@ Leaflet.Map.set_view latlng ~zoom:(Some 13) map diff --git a/example/map.html b/example/map.html new file mode 100644 index 0000000..341173f --- /dev/null +++ b/example/map.html @@ -0,0 +1,12 @@ + + + + + + + +
+
+
+ + From 68ee03beade8b32704f59d1fc3cb617d2dc3247d Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 16:16:37 +0200 Subject: [PATCH 13/99] make Map.create take Brr.El --- example/dune | 2 +- example/main.ml | 8 ++++++-- src/map.ml | 6 ++++-- src/map.mli | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/example/dune b/example/dune index 80423a9..1b81cc6 100644 --- a/example/dune +++ b/example/dune @@ -1,7 +1,7 @@ (executable (name main) (modules main) - (libraries leaflet) + (libraries brr leaflet) (modes js) (preprocess (pps js_of_ocaml-ppx))) diff --git a/example/main.ml b/example/main.ml index 9b8e97d..9e685c4 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1,7 +1,11 @@ (* create map *) let map = - let container_id = "map" in - Leaflet.Map.create container_id + let container = + match Brr.Document.find_el_by_id Brr.G.document (Jstr.of_string "map") with + | None -> failwith "map container not found" + | Some el -> el + in + Leaflet.Map.create container (* setup map *) let () = diff --git a/src/map.ml b/src/map.ml index 259efeb..8277a9a 100644 --- a/src/map.ml +++ b/src/map.ml @@ -6,8 +6,10 @@ let of_jv = Fun.id let to_jv = Fun.id -let create ?(options = Jv.null) container_id = - Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] +let create ?(options = Jv.null) container = + match Brr.El.at (Jstr.of_string "id") container with + | None -> failwith "container doesn't have id" + | Some id -> Jv.call Global.leaflet "map" [| Jv.of_jstr id; options |] let invalidate_size map = let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in diff --git a/src/map.mli b/src/map.mli index 96795cb..15c1f2b 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,7 +2,7 @@ type t -val create : ?options:Jv.t -> string -> t +val create : ?options:Jv.t -> Brr.El.t -> t val invalidate_size : t -> unit From 38c0d5ef53c52e1ca0e908edb18838395dbe87f3 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 22:42:28 +0200 Subject: [PATCH 14/99] add documentation, remove Map.as_target --- doc/index.mld | 14 ++------------ src/latlng.mli | 8 ++++++++ src/layer.ml | 1 - src/layer.mli | 14 ++++++++++++++ src/map.ml | 4 +--- src/map.mli | 23 ++++++++++++++++++++--- src/popup.mli | 5 +++++ 7 files changed, 50 insertions(+), 19 deletions(-) diff --git a/doc/index.mld b/doc/index.mld index c248edf..1676769 100644 --- a/doc/index.mld +++ b/doc/index.mld @@ -1,17 +1,7 @@ -{0 leaflet} +{0 Leaflet} -{{:https://TODO/leaflet} leaflet} is an {{:https://ocaml.org} OCaml} library/executable to TODO. - -{1:api API} +Leaflet is an [OCaml] bindings library for the {{:https://leafletjs.com} Leaflet} JavaScript library. {!modules: Leaflet } - -{1:private_api Private API} - -You shouldn't have to use any of these modules, they're used internally only. - -{!modules: -TODO -} diff --git a/src/latlng.mli b/src/latlng.mli index 9097890..120d165 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -2,14 +2,22 @@ type t +(** [create lat lng] is an object representing a geographical point with the + given latitude and longitude *) val create : float -> float -> t +(** [lat o] is the latitude of [o] *) val lat : t -> float +(** [lng o] is the longitude of [o] *) val lng : t -> float +(** [equals a b] is true iff [a] and [b] is at the same position (within a small + margin of error) *) val equals : t -> t -> bool +(** [of_jv jv] is [jv] as a [Latlng.t] *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml index 9808ebb..b1e8977 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -71,7 +71,6 @@ let create_marker : Latlng.t -> [ `Marker ] t = let create_tile_osm : string option -> [ `Tile ] t = fun url -> - (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) let url = Option.value url ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" diff --git a/src/layer.mli b/src/layer.mli index b3816e6..d049182 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -8,32 +8,46 @@ type _ t = (** Basic layers *) +(** [add_to map layer] adds [layer] to [map] *) val add_to : Map.t -> _ t -> unit +(** [remove layer] removes [layer] from the map it is currently active on *) val remove : _ t -> unit +(** [remove_from map layer] removes [layer] from [map] *) val remove_from : Map.t -> _ t -> unit +(** [bind_popup popup layer] binds [popup] to [layer] *) val bind_popup : Brr.El.t -> _ t -> unit +(** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit +(** [open_popup layer] opens the popup bound to [layer] *) val open_popup : _ t -> unit +(** [close_popup layer] closes the popup bound to [layer] *) val close_popup : _ t -> unit +(** [get_popup layer] is the popup bound to [layer] *) val get_popup : _ t -> Popup.t +(** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : _ t -> Jv.t (** Geojson layers *) +(** [create_geojson geojson] is a new geojson layer *) val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t (** Marker layers *) +(** [create_marker latlng] is a new marker with the same position as latlng *) val create_marker : Latlng.t -> [ `Marker ] t (** Tile layers *) +(** [create_tile_osm Some(url)] is a new tile layer with tile server specified + by [url]. Tile server default to [openstreetmap.org]. See + {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : string option -> [ `Tile ] t diff --git a/src/map.ml b/src/map.ml index 8277a9a..bbd5da3 100644 --- a/src/map.ml +++ b/src/map.ml @@ -30,8 +30,6 @@ let set_view latlng ~zoom map = in () -let as_target map = Brr.Ev.target_of_jv map - let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in @@ -43,5 +41,5 @@ let get_center map = Latlng.of_jv @@ Jv.call map "getCenter" [||] let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int -let wrapped_latlng latlng map = +let wrap_latlng latlng map = Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] diff --git a/src/map.mli b/src/map.mli index 15c1f2b..d027da4 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,26 +2,43 @@ type t +(** [create container] creates a map on [container]. * To have a functional map + you will need to add a tile layer to it. *) val create : ?options:Jv.t -> Brr.El.t -> t +(** [invalidate_size map] checks if the map container size changed and updates + the map if so *) val invalidate_size : t -> unit +(** [set_view latlng Some(zoom) map] sets the view of the [map] (geographical + center and zoom) *) val set_view : Latlng.t -> zoom:int option -> t -> unit +(** [fit_world map] sets a map view that mostly contains the whole world with + the maximum zoom level possible *) val fit_world : t -> unit +(** [get_container map] is the HTML element that contains [map] *) val get_container : t -> Brr.El.t +(** [on event handler map] add an event listener on [map] for event [event] with + handler [handler] *) val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit +(** [get_center map] is the geographical center of the map view *) val get_center : t -> Latlng.t +(** [get_zoom map] is the current zoom level of the map view *) val get_zoom : t -> int -val wrapped_latlng : Latlng.t -> t -> Latlng.t - -val as_target : t -> Brr.Ev.target +(** [wrap_latlng latlng map] returns a new [Latlng.t] where lat and lng has been + wrapped according to the map's CRS's wrapLat and wrapLng properties, if they + are outside the CRS's bounds. By default this means longitude is wrapped + around the dateline so its value is between -180 and +180 degrees *) +val wrap_latlng : Latlng.t -> t -> Latlng.t +(** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t diff --git a/src/popup.mli b/src/popup.mli index ee5df35..9983c5c 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -2,12 +2,17 @@ type t +(** [set_latlng latlng] changes the popup position to the given point*) val set_latlng : Latlng.t -> unit +(** [set_content s] changes the popup content to [s]*) val set_content : string -> unit +(** [open_on map] * Adds the popup to [map] and closes the previous one. *) val open_on : Map.t -> unit +(** [close map] * closes the popup of [map]*) val close : Map.t -> unit +(** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t From 06c614d2c520262ccf55fdc4bf9c5bfe6bb006e0 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 23:02:04 +0200 Subject: [PATCH 15/99] add usage to readme --- .ocamlformat | 2 +- CHANGES.md | 4 +++- README.md | 11 +++++------ dune-project | 1 + leaflet.opam | 1 + 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index 1b64a37..cec2d50 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.21.0 +version=0.22.4 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/CHANGES.md b/CHANGES.md index d9cd2e7..4cff088 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1 +1,3 @@ -## unreleased +## 0.1 + +Initial release. diff --git a/README.md b/README.md index 4c297f0..ffa9b2e 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,12 @@ If you don't have `opam`, you can install it following the [how to install opam] If you can't or don't want to use `opam`, consult the [opam file] for build instructions. -## Quickstart +## Usage -```ocaml -let () = Format.printf "TODO@." -``` +Have a look at the [example] folder. +The documentation can be consulted via `odig doc leaflet`. -For more, have a look at the [example] folder, at the [documentation] or at the [test suite]. +You will also need [leaflet's files] (CSS and images). ## About @@ -35,9 +34,9 @@ leaflet's original code was taken from a [NGI0 funded project] [opam file]: ./leaflet.opam [test suite]: ./test -[documentation]: TODO/leaflet [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ [Leaflet]: https://leafletjs.com/ +[leaflet's files]: https://leafletjs.com/download.html [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ diff --git a/dune-project b/dune-project index 1613163..1b5b654 100644 --- a/dune-project +++ b/dune-project @@ -29,5 +29,6 @@ (tags (leaflet javascript bindings interactive map openstreetmap)) (depends + brr (ocaml (>= 4.08)))) diff --git a/leaflet.opam b/leaflet.opam index deb4d45..70dc18a 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -16,6 +16,7 @@ doc: "TODO/leaflet" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} + "brr" "ocaml" {>= "4.08"} "odoc" {with-doc} ] From 83527f5caefc1c72c05833b14cf45391c6f5a9b4 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 18 Jun 2022 07:53:26 +0200 Subject: [PATCH 16/99] change map creation --- example/main.ml | 8 +------- src/map.ml | 11 +++++++---- src/map.mli | 11 ++++++++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/example/main.ml b/example/main.ml index 9e685c4..43b9fcd 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1,11 +1,5 @@ (* create map *) -let map = - let container = - match Brr.Document.find_el_by_id Brr.G.document (Jstr.of_string "map") with - | None -> failwith "map container not found" - | Some el -> el - in - Leaflet.Map.create container +let map = Leaflet.Map.create_on "map" (* setup map *) let () = diff --git a/src/map.ml b/src/map.ml index bbd5da3..2f2db23 100644 --- a/src/map.ml +++ b/src/map.ml @@ -6,10 +6,13 @@ let of_jv = Fun.id let to_jv = Fun.id -let create ?(options = Jv.null) container = - match Brr.El.at (Jstr.of_string "id") container with - | None -> failwith "container doesn't have id" - | Some id -> Jv.call Global.leaflet "map" [| Jv.of_jstr id; options |] +let create_on ?(options = Jv.null) id = + Jv.call Global.leaflet "map" [| Jv.of_string id; options |] + +let create_from_div ?(options = Jv.null) container = + if Brr.El.has_tag_name Brr.El.Name.div container then + Jv.call Global.leaflet "map" [| Brr.El.to_jv container; options |] + else failwith "container is not a
" let invalidate_size map = let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in diff --git a/src/map.mli b/src/map.mli index d027da4..c1a7770 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,9 +2,14 @@ type t -(** [create container] creates a map on [container]. * To have a functional map - you will need to add a tile layer to it. *) -val create : ?options:Jv.t -> Brr.El.t -> t +(** [create id] creates a map on the
with DOM id [id]. To have a + functional map you will need to add a tile layer to it. *) +val create_on : ?options:Jv.t -> string -> t + +(** [create_from_div container] creates a map given [container], an instance of + a
HTML element. To have a functional map you will need to add a tile + layer to it. *) +val create_from_div : ?options:Jv.t -> Brr.El.t -> t (** [invalidate_size map] checks if the map container size changed and updates the map if so *) From 10aaf21209d603dc10eb638841b293c3e299823f Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 18 Jun 2022 20:47:19 +0200 Subject: [PATCH 17/99] add js_of_ocaml to package dependency --- dune-project | 1 + example/dune | 4 +--- leaflet.opam | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dune-project b/dune-project index 1b5b654..896dd1a 100644 --- a/dune-project +++ b/dune-project @@ -30,5 +30,6 @@ (leaflet javascript bindings interactive map openstreetmap)) (depends brr + js_of_ocaml (ocaml (>= 4.08)))) diff --git a/example/dune b/example/dune index 1b81cc6..b868e46 100644 --- a/example/dune +++ b/example/dune @@ -2,6 +2,4 @@ (name main) (modules main) (libraries brr leaflet) - (modes js) - (preprocess - (pps js_of_ocaml-ppx))) + (modes js)) diff --git a/leaflet.opam b/leaflet.opam index 70dc18a..1b6ae70 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -17,6 +17,7 @@ bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} "brr" + "js_of_ocaml" "ocaml" {>= "4.08"} "odoc" {with-doc} ] From 5fecae013cf5946b07b4036ac08f2e224a27967a Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 06:52:05 +0200 Subject: [PATCH 18/99] add of_jv, on, ?options for bind_popup --- src/layer.ml | 29 ++++++++++++++++++++++++++--- src/layer.mli | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index b1e8977..beef402 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -6,6 +6,12 @@ type _ t = | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t +type _ sub = + | Basic : [> `Basic ] sub + | Geojson : [> `Geojson ] sub + | Marker : [> `Marker ] sub + | Tile : [> `Tile ] sub + (** Basic layers *) let add_to : type kind. Map.t -> kind t -> unit = @@ -25,10 +31,10 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> kind t -> unit = - fun el -> function +let bind_popup : type kind. Brr.El.t -> ?options:Jv.t -> kind t -> unit = + fun el ?(options = Jv.null) -> function | Basic l | Geojson l | Marker l | Tile l -> - let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el |] in + let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el; options |] in () let unbind_popup : type kind. kind t -> unit = function @@ -53,6 +59,23 @@ let get_popup : type kind. kind t -> Popup.t = function let to_jv : type kind. kind t -> Jv.t = function | Basic l | Geojson l | Marker l | Tile l -> l +let of_jv : type kind. kind sub -> Jv.t -> kind t = + fun tag l -> + match tag with + | Basic -> Basic l + | Geojson -> Geojson l + | Marker -> Marker l + | Tile -> Tile l + +let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = + fun event handler layer -> + let name = Event.sub_to_string event in + let handler v = handler @@ Event.of_jv event v in + let (_ : Jv.t) = + Jv.call (to_jv layer) "on" [| Jv.of_string name; Jv.repr handler |] + in + () + (** Geojson layers *) let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = diff --git a/src/layer.mli b/src/layer.mli index d049182..309d1f5 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -6,6 +6,12 @@ type _ t = | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t +type _ sub = + | Basic : [> `Basic ] sub + | Geojson : [> `Geojson ] sub + | Marker : [> `Marker ] sub + | Tile : [> `Tile ] sub + (** Basic layers *) (** [add_to map layer] adds [layer] to [map] *) @@ -18,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> _ t -> unit +val bind_popup : Brr.El.t -> ?options:Jv.t -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit @@ -35,6 +41,13 @@ val get_popup : _ t -> Popup.t (** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : _ t -> Jv.t +(** [of_jv tag o] is [o] as a [tag t] *) +val of_jv : 'a sub -> Jv.t -> 'a t + +(** [on event handler layer] add an event listener on [layer] for event [event] + with handler [handler] *) +val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit + (** Geojson layers *) (** [create_geojson geojson] is a new geojson layer *) From c3766414c3e8118e9cd9b90541d392435f110994 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 07:57:38 +0200 Subject: [PATCH 19/99] add icon --- src/dune | 2 +- src/icon.ml | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/icon.mli | 21 +++++++++++++++++++++ src/point.ml | 3 +++ src/point.mli | 3 +++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/icon.ml create mode 100644 src/icon.mli diff --git a/src/dune b/src/dune index 4e2d45f..52d85ee 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup point) + (modules event global latlng layer map popup point icon) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/icon.ml b/src/icon.ml new file mode 100644 index 0000000..0073d68 --- /dev/null +++ b/src/icon.ml @@ -0,0 +1,47 @@ +(* BSD-2-Clause License *) + +type t = Jv.t + +type opt = + | Icon_retina_url of string + | Icon_size of Point.t + | Icon_anchor of Point.t + | Popup_anchor of Point.t + | Tooltip_anchor of Point.t + | Shadow_url of string + | Shadow_retina_url of string + | Shadow_size of Point.t + | Shadow_anchor of Point.t + | Class_name of string + | Cross_origin of string option + +let to_string = function + | Icon_retina_url _ -> "iconRetinaUrl" + | Icon_size _ -> "iconSize" + | Icon_anchor _ -> "iconAnchor" + | Popup_anchor _ -> "popupAnchor" + | Tooltip_anchor _ -> "tooltipAnchor" + | Shadow_url _ -> "shadowUrl" + | Shadow_retina_url _ -> "shadowRetinaUrl" + | Shadow_size _ -> "shadowSize" + | Shadow_anchor _ -> "shadowAnchor" + | Class_name _ -> "className" + | Cross_origin _ -> "crossOrigin" + +let to_jv = function + | Icon_size p + | Icon_anchor p + | Popup_anchor p + | Tooltip_anchor p + | Shadow_size p + | Shadow_anchor p -> + Point.to_jv p + | Icon_retina_url s | Shadow_url s | Shadow_retina_url s | Class_name s -> + Jv.of_string s + | Cross_origin o -> ( + match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) + +let create icon_url options = + let l = List.map (fun o -> (to_string o, to_jv o)) options in + let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + Jv.call Global.leaflet "icon" [| Jv.obj tab |] diff --git a/src/icon.mli b/src/icon.mli new file mode 100644 index 0000000..0d58709 --- /dev/null +++ b/src/icon.mli @@ -0,0 +1,21 @@ +(* BSD-2-Clause License *) + +type t + +(* type for icon option used to create an icon*) +type opt = + | Icon_retina_url of string + | Icon_size of Point.t + | Icon_anchor of Point.t + | Popup_anchor of Point.t + | Tooltip_anchor of Point.t + | Shadow_url of string + | Shadow_retina_url of string + | Shadow_size of Point.t + | Shadow_anchor of Point.t + | Class_name of string + | Cross_origin of string option + +(** [create icon_url options] Creates an icon instance with the given [options], + and the required `iconUrl` option set to [icon_url] *) +val create : string -> opt list -> t diff --git a/src/point.ml b/src/point.ml index 0191894..00fceb9 100644 --- a/src/point.ml +++ b/src/point.ml @@ -9,3 +9,6 @@ let of_jv point = let x = Jv.get point "x" |> Jv.to_int in let y = Jv.get point "y" |> Jv.to_int in { x; y } + +let to_jv point = + Jv.call Global.leaflet "point" [| Jv.of_int point.x; Jv.of_int point.y |] diff --git a/src/point.mli b/src/point.mli index 2ca4de2..a9b9430 100644 --- a/src/point.mli +++ b/src/point.mli @@ -7,3 +7,6 @@ type t = (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t + +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t From fbcb87f0d86c235190be9ba10bac4d23018da5d0 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 08:16:21 +0200 Subject: [PATCH 20/99] add marker options --- src/icon.ml | 6 ++++-- src/icon.mli | 3 +++ src/layer.ml | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- src/layer.mli | 16 +++++++++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/icon.ml b/src/icon.ml index 0073d68..369c288 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -2,6 +2,8 @@ type t = Jv.t +let to_jv = Fun.id + type opt = | Icon_retina_url of string | Icon_size of Point.t @@ -28,7 +30,7 @@ let to_string = function | Class_name _ -> "className" | Cross_origin _ -> "crossOrigin" -let to_jv = function +let opt_to_jv = function | Icon_size p | Icon_anchor p | Popup_anchor p @@ -42,6 +44,6 @@ let to_jv = function match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) let create icon_url options = - let l = List.map (fun o -> (to_string o, to_jv o)) options in + let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in Jv.call Global.leaflet "icon" [| Jv.obj tab |] diff --git a/src/icon.mli b/src/icon.mli index 0d58709..df3b33e 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -2,6 +2,9 @@ type t +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t + (* type for icon option used to create an icon*) type opt = | Icon_retina_url of string diff --git a/src/layer.ml b/src/layer.ml index beef402..7f34d54 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -85,9 +85,52 @@ let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = (** Marker layers *) -let create_marker : Latlng.t -> [ `Marker ] t = - fun latlng -> - let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng |] in +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +let marker_opt_to_string : marker_opt -> string = function + | Icon _ -> "icon" + | Keyboard _ -> "keyboard" + | Title _ -> "title" + | Alt _ -> "alt" + | Z_index_offset _ -> "zIndexOffset" + | Opacity _ -> "opacity" + | Rise_on_hover _ -> "riseOnHover" + | Rise_offset _ -> "riseOffset" + | Pane _ -> "pane" + | Shadow_pane _ -> "shadowPane" + | Bubbling_mouse_events _ -> "bubblingMouseEvents" + | Auto_pan_on_focus _ -> "autoPanOnFocus" + +let marker_opt_to_jv = function + | Icon icon -> Icon.to_jv icon + | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b + -> + Jv.of_bool b + | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s + | Z_index_offset i | Rise_offset i -> Jv.of_int i + | Opacity f -> Jv.of_float f + +let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = + fun latlng options -> + let l = + Array.of_list + @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + in + let jv_t = + Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] + in Marker jv_t (** Tile layers *) diff --git a/src/layer.mli b/src/layer.mli index 309d1f5..9f85a0a 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -55,8 +55,22 @@ val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t (** Marker layers *) +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + (** [create_marker latlng] is a new marker with the same position as latlng *) -val create_marker : Latlng.t -> [ `Marker ] t +val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t (** Tile layers *) From a438e54f42afc995819dbf5f143a388e8b3e711b Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 09:17:23 +0200 Subject: [PATCH 21/99] add geojson options --- src/layer.ml | 36 +++++++++++++++++++++++++++++++++--- src/layer.mli | 15 +++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 7f34d54..b4261aa 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -78,9 +78,39 @@ let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = (** Geojson layers *) -let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = - fun ?(options = Jv.null) geojson -> - let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; options |] in +type geojson_opt = + | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Style of (Jv.t -> unit) + | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) + | Filter of (Jv.t -> bool) + | Coords_to_latlng of (Jv.t -> Latlng.t) + | Markers_inherit_options of bool + +let geojson_opt_to_string = function + | Point_to_layer _ -> "pointToLayer" + | Style _ -> "style" + | On_each_feature _ -> "onEachFeature" + | Filter _ -> "filter" + | Coords_to_latlng _ -> "coordsToLatLng" + | Markers_inherit_options _ -> "markersInheritOptions" + +let geojson_opt_to_jv = function + | Markers_inherit_options b -> Jv.of_bool b + | Point_to_layer f -> Jv.repr f + | Style f -> Jv.repr f + | On_each_feature f -> Jv.repr f + | Filter f -> Jv.repr f + | Coords_to_latlng f -> Jv.repr f + +let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = + fun geojson options -> + let l = + Array.of_list + @@ List.map + (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) + options + in + let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t (** Marker layers *) diff --git a/src/layer.mli b/src/layer.mli index 9f85a0a..204afab 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -50,11 +50,21 @@ val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit (** Geojson layers *) +(** type for geojson option, used to create geojson *) +type geojson_opt = + | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Style of (Jv.t -> unit) + | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) + | Filter of (Jv.t -> bool) + | Coords_to_latlng of (Jv.t -> Latlng.t) + | Markers_inherit_options of bool + (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t +val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t (** Marker layers *) +(** type for marker option, used to create marker *) type marker_opt = | Icon of Icon.t | Keyboard of bool @@ -69,7 +79,8 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -(** [create_marker latlng] is a new marker with the same position as latlng *) +(** [create_marker latlng options] is a new marker with the same position as + [latlng] and with options set to [options] *) val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t (** Tile layers *) From ede9b2076dd407fa5a5a106195b57bdaa0af7717 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 10:05:35 +0200 Subject: [PATCH 22/99] add popup options --- src/icon.ml | 4 ++-- src/icon.mli | 2 +- src/layer.ml | 19 ++++++++++++----- src/layer.mli | 2 +- src/popup.ml | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/popup.mli | 27 +++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/icon.ml b/src/icon.ml index 369c288..c40305d 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -45,5 +45,5 @@ let opt_to_jv = function let create icon_url options = let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in - let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in - Jv.call Global.leaflet "icon" [| Jv.obj tab |] + let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + Jv.call Global.leaflet "icon" [| Jv.obj l |] diff --git a/src/icon.mli b/src/icon.mli index df3b33e..534c9d9 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -5,7 +5,7 @@ type t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t -(* type for icon option used to create an icon*) +(** type for icon option used to create an icon*) type opt = | Icon_retina_url of string | Icon_size of Point.t diff --git a/src/layer.ml b/src/layer.ml index b4261aa..fd2042c 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -31,10 +31,16 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> ?options:Jv.t -> kind t -> unit = - fun el ?(options = Jv.null) -> function - | Basic l | Geojson l | Marker l | Tile l -> - let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el; options |] in +let bind_popup : type kind. Brr.El.t -> Popup.opt list -> kind t -> unit = + fun el options -> function + | Basic layer | Geojson layer | Marker layer | Tile layer -> + let l = + Array.of_list + @@ List.map (fun o -> (Popup.opt_to_string o, Popup.opt_to_jv o)) options + in + let (_ : Jv.t) = + Jv.call layer "bindPopup" [| Brr.El.to_jv el; Jv.obj l |] + in () let unbind_popup : type kind. kind t -> unit = function @@ -98,7 +104,10 @@ let geojson_opt_to_jv = function | Markers_inherit_options b -> Jv.of_bool b | Point_to_layer f -> Jv.repr f | Style f -> Jv.repr f - | On_each_feature f -> Jv.repr f + | On_each_feature f -> + (* we need to wrap the Jv.t *) + let f feature jv = jv |> of_jv Geojson |> f feature in + Jv.repr f | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f diff --git a/src/layer.mli b/src/layer.mli index 204afab..7eaabd2 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -24,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> ?options:Jv.t -> _ t -> unit +val bind_popup : Brr.El.t -> Popup.opt list -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit diff --git a/src/popup.ml b/src/popup.ml index 5447cd4..f7a1c69 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -21,3 +21,59 @@ let close map = () let of_jv = Fun.id + +type opt = + | Pane of string + | Offset of Point.t + | Max_width of int + | Min_width of int + | Max_height of int + | Auto_pan of bool + | Auto_pan_padding_top_left of Point.t + | Auto_pan_padding_bottom_right of Point.t + | Auto_pan_padding of Point.t + | Keep_in_view of bool + | Close_button of bool + | Auto_close of bool + | Close_on_escape_key of bool + | Close_on_click of bool + | Class_name of string + +let opt_to_string = function + | Pane _ -> "pane" + | Offset _ -> "offset" + | Max_width _ -> "maxWidth" + | Min_width _ -> "minWidth" + | Max_height _ -> "maxHeight" + | Auto_pan _ -> "autoPan" + | Auto_pan_padding_top_left _ -> "autoPanPaddingTopLeft" + | Auto_pan_padding_bottom_right _ -> "autoPanPaddingBottomRight" + | Auto_pan_padding _ -> "autoPanPadding" + | Keep_in_view _ -> "keepInView" + | Close_button _ -> "closeButton" + | Auto_close _ -> "autoClose" + | Close_on_escape_key _ -> "closeOnEscapeKey" + | Close_on_click _ -> "closeOnClick" + | Class_name _ -> "className" + +let opt_to_jv = function + | Offset p + | Auto_pan_padding_top_left p + | Auto_pan_padding_bottom_right p + | Auto_pan_padding p -> + Point.to_jv p + | Max_width i | Min_width i | Max_height i -> Jv.of_int i + | Auto_pan b + | Keep_in_view b + | Close_button b + | Auto_close b + | Close_on_escape_key b + | Close_on_click b -> + Jv.of_bool b + | Pane s | Class_name s -> Jv.of_string s + +let create options = + let l = + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options + in + Jv.call Global.leaflet "popup" [| Jv.obj l |] diff --git a/src/popup.mli b/src/popup.mli index 9983c5c..da7f27a 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -2,6 +2,24 @@ type t +(** type for popup option used to create an popup*) +type opt = + | Pane of string + | Offset of Point.t + | Max_width of int + | Min_width of int + | Max_height of int + | Auto_pan of bool + | Auto_pan_padding_top_left of Point.t + | Auto_pan_padding_bottom_right of Point.t + | Auto_pan_padding of Point.t + | Keep_in_view of bool + | Close_button of bool + | Auto_close of bool + | Close_on_escape_key of bool + | Close_on_click of bool + | Class_name of string + (** [set_latlng latlng] changes the popup position to the given point*) val set_latlng : Latlng.t -> unit @@ -16,3 +34,12 @@ val close : Map.t -> unit (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t + +(** [opt_to_string opt] is [opt] as {!string} *) +val opt_to_string : opt -> string + +(** [opt_to_jv opt] is [opt] as {!Jv.t} *) +val opt_to_jv : opt -> Jv.t + +(** [create options] is a new popup setup withs [options] *) +val create : opt list -> t From 2affa8b5fab6d678f861a4b3aead74574c0c2180 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 11:04:44 +0200 Subject: [PATCH 23/99] fix Point_to_layer --- src/layer.ml | 6 ++++-- src/layer.mli | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index fd2042c..b18c108 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -85,7 +85,7 @@ let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = (** Geojson layers *) type geojson_opt = - | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Point_to_layer of (Jv.t -> Latlng.t -> [ `Marker ] t) | Style of (Jv.t -> unit) | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) | Filter of (Jv.t -> bool) @@ -102,7 +102,9 @@ let geojson_opt_to_string = function let geojson_opt_to_jv = function | Markers_inherit_options b -> Jv.of_bool b - | Point_to_layer f -> Jv.repr f + | Point_to_layer f -> + (* the marker returned by `pointToLayer` is used internally by leaflet so we neet to unwrap it to a Jv.t *) + Jv.repr (fun geojsonpoint latlng -> to_jv @@ f geojsonpoint latlng) | Style f -> Jv.repr f | On_each_feature f -> (* we need to wrap the Jv.t *) diff --git a/src/layer.mli b/src/layer.mli index 7eaabd2..9c7a7cd 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -52,7 +52,7 @@ val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit (** type for geojson option, used to create geojson *) type geojson_opt = - | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Point_to_layer of (Jv.t -> Latlng.t -> [ `Marker ] t) | Style of (Jv.t -> unit) | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) | Filter of (Jv.t -> bool) From 23ea827e40b5203930b80fb60f611fef10822cd4 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 26 Jun 2022 04:08:53 +0200 Subject: [PATCH 24/99] better Layer.bind_popup and add Map.open/close_popup --- src/layer.ml | 12 +++--------- src/layer.mli | 2 +- src/map.ml | 6 ++++++ src/map.mli | 6 ++++++ src/popup.ml | 10 ++-------- src/popup.mli | 9 +++------ 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index b18c108..85a9ce8 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -31,16 +31,10 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> Popup.opt list -> kind t -> unit = - fun el options -> function +let bind_popup : type kind. Popup.t -> kind t -> unit = + fun popup -> function | Basic layer | Geojson layer | Marker layer | Tile layer -> - let l = - Array.of_list - @@ List.map (fun o -> (Popup.opt_to_string o, Popup.opt_to_jv o)) options - in - let (_ : Jv.t) = - Jv.call layer "bindPopup" [| Brr.El.to_jv el; Jv.obj l |] - in + let (_ : Jv.t) = Jv.call layer "bindPopup" [| Popup.to_jv popup |] in () let unbind_popup : type kind. kind t -> unit = function diff --git a/src/layer.mli b/src/layer.mli index 9c7a7cd..e819d2e 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -24,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> Popup.opt list -> _ t -> unit +val bind_popup : Popup.t -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit diff --git a/src/map.ml b/src/map.ml index 2f2db23..235510c 100644 --- a/src/map.ml +++ b/src/map.ml @@ -46,3 +46,9 @@ let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int let wrap_latlng latlng map = Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] + +let open_popup popup map = + ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] + +let close_popup popup map = + ignore @@ Jv.call map "closePopup" [| Popup.to_jv popup |] diff --git a/src/map.mli b/src/map.mli index c1a7770..db91af9 100644 --- a/src/map.mli +++ b/src/map.mli @@ -47,3 +47,9 @@ val of_jv : Jv.t -> t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t + +(* [open_popup popup map] opens [popup] on [map] *) +val open_popup : Popup.t -> t -> unit + +(* [close_popup popup map] closes [popup] on [map] *) +val close_popup : Popup.t -> t -> unit diff --git a/src/popup.ml b/src/popup.ml index f7a1c69..b2a5072 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -12,16 +12,10 @@ let set_content content = let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in () -let open_on map = - let (_ : Jv.t) = Jv.call popup "openOn" [| Map.to_jv map |] in - () - -let close map = - let (_ : Jv.t) = Jv.call (Map.to_jv map) "closePopup" [||] in - () - let of_jv = Fun.id +let to_jv = Fun.id + type opt = | Pane of string | Offset of Point.t diff --git a/src/popup.mli b/src/popup.mli index da7f27a..6391cee 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -26,15 +26,12 @@ val set_latlng : Latlng.t -> unit (** [set_content s] changes the popup content to [s]*) val set_content : string -> unit -(** [open_on map] * Adds the popup to [map] and closes the previous one. *) -val open_on : Map.t -> unit - -(** [close map] * closes the popup of [map]*) -val close : Map.t -> unit - (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t + (** [opt_to_string opt] is [opt] as {!string} *) val opt_to_string : opt -> string From 7effdcc5773c0acf65e13434d9bb3af7b8ef61c1 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 26 Jun 2022 05:07:45 +0200 Subject: [PATCH 25/99] better popups --- src/map.ml | 8 ++++++-- src/map.mli | 4 ++-- src/popup.ml | 41 +++++++++++++++++++++++++++++++++++------ src/popup.mli | 20 ++++++++++++++------ 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/map.ml b/src/map.ml index 235510c..9dec8d6 100644 --- a/src/map.ml +++ b/src/map.ml @@ -50,5 +50,9 @@ let wrap_latlng latlng map = let open_popup popup map = ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] -let close_popup popup map = - ignore @@ Jv.call map "closePopup" [| Popup.to_jv popup |] +let close_popup ~popup map = + ignore + @@ + match popup with + | None -> Jv.call map "closePopup" [||] + | Some popup -> Jv.call map "closePopup" [| Popup.to_jv popup |] diff --git a/src/map.mli b/src/map.mli index db91af9..d1bf3e4 100644 --- a/src/map.mli +++ b/src/map.mli @@ -51,5 +51,5 @@ val to_jv : t -> Jv.t (* [open_popup popup map] opens [popup] on [map] *) val open_popup : Popup.t -> t -> unit -(* [close_popup popup map] closes [popup] on [map] *) -val close_popup : Popup.t -> t -> unit +(* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) +val close_popup : popup:Popup.t option -> t -> unit diff --git a/src/popup.ml b/src/popup.ml index b2a5072..2792e23 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -2,16 +2,18 @@ type t = Jv.t -let popup = Jv.call Global.leaflet "popup" [||] - -let set_latlng latlng = +let set_latlng latlng popup = let (_ : Jv.t) = Jv.call popup "setLatLng" [| Latlng.to_jv latlng |] in () -let set_content content = +let set_content content popup = let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in () +let set_content_to_el el popup = + let (_ : Jv.t) = Jv.call popup "setContent" [| Brr.El.to_jv el |] in + () + let of_jv = Fun.id let to_jv = Fun.id @@ -66,8 +68,35 @@ let opt_to_jv = function Jv.of_bool b | Pane s | Class_name s -> Jv.of_string s -let create options = +let create content_opt ~latlng options = let l = Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in - Jv.call Global.leaflet "popup" [| Jv.obj l |] + let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in + let popup = + match latlng with + | None -> popup + | Some latlng -> + set_latlng latlng popup; + popup + in + match content_opt with + | None -> popup + | Some content -> + set_content content popup; + popup + +let create_from_el el ~latlng options = + let l = + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options + in + let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in + let popup = + match latlng with + | None -> popup + | Some latlng -> + set_latlng latlng popup; + popup + in + set_content_to_el el popup; + popup diff --git a/src/popup.mli b/src/popup.mli index 6391cee..dae1db8 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -20,11 +20,14 @@ type opt = | Close_on_click of bool | Class_name of string -(** [set_latlng latlng] changes the popup position to the given point*) -val set_latlng : Latlng.t -> unit +(** [set_latlng latlng popup] sets [popup] position to the given point*) +val set_latlng : Latlng.t -> t -> unit -(** [set_content s] changes the popup content to [s]*) -val set_content : string -> unit +(** [set_content s popup] sets [popup] content to [s]*) +val set_content : string -> t -> unit + +(** [set_content_to_el el s] sets [popup] content to [el]*) +val set_content_to_el : Brr.El.t -> t -> unit (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t @@ -38,5 +41,10 @@ val opt_to_string : opt -> string (** [opt_to_jv opt] is [opt] as {!Jv.t} *) val opt_to_jv : opt -> Jv.t -(** [create options] is a new popup setup withs [options] *) -val create : opt list -> t +(** [create s latlng options] is a new popup setup with [options], position set + to [latlng] and content to [s] *) +val create : string option -> latlng:Latlng.t option -> opt list -> t + +(** [create_from_el el latlng options] is a new popup setup with [options], + position set to [latlng] and content to [el] *) +val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt list -> t From ce8dcba87a518fe0e9166b44b2248309343084c6 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 24 Nov 2022 19:21:57 +0100 Subject: [PATCH 26/99] add Icon.create_div --- src/icon.ml | 20 ++++++++++++++++++++ src/icon.mli | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/src/icon.ml b/src/icon.ml index c40305d..f8e1bb5 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -4,6 +4,8 @@ type t = Jv.t let to_jv = Fun.id +let of_jv = Fun.id + type opt = | Icon_retina_url of string | Icon_size of Point.t @@ -47,3 +49,21 @@ let create icon_url options = let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in Jv.call Global.leaflet "icon" [| Jv.obj l |] + +let create_div ~html ~bg_pos options = + let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in + let div_options = + let html = + match html with + | None -> [] + | Some html -> [ ("html", Jv.of_string html) ] + in + let bg_pos = + match bg_pos with + | None -> [] + | Some bg_pos -> [ ("bgPos", Point.to_jv bg_pos) ] + in + html @ bg_pos + in + let l = Array.of_list @@ div_options @ l in + Jv.call Global.leaflet "divIcon" [| Jv.obj l |] diff --git a/src/icon.mli b/src/icon.mli index 534c9d9..d7734dd 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -5,6 +5,9 @@ type t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t +(** [of_jv o] is [o] as {!Icon.t} *) +val of_jv : Jv.t -> t + (** type for icon option used to create an icon*) type opt = | Icon_retina_url of string @@ -22,3 +25,9 @@ type opt = (** [create icon_url options] Creates an icon instance with the given [options], and the required `iconUrl` option set to [icon_url] *) val create : string -> opt list -> t + +(** [create_div ~html ~bg_pos options] Creates an DivIcon instance with the + given [options], [bg_pos] is the optional relative position of the + background, in pixels [html] is custom HTML code to put inside the div + element, empty by default. *) +val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t From 0c36e1336dda8e0810694c55ccc298b7f76fed8c Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 24 Nov 2022 19:22:18 +0100 Subject: [PATCH 27/99] more marker function --- src/layer.ml | 67 ++++++++++++++++++++++++++++++++++++--------------- src/layer.mli | 28 +++++++++++++++++---- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 85a9ce8..f98de08 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -118,7 +118,30 @@ let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t +(** Tile layers *) + +let create_tile_osm : string option -> [ `Tile ] t = + fun url -> + let url = + Option.value url + ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + in + let jv_t = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + in + Tile jv_t + (** Marker layers *) +(* TODO make a Marker module? *) type marker_opt = | Icon of Icon.t @@ -168,24 +191,28 @@ let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = in Marker jv_t -(** Tile layers *) +let get_latlng : [ `Marker ] t -> Latlng.t = function + | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv -let create_tile_osm : string option -> [ `Tile ] t = - fun url -> - let url = - Option.value url - ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - in - let jv_t = - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - in - Tile jv_t +let set_latlng latlng : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in + () + +let set_z_index_offset z_index : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in + () + +let get_icon : [ `Marker ] t -> Icon.t = function + | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv + +let set_icon icon : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in + () + +let set_opacity opacity : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in + () diff --git a/src/layer.mli b/src/layer.mli index e819d2e..84586d7 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,6 +62,13 @@ type geojson_opt = (** [create_geojson geojson] is a new geojson layer *) val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t +(** Tile layers *) + +(** [create_tile_osm Some(url)] is a new tile layer with tile server specified + by [url]. Tile server default to [openstreetmap.org]. See + {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) +val create_tile_osm : string option -> [ `Tile ] t + (** Marker layers *) (** type for marker option, used to create marker *) @@ -83,9 +90,20 @@ type marker_opt = [latlng] and with options set to [options] *) val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t -(** Tile layers *) +(** Returns the current geographical position of the marker. *) +val get_latlng : [ `Marker ] t -> Latlng.t -(** [create_tile_osm Some(url)] is a new tile layer with tile server specified - by [url]. Tile server default to [openstreetmap.org]. See - {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : string option -> [ `Tile ] t +(** Changes the marker position to the given point. *) +val set_latlng : Latlng.t -> [ `Marker ] t -> unit + +(** Changes the zIndex offset of the marker. *) +val set_z_index_offset : int -> [ `Marker ] t -> unit + +(** Returns the current icon used by the marker *) +val get_icon : [ `Marker ] t -> Icon.t + +(** Changes the marker icon. *) +val set_icon : Icon.t -> [ `Marker ] t -> unit + +(** Changes the opacity of the marker. *) +val set_opacity : int -> [ `Marker ] t -> unit From fd38f85f721244851011983a5f66708e9c1ec596 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 01:58:10 +0100 Subject: [PATCH 28/99] fix doc --- src/map.mli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.mli b/src/map.mli index d1bf3e4..5d7a912 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,7 +2,7 @@ type t -(** [create id] creates a map on the
with DOM id [id]. To have a +(** [create_on id] creates a map on the
with DOM id [id]. To have a functional map you will need to add a tile layer to it. *) val create_on : ?options:Jv.t -> string -> t From 1e581ef1729a6283a90345582086b32a38389c4a Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 01:59:30 +0100 Subject: [PATCH 29/99] update ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index cec2d50..c54116a 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.22.4 +version=0.24.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From b9c6864ef194d225dc2a46906b88c36bd7435d17 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 02:45:32 +0100 Subject: [PATCH 30/99] small popup change --- src/map.mli | 2 +- src/popup.ml | 4 ++-- src/popup.mli | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/map.mli b/src/map.mli index 5d7a912..ede2965 100644 --- a/src/map.mli +++ b/src/map.mli @@ -48,7 +48,7 @@ val of_jv : Jv.t -> t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t -(* [open_popup popup map] opens [popup] on [map] *) +(* [open_popup popup map] opens [popup] on [map]; Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability). *) val open_popup : Popup.t -> t -> unit (* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) diff --git a/src/popup.ml b/src/popup.ml index 2792e23..3960a81 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -68,7 +68,7 @@ let opt_to_jv = function Jv.of_bool b | Pane s | Class_name s -> Jv.of_string s -let create content_opt ~latlng options = +let create ~content ~latlng options = let l = Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in @@ -80,7 +80,7 @@ let create content_opt ~latlng options = set_latlng latlng popup; popup in - match content_opt with + match content with | None -> popup | Some content -> set_content content popup; diff --git a/src/popup.mli b/src/popup.mli index dae1db8..d099745 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -41,9 +41,9 @@ val opt_to_string : opt -> string (** [opt_to_jv opt] is [opt] as {!Jv.t} *) val opt_to_jv : opt -> Jv.t -(** [create s latlng options] is a new popup setup with [options], position set - to [latlng] and content to [s] *) -val create : string option -> latlng:Latlng.t option -> opt list -> t +(** [create ~content ~latlng options] is a new popup setup with [options], + position set to [latlng] and content to [s] *) +val create : content:string option -> latlng:Latlng.t option -> opt list -> t (** [create_from_el el latlng options] is a new popup setup with [options], position set to [latlng] and content to [el] *) From 11188892535b8623a591794c8720ebda3ddc3c95 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 20:27:37 +0100 Subject: [PATCH 31/99] -> Latlng.create ~lat ~lng --- .ocamlformat | 2 +- example/main.ml | 2 +- src/latlng.ml | 2 +- src/latlng.mli | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index c54116a..74ae9c5 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.24.1 +version=0.26.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/example/main.ml b/example/main.ml index 43b9fcd..4a90920 100644 --- a/example/main.ml +++ b/example/main.ml @@ -8,5 +8,5 @@ let () = Leaflet.Layer.add_to map osm_layer; (* set view *) - let latlng = Leaflet.Latlng.create 40.71 (-74.0) in + let latlng = Leaflet.Latlng.create ~lat:40.71 ~lng:(-74.0) in ignore @@ Leaflet.Map.set_view latlng ~zoom:(Some 13) map diff --git a/src/latlng.ml b/src/latlng.ml index 400200b..89cd3b8 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -2,7 +2,7 @@ type t = Jv.t -let create lat lng = +let create ~lat ~lng = Jv.call Global.leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] let lat latlng = Jv.get latlng "lat" |> Jv.to_float diff --git a/src/latlng.mli b/src/latlng.mli index 120d165..3bff192 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -4,7 +4,7 @@ type t (** [create lat lng] is an object representing a geographical point with the given latitude and longitude *) -val create : float -> float -> t +val create : lat:float -> lng:float -> t (** [lat o] is the latitude of [o] *) val lat : t -> float From a8266ae6155261bd9592c9955c5076a62413af65 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:07:41 +0100 Subject: [PATCH 32/99] move marker to separate module --- src/dune | 2 +- src/layer.ml | 77 ------------------------------------------------- src/layer.mli | 39 ------------------------- src/marker.ml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/marker.mli | 38 ++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 117 deletions(-) create mode 100644 src/marker.ml create mode 100644 src/marker.mli diff --git a/src/dune b/src/dune index 52d85ee..c29d930 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup point icon) + (modules event global latlng layer map marker popup point icon) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/layer.ml b/src/layer.ml index f98de08..e6ac275 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -139,80 +139,3 @@ let create_tile_osm : string option -> [ `Tile ] t = |] in Tile jv_t - -(** Marker layers *) -(* TODO make a Marker module? *) - -type marker_opt = - | Icon of Icon.t - | Keyboard of bool - | Title of string - | Alt of string - | Z_index_offset of int - | Opacity of float - | Rise_on_hover of bool - | Rise_offset of int - | Pane of string - | Shadow_pane of string - | Bubbling_mouse_events of bool - | Auto_pan_on_focus of bool - -let marker_opt_to_string : marker_opt -> string = function - | Icon _ -> "icon" - | Keyboard _ -> "keyboard" - | Title _ -> "title" - | Alt _ -> "alt" - | Z_index_offset _ -> "zIndexOffset" - | Opacity _ -> "opacity" - | Rise_on_hover _ -> "riseOnHover" - | Rise_offset _ -> "riseOffset" - | Pane _ -> "pane" - | Shadow_pane _ -> "shadowPane" - | Bubbling_mouse_events _ -> "bubblingMouseEvents" - | Auto_pan_on_focus _ -> "autoPanOnFocus" - -let marker_opt_to_jv = function - | Icon icon -> Icon.to_jv icon - | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b - -> - Jv.of_bool b - | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s - | Z_index_offset i | Rise_offset i -> Jv.of_int i - | Opacity f -> Jv.of_float f - -let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = - fun latlng options -> - let l = - Array.of_list - @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options - in - let jv_t = - Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] - in - Marker jv_t - -let get_latlng : [ `Marker ] t -> Latlng.t = function - | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv - -let set_latlng latlng : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in - () - -let set_z_index_offset z_index : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in - () - -let get_icon : [ `Marker ] t -> Icon.t = function - | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv - -let set_icon icon : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in - () - -let set_opacity opacity : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in - () diff --git a/src/layer.mli b/src/layer.mli index 84586d7..10cedc2 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -68,42 +68,3 @@ val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t by [url]. Tile server default to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : string option -> [ `Tile ] t - -(** Marker layers *) - -(** type for marker option, used to create marker *) -type marker_opt = - | Icon of Icon.t - | Keyboard of bool - | Title of string - | Alt of string - | Z_index_offset of int - | Opacity of float - | Rise_on_hover of bool - | Rise_offset of int - | Pane of string - | Shadow_pane of string - | Bubbling_mouse_events of bool - | Auto_pan_on_focus of bool - -(** [create_marker latlng options] is a new marker with the same position as - [latlng] and with options set to [options] *) -val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t - -(** Returns the current geographical position of the marker. *) -val get_latlng : [ `Marker ] t -> Latlng.t - -(** Changes the marker position to the given point. *) -val set_latlng : Latlng.t -> [ `Marker ] t -> unit - -(** Changes the zIndex offset of the marker. *) -val set_z_index_offset : int -> [ `Marker ] t -> unit - -(** Returns the current icon used by the marker *) -val get_icon : [ `Marker ] t -> Icon.t - -(** Changes the marker icon. *) -val set_icon : Icon.t -> [ `Marker ] t -> unit - -(** Changes the opacity of the marker. *) -val set_opacity : int -> [ `Marker ] t -> unit diff --git a/src/marker.ml b/src/marker.ml new file mode 100644 index 0000000..16a99c0 --- /dev/null +++ b/src/marker.ml @@ -0,0 +1,78 @@ +(** Marker layers *) +include Layer + +type t = [ `Marker ] Layer.t + +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +let marker_opt_to_string : marker_opt -> string = function + | Icon _ -> "icon" + | Keyboard _ -> "keyboard" + | Title _ -> "title" + | Alt _ -> "alt" + | Z_index_offset _ -> "zIndexOffset" + | Opacity _ -> "opacity" + | Rise_on_hover _ -> "riseOnHover" + | Rise_offset _ -> "riseOffset" + | Pane _ -> "pane" + | Shadow_pane _ -> "shadowPane" + | Bubbling_mouse_events _ -> "bubblingMouseEvents" + | Auto_pan_on_focus _ -> "autoPanOnFocus" + +let marker_opt_to_jv = function + | Icon icon -> Icon.to_jv icon + | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b + -> + Jv.of_bool b + | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s + | Z_index_offset i | Rise_offset i -> Jv.of_int i + | Opacity f -> Jv.of_float f + +let create_marker : Latlng.t -> marker_opt list -> t = + fun latlng options -> + let l = + Array.of_list + @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + in + let jv_t = + Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] + in + Marker jv_t + +let get_latlng : t -> Latlng.t = function + | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv + +let set_latlng latlng : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in + () + +let set_z_index_offset z_index : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in + () + +let get_icon : t -> Icon.t = function + | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv + +let set_icon icon : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in + () + +let set_opacity opacity : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in + () diff --git a/src/marker.mli b/src/marker.mli new file mode 100644 index 0000000..538ac95 --- /dev/null +++ b/src/marker.mli @@ -0,0 +1,38 @@ +type t = [ `Marker ] Layer.t + +(** type for marker option, used to create marker *) +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +(** [create_marker latlng options] is a new marker with the same position as + [latlng] and with options set to [options] *) +val create_marker : Latlng.t -> marker_opt list -> t + +(** Returns the current geographical position of the marker. *) +val get_latlng : t -> Latlng.t + +(** Changes the marker position to the given point. *) +val set_latlng : Latlng.t -> t -> unit + +(** Changes the zIndex offset of the marker. *) +val set_z_index_offset : int -> t -> unit + +(** Returns the current icon used by the marker *) +val get_icon : t -> Icon.t + +(** Changes the marker icon. *) +val set_icon : Icon.t -> t -> unit + +(** Changes the opacity of the marker. *) +val set_opacity : int -> t -> unit From b2c78c1e5d633d6e0bd4b9884d45924505182f3c Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:08:10 +0100 Subject: [PATCH 33/99] add Icon.set_default_image_path --- src/icon.ml | 5 +++++ src/icon.mli | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/icon.ml b/src/icon.ml index f8e1bb5..4ed4972 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -67,3 +67,8 @@ let create_div ~html ~bg_pos options = in let l = Array.of_list @@ div_options @ l in Jv.call Global.leaflet "divIcon" [| Jv.obj l |] + +let set_default_image_path s = + let icon = Jv.get Global.leaflet "Icon" in + let icon_default = Jv.get icon "Default" in + Jv.set icon_default "imagePath" (Jv.of_string s) diff --git a/src/icon.mli b/src/icon.mli index d7734dd..451b51f 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -31,3 +31,6 @@ val create : string -> opt list -> t background, in pixels [html] is custom HTML code to put inside the div element, empty by default. *) val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t + +(** Sets the path of the default icon *) +val set_default_image_path : string -> unit From bbe481c064f866c0edf355621df418e6bb04cf39 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:49:31 +0100 Subject: [PATCH 34/99] add tile_layer_opt; untested --- example/main.ml | 2 +- src/layer.ml | 73 +++++++++++++++++++++++++++++++++++++++---------- src/layer.mli | 22 +++++++++++++-- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/example/main.ml b/example/main.ml index 4a90920..abfe34a 100644 --- a/example/main.ml +++ b/example/main.ml @@ -4,7 +4,7 @@ let map = Leaflet.Map.create_on "map" (* setup map *) let () = (* set osm layer *) - let osm_layer = Leaflet.Layer.create_tile_osm None in + let osm_layer = Leaflet.Layer.create_tile_osm [] in Leaflet.Layer.add_to map osm_layer; (* set view *) diff --git a/src/layer.ml b/src/layer.ml index e6ac275..fa9dc0d 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -120,22 +120,65 @@ let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = (** Tile layers *) -let create_tile_osm : string option -> [ `Tile ] t = - fun url -> - let url = - Option.value url - ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" +type tile_layer_opt = + | Min_zoom of int + | Max_zoom of int + | Subdomains of string array + | Error_tile_url of string + | Zoom_offset of int + | Tms of bool + | Zoom_reverse of bool + | Detect_retina of bool + (* TODO allow string for those two + "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." + *) + | Cross_origin of bool + | Referrer_policy of bool + +let tile_layer_opt_to_string = function + | Min_zoom _ -> "minZoom" + | Max_zoom _ -> "maxZoom" + | Subdomains _ -> "subdomains" + | Error_tile_url _ -> "errorTileUrl" + | Zoom_offset _ -> "zoomOffset" + | Tms _ -> "tms" + | Zoom_reverse _ -> "zoomReverse" + | Detect_retina _ -> "detectRetina" + | Cross_origin _ -> "crossOrigin" + | Referrer_policy _ -> "referrerPolicy" + +let tile_layer_opt_to_jv = function + | Min_zoom o | Max_zoom o | Zoom_offset o -> Jv.of_int o + | Tms o + | Zoom_reverse o + | Detect_retina o + | Cross_origin o + | Referrer_policy o -> + Jv.of_bool o + | Error_tile_url o -> Jv.of_string o + | Subdomains o -> Jv.of_array Jv.of_string o + +let create_tile : + string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = + fun url ~attribution options -> + let arr = + Array.of_list + @@ ("attribution", Jv.of_string attribution) + :: List.map + (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) + options in let jv_t = - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] + Jv.call Global.leaflet "tileLayer" [| Jv.of_string url; Jv.obj arr |] in Tile jv_t + +let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = + fun options -> + let url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" in + let attribution = + "© OpenStreetMap \ + contributors" + in + create_tile url ~attribution options diff --git a/src/layer.mli b/src/layer.mli index 10cedc2..bd5513d 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -64,7 +64,23 @@ val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t (** Tile layers *) -(** [create_tile_osm Some(url)] is a new tile layer with tile server specified - by [url]. Tile server default to [openstreetmap.org]. See +type tile_layer_opt = + | Min_zoom of int + | Max_zoom of int + | Subdomains of string array + | Error_tile_url of string + | Zoom_offset of int + | Tms of bool + | Zoom_reverse of bool + | Detect_retina of bool + | Cross_origin of bool + | Referrer_policy of bool + +(** [create_tile url attribution opts] create a new tile layer *) +val create_tile : + string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t + +(** [create_tile_osm opts] create a new tile layer with tile server and + attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : string option -> [ `Tile ] t +val create_tile_osm : tile_layer_opt list -> [ `Tile ] t From 71cdf5f97c4c26a1233b970e030619d877a85479 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 23:05:24 +0100 Subject: [PATCH 35/99] cleanup Marker --- src/marker.ml | 11 +++++------ src/marker.mli | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/marker.ml b/src/marker.ml index 16a99c0..93ebd05 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -3,7 +3,7 @@ include Layer type t = [ `Marker ] Layer.t -type marker_opt = +type opt = | Icon of Icon.t | Keyboard of bool | Title of string @@ -17,7 +17,7 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -let marker_opt_to_string : marker_opt -> string = function +let opt_to_string : opt -> string = function | Icon _ -> "icon" | Keyboard _ -> "keyboard" | Title _ -> "title" @@ -31,7 +31,7 @@ let marker_opt_to_string : marker_opt -> string = function | Bubbling_mouse_events _ -> "bubblingMouseEvents" | Auto_pan_on_focus _ -> "autoPanOnFocus" -let marker_opt_to_jv = function +let opt_to_jv = function | Icon icon -> Icon.to_jv icon | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b -> @@ -40,11 +40,10 @@ let marker_opt_to_jv = function | Z_index_offset i | Rise_offset i -> Jv.of_int i | Opacity f -> Jv.of_float f -let create_marker : Latlng.t -> marker_opt list -> t = +let create : Latlng.t -> opt list -> t = fun latlng options -> let l = - Array.of_list - @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] diff --git a/src/marker.mli b/src/marker.mli index 538ac95..ebb8096 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -1,7 +1,7 @@ type t = [ `Marker ] Layer.t (** type for marker option, used to create marker *) -type marker_opt = +type opt = | Icon of Icon.t | Keyboard of bool | Title of string @@ -15,9 +15,9 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -(** [create_marker latlng options] is a new marker with the same position as - [latlng] and with options set to [options] *) -val create_marker : Latlng.t -> marker_opt list -> t +(** [create latlng options] is a new marker with the same position as [latlng] + and with options set to [options] *) +val create : Latlng.t -> opt list -> t (** Returns the current geographical position of the marker. *) val get_latlng : t -> Latlng.t From 076e3dd2799d046c2163429276fc72ff674a4520 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 00:20:36 +0100 Subject: [PATCH 36/99] add more options to tile_layer --- src/layer.ml | 57 ++++++++++++++++++++++++++++++++++++++++++++------- src/layer.mli | 13 ++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index fa9dc0d..ec9bb68 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -129,11 +129,25 @@ type tile_layer_opt = | Tms of bool | Zoom_reverse of bool | Detect_retina of bool - (* TODO allow string for those two - "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." - *) - | Cross_origin of bool + | (* TODO allow string for those two + "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." + *) + Cross_origin of bool | Referrer_policy of bool + | (* GridLayer options *) + Tile_size of Point.t + | Opacity of float + | Update_when_idle of bool + | Update_when_zooming of bool + | Update_interval of int + | Z_index of int + | Bounds of (* LatLngBounds *) Latlng.t * Latlng.t + | Max_native_zoom of int + | Min_native_zoom of int + | No_wrap of bool + | Pane of string + | Class_name of string + | Keep_buffer of int let tile_layer_opt_to_string = function | Min_zoom _ -> "minZoom" @@ -146,17 +160,46 @@ let tile_layer_opt_to_string = function | Detect_retina _ -> "detectRetina" | Cross_origin _ -> "crossOrigin" | Referrer_policy _ -> "referrerPolicy" + | Tile_size _ -> "tileSize" + | Opacity _ -> "opacity" + | Update_when_idle _ -> "updateWhenIdle" + | Update_when_zooming _ -> "updateWhenZooming" + | Update_interval _ -> "updateInterval" + | Z_index _ -> "zIndex" + | Bounds _ -> "bounds" + | Max_native_zoom _ -> "maxNativeZoom" + | Min_native_zoom _ -> "minNativeZoom" + | No_wrap _ -> "noWrap" + | Pane _ -> "pane" + | Class_name _ -> "className" + | Keep_buffer _ -> "keepBuffer" let tile_layer_opt_to_jv = function - | Min_zoom o | Max_zoom o | Zoom_offset o -> Jv.of_int o + | Min_zoom o + | Max_zoom o + | Zoom_offset o + | Update_interval o + | Z_index o + | Keep_buffer o + | Min_native_zoom o + | Max_native_zoom o -> + Jv.of_int o | Tms o | Zoom_reverse o | Detect_retina o | Cross_origin o - | Referrer_policy o -> + | Referrer_policy o + | Update_when_idle o + | Update_when_zooming o + | No_wrap o -> Jv.of_bool o - | Error_tile_url o -> Jv.of_string o + | Error_tile_url o | Pane o | Class_name o -> Jv.of_string o | Subdomains o -> Jv.of_array Jv.of_string o + | Opacity o -> Jv.of_float o + | Tile_size o -> Point.to_jv o + | Bounds (a, b) -> + (* create the actual LatlngBounds from the pair *) + Jv.call Global.leaflet "latLngBounds" [| Latlng.to_jv a; Latlng.to_jv b |] let create_tile : string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = diff --git a/src/layer.mli b/src/layer.mli index bd5513d..5c28258 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -75,6 +75,19 @@ type tile_layer_opt = | Detect_retina of bool | Cross_origin of bool | Referrer_policy of bool + | Tile_size of Point.t + | Opacity of float + | Update_when_idle of bool + | Update_when_zooming of bool + | Update_interval of int + | Z_index of int + | Bounds of (* LatLngBounds *) Latlng.t * Latlng.t + | Max_native_zoom of int + | Min_native_zoom of int + | No_wrap of bool + | Pane of string + | Class_name of string + | Keep_buffer of int (** [create_tile url attribution opts] create a new tile layer *) val create_tile : From 3d19bc3f4087782be2e6177baa19bf2b8209e0ff Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 00:48:37 +0100 Subject: [PATCH 37/99] add polyline layer --- src/layer.ml | 29 ++++++++++++++++++++--------- src/layer.mli | 5 +++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index ec9bb68..12c35c3 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -5,59 +5,61 @@ type _ t = | Geojson : Jv.t -> [> `Geojson ] t | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t + | Vector : Jv.t -> [> `Vector ] t type _ sub = | Basic : [> `Basic ] sub | Geojson : [> `Geojson ] sub | Marker : [> `Marker ] sub | Tile : [> `Tile ] sub + | Vector : [> `Vector ] sub (** Basic layers *) let add_to : type kind. Map.t -> kind t -> unit = fun map -> function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "addTo" [| Map.to_jv map |] in () let remove : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "remove" [||] in () let remove_from : type kind. Map.t -> kind t -> unit = fun map -> function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () let bind_popup : type kind. Popup.t -> kind t -> unit = fun popup -> function - | Basic layer | Geojson layer | Marker layer | Tile layer -> + | Basic layer | Geojson layer | Marker layer | Tile layer | Vector layer -> let (_ : Jv.t) = Jv.call layer "bindPopup" [| Popup.to_jv popup |] in () let unbind_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "unbindPopup" [||] in () let open_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "openPopup" [||] in () let close_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "closePopup" [||] in () let get_popup : type kind. kind t -> Popup.t = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> Jv.call l "getPopup" [||] |> Popup.of_jv let to_jv : type kind. kind t -> Jv.t = function - | Basic l | Geojson l | Marker l | Tile l -> l + | Basic l | Geojson l | Marker l | Tile l | Vector l -> l let of_jv : type kind. kind sub -> Jv.t -> kind t = fun tag l -> @@ -66,6 +68,7 @@ let of_jv : type kind. kind sub -> Jv.t -> kind t = | Geojson -> Geojson l | Marker -> Marker l | Tile -> Tile l + | Vector -> Vector l let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = fun event handler layer -> @@ -225,3 +228,11 @@ let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = contributors" in create_tile url ~attribution options + +(* Vector Layers *) + +let create_polyline : Latlng.t list -> [ `Vector ] t = + fun l -> + let l = Jv.of_list Latlng.to_jv l in + let jv_t = Jv.call Global.leaflet "polyline" [| l |] in + Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 5c28258..1f34363 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -5,12 +5,14 @@ type _ t = | Geojson : Jv.t -> [> `Geojson ] t | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t + | Vector : Jv.t -> [> `Vector ] t type _ sub = | Basic : [> `Basic ] sub | Geojson : [> `Geojson ] sub | Marker : [> `Marker ] sub | Tile : [> `Tile ] sub + | Vector : [> `Vector ] sub (** Basic layers *) @@ -97,3 +99,6 @@ val create_tile : attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : tile_layer_opt list -> [ `Tile ] t + +(** [create_polyline l] create a polyline layer from [l] *) +val create_polyline : Latlng.t list -> [ `Vector ] t From 16e5fe0b2e8a0b573658f6090ef7d1ade29d4f04 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 16:55:19 +0100 Subject: [PATCH 38/99] list -> array --- example/main.ml | 2 +- src/icon.ml | 10 +++++----- src/icon.mli | 4 ++-- src/layer.ml | 25 +++++++++++-------------- src/layer.mli | 8 ++++---- src/marker.ml | 6 ++---- src/marker.mli | 2 +- src/popup.ml | 8 ++------ src/popup.mli | 4 ++-- 9 files changed, 30 insertions(+), 39 deletions(-) diff --git a/example/main.ml b/example/main.ml index abfe34a..5fbe7c4 100644 --- a/example/main.ml +++ b/example/main.ml @@ -4,7 +4,7 @@ let map = Leaflet.Map.create_on "map" (* setup map *) let () = (* set osm layer *) - let osm_layer = Leaflet.Layer.create_tile_osm [] in + let osm_layer = Leaflet.Layer.create_tile_osm [||] in Leaflet.Layer.add_to map osm_layer; (* set view *) diff --git a/src/icon.ml b/src/icon.ml index 4ed4972..d59a69f 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -46,12 +46,12 @@ let opt_to_jv = function match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) let create icon_url options = - let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in - let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + let l = Array.map (fun o -> (to_string o, opt_to_jv o)) options in + let l = Array.append [| ("iconUrl", Jv.of_string icon_url) |] l in Jv.call Global.leaflet "icon" [| Jv.obj l |] let create_div ~html ~bg_pos options = - let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in + let l = Array.map (fun o -> (to_string o, opt_to_jv o)) options in let div_options = let html = match html with @@ -63,9 +63,9 @@ let create_div ~html ~bg_pos options = | None -> [] | Some bg_pos -> [ ("bgPos", Point.to_jv bg_pos) ] in - html @ bg_pos + html @ bg_pos |> Array.of_list in - let l = Array.of_list @@ div_options @ l in + let l = Array.append div_options l in Jv.call Global.leaflet "divIcon" [| Jv.obj l |] let set_default_image_path s = diff --git a/src/icon.mli b/src/icon.mli index 451b51f..f490910 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -24,13 +24,13 @@ type opt = (** [create icon_url options] Creates an icon instance with the given [options], and the required `iconUrl` option set to [icon_url] *) -val create : string -> opt list -> t +val create : string -> opt array -> t (** [create_div ~html ~bg_pos options] Creates an DivIcon instance with the given [options], [bg_pos] is the optional relative position of the background, in pixels [html] is custom HTML code to put inside the div element, empty by default. *) -val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t +val create_div : html:string option -> bg_pos:Point.t option -> opt array -> t (** Sets the path of the default icon *) val set_default_image_path : string -> unit diff --git a/src/layer.ml b/src/layer.ml index 12c35c3..e001331 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -110,13 +110,10 @@ let geojson_opt_to_jv = function | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f -let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = +let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t = fun geojson options -> let l = - Array.of_list - @@ List.map - (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) - options + Array.map (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t @@ -205,21 +202,21 @@ let tile_layer_opt_to_jv = function Jv.call Global.leaflet "latLngBounds" [| Latlng.to_jv a; Latlng.to_jv b |] let create_tile : - string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = + string -> attribution:string -> tile_layer_opt array -> [ `Tile ] t = fun url ~attribution options -> let arr = - Array.of_list - @@ ("attribution", Jv.of_string attribution) - :: List.map - (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) - options + Array.append + [| ("attribution", Jv.of_string attribution) |] + (Array.map + (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) + options ) in let jv_t = Jv.call Global.leaflet "tileLayer" [| Jv.of_string url; Jv.obj arr |] in Tile jv_t -let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = +let create_tile_osm : tile_layer_opt array -> [ `Tile ] t = fun options -> let url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" in let attribution = @@ -231,8 +228,8 @@ let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = (* Vector Layers *) -let create_polyline : Latlng.t list -> [ `Vector ] t = +let create_polyline : Latlng.t array -> [ `Vector ] t = fun l -> - let l = Jv.of_list Latlng.to_jv l in + let l = Jv.of_array Latlng.to_jv l in let jv_t = Jv.call Global.leaflet "polyline" [| l |] in Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 1f34363..170ceb9 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,7 +62,7 @@ type geojson_opt = | Markers_inherit_options of bool (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t +val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t (** Tile layers *) @@ -93,12 +93,12 @@ type tile_layer_opt = (** [create_tile url attribution opts] create a new tile layer *) val create_tile : - string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t + string -> attribution:string -> tile_layer_opt array -> [ `Tile ] t (** [create_tile_osm opts] create a new tile layer with tile server and attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : tile_layer_opt list -> [ `Tile ] t +val create_tile_osm : tile_layer_opt array -> [ `Tile ] t (** [create_polyline l] create a polyline layer from [l] *) -val create_polyline : Latlng.t list -> [ `Vector ] t +val create_polyline : Latlng.t array -> [ `Vector ] t diff --git a/src/marker.ml b/src/marker.ml index 93ebd05..7bf5f14 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -40,11 +40,9 @@ let opt_to_jv = function | Z_index_offset i | Rise_offset i -> Jv.of_int i | Opacity f -> Jv.of_float f -let create : Latlng.t -> opt list -> t = +let create : Latlng.t -> opt array -> t = fun latlng options -> - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] in diff --git a/src/marker.mli b/src/marker.mli index ebb8096..a8c1237 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -17,7 +17,7 @@ type opt = (** [create latlng options] is a new marker with the same position as [latlng] and with options set to [options] *) -val create : Latlng.t -> opt list -> t +val create : Latlng.t -> opt array -> t (** Returns the current geographical position of the marker. *) val get_latlng : t -> Latlng.t diff --git a/src/popup.ml b/src/popup.ml index 3960a81..d3c077a 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -69,9 +69,7 @@ let opt_to_jv = function | Pane s | Class_name s -> Jv.of_string s let create ~content ~latlng options = - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in let popup = match latlng with @@ -87,9 +85,7 @@ let create ~content ~latlng options = popup let create_from_el el ~latlng options = - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in let popup = match latlng with diff --git a/src/popup.mli b/src/popup.mli index d099745..f8dfc84 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -43,8 +43,8 @@ val opt_to_jv : opt -> Jv.t (** [create ~content ~latlng options] is a new popup setup with [options], position set to [latlng] and content to [s] *) -val create : content:string option -> latlng:Latlng.t option -> opt list -> t +val create : content:string option -> latlng:Latlng.t option -> opt array -> t (** [create_from_el el latlng options] is a new popup setup with [options], position set to [latlng] and content to [el] *) -val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt list -> t +val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt array -> t From a44f13085d9cb318283bf5180de85b6fdb85bb0e Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 18:45:24 +0100 Subject: [PATCH 39/99] add cirecle marker --- src/layer.ml | 9 +++++++++ src/layer.mli | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/layer.ml b/src/layer.ml index e001331..8475a90 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -228,8 +228,17 @@ let create_tile_osm : tile_layer_opt array -> [ `Tile ] t = (* Vector Layers *) +(* TODO add options *) + let create_polyline : Latlng.t array -> [ `Vector ] t = fun l -> let l = Jv.of_array Latlng.to_jv l in let jv_t = Jv.call Global.leaflet "polyline" [| l |] in Vector jv_t + +let create_circle_marker : Latlng.t -> float -> [ `Vector ] t = + fun center radius -> + let center = Latlng.to_jv center in + let arr = [| ("radius", Jv.of_float radius) |] in + let jv_t = Jv.call Global.leaflet "circleMarker" [| center; Jv.obj arr |] in + Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 170ceb9..b2da3ae 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -102,3 +102,7 @@ val create_tile_osm : tile_layer_opt array -> [ `Tile ] t (** [create_polyline l] create a polyline layer from [l] *) val create_polyline : Latlng.t array -> [ `Vector ] t + +(** [create_circle_marker c r] create a cirecle marker layer with center [c] and + radius [r] *) +val create_circle_marker : Latlng.t -> float -> [ `Vector ] t From f0a168c8e9f51e88a8230a2977717ed37c89269e Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 3 Jul 2024 11:19:26 +0200 Subject: [PATCH 40/99] close_popup: rm label --- src/map.ml | 2 +- src/map.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.ml b/src/map.ml index 9dec8d6..3c3ae0e 100644 --- a/src/map.ml +++ b/src/map.ml @@ -50,7 +50,7 @@ let wrap_latlng latlng map = let open_popup popup map = ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] -let close_popup ~popup map = +let close_popup popup map = ignore @@ match popup with diff --git a/src/map.mli b/src/map.mli index ede2965..b50e841 100644 --- a/src/map.mli +++ b/src/map.mli @@ -52,4 +52,4 @@ val to_jv : t -> Jv.t val open_popup : Popup.t -> t -> unit (* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) -val close_popup : popup:Popup.t option -> t -> unit +val close_popup : Popup.t option -> t -> unit From 7fd1ca44e4caf635afb44f28c9be7975773b17aa Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 3 Jul 2024 11:19:48 +0200 Subject: [PATCH 41/99] ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index 74ae9c5..f948087 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.26.1 +version=0.26.2 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From ce61a7a77a8c0cacbd196434667cab0451362ed6 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 18 Jul 2024 10:36:27 +0200 Subject: [PATCH 42/99] create_geojson need a json object --- src/layer.ml | 2 +- src/layer.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 8475a90..69b0f7d 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -110,7 +110,7 @@ let geojson_opt_to_jv = function | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f -let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t = +let create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t = fun geojson options -> let l = Array.map (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) options diff --git a/src/layer.mli b/src/layer.mli index b2da3ae..e01be64 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,7 +62,7 @@ type geojson_opt = | Markers_inherit_options of bool (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t +val create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t (** Tile layers *) From 8ade976f6c60993ca3173ec28e7910b78f46c848 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 8 Feb 2024 15:37:38 +0100 Subject: [PATCH 43/99] update leaflet.js --- src/leaflet.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/leaflet.js b/src/leaflet.js index 21f499c..a3bf693 100644 --- a/src/leaflet.js +++ b/src/leaflet.js @@ -1,6 +1,6 @@ /* @preserve - * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com - * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ -!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";function h(t){for(var i,e,n=1,o=arguments.length;n=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt={ie:tt,ielt9:it,edge:et,webkit:nt,android:ot,android23:st,androidStock:at,opera:ht,chrome:ut,gecko:lt,safari:ct,phantom:_t,opera12:dt,win:pt,ie3d:mt,webkit3d:ft,gecko3d:gt,any3d:vt,mobile:yt,mobileWebkit:xt,mobileWebkit3d:wt,msPointer:Pt,pointer:Lt,touch:bt,mobileOpera:Tt,mobileGecko:Mt,retina:zt,passiveEvents:Ct,canvas:St,svg:Zt,vml:Et},At=Pt?"MSPointerDown":"pointerdown",It=Pt?"MSPointerMove":"pointermove",Ot=Pt?"MSPointerUp":"pointerup",Rt=Pt?"MSPointerCancel":"pointercancel",Nt={},Dt=!1;function jt(t,i,e,n){function o(t){Ut(t,r)}var s,r,a,h,u,l,c,_;function d(t){t.pointerType===(t.MSPOINTER_TYPE_MOUSE||"mouse")&&0===t.buttons||Ut(t,h)}return"touchstart"===i?(u=t,l=e,c=n,_=p(function(t){t.MSPOINTER_TYPE_TOUCH&&t.pointerType===t.MSPOINTER_TYPE_TOUCH&&Ri(t),Ut(t,l)}),u["_leaflet_touchstart"+c]=_,u.addEventListener(At,_,!1),Dt||(document.addEventListener(At,Wt,!0),document.addEventListener(It,Ht,!0),document.addEventListener(Ot,Ft,!0),document.addEventListener(Rt,Ft,!0),Dt=!0)):"touchmove"===i?(h=e,(a=t)["_leaflet_touchmove"+n]=d,a.addEventListener(It,d,!1)):"touchend"===i&&(r=e,(s=t)["_leaflet_touchend"+n]=o,s.addEventListener(Ot,o,!1),s.addEventListener(Rt,o,!1)),this}function Wt(t){Nt[t.pointerId]=t}function Ht(t){Nt[t.pointerId]&&(Nt[t.pointerId]=t)}function Ft(t){delete Nt[t.pointerId]}function Ut(t,i){for(var e in t.touches=[],Nt)t.touches.push(Nt[e]);t.changedTouches=[t],i(t)}var Vt=Pt?"MSPointerDown":Lt?"pointerdown":"touchstart",qt=Pt?"MSPointerUp":Lt?"pointerup":"touchend",Gt="_leaflet_";var Kt,Yt,Xt,Jt,$t,Qt,ti=fi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ii=fi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ei="webkitTransition"===ii||"OTransition"===ii?ii+"End":"transitionend";function ni(t){return"string"==typeof t?document.getElementById(t):t}function oi(t,i){var e,n=t.style[i]||t.currentStyle&&t.currentStyle[i];return n&&"auto"!==n||!document.defaultView||(n=(e=document.defaultView.getComputedStyle(t,null))?e[i]:null),"auto"===n?null:n}function si(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ri(t){var i=t.parentNode;i&&i.removeChild(t)}function ai(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function hi(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function ui(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function li(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=pi(t);return 0this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,N(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e,n,o=A((i=i||{}).paddingTopLeft||i.padding||[0,0]),s=A(i.paddingBottomRight||i.padding||[0,0]),r=this.getCenter(),a=this.project(r),h=this.project(t),u=this.getPixelBounds(),l=u.getSize().divideBy(2),c=O([u.min.add(o),u.max.subtract(s)]);return c.contains(h)||(this._enforcingBounds=!0,e=a.subtract(h),n=A(h.x+e.x,h.y+e.y),(h.xc.max.x)&&(n.x=a.x-e.x,0c.max.y)&&(n.y=a.y-e.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[m(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Vi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Vi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){var i;this._loaded&&!Ui(t)&&("mousedown"!==(i=t.type)&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Pi(t.target||t.srcElement),this._fireDOMEvent(t,i))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){var n;if("click"===t.type&&((n=h({},t)).type="preclick",this._fireDOMEvent(n,n.type,e)),!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Ri(t);var s,r={originalEvent:t};"keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(s=o.getLatLng&&(!o._radius||o._radius<=10),r.containerPoint=s?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s?o.getLatLng():this.layerPointToLatLng(r.layerPoint));for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,ci(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(p(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&_i(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Yi(t){return new Xi(t)}var Xi=S.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return ci(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ri(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+m(this),n),this._layerControlInputs.push(i),i.layerId=m(t.layer),zi(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),$i=Xi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=si("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=si("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Oi(s),zi(s,"click",Ni),zi(s,"click",o,this),zi(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";_i(this._zoomInButton,i),_i(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||ci(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||ci(this._zoomInButton,i)}});Ki.mergeOptions({zoomControl:!0}),Ki.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new $i,this.addControl(this.zoomControl))});var Qi=Xi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=si("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=si("div",i,e)),t.imperial&&(this._iScale=si("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=si("div","leaflet-control-attribution"),Oi(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ki.mergeOptions({attributionControl:!0}),Ki.addInitHook(function(){this.options.attributionControl&&(new te).addTo(this)});Xi.Layers=Ji,Xi.Zoom=$i,Xi.Scale=Qi,Xi.Attribution=te,Yi.layers=function(t,i,e){return new Ji(t,i,e)},Yi.zoom=function(t){return new $i(t)},Yi.scale=function(t){return new Qi(t)},Yi.attribution=function(t){return new te(t)};var ie=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});ie.addTo=function(t,i){return t.addHandler(i,this),this};var ee,ne={Events:Z},oe=bt?"touchstart mousedown":"mousedown",se={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},re={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ae=E.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){c(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(zi(this._dragStartTarget,oe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ae._dragging===this&&this.finishDrag(),Si(this._dragStartTarget,oe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var i,e;!t._simulated&&this._enabled&&(this._moved=!1,li(this._element,"leaflet-zoom-anim")||ae._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ae._dragging=this)._preventOutline&&Pi(this._element),xi(),Xt(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=bi(this._element),this._startPoint=new k(i.clientX,i.clientY),this._parentScale=Ti(e),zi(document,re[t.type],this._onMove,this),zi(document,se[t.type],this._onUp,this))))},_onMove:function(t){var i,e;!t._simulated&&this._enabled&&(t.touches&&1i&&(e.push(t[n]),o=n);oi.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function de(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||Oe.prototype._containsPoint.call(this,t,!0)}});var Ne=Ce.extend({initialize:function(t,i){c(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=g(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c]))},_onCloseButtonClick:function(t){this._close(),Ni(t)},_getAnchor:function(){return A(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ki.mergeOptions({closePopupOnClick:!0}),Ki.include({openPopup:function(t,i,e){return t instanceof tn||(t=new tn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Me.include({bindPopup:function(t,i){return t instanceof tn?(c(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new tn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Ni(t),i instanceof Be?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var en=Qe.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Qe.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Qe.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Qe.prototype.getEvents.call(this);return bt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=si("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i,e=this._map,n=this._container,o=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=n.offsetWidth,h=n.offsetHeight,u=A(this.options.offset),l=this._getAnchor(),c="top"===r?(i=a/2,h):"bottom"===r?(i=a/2,0):(i="center"===r?a/2:"right"===r?0:"left"===r?a:s.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return N(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new R(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new k(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ri(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){ci(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=a,t.onmousemove=a,it&&this.options.opacity<1&&mi(t,this.options.opacity),ot&&!st&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),p(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(p(this._tileReady,this,t,null,o)),vi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(mi(e.el,0),z(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(ci(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),it||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(p(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new k(this._wrapX?o(t.x,this._wrapX):t.x,this._wrapY?o(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new I(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var sn=on.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=c(this,i)).detectRetina&&zt&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_n={_initContainer:function(){this._container=si("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(hn.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=cn("shape");ci(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=cn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ri(i),t.removeInteractiveTarget(i),delete this._layers[m(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i=i||(t._stroke=cn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=g(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e=e||(t._fill=cn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){hi(t._container)},_bringToBack:function(t){ui(t._container)}},dn=Et?cn:J,pn=hn.extend({getEvents:function(){var t=hn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ri(this._container),Si(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){var t,i,e;this._map._animatingZoom&&this._bounds||(hn.prototype._update.call(this),i=(t=this._bounds).getSize(),e=this._container,this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),vi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update"))},_initPath:function(t){var i=t._path=dn("path");t.options.className&&ci(i,t.options.className),t.options.interactive&&ci(i,"leaflet-interactive"),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ri(t._path),t.removeInteractiveTarget(t._path),delete this._layers[m(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,$(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){hi(t._path)},_bringToBack:function(t){ui(t._path)}});function mn(t){return Zt||Et?new pn(t):null}Et&&pn.include(_n),Ki.include({getRenderer:function(t){var i=(i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&ln(t)||mn(t)}});var fn=Re.extend({initialize:function(t,i){Re.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=N(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});pn.create=dn,pn.pointsToPath=$,Ne.geometryToLayer=De,Ne.coordsToLatLng=We,Ne.coordsToLatLngs=He,Ne.latLngToCoords=Fe,Ne.latLngsToCoords=Ue,Ne.getFeature=Ve,Ne.asFeature=qe,Ki.mergeOptions({boxZoom:!0});var gn=ie.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){zi(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Si(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ri(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Xt(),xi(),this._startPoint=this._map.mouseEventToContainerPoint(t),zi(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=si("div","leaflet-zoom-box",this._container),ci(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new I(this._point,this._startPoint),e=i.getSize();vi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ri(this._box),_i(this._container,"leaflet-crosshair")),Jt(),wi(),Si(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){var i;1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(p(this._resetState,this),0),i=new R(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})))},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ki.addInitHook("addHandler","boxZoom",gn),Ki.mergeOptions({doubleClickZoom:!0});var vn=ie.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ki.addInitHook("addHandler","doubleClickZoom",vn),Ki.mergeOptions({dragging:!0,inertia:!st,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var yn=ie.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new ae(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),ci(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){_i(this._map._container,"leaflet-grab"),_i(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,i=this._map;i._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=N(this._map.options.maxBounds),this._offsetLimit=O(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,i.fire("movestart").fire("dragstart"),i.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var i,e;this._map.options.inertia&&(i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(e),this._times.push(i),this._prunePositions(i)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1 Date: Thu, 8 Feb 2024 15:58:52 +0100 Subject: [PATCH 44/99] use dune-site --- dune-project | 9 ++- example/css_path.ml | 14 ++++ example/dune | 13 +++- example/map.html | 7 +- example/{main.ml => script.ml} | 4 + leaflet.opam | 1 + src/dune | 20 ++++- src/vendor/images/layers-2x.png | Bin 0 -> 1259 bytes src/vendor/images/layers.png | Bin 0 -> 696 bytes src/vendor/images/marker-icon-2x.png | Bin 0 -> 2464 bytes src/vendor/images/marker-icon.png | Bin 0 -> 1466 bytes src/vendor/images/marker-shadow.png | Bin 0 -> 618 bytes {example => src/vendor}/leaflet.css | 111 ++++++++++++++++----------- src/{ => vendor}/leaflet.js | 0 14 files changed, 126 insertions(+), 53 deletions(-) create mode 100644 example/css_path.ml rename example/{main.ml => script.ml} (72%) create mode 100644 src/vendor/images/layers-2x.png create mode 100644 src/vendor/images/layers.png create mode 100644 src/vendor/images/marker-icon-2x.png create mode 100644 src/vendor/images/marker-icon.png create mode 100644 src/vendor/images/marker-shadow.png rename {example => src/vendor}/leaflet.css (83%) rename src/{ => vendor}/leaflet.js (100%) diff --git a/dune-project b/dune-project index 896dd1a..41f5cea 100644 --- a/dune-project +++ b/dune-project @@ -1,6 +1,7 @@ (lang dune 2.9) - -(implicit_transitive_deps false) +(using dune_site 0.1) +;uncomment when fixed: https://github.com/ocaml/dune/issues/9661 +;(implicit_transitive_deps false) (name leaflet) @@ -31,5 +32,7 @@ (depends brr js_of_ocaml + dune-site (ocaml - (>= 4.08)))) + (>= 4.08))) + (sites (share css) (share images))) diff --git a/example/css_path.ml b/example/css_path.ml new file mode 100644 index 0000000..96a5634 --- /dev/null +++ b/example/css_path.ml @@ -0,0 +1,14 @@ +(* get leaflet.css path from dune-site *) + +let dune_site = List.filter Sys.file_exists Mysites.Sites.css + +let lookup_file filename = + List.find_map + (fun dir -> + let filename' = Filename.concat dir filename in + if Sys.file_exists filename' then Some filename' else None ) + dune_site + +let leaflet_css = lookup_file "leaflet.css" |> Option.get + +let () = Format.printf "%s@." leaflet_css diff --git a/example/dune b/example/dune index b868e46..1e537ac 100644 --- a/example/dune +++ b/example/dune @@ -1,5 +1,14 @@ (executable - (name main) - (modules main) + (name css_path) + (modules css_path mysites) + (libraries dune-site)) + +(generate_sites_module + (module mysites) + (sites leaflet)) + +(executable + (name script) + (modules script) (libraries brr leaflet) (modes js)) diff --git a/example/map.html b/example/map.html index 341173f..053dd17 100644 --- a/example/map.html +++ b/example/map.html @@ -1,12 +1,15 @@ + - +
-
+ +
diff --git a/example/main.ml b/example/script.ml similarity index 72% rename from example/main.ml rename to example/script.ml index 5fbe7c4..4dfe92f 100644 --- a/example/main.ml +++ b/example/script.ml @@ -1,3 +1,7 @@ +(* this file will be compiled to js + you can then open map.html to see a simple page with a map loaded + by this script *) + (* create map *) let map = Leaflet.Map.create_on "map" diff --git a/leaflet.opam b/leaflet.opam index 1b6ae70..d4db64e 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -18,6 +18,7 @@ depends: [ "dune" {>= "2.9"} "brr" "js_of_ocaml" + "dune-site" "ocaml" {>= "4.08"} "odoc" {with-doc} ] diff --git a/src/dune b/src/dune index c29d930..e34b390 100644 --- a/src/dune +++ b/src/dune @@ -4,4 +4,22 @@ (private_modules global) (libraries brr) (js_of_ocaml - (javascript_files leaflet.js))) + (javascript_files vendor/leaflet.js))) + +(install + (section + (site + (leaflet css))) + (files + (vendor/leaflet.css as leaflet.css))) + +(install + (section + (site + (leaflet images))) + (files + (vendor/images/layers-2x.png as images/layers-2x.png) + (vendor/images/layers.png as images/layers.png) + (vendor/images/marker-icon-2x.png as images/marker-icon-2x.png) + (vendor/images/marker-icon.png as images/marker-icon.png) + (vendor/images/marker-shadow.png as images/marker-shadow.png))) diff --git a/src/vendor/images/layers-2x.png b/src/vendor/images/layers-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..200c333dca9652ac4cba004d609e5af4eee168c1 GIT binary patch literal 1259 zcmeAS@N?(olHy`uVBq!ia0y~yU@!q;4i*LmhWx_I2@DJ@n><|{Ln;`Pe)y|cT4BSrpMM7AKE|dn|XR+k!t#k(tv`Q zFW(sEd!8~#>$+9`f9l__#fF!KZ}B_rzo8eC{r}xGzO@x)!A}C+%Y(`<1s-2^LiGH- zNefThzU1_3Qe}!q>B&sRiQ8E#H9j`Wp1zeElOM1<_xPqG{7q&i{}sRA|NWDBa`yhi zf4~1}Z!&l?D{`K~v~Df`g0pk31-#L={QUP&^~BTfPt276eJZ4F#OLLkrWm<1w?G}$K(_Zg>&?>%7rSDWy?-oPVGDw+3f6ddKzommMznMtmE1m^mE;|X)^@3r5^M>q%(7WwwkhRUVZzX zFui*B_UL;{ERE{7ySzCa{A5c-^`03^s-Cnw)fD`#!?J7Jk{=GMTBd1ws=RS{H7RMA z+lH2N3m&&zxMt!%-Q)BVRe@_$r#$1#RlV@>f}~i)v%B7(D}^uiKE0`=J9&~rL}git za^vjh=XaOCc>eeO>kuD~_nyZSSrR*HoRZ?^jT=9HS|#-C z#I0=$9oqx1b}%c7@V%LR;e=gTTa&Q*O*Q|E%7{caZdK)_+ZJf zZ?&H!g%0t3zQ`e9eahh1=NZBi3YOTd+htU}IKfpW%e~b`fYbPb(yyJ0eX|!$;Jmtc zpGlI(Uq{=OPOf@MjvXyZfAUxkxkT|?T2R1T7_4W$NpIDXdncV=-Og(5O3XcC)5tQ> zz+Ah^=e$i`pnF#TudS&IcRlWTsKE8W$-*hoo%u=2$;`|LE*k2wcM@{W?B28Hj1!|( z?&`3_D`smL6xn7gD*L#dPAd}*D+qeymA_@1k^7b7fk)o?9(Qdv5?I?{*Qdo6H_a$Z zWx4ILe&t;!1-}-TBu7TxOI@rh@5%8t*~M7);;#tq)bxD@K>`uh2LySGU20__qc2Mz zz5e8&(8Q{b_nT$qIxJK3ZwNANm$G;z+!`QW&+ygqZIXsCQ=*b?Q`wxE@t%9{h$R(y z`}7A0eZ8=B>r+-n=MV*-1+Ej;cKH>13)vbyyUbGSW~KP1V^g_>mQb1#clPCv9d}vs ze&jIq>z1(p^?bgvyl$yv;Vr)mizp0?3uUtD~sA1FSi+%x^t@XE}h@-tYzk9 zqoeJq#fQ#h%zQM#GO;LXnVpKdkC%5qo68}Ws3tQNA+-xadlV-caB*y5$@NebP0l+XkKIZj$K literal 0 HcmV?d00001 diff --git a/src/vendor/images/layers.png b/src/vendor/images/layers.png new file mode 100644 index 0000000000000000000000000000000000000000..1a72e5784b2b456eac5d7670738db80697af3377 GIT binary patch literal 696 zcmeAS@N?(olHy`uVBq!ia0y~yV2}b~4i*Lm24?3LR|W>AdQTU}kP61$5aS9JMv;5A zx9={r3D-Qo$}jd-@Kme(q}h{gk8N9f^YEHSI?4X$wi&*^XXUqVf93n@6)G0|HB0O+ z{oGRd;!&;aKiPjre@~N1y8by_{oP(ApF5A&Z+bmlV3plXXQ4Q^(0Q+y~?G3 z!a`R6-Bzb}>nxoMS3g;|c>CL9(`O!9VDQ7}^1l9i({>+QJ4%7S^9P-Qtwc)jUmWjVlF-6H4cVyjqg@ zMm}=+(G^1+f9k%t3*NyNhGDITISixbZs=XtX?<#@#To^} zllR&yC7Q0b2+Ufee$_3@VyDHEwjITj6hhx>ORdzOd~VN~YpdKO9dmD=@;Ir&?!Ka0 ze9@!>sms1^+w^n(%oWF3dR*t__&0jzGw-8qqez~?-<4~x zU6bljyRxA4^qUU`2YDx)`}y=x*@+KtSBac>;qcY?zuAd~x7`1fA4n|jeLTA^%I{0R z&%u&I8&&`GCa_jieR-P2?K98qLyM^QzxM~_RzHi!*UqnACyylIHN^Rj+B6T>B0g6wD2rb>45pm~>lr(g1)bIG-PU&x&EkqfVSO*&yS z;hbgfS=;Jm?$a(hPCjqmxW%!3m-FO{289cX=kK>@-tIN=m|6E(zuA|q`_Fk#J#X4| z*0y{tG5mYrJM&be(p=rT6IlmmfW5UU2Hz<2n7J+mwrr-TRF?&V zs_)#7Uw`VB9X@~mmHni1?h{YB&A71m;5DZS7tY*$5wYNs%e3=LkK8nDKjS{>tX=Pg zt!M9fH?R8l@Bi^z&p&_vW!`i4?dR`v_g=Q2d_K5+tzXB6px$jMQ@2gtej$F@_2e0Q z9Xb!V_n&Z^e9@s{ZR~{2!982zCT(|`dj84V&nBH`ww%75u>873@7dlh=bfjXH|{(W z7d!Ji0|SF|NswPKgN%7_eosI1qqlQh)VQ0z2_?Q_-+JKUU7huPe~$OxD4((Q%=1rn z?q4@-&3bU7TsbLBvg!I5S2dYWD;2#S7ZU|h_he3U@wtzOHt*icIpHmL zy?Ai&|Ch$MFYn&^pnlOR%aGe&>)tMux+?e~{z}Q!-sv)H?Z4&ghKAqWlXPcq>ejrS z$BVzazm`65urEF{ge%(WbpDLf>%-W3W7Q8Z-diaxRrFdX{@IL*dsFs5{QGXyqWOP4-1PE)zwr(UqLCNG@BDShIb@BbQOH~rvz6x(1rM{&)h zCI2^1ie0}woOhbaNv}DX8hPC_CNKHouloIxr(aOX;V(s%tEQ{y7mEGo6BjSNdm(Vs z!BXu_x9&`h);d4=?!Ti)lNFxZ-a1{#+&m+>>+vSZ{Dx(nJA39omT)(Wd}d*OchY}> zS=Wlr9G}5lbce-J`;++A6P>4z=5$@YRO0(?M@{jf7aF}sW!InoesgvD`S0uR{y+7c zJM*Z^%fdw#&#l*lSVe4|v9FI;Blz0)M}eM4}1S7y|fO|lGIHmwo6)ysN) z@`Y2E&hx0QzQ6Ic0N5mtVH?#oTPjdTv<|H^U?6ohXl5NmKFtfVaU1XGt93HWL;;RCz(~i-B@2 ztMZwa3;7ji`<>cuYUsWYyyfT~aW>~)Ttdp0haa*^A7`rEIn48j^>mNb9mZLUU;Dgq zb(BBsvZ#Nx_Uel(roBAMoph#Zi{zHxs=z<2V(tqsuD&`oda+X07I6J*oa%H2;&Oq~}6b8UMv1o^cHB zw@!+h7H6D zE$XK?O<(fKWT9kaoQA9NCob2O4UaD6IrQb)Yuwtmc1m82EZ4gF#as5z)n(u0^CphP zQoO8O{?ujuQ*uXBbiS=f+M{6qXZNIC-#wKX9$WmgkWlOGG%UQt>8v8C#bLHj^{?#p zq^}Oqw=ccclsgm}$Rb#}qSsU0T>Y|%q3Of?gq$MZT@r_@Zu{PyecS50-wK8AYV-e2 zfB!+nf3KYzTfhAMRX%I(>aI5GIrFb~>*ZDV4V`!wuLxajKX3Ps*sJFZ{dk2L|LmL? zzat=TpVAF?U;l!InHzU3j`scCuEl+urt8mrgm91(dc6j+tP z6A`%Mx>-aj?~J8<#TLO+mYPp{qlT&iN z&a1S3<*O-TZj{@!u_4N6X2lKeSu#n_P@}6L{b6Jl@&cjG~%U8!&Dx}z( zrMAAcayuD$-&lEawocKa4aqJsJ&X3~rhP8ov`9`;z3BX#j-a~m>C=zc{$M|Ob;m?a ziOFe4?k@Rq<_XD> zB4=;4Zhd?AM&|77+xND~`rPKZmAu(>+oP1++ovkt{rkN7+x4_tFaL!ukK6nGo$YfQ z^*v9n8!cmLEqlSVG%sR-0gvk$*DRbW z{m-p)*DZrjd!y_xaa_#o*4U(@uKo4!Pp!ij7T!1}%l>}rjh7!Q-(N81zW?~clRw*E z{?k)GYWmiy#bRlmL;oJl&J$aiudgm)F0-iHas2Qk`y1cI?%sa8bcrAT(b;!%I<0P9 z{GTy@w!r#Jyj6z3I9)}Su6`_XYb*QXS!FV5bHD9z{itSs)R*aqqTRyE=Ymg+ZNB$v zHnpZ&)$hNave^Ci{e>)>+mm|UX)=F2arlas*Y!VZ^`gp;W=x!PmHFb<*?e}lzMCE0 zvRk9d-y7$jUC*^W@geu4@I-OlYNyz3uMQ~hJ@ZAvR^;ZhPs}lPSAO%o7BSQa zbpPGC@q~NNuAHs@aeMx#hPkYYE#J1MVCVaHeA;*K{uFcFvg=QSSx&=`UA`hqVtqd? zdYU5{zPVBEP0{7r*yQI8{Cgfe_xwDKZM9d}j|Vzyjy`R7nLK@io8wY#kL`E7Jf<68x9vugLJO(0z-KZ&Qdg!24aAb07_69#wwGGo2xYnJYN`~G6Y z{f5WJTvyi~d3Pw}=hJ5XJrB~|HdTa{+%+rHYo0wvW<#>j?DETdO_@vH{3w)qU%ji; z_NZx&{M3G{ii77TKhyiAxALr4;M%-PCKi?|B^8>h(u}9Bzu_-jd+e)R*D9HVSAKyF zecrkG`QJvbip||uzVh)2I2K)AknA*Z-`f1(ke>{yQhV!uK44yNk^b+!z|FQq$H>U% z4;rj)&CipZ6`-=U+SoNLchL;9^D}-vc+R=`7mwnv#>0hg<$|tQStOh|DXSMGs-QM%v9#OT6aOo!0u!OS>mk{4v*^-gU{kUv-=DI!X3RTGs59 zrms7aq`qxvdDNrlbwOV>GmT$cCUm!OcDu!Xn-2~CQ?8YY{CTrg$>;Sw`KWyp56!-# zvTn<7$3qHR4xXKK)bzH)nQ1H9&39e2*J8I>_;hw(^Yq=jSu~fmADQ`g-w!kW*($3f zq`R`zS+DL4=#y?Q`_N(ZtLBi%<=QzX-b%(U=MFlvzxDbXmD0JBS)OidXsr40A^42_ zgQZVg7!FDwD~idOcvfy#ai6Y&gUYVfn=F;xwLJ0PR(xmSKH_ux;D=dz-;~^0xZPL! z1ozroz7KYO?cK)hC-BfMm|Z;L!tIi4FB=3m3Vm8)$!*y6sqlWqio>o2PxU5+TD=Tg zTYBn%ncKVvzMt<;x^8t&I-EsdU*;9>P2#^cg&*=|96!BiOWgcbr%qb!*P729?QZ?6 zRrA<$=6|mncDLWmyzk*RUeFH>vO3!Qi?h`T=KR)_2Cros(q` zrr!L0L#TAiV);U2p+@gxZ`B_y65O@-44>dO5ph1@TNmwv1>fy$%wBo$+&WgT#8pop z)W1KvrsG3JiO}O;u{)0M6cpu=b+0}4U()?P(=nGF;+fwCy{@FkvLxKGX3gAtJaCcS qX{9?EN|FMnBE=+YEB(x$$D3}plVUPRyu-l2z~JfX=d#Wzp$P!`FXGq$ literal 0 HcmV?d00001 diff --git a/src/vendor/images/marker-shadow.png b/src/vendor/images/marker-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2979532a19a15b824ce763c76e04a8dafadfb GIT binary patch literal 618 zcmeAS@N?(olHy`uVBq!ia0y~yV9*3%4i*Lm2ByptwG0eQhMq2tAr*{oFSYhPb`W5> zz-9dRf4!`+aT{;(+DlW`OuKvh(cD`Fe?o50tvmGJPyYYkI}^-Pj=%i->5t$_?z+Eg z<0t)EHE)aXMy2F{nEjj_T;IYwdK?Rnnaqjf{1)D-;#kNmzt4GE;O+QxK@S+5(^AaU z7N=aDb)V1U?7Vn^%sUpxJr3q=Te918=e*elN$zhlHIzdXC1oeM8Mbg5Nj2o3WOPw+ zpMOwu*&gweJLb*OS~P7Ar@rLmS*ayg8lq+dZ0+?Zm6nX!yo^w|MJ60@P{_ADQggak&v`^0oPSK8g z6Zm$gzJVJ145{rKZ=dn?y=(KrV#&L&JR6VjWuMu>*SMBLWeLMd-$OHax6Mdiqt~NQ zs^Y#(?6|a*=efdFwcBoGHo3%{*nZNbWKCU{!`kM%S>CBD4~8GC3UcaXD%fwav8F%f z=oGOgmCmZ50aHZd{ Date: Sun, 29 Sep 2024 09:28:50 +0200 Subject: [PATCH 45/99] Map.on: make handler type be (.. -> unit) --- src/map.ml | 2 +- src/map.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.ml b/src/map.ml index 3c3ae0e..146055d 100644 --- a/src/map.ml +++ b/src/map.ml @@ -33,7 +33,7 @@ let set_view latlng ~zoom map = in () -let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = +let on : type kind. kind Event.sub -> (kind Event.t -> unit) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in let handler v = handler @@ Event.of_jv event v in diff --git a/src/map.mli b/src/map.mli index b50e841..4b8db43 100644 --- a/src/map.mli +++ b/src/map.mli @@ -28,7 +28,7 @@ val get_container : t -> Brr.El.t (** [on event handler map] add an event listener on [map] for event [event] with handler [handler] *) -val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit +val on : 'a Event.sub -> ('a Event.t -> unit) -> t -> unit (** [get_center map] is the geographical center of the map view *) val get_center : t -> Latlng.t From 107c27db959a670048893e7d7072c9a7f2abe2ae Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 15 Dec 2024 06:58:09 +0100 Subject: [PATCH 46/99] ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index f948087..eb9f4e0 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.26.2 +version=0.27.0 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From 7ab765a333bf0b2176eb54aef270fcac18391c07 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 6 Feb 2025 01:28:39 +0100 Subject: [PATCH 47/99] basic example with tiny_httpd --- dune-project | 6 +++-- example/css_path.ml | 14 ---------- example/dune | 29 ++++++++++++++------- example/{map.html => index.html} | 4 +-- example/server.ml | 44 ++++++++++++++++++++++++++++++++ leaflet.opam | 3 ++- 6 files changed, 72 insertions(+), 28 deletions(-) rename example/{map.html => index.html} (68%) create mode 100644 example/server.ml diff --git a/dune-project b/dune-project index 41f5cea..d65af52 100644 --- a/dune-project +++ b/dune-project @@ -30,9 +30,11 @@ (tags (leaflet javascript bindings interactive map openstreetmap)) (depends + (ocaml + (>= 4.08)) brr js_of_ocaml dune-site - (ocaml - (>= 4.08))) + (tiny_httpd :with-test) + ) (sites (share css) (share images))) diff --git a/example/css_path.ml b/example/css_path.ml index 96a5634..e69de29 100644 --- a/example/css_path.ml +++ b/example/css_path.ml @@ -1,14 +0,0 @@ -(* get leaflet.css path from dune-site *) - -let dune_site = List.filter Sys.file_exists Mysites.Sites.css - -let lookup_file filename = - List.find_map - (fun dir -> - let filename' = Filename.concat dir filename in - if Sys.file_exists filename' then Some filename' else None ) - dune_site - -let leaflet_css = lookup_file "leaflet.css" |> Option.get - -let () = Format.printf "%s@." leaflet_css diff --git a/example/dune b/example/dune index 1e537ac..b7b1c0c 100644 --- a/example/dune +++ b/example/dune @@ -1,14 +1,25 @@ -(executable - (name css_path) - (modules css_path mysites) - (libraries dune-site)) - -(generate_sites_module - (module mysites) - (sites leaflet)) - (executable (name script) (modules script) (libraries brr leaflet) (modes js)) + +(executable + (name server) + (modules content server css_path mysites) + (libraries dune-site tiny_httpd)) + +(generate_sites_module + (module mysites) + (sites leaflet)) + +(rule + (with-stdout-to + content.ml + (progn + (echo "let index_html = {|") + (cat index.html) + (echo "|}") + (echo "let script_js = {|") + (cat script.bc.js) + (echo "|}")))) diff --git a/example/map.html b/example/index.html similarity index 68% rename from example/map.html rename to example/index.html index 053dd17..4ba93c9 100644 --- a/example/map.html +++ b/example/index.html @@ -4,12 +4,12 @@ - +
-
+
diff --git a/example/server.ml b/example/server.ml new file mode 100644 index 0000000..755e2ab --- /dev/null +++ b/example/server.ml @@ -0,0 +1,44 @@ +let read_file file = In_channel.with_open_bin file In_channel.input_all + +let leaflet_css = + (* get leaflet.css path from dune-site *) + let dune_site = List.filter Sys.file_exists Mysites.Sites.css in + let lookup_file filename = + List.find_map + (fun dir -> + let filename' = Filename.concat dir filename in + if Sys.file_exists filename' then Some filename' else None ) + dune_site + in + let path = + match lookup_file "leaflet.css" with + | None -> + Printf.eprintf + "File 'leaflet.css' not found.\n\ + It should have been installed with dune-site.\n\ + Did you run `dune build @install`?\n"; + exit 1 + | Some o -> o + in + read_file path + +let script_js = Content.script_js + +let index_html = Content.index_html + +module S = Tiny_httpd + +let () = + let server = S.create () in + S.add_route_handler server + S.Route.(exact "leaflet.css" @/ return) + (fun _req -> S.Response.make_string (Ok leaflet_css)); + S.add_route_handler server + S.Route.(exact "script.js" @/ return) + (fun _req -> S.Response.make_string (Ok script_js)); + S.add_route_handler server + S.Route.(return) + (fun _req -> S.Response.make_string (Ok index_html)); + + Printf.printf "listening on http://%s:%d/\n%!" (S.addr server) (S.port server); + match S.run server with Ok () -> () | Error e -> raise e diff --git a/leaflet.opam b/leaflet.opam index d4db64e..9c0c18f 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -16,10 +16,11 @@ doc: "TODO/leaflet" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} + "ocaml" {>= "4.08"} "brr" "js_of_ocaml" "dune-site" - "ocaml" {>= "4.08"} + "tiny_httpd" {with-test} "odoc" {with-doc} ] build: [ From 0756aef64b81800a0418029e3c005c3c64fbe017 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 6 Feb 2025 01:53:13 +0100 Subject: [PATCH 48/99] better readme; rm empty test/ --- README.md | 22 +++++++++++++--------- dune-project | 6 ++---- leaflet.opam | 1 - test/dune | 3 --- test/test.ml | 1 - 5 files changed, 15 insertions(+), 18 deletions(-) delete mode 100644 test/dune delete mode 100644 test/test.ml diff --git a/README.md b/README.md index ffa9b2e..a43ea72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # leaflet -`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library. +`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library (v1.9.4). ## Installation @@ -16,27 +16,31 @@ If you can't or don't want to use `opam`, consult the [opam file] for build inst ## Usage -Have a look at the [example] folder. -The documentation can be consulted via `odig doc leaflet`. +The library use `dune-site` to install [leaflet's files] (CSS and images). -You will also need [leaflet's files] (CSS and images). +Have a look at the [example] folder. +It use [tiny_httpd] to provide a simple web page with a map that use [OpenStreetMap] tiles: +```sh +dune build @install +dune exec example/server.exe +``` ## About -leaflet's original code was taken from a [NGI0 funded project] +This library started off from the code of a [NGI0 funded project] - [LICENSE] - [CHANGELOG] [CHANGELOG]: ./CHANGES.md -[example]: ./example [LICENSE]: ./LICENSE.md [opam file]: ./leaflet.opam -[test suite]: ./test - [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ [Leaflet]: https://leafletjs.com/ -[leaflet's files]: https://leafletjs.com/download.html +[Leaflet's files]: ./src/vendor/ [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ +[tiny_httpd]: https://github.com/c-cube/tiny_httpd +[example]: ./example/ +[OpenStreetMap]: https://www.openstreetmap.org diff --git a/dune-project b/dune-project index d65af52..90cc610 100644 --- a/dune-project +++ b/dune-project @@ -5,6 +5,8 @@ (name leaflet) +(generate_opam_files true) + (license BSD-2-Clause) (authors "pukkamustard " "swrup " "Léo Andrès ") @@ -18,10 +20,6 @@ (bug_reports https://git.zapashcanon.fr/swrup/leaflet/issues) -(documentation TODO/leaflet) - -(generate_opam_files true) - (package (name leaflet) (synopsis "Bindings for the Leaflet JavaScript library") diff --git a/leaflet.opam b/leaflet.opam index 9c0c18f..ac98590 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -12,7 +12,6 @@ authors: [ license: "BSD-2-Clause" tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] homepage: "https://git.zapashcanon.fr/swrup/leaflet" -doc: "TODO/leaflet" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" depends: [ "dune" {>= "2.9"} diff --git a/test/dune b/test/dune deleted file mode 100644 index f929c11..0000000 --- a/test/dune +++ /dev/null @@ -1,3 +0,0 @@ -(test - (name test) - (modules test)) diff --git a/test/test.ml b/test/test.ml deleted file mode 100644 index 29ef5f9..0000000 --- a/test/test.ml +++ /dev/null @@ -1 +0,0 @@ -let () = assert true (* TODO *) From 25be80020b0ff6450e927c11c58c2ad7a0b98b20 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 6 Feb 2025 02:39:11 +0100 Subject: [PATCH 49/99] don't generate opam file with dune --- dune-project | 20 +------------------- leaflet.opam | 3 ++- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/dune-project b/dune-project index 90cc610..3227a39 100644 --- a/dune-project +++ b/dune-project @@ -5,28 +5,10 @@ (name leaflet) -(generate_opam_files true) - -(license BSD-2-Clause) - -(authors "pukkamustard " "swrup " "Léo Andrès ") - -(maintainers "swrup ") - -(source - (uri git+https://git.zapashcanon.fr/swrup/leaflet.git)) - -(homepage https://git.zapashcanon.fr/swrup/leaflet) - -(bug_reports https://git.zapashcanon.fr/swrup/leaflet/issues) +(generate_opam_files false) (package (name leaflet) - (synopsis "Bindings for the Leaflet JavaScript library") - (description - "leaflet is an OCaml bindings library for the Leaflet JavaScript library.") - (tags - (leaflet javascript bindings interactive map openstreetmap)) (depends (ocaml (>= 4.08)) diff --git a/leaflet.opam b/leaflet.opam index ac98590..25c8f4d 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -1,5 +1,6 @@ -# This file is generated by dune, edit dune-project instead opam-version: "2.0" +name: "leaflet" +version: "0.2" synopsis: "Bindings for the Leaflet JavaScript library" description: "leaflet is an OCaml bindings library for the Leaflet JavaScript library." From e16618f49ecbdbf97aa2e07c3107504aae9d92d2 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 23 Nov 2024 09:51:13 +0100 Subject: [PATCH 50/99] version 0.2 --- CHANGES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 4cff088..0c40b06 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +## 0.2 + +- use leaflet.js v1.9.4 +- some small breaking changes +- add more bindings +- use dune-site to "install" css and images files +- provide example + ## 0.1 Initial release. From db37034a70626e7b282957a63705a1a4696b6067 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 Mar 2026 21:37:09 +0100 Subject: [PATCH 51/99] migrate to forge.kumikode.org --- .ocamlformat | 2 +- leaflet.opam | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index eb9f4e0..6f010c4 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.27.0 +version=0.28.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/leaflet.opam b/leaflet.opam index 25c8f4d..b06ac7f 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -8,12 +8,12 @@ maintainer: ["swrup "] authors: [ "pukkamustard " "swrup " - "Léo Andrès " + "pena " ] license: "BSD-2-Clause" tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] -homepage: "https://git.zapashcanon.fr/swrup/leaflet" -bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" +homepage: "https://forge.kumikode.org/kumikode/leaflet" +bug-reports: "https://forge.kumikode.org/kumikode/leaflet/issues" depends: [ "dune" {>= "2.9"} "ocaml" {>= "4.08"} @@ -39,4 +39,4 @@ build: [ ] ["dune" "install" "-p" name "--create-install-files" name] ] -dev-repo: "git+https://git.zapashcanon.fr/swrup/leaflet.git" +dev-repo: "git+https://forge.kumikode.org/kumikode/leaflet.git" From 38bff4feb452bf15d66a9271e47f9c94c95281e1 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 5 Apr 2022 16:33:14 +0200 Subject: [PATCH 52/99] make geopub/leaflet a separate library --- .gitignore | 1 + .ocamlformat | 42 +++++++++++++++++++++ CHANGES.md | 1 + LICENSE.md | 8 ++++ README.md | 40 ++++++++++++++++++++ doc/dune | 3 ++ doc/index.mld | 17 +++++++++ dune-project | 19 ++++++++++ example/dune | 3 ++ example/main.ml | 1 + leaflet.opam | 42 +++++++++++++++++++++ src/dune | 7 ++++ src/leaflet.js | 6 +++ src/leaflet.js.license | 3 ++ src/leaflet.ml | 83 ++++++++++++++++++++++++++++++++++++++++++ src/leaflet.mli | 67 ++++++++++++++++++++++++++++++++++ test/dune | 3 ++ test/test.ml | 1 + 18 files changed, 347 insertions(+) create mode 100644 .gitignore create mode 100644 .ocamlformat create mode 100644 CHANGES.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 doc/dune create mode 100644 doc/index.mld create mode 100644 dune-project create mode 100644 example/dune create mode 100644 example/main.ml create mode 100644 leaflet.opam create mode 100644 src/dune create mode 100644 src/leaflet.js create mode 100644 src/leaflet.js.license create mode 100644 src/leaflet.ml create mode 100644 src/leaflet.mli create mode 100644 test/dune create mode 100644 test/test.ml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_build diff --git a/.ocamlformat b/.ocamlformat new file mode 100644 index 0000000..1b64a37 --- /dev/null +++ b/.ocamlformat @@ -0,0 +1,42 @@ +version=0.21.0 +assignment-operator=end-line +break-cases=fit +break-fun-decl=wrap +break-fun-sig=wrap +break-infix=wrap +break-infix-before-func=false +break-separators=before +break-sequences=true +cases-exp-indent=2 +cases-matching-exp-indent=normal +doc-comments=before +doc-comments-padding=2 +doc-comments-tag-only=default +dock-collection-brackets=false +exp-grouping=preserve +field-space=loose +if-then-else=compact +indicate-multiline-delimiters=space +indicate-nested-or-patterns=unsafe-no +infix-precedence=indent +leading-nested-match-parens=false +let-and=sparse +let-binding-spacing=compact +let-module=compact +margin=80 +max-indent=68 +module-item-spacing=sparse +ocp-indent-compat=false +parens-ite=false +parens-tuple=always +parse-docstrings=true +sequence-blank-line=preserve-one +sequence-style=terminator +single-case=compact +space-around-arrays=true +space-around-lists=true +space-around-records=true +space-around-variants=true +type-decl=sparse +wrap-comments=false +wrap-fun-args=true diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..d9cd2e7 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1 @@ +## unreleased diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c0fd71b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,8 @@ +The ISC License (ISC) +===================== + +Copyright © 2022, TODO + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e628def --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# leaflet + +[leaflet] is an [OCaml] executable/library to TODO. + +## Installation + +`leaflet` can be installed with [opam]: + +```sh +opam install leaflet +``` + +If you don't have `opam`, you can install it following the [how to install opam] guide. + +If you can't or don't want to use `opam`, consult the [opam file] for build instructions. + +## Quickstart + +```ocaml +let () = Format.printf "TODO@." +``` + +For more, have a look at the [example] folder, at the [documentation] or at the [test suite]. + +## About + +- [LICENSE] +- [CHANGELOG] + +[CHANGELOG]: ./CHANGES.md +[example]: ./example +[LICENSE]: ./LICENSE.md +[opam file]: ./leaflet.opam +[test suite]: ./test + +[documentation]: TODO/leaflet +[how to install opam]: https://opam.ocaml.org/doc/Install.html +[OCaml]: https://ocaml.org +[opam]: https://opam.ocaml.org/ +[leaflet]: TODO/leaflet diff --git a/doc/dune b/doc/dune new file mode 100644 index 0000000..f03de7c --- /dev/null +++ b/doc/dune @@ -0,0 +1,3 @@ +(documentation + (package leaflet) + (mld_files index)) diff --git a/doc/index.mld b/doc/index.mld new file mode 100644 index 0000000..c248edf --- /dev/null +++ b/doc/index.mld @@ -0,0 +1,17 @@ +{0 leaflet} + +{{:https://TODO/leaflet} leaflet} is an {{:https://ocaml.org} OCaml} library/executable to TODO. + +{1:api API} + +{!modules: +Leaflet +} + +{1:private_api Private API} + +You shouldn't have to use any of these modules, they're used internally only. + +{!modules: +TODO +} diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..1c832fe --- /dev/null +++ b/dune-project @@ -0,0 +1,19 @@ +(lang dune 2.9) +(using dune_site 0.1) +;uncomment when fixed: https://github.com/ocaml/dune/issues/9661 +;(implicit_transitive_deps false) + +(name leaflet) + +(generate_opam_files false) + +(package + (name leaflet) + (depends + (ocaml + (>= 4.08)) + brr + js_of_ocaml + dune-site + (tiny_httpd :with-test)) + (sites (share css) (share images))) diff --git a/example/dune b/example/dune new file mode 100644 index 0000000..e36b142 --- /dev/null +++ b/example/dune @@ -0,0 +1,3 @@ +(executable + (name main) + (modules main)) diff --git a/example/main.ml b/example/main.ml new file mode 100644 index 0000000..16c9b9f --- /dev/null +++ b/example/main.ml @@ -0,0 +1 @@ +let () = Format.printf "TODO@." diff --git a/leaflet.opam b/leaflet.opam new file mode 100644 index 0000000..b06ac7f --- /dev/null +++ b/leaflet.opam @@ -0,0 +1,42 @@ +opam-version: "2.0" +name: "leaflet" +version: "0.2" +synopsis: "Bindings for the Leaflet JavaScript library" +description: + "leaflet is an OCaml bindings library for the Leaflet JavaScript library." +maintainer: ["swrup "] +authors: [ + "pukkamustard " + "swrup " + "pena " +] +license: "BSD-2-Clause" +tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] +homepage: "https://forge.kumikode.org/kumikode/leaflet" +bug-reports: "https://forge.kumikode.org/kumikode/leaflet/issues" +depends: [ + "dune" {>= "2.9"} + "ocaml" {>= "4.08"} + "brr" + "js_of_ocaml" + "dune-site" + "tiny_httpd" {with-test} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "--promote-install-files=false" + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] + ["dune" "install" "-p" name "--create-install-files" name] +] +dev-repo: "git+https://forge.kumikode.org/kumikode/leaflet.git" diff --git a/src/dune b/src/dune new file mode 100644 index 0000000..a2d7907 --- /dev/null +++ b/src/dune @@ -0,0 +1,7 @@ +(library + (name leaflet) + (public_name leaflet) + (modules leaflet) + (libraries brr js_of_ocaml) + (js_of_ocaml + (javascript_files leaflet.js))) diff --git a/src/leaflet.js b/src/leaflet.js new file mode 100644 index 0000000..21f499c --- /dev/null +++ b/src/leaflet.js @@ -0,0 +1,6 @@ +/* @preserve + * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com + * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";function h(t){for(var i,e,n=1,o=arguments.length;n=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt={ie:tt,ielt9:it,edge:et,webkit:nt,android:ot,android23:st,androidStock:at,opera:ht,chrome:ut,gecko:lt,safari:ct,phantom:_t,opera12:dt,win:pt,ie3d:mt,webkit3d:ft,gecko3d:gt,any3d:vt,mobile:yt,mobileWebkit:xt,mobileWebkit3d:wt,msPointer:Pt,pointer:Lt,touch:bt,mobileOpera:Tt,mobileGecko:Mt,retina:zt,passiveEvents:Ct,canvas:St,svg:Zt,vml:Et},At=Pt?"MSPointerDown":"pointerdown",It=Pt?"MSPointerMove":"pointermove",Ot=Pt?"MSPointerUp":"pointerup",Rt=Pt?"MSPointerCancel":"pointercancel",Nt={},Dt=!1;function jt(t,i,e,n){function o(t){Ut(t,r)}var s,r,a,h,u,l,c,_;function d(t){t.pointerType===(t.MSPOINTER_TYPE_MOUSE||"mouse")&&0===t.buttons||Ut(t,h)}return"touchstart"===i?(u=t,l=e,c=n,_=p(function(t){t.MSPOINTER_TYPE_TOUCH&&t.pointerType===t.MSPOINTER_TYPE_TOUCH&&Ri(t),Ut(t,l)}),u["_leaflet_touchstart"+c]=_,u.addEventListener(At,_,!1),Dt||(document.addEventListener(At,Wt,!0),document.addEventListener(It,Ht,!0),document.addEventListener(Ot,Ft,!0),document.addEventListener(Rt,Ft,!0),Dt=!0)):"touchmove"===i?(h=e,(a=t)["_leaflet_touchmove"+n]=d,a.addEventListener(It,d,!1)):"touchend"===i&&(r=e,(s=t)["_leaflet_touchend"+n]=o,s.addEventListener(Ot,o,!1),s.addEventListener(Rt,o,!1)),this}function Wt(t){Nt[t.pointerId]=t}function Ht(t){Nt[t.pointerId]&&(Nt[t.pointerId]=t)}function Ft(t){delete Nt[t.pointerId]}function Ut(t,i){for(var e in t.touches=[],Nt)t.touches.push(Nt[e]);t.changedTouches=[t],i(t)}var Vt=Pt?"MSPointerDown":Lt?"pointerdown":"touchstart",qt=Pt?"MSPointerUp":Lt?"pointerup":"touchend",Gt="_leaflet_";var Kt,Yt,Xt,Jt,$t,Qt,ti=fi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ii=fi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ei="webkitTransition"===ii||"OTransition"===ii?ii+"End":"transitionend";function ni(t){return"string"==typeof t?document.getElementById(t):t}function oi(t,i){var e,n=t.style[i]||t.currentStyle&&t.currentStyle[i];return n&&"auto"!==n||!document.defaultView||(n=(e=document.defaultView.getComputedStyle(t,null))?e[i]:null),"auto"===n?null:n}function si(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ri(t){var i=t.parentNode;i&&i.removeChild(t)}function ai(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function hi(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function ui(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function li(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=pi(t);return 0this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,N(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e,n,o=A((i=i||{}).paddingTopLeft||i.padding||[0,0]),s=A(i.paddingBottomRight||i.padding||[0,0]),r=this.getCenter(),a=this.project(r),h=this.project(t),u=this.getPixelBounds(),l=u.getSize().divideBy(2),c=O([u.min.add(o),u.max.subtract(s)]);return c.contains(h)||(this._enforcingBounds=!0,e=a.subtract(h),n=A(h.x+e.x,h.y+e.y),(h.xc.max.x)&&(n.x=a.x-e.x,0c.max.y)&&(n.y=a.y-e.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[m(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Vi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Vi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){var i;this._loaded&&!Ui(t)&&("mousedown"!==(i=t.type)&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Pi(t.target||t.srcElement),this._fireDOMEvent(t,i))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){var n;if("click"===t.type&&((n=h({},t)).type="preclick",this._fireDOMEvent(n,n.type,e)),!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Ri(t);var s,r={originalEvent:t};"keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(s=o.getLatLng&&(!o._radius||o._radius<=10),r.containerPoint=s?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s?o.getLatLng():this.layerPointToLatLng(r.layerPoint));for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,ci(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(p(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&_i(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Yi(t){return new Xi(t)}var Xi=S.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return ci(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ri(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+m(this),n),this._layerControlInputs.push(i),i.layerId=m(t.layer),zi(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),$i=Xi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=si("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=si("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Oi(s),zi(s,"click",Ni),zi(s,"click",o,this),zi(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";_i(this._zoomInButton,i),_i(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||ci(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||ci(this._zoomInButton,i)}});Ki.mergeOptions({zoomControl:!0}),Ki.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new $i,this.addControl(this.zoomControl))});var Qi=Xi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=si("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=si("div",i,e)),t.imperial&&(this._iScale=si("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=si("div","leaflet-control-attribution"),Oi(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ki.mergeOptions({attributionControl:!0}),Ki.addInitHook(function(){this.options.attributionControl&&(new te).addTo(this)});Xi.Layers=Ji,Xi.Zoom=$i,Xi.Scale=Qi,Xi.Attribution=te,Yi.layers=function(t,i,e){return new Ji(t,i,e)},Yi.zoom=function(t){return new $i(t)},Yi.scale=function(t){return new Qi(t)},Yi.attribution=function(t){return new te(t)};var ie=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});ie.addTo=function(t,i){return t.addHandler(i,this),this};var ee,ne={Events:Z},oe=bt?"touchstart mousedown":"mousedown",se={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},re={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ae=E.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){c(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(zi(this._dragStartTarget,oe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ae._dragging===this&&this.finishDrag(),Si(this._dragStartTarget,oe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var i,e;!t._simulated&&this._enabled&&(this._moved=!1,li(this._element,"leaflet-zoom-anim")||ae._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ae._dragging=this)._preventOutline&&Pi(this._element),xi(),Xt(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=bi(this._element),this._startPoint=new k(i.clientX,i.clientY),this._parentScale=Ti(e),zi(document,re[t.type],this._onMove,this),zi(document,se[t.type],this._onUp,this))))},_onMove:function(t){var i,e;!t._simulated&&this._enabled&&(t.touches&&1i&&(e.push(t[n]),o=n);oi.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function de(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||Oe.prototype._containsPoint.call(this,t,!0)}});var Ne=Ce.extend({initialize:function(t,i){c(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=g(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c]))},_onCloseButtonClick:function(t){this._close(),Ni(t)},_getAnchor:function(){return A(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ki.mergeOptions({closePopupOnClick:!0}),Ki.include({openPopup:function(t,i,e){return t instanceof tn||(t=new tn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Me.include({bindPopup:function(t,i){return t instanceof tn?(c(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new tn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Ni(t),i instanceof Be?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var en=Qe.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Qe.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Qe.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Qe.prototype.getEvents.call(this);return bt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=si("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i,e=this._map,n=this._container,o=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=n.offsetWidth,h=n.offsetHeight,u=A(this.options.offset),l=this._getAnchor(),c="top"===r?(i=a/2,h):"bottom"===r?(i=a/2,0):(i="center"===r?a/2:"right"===r?0:"left"===r?a:s.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return N(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new R(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new k(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ri(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){ci(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=a,t.onmousemove=a,it&&this.options.opacity<1&&mi(t,this.options.opacity),ot&&!st&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),p(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(p(this._tileReady,this,t,null,o)),vi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(mi(e.el,0),z(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(ci(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),it||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(p(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new k(this._wrapX?o(t.x,this._wrapX):t.x,this._wrapY?o(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new I(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var sn=on.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=c(this,i)).detectRetina&&zt&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_n={_initContainer:function(){this._container=si("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(hn.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=cn("shape");ci(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=cn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ri(i),t.removeInteractiveTarget(i),delete this._layers[m(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i=i||(t._stroke=cn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=g(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e=e||(t._fill=cn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){hi(t._container)},_bringToBack:function(t){ui(t._container)}},dn=Et?cn:J,pn=hn.extend({getEvents:function(){var t=hn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ri(this._container),Si(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){var t,i,e;this._map._animatingZoom&&this._bounds||(hn.prototype._update.call(this),i=(t=this._bounds).getSize(),e=this._container,this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),vi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update"))},_initPath:function(t){var i=t._path=dn("path");t.options.className&&ci(i,t.options.className),t.options.interactive&&ci(i,"leaflet-interactive"),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ri(t._path),t.removeInteractiveTarget(t._path),delete this._layers[m(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,$(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){hi(t._path)},_bringToBack:function(t){ui(t._path)}});function mn(t){return Zt||Et?new pn(t):null}Et&&pn.include(_n),Ki.include({getRenderer:function(t){var i=(i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&ln(t)||mn(t)}});var fn=Re.extend({initialize:function(t,i){Re.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=N(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});pn.create=dn,pn.pointsToPath=$,Ne.geometryToLayer=De,Ne.coordsToLatLng=We,Ne.coordsToLatLngs=He,Ne.latLngToCoords=Fe,Ne.latLngsToCoords=Ue,Ne.getFeature=Ve,Ne.asFeature=qe,Ki.mergeOptions({boxZoom:!0});var gn=ie.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){zi(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Si(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ri(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Xt(),xi(),this._startPoint=this._map.mouseEventToContainerPoint(t),zi(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=si("div","leaflet-zoom-box",this._container),ci(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new I(this._point,this._startPoint),e=i.getSize();vi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ri(this._box),_i(this._container,"leaflet-crosshair")),Jt(),wi(),Si(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){var i;1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(p(this._resetState,this),0),i=new R(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})))},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ki.addInitHook("addHandler","boxZoom",gn),Ki.mergeOptions({doubleClickZoom:!0});var vn=ie.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ki.addInitHook("addHandler","doubleClickZoom",vn),Ki.mergeOptions({dragging:!0,inertia:!st,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var yn=ie.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new ae(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),ci(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){_i(this._map._container,"leaflet-grab"),_i(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,i=this._map;i._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=N(this._map.options.maxBounds),this._offsetLimit=O(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,i.fire("movestart").fire("dragstart"),i.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var i,e;this._map.options.inertia&&(i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(e),this._times.push(i),this._prunePositions(i)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1 + * + * SPDX-License-Identifier: AGPL-3.0-or-later + *) +open Brr + +let leaflet = + match Jv.(find global "L") with + | Some l -> l + | None -> failwith "Could not load Leaflet" + +module LatLng = struct + type t = Jv.t + + let create lat lng = + Jv.call leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] + + let lat latlng = Jv.get latlng "lat" |> Jv.to_float + let lng latlng = Jv.get latlng "lng" |> Jv.to_float +end + +module Ev = struct + module MouseEvent = struct + type t = Jv.t + + let latlng e = Jv.get e "latlng" + end +end + +module Map = struct + type t = Jv.t + + let create ?(options = Jv.null) el = + Jv.call leaflet "map" [| El.to_jv el; options |] + + let invalidate_size map = + ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] + + let fit_world map = ignore @@ Jv.call map "fitWorld" [||] + let get_container map = Jv.call map "getContainer" [||] |> El.of_jv + + let set_view latlng ~zoom map = + ignore @@ Jv.call map "setView" [| latlng; Jv.of_int zoom |]; + map + + let as_target map = Brr.Ev.target_of_jv map + let click = Brr.Ev.Type.create (Jstr.v "click") +end + +module TileLayer = struct + type t = Jv.t + + let create_osm () = + Jv.call leaflet "tileLayer" + [| + Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; + Jv.obj + [| + ( "attribution", + Jv.of_string + "© OpenStreetMap \ + contributors" ); + |]; + |] + + let add_to tile_layer map = ignore @@ Jv.call tile_layer "addTo" [| map |] +end + +module Marker = struct + type t = Jv.t + + let create latlng = Jv.call leaflet "marker" [| latlng |] + let add_to marker map = ignore @@ Jv.call marker "addTo" [| map |] + + let bind_popup el marker = + ignore @@ Jv.call marker "bindPopup" [| El.to_jv el |]; + marker + + let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] +end + diff --git a/src/leaflet.mli b/src/leaflet.mli new file mode 100644 index 0000000..16f36fc --- /dev/null +++ b/src/leaflet.mli @@ -0,0 +1,67 @@ +(* + * SPDX-FileCopyrightText: 2021 pukkamustard + * + * SPDX-License-Identifier: AGPL-3.0-or-later + *) + +open Brr +(** {1 Leaflet} + +This module provides bindings to the Leaflet JavaScript library for +mobile-friendly interactive maps. + +See also the [Leaflet API reference](https://leafletjs.com/reference.html). +*) + +module LatLng : sig + type t + + val create : float -> float -> t + val lat : t -> float + val lng : t -> float +end + +module Ev : sig + module MouseEvent : sig + type t + + val latlng : t -> LatLng.t + end +end + +module Map : sig + type t + + val create : ?options:Jv.t -> El.t -> t + val invalidate_size : t -> unit + val set_view : LatLng.t -> zoom:int -> t -> t + val fit_world : t -> unit + val get_container : t -> El.t + + (** {1 Events} **) + + val as_target : t -> Brr.Ev.target + + (** {2 Interaction events} **) + + val click : Ev.MouseEvent.t Brr.Ev.type' +end + +module TileLayer : sig + type t + + val create_osm : unit -> t + val add_to : t -> Map.t -> unit +end + +module Marker : sig + type t + + val create : LatLng.t -> t + val add_to : t -> Map.t -> unit + + (** {2 Popup methods} *) + + val bind_popup : El.t -> t -> t + val open_popup : t -> unit +end diff --git a/test/dune b/test/dune new file mode 100644 index 0000000..f929c11 --- /dev/null +++ b/test/dune @@ -0,0 +1,3 @@ +(test + (name test) + (modules test)) diff --git a/test/test.ml b/test/test.ml new file mode 100644 index 0000000..29ef5f9 --- /dev/null +++ b/test/test.ml @@ -0,0 +1 @@ +let () = assert true (* TODO *) From 797352775729b510d0dc73218bedc6f24fbf4b83 Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 6 Apr 2022 19:56:13 +0200 Subject: [PATCH 53/99] add more functions --- src/leaflet.ml | 68 ++++++++++++++++++++++++++++++++++++++----------- src/leaflet.mli | 50 +++++++++++++++++++++++++++++++----- 2 files changed, 96 insertions(+), 22 deletions(-) diff --git a/src/leaflet.ml b/src/leaflet.ml index e1c5948..fca38f9 100644 --- a/src/leaflet.ml +++ b/src/leaflet.ml @@ -17,7 +17,10 @@ module LatLng = struct Jv.call leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] let lat latlng = Jv.get latlng "lat" |> Jv.to_float + let lng latlng = Jv.get latlng "lng" |> Jv.to_float + + let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool end module Ev = struct @@ -31,21 +34,36 @@ end module Map = struct type t = Jv.t - let create ?(options = Jv.null) el = - Jv.call leaflet "map" [| El.to_jv el; options |] + let create ?(options = Jv.null) container_id = + Jv.call leaflet "map" [| Jv.of_string container_id; options |] let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] let fit_world map = ignore @@ Jv.call map "fitWorld" [||] + let get_container map = Jv.call map "getContainer" [||] |> El.of_jv - let set_view latlng ~zoom map = - ignore @@ Jv.call map "setView" [| latlng; Jv.of_int zoom |]; - map + let set_view latlng ?zoom map = + ignore + @@ + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] let as_target map = Brr.Ev.target_of_jv map + let click = Brr.Ev.Type.create (Jstr.v "click") + (*?= let click = Brr.Ev.click *) + + let on ~event ~handler map = + ignore @@ Jv.call map "on" [| Jv.of_string event; Jv.repr handler |] + + let get_center map = Jv.call map "getCenter" [||] + + let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int + + let wrapped_latlng latlng map = Jv.call map "wrapLatLng" [| latlng |] end module TileLayer = struct @@ -53,25 +71,33 @@ module TileLayer = struct let create_osm () = Jv.call leaflet "tileLayer" - [| - Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"; - Jv.obj - [| - ( "attribution", - Jv.of_string - "© OpenStreetMap \ - contributors" ); - |]; + [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] |] let add_to tile_layer map = ignore @@ Jv.call tile_layer "addTo" [| map |] end +module GeojsonLayer = struct + type t = Jv.t + + let create ?(options = Jv.null) geojson = + Jv.call leaflet "geoJSON" [| geojson; options |] + + let add_to layer map = ignore @@ Jv.call layer "addTo" [| map |] +end + module Marker = struct type t = Jv.t let create latlng = Jv.call leaflet "marker" [| latlng |] + let add_to marker map = ignore @@ Jv.call marker "addTo" [| map |] let bind_popup el marker = @@ -81,3 +107,15 @@ module Marker = struct let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] end +module Popup = struct + let popup = Jv.call leaflet "popup" [||] + + let set_latlng latlng = ignore @@ Jv.call popup "setLatLng" [| latlng |] + + let set_content content = + ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + + let open_on map = ignore @@ Jv.call popup "openOn" [| map |] + + let close map = ignore @@ Jv.call map "closePopup" [||] +end diff --git a/src/leaflet.mli b/src/leaflet.mli index 16f36fc..dd166cf 100644 --- a/src/leaflet.mli +++ b/src/leaflet.mli @@ -4,21 +4,24 @@ * SPDX-License-Identifier: AGPL-3.0-or-later *) -open Brr (** {1 Leaflet} -This module provides bindings to the Leaflet JavaScript library for -mobile-friendly interactive maps. + This module provides bindings to the Leaflet JavaScript library for + mobile-friendly interactive maps. -See also the [Leaflet API reference](https://leafletjs.com/reference.html). -*) + See also the [Leaflet API reference](https://leafletjs.com/reference.html). *) +open Brr module LatLng : sig type t val create : float -> float -> t + val lat : t -> float + val lng : t -> float + + val equals : t -> t -> bool end module Ev : sig @@ -32,12 +35,24 @@ end module Map : sig type t - val create : ?options:Jv.t -> El.t -> t + val create : ?options:Jv.t -> string -> t + val invalidate_size : t -> unit - val set_view : LatLng.t -> zoom:int -> t -> t + + val set_view : LatLng.t -> ?zoom:int -> t -> unit + val fit_world : t -> unit + val get_container : t -> El.t + val on : event:string -> handler:('a -> 'b) -> t -> unit + + val get_center : t -> LatLng.t + + val get_zoom : t -> int + + val wrapped_latlng : LatLng.t -> t -> LatLng.t + (** {1 Events} **) val as_target : t -> Brr.Ev.target @@ -51,6 +66,15 @@ module TileLayer : sig type t val create_osm : unit -> t + + val add_to : t -> Map.t -> unit +end + +module GeojsonLayer : sig + type t + + val create : ?options:Jv.t -> Jv.t -> t + val add_to : t -> Map.t -> unit end @@ -58,10 +82,22 @@ module Marker : sig type t val create : LatLng.t -> t + val add_to : t -> Map.t -> unit (** {2 Popup methods} *) val bind_popup : El.t -> t -> t + val open_popup : t -> unit end + +module Popup : sig + val set_latlng : LatLng.t -> unit + + val set_content : string -> unit + + val open_on : Map.t -> unit + + val close : Map.t -> unit +end From 982a1f295b5df1eb055e3d47d98a8cfdec1048ec Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 14:45:11 +0200 Subject: [PATCH 54/99] split modules and fix Ev --- src/dune | 2 +- src/ev.ml | 12 +++++ src/ev.mli | 11 ++++ src/geojson_layer.ml | 7 +++ src/geojson_layer.mli | 5 ++ src/global.ml | 4 ++ src/latlng.ml | 14 +++++ src/latlng.mli | 13 +++++ src/leaflet.ml | 121 ------------------------------------------ src/leaflet.mli | 103 ----------------------------------- src/map.ml | 46 ++++++++++++++++ src/map.mli | 34 ++++++++++++ src/marker.ml | 11 ++++ src/marker.mli | 11 ++++ src/popup.ml | 11 ++++ src/popup.mli | 7 +++ src/tile_layer.ml | 16 ++++++ src/tile_layer.mli | 5 ++ 18 files changed, 208 insertions(+), 225 deletions(-) create mode 100644 src/ev.ml create mode 100644 src/ev.mli create mode 100644 src/geojson_layer.ml create mode 100644 src/geojson_layer.mli create mode 100644 src/global.ml create mode 100644 src/latlng.ml create mode 100644 src/latlng.mli delete mode 100644 src/leaflet.ml delete mode 100644 src/leaflet.mli create mode 100644 src/map.ml create mode 100644 src/map.mli create mode 100644 src/marker.ml create mode 100644 src/marker.mli create mode 100644 src/popup.ml create mode 100644 src/popup.mli create mode 100644 src/tile_layer.ml create mode 100644 src/tile_layer.mli diff --git a/src/dune b/src/dune index a2d7907..e7f3daf 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,7 @@ (library (name leaflet) (public_name leaflet) - (modules leaflet) + (modules ev latlng geojson_layer tile_layer popup marker map global) (libraries brr js_of_ocaml) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/ev.ml b/src/ev.ml new file mode 100644 index 0000000..d4f9aad --- /dev/null +++ b/src/ev.ml @@ -0,0 +1,12 @@ +type type' = Jv.t + +module Event = struct + (*type for simple Event *) + type t = type' +end + +module Mouse = struct + type t = type' + + let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" +end diff --git a/src/ev.mli b/src/ev.mli new file mode 100644 index 0000000..0a93bcf --- /dev/null +++ b/src/ev.mli @@ -0,0 +1,11 @@ +type type' + +module Event : sig + type t +end + +module Mouse : sig + type t + + val latlng : t -> Latlng.t +end diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml new file mode 100644 index 0000000..66ed14a --- /dev/null +++ b/src/geojson_layer.ml @@ -0,0 +1,7 @@ +(*TODO merge with TileLayer*) +type t = Jv.t + +let create ?(options = Jv.null) geojson = + Jv.call Global.leaflet "geoJSON" [| geojson; options |] + +let add_to layer map = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli new file mode 100644 index 0000000..12bb980 --- /dev/null +++ b/src/geojson_layer.mli @@ -0,0 +1,5 @@ +type t + +val create : ?options:Jv.t -> Jv.t -> t + +val add_to : t -> Map.t -> unit diff --git a/src/global.ml b/src/global.ml new file mode 100644 index 0000000..c209f3d --- /dev/null +++ b/src/global.ml @@ -0,0 +1,4 @@ +let leaflet = + match Jv.(find global "L") with + | Some l -> l + | None -> failwith "Could not load Leaflet" diff --git a/src/latlng.ml b/src/latlng.ml new file mode 100644 index 0000000..d2b4dbc --- /dev/null +++ b/src/latlng.ml @@ -0,0 +1,14 @@ +type t = Jv.t + +let create lat lng = + Jv.call Global.leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] + +let lat latlng = Jv.get latlng "lat" |> Jv.to_float + +let lng latlng = Jv.get latlng "lng" |> Jv.to_float + +let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool + +let of_jv_t = Fun.id + +let to_jv_t = Fun.id diff --git a/src/latlng.mli b/src/latlng.mli new file mode 100644 index 0000000..fb793ae --- /dev/null +++ b/src/latlng.mli @@ -0,0 +1,13 @@ +type t + +val create : float -> float -> t + +val lat : t -> float + +val lng : t -> float + +val equals : t -> t -> bool + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/leaflet.ml b/src/leaflet.ml deleted file mode 100644 index fca38f9..0000000 --- a/src/leaflet.ml +++ /dev/null @@ -1,121 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2021 pukkamustard - * - * SPDX-License-Identifier: AGPL-3.0-or-later - *) -open Brr - -let leaflet = - match Jv.(find global "L") with - | Some l -> l - | None -> failwith "Could not load Leaflet" - -module LatLng = struct - type t = Jv.t - - let create lat lng = - Jv.call leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] - - let lat latlng = Jv.get latlng "lat" |> Jv.to_float - - let lng latlng = Jv.get latlng "lng" |> Jv.to_float - - let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool -end - -module Ev = struct - module MouseEvent = struct - type t = Jv.t - - let latlng e = Jv.get e "latlng" - end -end - -module Map = struct - type t = Jv.t - - let create ?(options = Jv.null) container_id = - Jv.call leaflet "map" [| Jv.of_string container_id; options |] - - let invalidate_size map = - ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] - - let fit_world map = ignore @@ Jv.call map "fitWorld" [||] - - let get_container map = Jv.call map "getContainer" [||] |> El.of_jv - - let set_view latlng ?zoom map = - ignore - @@ - match zoom with - | None -> Jv.call map "setView" [| latlng |] - | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] - - let as_target map = Brr.Ev.target_of_jv map - - let click = Brr.Ev.Type.create (Jstr.v "click") - (*?= let click = Brr.Ev.click *) - - let on ~event ~handler map = - ignore @@ Jv.call map "on" [| Jv.of_string event; Jv.repr handler |] - - let get_center map = Jv.call map "getCenter" [||] - - let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int - - let wrapped_latlng latlng map = Jv.call map "wrapLatLng" [| latlng |] -end - -module TileLayer = struct - type t = Jv.t - - let create_osm () = - Jv.call leaflet "tileLayer" - [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - - let add_to tile_layer map = ignore @@ Jv.call tile_layer "addTo" [| map |] -end - -module GeojsonLayer = struct - type t = Jv.t - - let create ?(options = Jv.null) geojson = - Jv.call leaflet "geoJSON" [| geojson; options |] - - let add_to layer map = ignore @@ Jv.call layer "addTo" [| map |] -end - -module Marker = struct - type t = Jv.t - - let create latlng = Jv.call leaflet "marker" [| latlng |] - - let add_to marker map = ignore @@ Jv.call marker "addTo" [| map |] - - let bind_popup el marker = - ignore @@ Jv.call marker "bindPopup" [| El.to_jv el |]; - marker - - let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] -end - -module Popup = struct - let popup = Jv.call leaflet "popup" [||] - - let set_latlng latlng = ignore @@ Jv.call popup "setLatLng" [| latlng |] - - let set_content content = - ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] - - let open_on map = ignore @@ Jv.call popup "openOn" [| map |] - - let close map = ignore @@ Jv.call map "closePopup" [||] -end diff --git a/src/leaflet.mli b/src/leaflet.mli deleted file mode 100644 index dd166cf..0000000 --- a/src/leaflet.mli +++ /dev/null @@ -1,103 +0,0 @@ -(* - * SPDX-FileCopyrightText: 2021 pukkamustard - * - * SPDX-License-Identifier: AGPL-3.0-or-later - *) - -(** {1 Leaflet} - - This module provides bindings to the Leaflet JavaScript library for - mobile-friendly interactive maps. - - See also the [Leaflet API reference](https://leafletjs.com/reference.html). *) -open Brr - -module LatLng : sig - type t - - val create : float -> float -> t - - val lat : t -> float - - val lng : t -> float - - val equals : t -> t -> bool -end - -module Ev : sig - module MouseEvent : sig - type t - - val latlng : t -> LatLng.t - end -end - -module Map : sig - type t - - val create : ?options:Jv.t -> string -> t - - val invalidate_size : t -> unit - - val set_view : LatLng.t -> ?zoom:int -> t -> unit - - val fit_world : t -> unit - - val get_container : t -> El.t - - val on : event:string -> handler:('a -> 'b) -> t -> unit - - val get_center : t -> LatLng.t - - val get_zoom : t -> int - - val wrapped_latlng : LatLng.t -> t -> LatLng.t - - (** {1 Events} **) - - val as_target : t -> Brr.Ev.target - - (** {2 Interaction events} **) - - val click : Ev.MouseEvent.t Brr.Ev.type' -end - -module TileLayer : sig - type t - - val create_osm : unit -> t - - val add_to : t -> Map.t -> unit -end - -module GeojsonLayer : sig - type t - - val create : ?options:Jv.t -> Jv.t -> t - - val add_to : t -> Map.t -> unit -end - -module Marker : sig - type t - - val create : LatLng.t -> t - - val add_to : t -> Map.t -> unit - - (** {2 Popup methods} *) - - val bind_popup : El.t -> t -> t - - val open_popup : t -> unit -end - -module Popup : sig - val set_latlng : LatLng.t -> unit - - val set_content : string -> unit - - val open_on : Map.t -> unit - - val close : Map.t -> unit -end diff --git a/src/map.ml b/src/map.ml new file mode 100644 index 0000000..3efedd7 --- /dev/null +++ b/src/map.ml @@ -0,0 +1,46 @@ +type t = Jv.t + +module Event = struct + let to_brr s = s |> Jstr.v |> Brr.Ev.Type.create + + let click = to_brr "click" + + let moveend = to_brr "moveend" + + let zoomend = to_brr "zoomend" +end + +let of_jv_t = Fun.id + +let to_jv_t = Fun.id + +let create ?(options = Jv.null) container_id = + Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] + +let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] + +let fit_world map = ignore @@ Jv.call map "fitWorld" [||] + +let get_container map = + Jv.call (to_jv_t map) "getContainer" [||] |> Brr.El.of_jv + +let set_view latlng ?zoom map = + let latlng = Latlng.to_jv_t latlng in + ignore + @@ + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] + +let as_target map = Brr.Ev.target_of_jv map + +let on ~event ~handler map = + let name = Brr.Ev.Type.name event |> Jv.of_jstr in + ignore @@ Jv.call map "on" [| name; Jv.repr handler |] + +let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] + +let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int + +let wrapped_latlng latlng map = + Latlng.of_jv_t @@ Jv.call map "wrapLatLng" [| Latlng.to_jv_t latlng |] diff --git a/src/map.mli b/src/map.mli new file mode 100644 index 0000000..c373001 --- /dev/null +++ b/src/map.mli @@ -0,0 +1,34 @@ +type t + +module Event : sig + (* TODO do this need to be wrapped in Brr.Ev.type' ?*) + val click : Ev.Mouse.t Brr.Ev.type' + + val moveend : Ev.Event.t Brr.Ev.type' + + val zoomend : Ev.Event.t Brr.Ev.type' +end + +val create : ?options:Jv.t -> string -> t + +val invalidate_size : t -> unit + +val set_view : Latlng.t -> ?zoom:int -> t -> unit + +val fit_world : t -> unit + +val get_container : t -> Brr.El.t + +val on : event:'a Brr.Ev.type' -> handler:('a -> 'b) -> t -> unit + +val get_center : t -> Latlng.t + +val get_zoom : t -> int + +val wrapped_latlng : Latlng.t -> t -> Latlng.t + +val as_target : t -> Brr.Ev.target + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml new file mode 100644 index 0000000..cfcd0b3 --- /dev/null +++ b/src/marker.ml @@ -0,0 +1,11 @@ +type t = Jv.t + +let create latlng = Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] + +let add_to marker map = ignore @@ Jv.call marker "addTo" [| Map.to_jv_t map |] + +let bind_popup el marker = + ignore @@ Jv.call marker "bindPopup" [| Brr.El.to_jv el |]; + marker + +let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] diff --git a/src/marker.mli b/src/marker.mli new file mode 100644 index 0000000..3bf1691 --- /dev/null +++ b/src/marker.mli @@ -0,0 +1,11 @@ +type t + +val create : Latlng.t -> t + +val add_to : t -> Map.t -> unit + +(** {2 Popup methods} *) + +val bind_popup : Brr.El.t -> t -> t + +val open_popup : t -> unit diff --git a/src/popup.ml b/src/popup.ml new file mode 100644 index 0000000..9a268db --- /dev/null +++ b/src/popup.ml @@ -0,0 +1,11 @@ +let popup = Jv.call Global.leaflet "popup" [||] + +let set_latlng latlng = + ignore @@ Jv.call popup "setLatLng" [| Latlng.to_jv_t latlng |] + +let set_content content = + ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + +let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] + +let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] diff --git a/src/popup.mli b/src/popup.mli new file mode 100644 index 0000000..cda85f6 --- /dev/null +++ b/src/popup.mli @@ -0,0 +1,7 @@ +val set_latlng : Latlng.t -> unit + +val set_content : string -> unit + +val open_on : Map.t -> unit + +val close : Map.t -> unit diff --git a/src/tile_layer.ml b/src/tile_layer.ml new file mode 100644 index 0000000..fe32d14 --- /dev/null +++ b/src/tile_layer.ml @@ -0,0 +1,16 @@ +type t = Jv.t + +let create_osm () = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + +let add_to tile_layer map = + ignore @@ Jv.call tile_layer "addTo" [| Map.to_jv_t map |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli new file mode 100644 index 0000000..afcd56e --- /dev/null +++ b/src/tile_layer.mli @@ -0,0 +1,5 @@ +type t + +val create_osm : unit -> t + +val add_to : t -> Map.t -> unit From 2004c6ff60d43ce13f90d7f1073fa11d90d2b6e4 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 15:24:25 +0200 Subject: [PATCH 55/99] change type' to type t --- src/ev.ml | 6 +++--- src/ev.mli | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ev.ml b/src/ev.ml index d4f9aad..911e749 100644 --- a/src/ev.ml +++ b/src/ev.ml @@ -1,12 +1,12 @@ -type type' = Jv.t +type t = Jv.t module Event = struct (*type for simple Event *) - type t = type' + type nonrec t = t end module Mouse = struct - type t = type' + type nonrec t = t let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" end diff --git a/src/ev.mli b/src/ev.mli index 0a93bcf..fffa63d 100644 --- a/src/ev.mli +++ b/src/ev.mli @@ -1,4 +1,4 @@ -type type' +type t module Event : sig type t From 795508ff8f5434cb2f3ee0f9935228fb27911ffd Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 17:58:01 +0200 Subject: [PATCH 56/99] add tile_url option --- src/tile_layer.ml | 9 +++++++-- src/tile_layer.mli | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tile_layer.ml b/src/tile_layer.ml index fe32d14..137eb64 100644 --- a/src/tile_layer.ml +++ b/src/tile_layer.ml @@ -1,8 +1,13 @@ type t = Jv.t -let create_osm () = +let create_osm ?tile_url () = + (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) + let tile_url = + Option.fold ~some:Fun.id + ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url + in Jv.call Global.leaflet "tileLayer" - [| Jv.of_string "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + [| Jv.of_string tile_url ; Jv.obj [| ( "attribution" , Jv.of_string diff --git a/src/tile_layer.mli b/src/tile_layer.mli index afcd56e..4fffaa2 100644 --- a/src/tile_layer.mli +++ b/src/tile_layer.mli @@ -1,5 +1,5 @@ type t -val create_osm : unit -> t +val create_osm : ?tile_url:string -> unit -> t val add_to : t -> Map.t -> unit From e99015e3350582867e2d6d14efcc30d8278f1546 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 7 Apr 2022 19:04:33 +0200 Subject: [PATCH 57/99] better Ev --- src/ev.ml | 33 +++++++++++++++++++++++------- src/ev.mli | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/ev.ml b/src/ev.ml index 911e749..7823351 100644 --- a/src/ev.ml +++ b/src/ev.ml @@ -1,12 +1,31 @@ -type t = Jv.t +module Make () = struct + type t = Jv.t -module Event = struct - (*type for simple Event *) - type nonrec t = t -end + let type' e = Jv.get e "type" |> Jv.to_string -module Mouse = struct - type nonrec t = t + let target e = Jv.get e "target" |> Brr.Ev.target_of_jv + + let source_target e = Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv + + let propagated_from e = Jv.get e "propagatedFrom" let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" + + let layer_point e = Jv.get e "layerPoint" + + let container_point e = Jv.get e "containerPoint" + + let original_event e = Jv.get e "originalEvent" + + let message e = Jv.get e "message" |> Jv.to_string + + let code e = Jv.get e "code" |> Jv.to_int end + +module Event = Make () + +module Keyboard = Make () + +module Mouse = Make () + +module Error = Make () diff --git a/src/ev.mli b/src/ev.mli index fffa63d..520b5ff 100644 --- a/src/ev.mli +++ b/src/ev.mli @@ -1,11 +1,66 @@ -type t - module Event : sig type t + + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + (* TODO this should return Point *) + val propagated_from : t -> Jv.t +end + +module Keyboard : sig + type t + + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + val propagated_from : t -> Jv.t + + (* TODO this should return BrrDomEvent*) + val original_event : t -> Jv.t end module Mouse : sig type t + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + val propagated_from : t -> Jv.t + val latlng : t -> Latlng.t + + (* TODO this should return Point *) + val layer_point : t -> Jv.t + + (* TODO this should return Point *) + val container_point : t -> Jv.t + + (* TODO this should return BrrDomEvent*) + val original_event : t -> Jv.t +end + +module Error : sig + type t + + val type' : t -> string + + val target : t -> Brr.Ev.target + + val source_target : t -> Brr.Ev.target + + val propagated_from : t -> Jv.t + + val message : t -> string + + val code : t -> int end From 6e1ac0d96dbb2648760179a33a4ab79c4cc628c8 Mon Sep 17 00:00:00 2001 From: Swrup Date: Fri, 8 Apr 2022 13:21:20 +0200 Subject: [PATCH 58/99] add layer --- src/dune | 2 +- src/geojson_layer.ml | 7 ++----- src/geojson_layer.mli | 20 +++++++++++++++++++- src/layer.ml | 23 +++++++++++++++++++++++ src/layer.mli | 21 +++++++++++++++++++++ src/marker.ml | 13 +++---------- src/marker.mli | 18 +++++++++++++++--- src/popup.ml | 4 ++++ src/popup.mli | 4 ++++ src/tile_layer.ml | 26 ++++++++++++-------------- src/tile_layer.mli | 20 +++++++++++++++++++- 11 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 src/layer.ml create mode 100644 src/layer.mli diff --git a/src/dune b/src/dune index e7f3daf..8f28969 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,7 @@ (library (name leaflet) (public_name leaflet) - (modules ev latlng geojson_layer tile_layer popup marker map global) + (modules ev latlng geojson_layer tile_layer popup marker map global layer) (libraries brr js_of_ocaml) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml index 66ed14a..c5c113d 100644 --- a/src/geojson_layer.ml +++ b/src/geojson_layer.ml @@ -1,7 +1,4 @@ -(*TODO merge with TileLayer*) -type t = Jv.t +include Layer let create ?(options = Jv.null) geojson = - Jv.call Global.leaflet "geoJSON" [| geojson; options |] - -let add_to layer map = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] + of_jv_t @@ Jv.call Global.leaflet "geoJSON" [| geojson; options |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli index 12bb980..e8c4660 100644 --- a/src/geojson_layer.mli +++ b/src/geojson_layer.mli @@ -2,4 +2,22 @@ type t val create : ?options:Jv.t -> Jv.t -> t -val add_to : t -> Map.t -> unit +val add_to : Map.t -> t -> unit + +val remove : t -> unit + +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit + +val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml new file mode 100644 index 0000000..d0c8b62 --- /dev/null +++ b/src/layer.ml @@ -0,0 +1,23 @@ +type t = Jv.t + +let add_to map layer = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] + +let remove layer = ignore @@ Jv.call layer "remove" [||] + +let remove_from map layer = + ignore @@ Jv.call layer "removeFrom" [| Map.to_jv_t map |] + +let bind_popup el layer = + ignore @@ Jv.call layer "bindPopup" [| Brr.El.to_jv el |] + +let unbind_popup layer = ignore @@ Jv.call layer "unbindPopup" [||] + +let open_popup layer = ignore @@ Jv.call layer "openPopup" [||] + +let close_popup layer = ignore @@ Jv.call layer "closePopup" [||] + +let get_popup layer = Popup.of_jv_t @@ Jv.call layer "getPopup" [||] + +let of_jv_t = Fun.id + +let to_jv_t = Fun.id diff --git a/src/layer.mli b/src/layer.mli new file mode 100644 index 0000000..98fe10c --- /dev/null +++ b/src/layer.mli @@ -0,0 +1,21 @@ +type t + +val add_to : Map.t -> t -> unit + +val remove : t -> unit + +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit + +val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml index cfcd0b3..44925a1 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -1,11 +1,4 @@ -type t = Jv.t +include Layer -let create latlng = Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] - -let add_to marker map = ignore @@ Jv.call marker "addTo" [| Map.to_jv_t map |] - -let bind_popup el marker = - ignore @@ Jv.call marker "bindPopup" [| Brr.El.to_jv el |]; - marker - -let open_popup marker = ignore @@ Jv.call marker "openPopup" [||] +let create latlng = + of_jv_t @@ Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] diff --git a/src/marker.mli b/src/marker.mli index 3bf1691..ab77fc5 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -2,10 +2,22 @@ type t val create : Latlng.t -> t -val add_to : t -> Map.t -> unit +val add_to : Map.t -> t -> unit -(** {2 Popup methods} *) +val remove : t -> unit -val bind_popup : Brr.El.t -> t -> t +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t diff --git a/src/popup.ml b/src/popup.ml index 9a268db..bc0febf 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -1,3 +1,5 @@ +type t = Jv.t + let popup = Jv.call Global.leaflet "popup" [||] let set_latlng latlng = @@ -9,3 +11,5 @@ let set_content content = let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] + +let of_jv_t = Fun.id diff --git a/src/popup.mli b/src/popup.mli index cda85f6..5ca939b 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -1,3 +1,5 @@ +type t + val set_latlng : Latlng.t -> unit val set_content : string -> unit @@ -5,3 +7,5 @@ val set_content : string -> unit val open_on : Map.t -> unit val close : Map.t -> unit + +val of_jv_t : Jv.t -> t diff --git a/src/tile_layer.ml b/src/tile_layer.ml index 137eb64..1dae48c 100644 --- a/src/tile_layer.ml +++ b/src/tile_layer.ml @@ -1,4 +1,4 @@ -type t = Jv.t +include Layer let create_osm ?tile_url () = (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) @@ -6,16 +6,14 @@ let create_osm ?tile_url () = Option.fold ~some:Fun.id ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url in - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string tile_url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - -let add_to tile_layer map = - ignore @@ Jv.call tile_layer "addTo" [| Map.to_jv_t map |] + of_jv_t + @@ Jv.call Global.leaflet "tileLayer" + [| Jv.of_string tile_url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli index 4fffaa2..b1834b5 100644 --- a/src/tile_layer.mli +++ b/src/tile_layer.mli @@ -2,4 +2,22 @@ type t val create_osm : ?tile_url:string -> unit -> t -val add_to : t -> Map.t -> unit +val add_to : Map.t -> t -> unit + +val remove : t -> unit + +val remove_from : Map.t -> t -> unit + +val bind_popup : Brr.El.t -> t -> unit + +val unbind_popup : t -> unit + +val open_popup : t -> unit + +val close_popup : t -> unit + +val get_popup : t -> Popup.t + +val of_jv_t : Jv.t -> t + +val to_jv_t : t -> Jv.t From 9e66f26b71da0a76817503616834ec226e9aea6f Mon Sep 17 00:00:00 2001 From: pena Date: Fri, 8 Apr 2022 22:43:31 +0200 Subject: [PATCH 59/99] use gadts for event, clean repo --- src/dune | 14 +++++++-- src/ev.ml | 31 -------------------- src/ev.mli | 66 ------------------------------------------ src/event.ml | 59 +++++++++++++++++++++++++++++++++++++ src/event.mli | 42 +++++++++++++++++++++++++++ src/leaflet.js.license | 3 -- src/map.ml | 18 ++++-------- src/map.mli | 11 +------ 8 files changed, 118 insertions(+), 126 deletions(-) delete mode 100644 src/ev.ml delete mode 100644 src/ev.mli create mode 100644 src/event.ml create mode 100644 src/event.mli delete mode 100644 src/leaflet.js.license diff --git a/src/dune b/src/dune index 8f28969..bce2f76 100644 --- a/src/dune +++ b/src/dune @@ -1,7 +1,15 @@ (library - (name leaflet) (public_name leaflet) - (modules ev latlng geojson_layer tile_layer popup marker map global layer) - (libraries brr js_of_ocaml) + (modules + event + geojson_layer + global + latlng + layer + map + marker + popup + tile_layer) + (libraries brr) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/ev.ml b/src/ev.ml deleted file mode 100644 index 7823351..0000000 --- a/src/ev.ml +++ /dev/null @@ -1,31 +0,0 @@ -module Make () = struct - type t = Jv.t - - let type' e = Jv.get e "type" |> Jv.to_string - - let target e = Jv.get e "target" |> Brr.Ev.target_of_jv - - let source_target e = Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv - - let propagated_from e = Jv.get e "propagatedFrom" - - let latlng e = Latlng.of_jv_t @@ Jv.get e "latlng" - - let layer_point e = Jv.get e "layerPoint" - - let container_point e = Jv.get e "containerPoint" - - let original_event e = Jv.get e "originalEvent" - - let message e = Jv.get e "message" |> Jv.to_string - - let code e = Jv.get e "code" |> Jv.to_int -end - -module Event = Make () - -module Keyboard = Make () - -module Mouse = Make () - -module Error = Make () diff --git a/src/ev.mli b/src/ev.mli deleted file mode 100644 index 520b5ff..0000000 --- a/src/ev.mli +++ /dev/null @@ -1,66 +0,0 @@ -module Event : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - (* TODO this should return Point *) - val propagated_from : t -> Jv.t -end - -module Keyboard : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - (* TODO this should return BrrDomEvent*) - val original_event : t -> Jv.t -end - -module Mouse : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - val latlng : t -> Latlng.t - - (* TODO this should return Point *) - val layer_point : t -> Jv.t - - (* TODO this should return Point *) - val container_point : t -> Jv.t - - (* TODO this should return BrrDomEvent*) - val original_event : t -> Jv.t -end - -module Error : sig - type t - - val type' : t -> string - - val target : t -> Brr.Ev.target - - val source_target : t -> Brr.Ev.target - - val propagated_from : t -> Jv.t - - val message : t -> string - - val code : t -> int -end diff --git a/src/event.ml b/src/event.ml new file mode 100644 index 0000000..491f322 --- /dev/null +++ b/src/event.ml @@ -0,0 +1,59 @@ +type _ t = + | Keyboard : Jv.t -> [> `Keyboard ] t + | Mouse : Jv.t -> [> `Mouse ] t + | Error : Jv.t -> [> `Error ] t + | Basic : Jv.t -> [> `Basic ] t + +type _ sub = + | Click : [> `Mouse ] sub + | Move_end : [> `Basic ] sub + | Zoom_end : [> `Basic ] sub + +let of_jv_t : type kind. kind sub -> Jv.t -> kind t = + fun tag e -> + match tag with Click -> Mouse e | Move_end -> Basic e | Zoom_end -> Basic e + +let sub_to_string : type kind. kind sub -> string = function + | Click -> "click" + | Move_end -> "moveend" + | Zoom_end -> "zoomend" + +(** Basic events *) + +let get_type : type kind. kind t -> string = function + | Keyboard e | Mouse e | Error e | Basic e -> Jv.get e "type" |> Jv.to_string + +let target : type kind. kind t -> Brr.Ev.target = function + | Keyboard e | Mouse e | Error e | Basic e -> + Jv.get e "target" |> Brr.Ev.target_of_jv + +let source_target : type kind. kind t -> Brr.Ev.target = function + | Keyboard e | Mouse e | Error e | Basic e -> + Jv.get e "sourceTarget" |> Brr.Ev.target_of_jv + +let propagated_from : type kind. kind t -> Jv.t = function + | Keyboard e | Mouse e | Error e | Basic e -> Jv.get e "propagatedFrom" + +(** Keyboard & Mouse events *) + +let original_event : [ `Keyboard | `Mouse ] t -> Jv.t = function + | Keyboard e | Mouse e -> Jv.get e "originalEvent" + +(** Mouse events *) + +let container_point : [ `Mouse ] t -> Jv.t = function + | Mouse e -> Jv.get e "containerPoint" + +let layer_point : [ `Mouse ] t -> Jv.t = function + | Mouse e -> Jv.get e "layerPoint" + +let latlng : [ `Mouse ] t -> Latlng.t = function + | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv_t + +(** Error events *) + +let code : [ `Error ] t -> int = function + | Error e -> Jv.get e "code" |> Jv.to_int + +let message : [ `Error ] t -> string = function + | Error e -> Jv.get e "message" |> Jv.to_string diff --git a/src/event.mli b/src/event.mli new file mode 100644 index 0000000..bf4f2d7 --- /dev/null +++ b/src/event.mli @@ -0,0 +1,42 @@ +type _ t = + | Keyboard : Jv.t -> [> `Keyboard ] t + | Mouse : Jv.t -> [> `Mouse ] t + | Error : Jv.t -> [> `Error ] t + | Basic : Jv.t -> [> `Basic ] t + +type _ sub = + | Click : [> `Mouse ] sub + | Move_end : [> `Basic ] sub + | Zoom_end : [> `Basic ] sub + +val of_jv_t : 'a sub -> Jv.t -> 'a t + +val sub_to_string : _ sub -> string + +(** Basic events *) + +val get_type : _ t -> string + +val target : _ t -> Brr.Ev.target + +val source_target : _ t -> Brr.Ev.target + +val propagated_from : _ t -> Jv.t + +(** Keyboard & Mouse events *) + +val original_event : [ `Keyboard | `Mouse ] t -> Jv.t + +(** Mouse events *) + +val container_point : [ `Mouse ] t -> Jv.t + +val layer_point : [ `Mouse ] t -> Jv.t + +val latlng : [ `Mouse ] t -> Latlng.t + +(** Error events *) + +val code : [ `Error ] t -> int + +val message : [ `Error ] t -> string diff --git a/src/leaflet.js.license b/src/leaflet.js.license deleted file mode 100644 index 8f54aad..0000000 --- a/src/leaflet.js.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2010-2021 Vladimir Agafonkin - -SPDX-License-Identifier: BSD-2-Clause \ No newline at end of file diff --git a/src/map.ml b/src/map.ml index 3efedd7..e070351 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,15 +1,5 @@ type t = Jv.t -module Event = struct - let to_brr s = s |> Jstr.v |> Brr.Ev.Type.create - - let click = to_brr "click" - - let moveend = to_brr "moveend" - - let zoomend = to_brr "zoomend" -end - let of_jv_t = Fun.id let to_jv_t = Fun.id @@ -34,9 +24,11 @@ let set_view latlng ?zoom map = let as_target map = Brr.Ev.target_of_jv map -let on ~event ~handler map = - let name = Brr.Ev.Type.name event |> Jv.of_jstr in - ignore @@ Jv.call map "on" [| name; Jv.repr handler |] +let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = + fun event handler map -> + let name = Event.sub_to_string event in + let handler v = handler @@ Event.of_jv_t event v in + ignore @@ Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] diff --git a/src/map.mli b/src/map.mli index c373001..fdbd710 100644 --- a/src/map.mli +++ b/src/map.mli @@ -1,14 +1,5 @@ type t -module Event : sig - (* TODO do this need to be wrapped in Brr.Ev.type' ?*) - val click : Ev.Mouse.t Brr.Ev.type' - - val moveend : Ev.Event.t Brr.Ev.type' - - val zoomend : Ev.Event.t Brr.Ev.type' -end - val create : ?options:Jv.t -> string -> t val invalidate_size : t -> unit @@ -19,7 +10,7 @@ val fit_world : t -> unit val get_container : t -> Brr.El.t -val on : event:'a Brr.Ev.type' -> handler:('a -> 'b) -> t -> unit +val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit val get_center : t -> Latlng.t From 9db5cdfd226c45e3833d8ed94877f4cb94275b4f Mon Sep 17 00:00:00 2001 From: pena Date: Sat, 9 Apr 2022 22:21:22 +0200 Subject: [PATCH 60/99] use gadts for layer, clean code --- src/dune | 12 +----- src/event.ml | 4 +- src/event.mli | 2 +- src/geojson_layer.ml | 4 -- src/geojson_layer.mli | 23 ----------- src/latlng.ml | 4 +- src/latlng.mli | 4 +- src/layer.ml | 92 +++++++++++++++++++++++++++++++++++++------ src/layer.mli | 38 ++++++++++++------ src/map.ml | 39 ++++++++++-------- src/map.mli | 6 +-- src/marker.ml | 4 -- src/marker.mli | 23 ----------- src/popup.ml | 16 +++++--- src/popup.mli | 2 +- src/tile_layer.ml | 19 --------- src/tile_layer.mli | 23 ----------- 17 files changed, 152 insertions(+), 163 deletions(-) delete mode 100644 src/geojson_layer.ml delete mode 100644 src/geojson_layer.mli delete mode 100644 src/marker.ml delete mode 100644 src/marker.mli delete mode 100644 src/tile_layer.ml delete mode 100644 src/tile_layer.mli diff --git a/src/dune b/src/dune index bce2f76..ed4515f 100644 --- a/src/dune +++ b/src/dune @@ -1,15 +1,7 @@ (library (public_name leaflet) - (modules - event - geojson_layer - global - latlng - layer - map - marker - popup - tile_layer) + (modules event global latlng layer map popup) + (private_modules global) (libraries brr) (js_of_ocaml (javascript_files leaflet.js))) diff --git a/src/event.ml b/src/event.ml index 491f322..6b456d2 100644 --- a/src/event.ml +++ b/src/event.ml @@ -9,7 +9,7 @@ type _ sub = | Move_end : [> `Basic ] sub | Zoom_end : [> `Basic ] sub -let of_jv_t : type kind. kind sub -> Jv.t -> kind t = +let of_jv : type kind. kind sub -> Jv.t -> kind t = fun tag e -> match tag with Click -> Mouse e | Move_end -> Basic e | Zoom_end -> Basic e @@ -48,7 +48,7 @@ let layer_point : [ `Mouse ] t -> Jv.t = function | Mouse e -> Jv.get e "layerPoint" let latlng : [ `Mouse ] t -> Latlng.t = function - | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv_t + | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv (** Error events *) diff --git a/src/event.mli b/src/event.mli index bf4f2d7..9592bfb 100644 --- a/src/event.mli +++ b/src/event.mli @@ -9,7 +9,7 @@ type _ sub = | Move_end : [> `Basic ] sub | Zoom_end : [> `Basic ] sub -val of_jv_t : 'a sub -> Jv.t -> 'a t +val of_jv : 'a sub -> Jv.t -> 'a t val sub_to_string : _ sub -> string diff --git a/src/geojson_layer.ml b/src/geojson_layer.ml deleted file mode 100644 index c5c113d..0000000 --- a/src/geojson_layer.ml +++ /dev/null @@ -1,4 +0,0 @@ -include Layer - -let create ?(options = Jv.null) geojson = - of_jv_t @@ Jv.call Global.leaflet "geoJSON" [| geojson; options |] diff --git a/src/geojson_layer.mli b/src/geojson_layer.mli deleted file mode 100644 index e8c4660..0000000 --- a/src/geojson_layer.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create : ?options:Jv.t -> Jv.t -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t diff --git a/src/latlng.ml b/src/latlng.ml index d2b4dbc..6611746 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -9,6 +9,6 @@ let lng latlng = Jv.get latlng "lng" |> Jv.to_float let equals a b = Jv.call a "equals" [| b |] |> Jv.to_bool -let of_jv_t = Fun.id +let of_jv = Fun.id -let to_jv_t = Fun.id +let to_jv = Fun.id diff --git a/src/latlng.mli b/src/latlng.mli index fb793ae..c63a970 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -8,6 +8,6 @@ val lng : t -> float val equals : t -> t -> bool -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t -val to_jv_t : t -> Jv.t +val to_jv : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml index d0c8b62..fd9b07a 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -1,23 +1,89 @@ -type t = Jv.t +type _ t = + | Basic : Jv.t -> [> `Basic ] t + | Geojson : Jv.t -> [> `Geojson ] t + | Marker : Jv.t -> [> `Marker ] t + | Tile : Jv.t -> [> `Tile ] t -let add_to map layer = ignore @@ Jv.call layer "addTo" [| Map.to_jv_t map |] +(** Basic layers *) -let remove layer = ignore @@ Jv.call layer "remove" [||] +let add_to : type kind. Map.t -> kind t -> unit = + fun map -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "addTo" [| Map.to_jv map |] in + () -let remove_from map layer = - ignore @@ Jv.call layer "removeFrom" [| Map.to_jv_t map |] +let remove : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "remove" [||] in + () -let bind_popup el layer = - ignore @@ Jv.call layer "bindPopup" [| Brr.El.to_jv el |] +let remove_from : type kind. Map.t -> kind t -> unit = + fun map -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in + () -let unbind_popup layer = ignore @@ Jv.call layer "unbindPopup" [||] +let bind_popup : type kind. Brr.El.t -> kind t -> unit = + fun el -> function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el |] in + () -let open_popup layer = ignore @@ Jv.call layer "openPopup" [||] +let unbind_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "unbindPopup" [||] in + () -let close_popup layer = ignore @@ Jv.call layer "closePopup" [||] +let open_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "openPopup" [||] in + () -let get_popup layer = Popup.of_jv_t @@ Jv.call layer "getPopup" [||] +let close_popup : type kind. kind t -> unit = function + | Basic l | Geojson l | Marker l | Tile l -> + let (_ : Jv.t) = Jv.call l "closePopup" [||] in + () -let of_jv_t = Fun.id +let get_popup : type kind. kind t -> Popup.t = function + | Basic l | Geojson l | Marker l | Tile l -> + Jv.call l "getPopup" [||] |> Popup.of_jv -let to_jv_t = Fun.id +let to_jv : type kind. kind t -> Jv.t = function + | Basic l | Geojson l | Marker l | Tile l -> l + +(** Geojson layers *) + +let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = + fun ?(options = Jv.null) geojson -> + let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; options |] in + Geojson jv_t + +(** Marker layers *) + +let create_marker : Latlng.t -> [ `Marker ] t = + fun latlng -> + let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng |] in + Marker jv_t + +(** Tile layers *) + +let create_tile_osm : string option -> [ `Tile ] t = + fun url -> + (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) + let url = + Option.value url + ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + in + let jv_t = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + in + Tile jv_t diff --git a/src/layer.mli b/src/layer.mli index 98fe10c..0baf3fd 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -1,21 +1,37 @@ -type t +type _ t = + | Basic : Jv.t -> [> `Basic ] t + | Geojson : Jv.t -> [> `Geojson ] t + | Marker : Jv.t -> [> `Marker ] t + | Tile : Jv.t -> [> `Tile ] t -val add_to : Map.t -> t -> unit +(** Basic layers *) -val remove : t -> unit +val add_to : Map.t -> _ t -> unit -val remove_from : Map.t -> t -> unit +val remove : _ t -> unit -val bind_popup : Brr.El.t -> t -> unit +val remove_from : Map.t -> _ t -> unit -val unbind_popup : t -> unit +val bind_popup : Brr.El.t -> _ t -> unit -val open_popup : t -> unit +val unbind_popup : _ t -> unit -val close_popup : t -> unit +val open_popup : _ t -> unit -val get_popup : t -> Popup.t +val close_popup : _ t -> unit -val of_jv_t : Jv.t -> t +val get_popup : _ t -> Popup.t -val to_jv_t : t -> Jv.t +val to_jv : _ t -> Jv.t + +(** Geojson layers *) + +val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t + +(** Marker layers *) + +val create_marker : Latlng.t -> [ `Marker ] t + +(** Tile layers *) + +val create_tile_osm : string option -> [ `Tile ] t diff --git a/src/map.ml b/src/map.ml index e070351..57598f4 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,38 +1,43 @@ type t = Jv.t -let of_jv_t = Fun.id +let of_jv = Fun.id -let to_jv_t = Fun.id +let to_jv = Fun.id let create ?(options = Jv.null) container_id = Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] -let invalidate_size map = ignore @@ Jv.call map "invalidateSize" [| Jv.true' |] +let invalidate_size map = + let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in + () -let fit_world map = ignore @@ Jv.call map "fitWorld" [||] +let fit_world map = + let (_ : Jv.t) = Jv.call map "fitWorld" [||] in + () -let get_container map = - Jv.call (to_jv_t map) "getContainer" [||] |> Brr.El.of_jv +let get_container map = Jv.call (to_jv map) "getContainer" [||] |> Brr.El.of_jv -let set_view latlng ?zoom map = - let latlng = Latlng.to_jv_t latlng in - ignore - @@ - match zoom with - | None -> Jv.call map "setView" [| latlng |] - | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] +let set_view latlng ~zoom map = + let latlng = Latlng.to_jv latlng in + let (_ : Jv.t) = + match zoom with + | None -> Jv.call map "setView" [| latlng |] + | Some zoom -> Jv.call map "setView" [| latlng; Jv.of_int zoom |] + in + () let as_target map = Brr.Ev.target_of_jv map let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in - let handler v = handler @@ Event.of_jv_t event v in - ignore @@ Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] + let handler v = handler @@ Event.of_jv event v in + let (_ : Jv.t) = Jv.call map "on" [| Jv.of_string name; Jv.repr handler |] in + () -let get_center map = Latlng.of_jv_t @@ Jv.call map "getCenter" [||] +let get_center map = Latlng.of_jv @@ Jv.call map "getCenter" [||] let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int let wrapped_latlng latlng map = - Latlng.of_jv_t @@ Jv.call map "wrapLatLng" [| Latlng.to_jv_t latlng |] + Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] diff --git a/src/map.mli b/src/map.mli index fdbd710..f4f6f2b 100644 --- a/src/map.mli +++ b/src/map.mli @@ -4,7 +4,7 @@ val create : ?options:Jv.t -> string -> t val invalidate_size : t -> unit -val set_view : Latlng.t -> ?zoom:int -> t -> unit +val set_view : Latlng.t -> zoom:int option -> t -> unit val fit_world : t -> unit @@ -20,6 +20,6 @@ val wrapped_latlng : Latlng.t -> t -> Latlng.t val as_target : t -> Brr.Ev.target -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t -val to_jv_t : t -> Jv.t +val to_jv : t -> Jv.t diff --git a/src/marker.ml b/src/marker.ml deleted file mode 100644 index 44925a1..0000000 --- a/src/marker.ml +++ /dev/null @@ -1,4 +0,0 @@ -include Layer - -let create latlng = - of_jv_t @@ Jv.call Global.leaflet "marker" [| Latlng.to_jv_t latlng |] diff --git a/src/marker.mli b/src/marker.mli deleted file mode 100644 index ab77fc5..0000000 --- a/src/marker.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create : Latlng.t -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t diff --git a/src/popup.ml b/src/popup.ml index bc0febf..fb0264c 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -3,13 +3,19 @@ type t = Jv.t let popup = Jv.call Global.leaflet "popup" [||] let set_latlng latlng = - ignore @@ Jv.call popup "setLatLng" [| Latlng.to_jv_t latlng |] + let (_ : Jv.t) = Jv.call popup "setLatLng" [| Latlng.to_jv latlng |] in + () let set_content content = - ignore @@ Jv.call popup "setContent" [| Jv.of_string content |] + let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in + () -let open_on map = ignore @@ Jv.call popup "openOn" [| Map.to_jv_t map |] +let open_on map = + let (_ : Jv.t) = Jv.call popup "openOn" [| Map.to_jv map |] in + () -let close map = ignore @@ Jv.call (Map.to_jv_t map) "closePopup" [||] +let close map = + let (_ : Jv.t) = Jv.call (Map.to_jv map) "closePopup" [||] in + () -let of_jv_t = Fun.id +let of_jv = Fun.id diff --git a/src/popup.mli b/src/popup.mli index 5ca939b..65e5dfc 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -8,4 +8,4 @@ val open_on : Map.t -> unit val close : Map.t -> unit -val of_jv_t : Jv.t -> t +val of_jv : Jv.t -> t diff --git a/src/tile_layer.ml b/src/tile_layer.ml deleted file mode 100644 index 1dae48c..0000000 --- a/src/tile_layer.ml +++ /dev/null @@ -1,19 +0,0 @@ -include Layer - -let create_osm ?tile_url () = - (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) - let tile_url = - Option.fold ~some:Fun.id - ~none:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" tile_url - in - of_jv_t - @@ Jv.call Global.leaflet "tileLayer" - [| Jv.of_string tile_url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] diff --git a/src/tile_layer.mli b/src/tile_layer.mli deleted file mode 100644 index b1834b5..0000000 --- a/src/tile_layer.mli +++ /dev/null @@ -1,23 +0,0 @@ -type t - -val create_osm : ?tile_url:string -> unit -> t - -val add_to : Map.t -> t -> unit - -val remove : t -> unit - -val remove_from : Map.t -> t -> unit - -val bind_popup : Brr.El.t -> t -> unit - -val unbind_popup : t -> unit - -val open_popup : t -> unit - -val close_popup : t -> unit - -val get_popup : t -> Popup.t - -val of_jv_t : Jv.t -> t - -val to_jv_t : t -> Jv.t From e7e40c3ce9b75965c21419ff7036822c5ba79b9e Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 12 Apr 2022 13:46:37 +0200 Subject: [PATCH 61/99] license --- LICENSE.md | 11 ++++++----- README.md | 7 +++++-- src/event.ml | 2 ++ src/event.mli | 2 ++ src/global.ml | 2 ++ src/latlng.ml | 2 ++ src/latlng.mli | 2 ++ src/layer.ml | 2 ++ src/layer.mli | 2 ++ src/map.ml | 2 ++ src/map.mli | 2 ++ src/popup.ml | 2 ++ src/popup.mli | 2 ++ 13 files changed, 33 insertions(+), 7 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index c0fd71b..5a2b10a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,8 +1,9 @@ -The ISC License (ISC) -===================== +Copyright 2022 pukkamustard , swrup , pena -Copyright © 2022, TODO +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index e628def..4c297f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # leaflet -[leaflet] is an [OCaml] executable/library to TODO. +`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library. ## Installation @@ -24,6 +24,8 @@ For more, have a look at the [example] folder, at the [documentation] or at the ## About +leaflet's original code was taken from a [NGI0 funded project] + - [LICENSE] - [CHANGELOG] @@ -37,4 +39,5 @@ For more, have a look at the [example] folder, at the [documentation] or at the [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ -[leaflet]: TODO/leaflet +[Leaflet]: https://leafletjs.com/ +[NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ diff --git a/src/event.ml b/src/event.ml index 6b456d2..2b39417 100644 --- a/src/event.ml +++ b/src/event.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Keyboard : Jv.t -> [> `Keyboard ] t | Mouse : Jv.t -> [> `Mouse ] t diff --git a/src/event.mli b/src/event.mli index 9592bfb..8723a09 100644 --- a/src/event.mli +++ b/src/event.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Keyboard : Jv.t -> [> `Keyboard ] t | Mouse : Jv.t -> [> `Mouse ] t diff --git a/src/global.ml b/src/global.ml index c209f3d..a4ebdfa 100644 --- a/src/global.ml +++ b/src/global.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + let leaflet = match Jv.(find global "L") with | Some l -> l diff --git a/src/latlng.ml b/src/latlng.ml index 6611746..400200b 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let create lat lng = diff --git a/src/latlng.mli b/src/latlng.mli index c63a970..9097890 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val create : float -> float -> t diff --git a/src/layer.ml b/src/layer.ml index fd9b07a..9808ebb 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Basic : Jv.t -> [> `Basic ] t | Geojson : Jv.t -> [> `Geojson ] t diff --git a/src/layer.mli b/src/layer.mli index 0baf3fd..b3816e6 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type _ t = | Basic : Jv.t -> [> `Basic ] t | Geojson : Jv.t -> [> `Geojson ] t diff --git a/src/map.ml b/src/map.ml index 57598f4..259efeb 100644 --- a/src/map.ml +++ b/src/map.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let of_jv = Fun.id diff --git a/src/map.mli b/src/map.mli index f4f6f2b..96795cb 100644 --- a/src/map.mli +++ b/src/map.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val create : ?options:Jv.t -> string -> t diff --git a/src/popup.ml b/src/popup.ml index fb0264c..5447cd4 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t = Jv.t let popup = Jv.call Global.leaflet "popup" [||] diff --git a/src/popup.mli b/src/popup.mli index 65e5dfc..ee5df35 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -1,3 +1,5 @@ +(* BSD-2-Clause License *) + type t val set_latlng : Latlng.t -> unit From 47c442f84bdeefdffe74d350461268e29f9b3304 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 12 Apr 2022 15:26:49 +0200 Subject: [PATCH 62/99] add point --- src/dune | 2 +- src/event.ml | 8 ++++---- src/event.mli | 4 ++-- src/point.ml | 11 +++++++++++ src/point.mli | 9 +++++++++ 5 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 src/point.ml create mode 100644 src/point.mli diff --git a/src/dune b/src/dune index ed4515f..4e2d45f 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup) + (modules event global latlng layer map popup point) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/event.ml b/src/event.ml index 2b39417..2b9cb77 100644 --- a/src/event.ml +++ b/src/event.ml @@ -43,11 +43,11 @@ let original_event : [ `Keyboard | `Mouse ] t -> Jv.t = function (** Mouse events *) -let container_point : [ `Mouse ] t -> Jv.t = function - | Mouse e -> Jv.get e "containerPoint" +let container_point : [ `Mouse ] t -> Point.t = function + | Mouse e -> Jv.get e "containerPoint" |> Point.of_jv -let layer_point : [ `Mouse ] t -> Jv.t = function - | Mouse e -> Jv.get e "layerPoint" +let layer_point : [ `Mouse ] t -> Point.t = function + | Mouse e -> Jv.get e "layerPoint" |> Point.of_jv let latlng : [ `Mouse ] t -> Latlng.t = function | Mouse e -> Jv.get e "latlng" |> Latlng.of_jv diff --git a/src/event.mli b/src/event.mli index 8723a09..5793744 100644 --- a/src/event.mli +++ b/src/event.mli @@ -31,9 +31,9 @@ val original_event : [ `Keyboard | `Mouse ] t -> Jv.t (** Mouse events *) -val container_point : [ `Mouse ] t -> Jv.t +val container_point : [ `Mouse ] t -> Point.t -val layer_point : [ `Mouse ] t -> Jv.t +val layer_point : [ `Mouse ] t -> Point.t val latlng : [ `Mouse ] t -> Latlng.t diff --git a/src/point.ml b/src/point.ml new file mode 100644 index 0000000..0191894 --- /dev/null +++ b/src/point.ml @@ -0,0 +1,11 @@ +(* BSD-2-Clause License *) + +type t = + { x : int + ; y : int + } + +let of_jv point = + let x = Jv.get point "x" |> Jv.to_int in + let y = Jv.get point "y" |> Jv.to_int in + { x; y } diff --git a/src/point.mli b/src/point.mli new file mode 100644 index 0000000..2ca4de2 --- /dev/null +++ b/src/point.mli @@ -0,0 +1,9 @@ +(* BSD-2-Clause License *) + +type t = + { x : int + ; y : int + } + +(** [of_jv jv] is [jv] as {!t} *) +val of_jv : Jv.t -> t From 2a126d08224cb9f2b108226e2c9bb55d6366edb9 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 15:46:43 +0200 Subject: [PATCH 63/99] add example --- example/dune | 6 +- example/leaflet.css | 640 ++++++++++++++++++++++++++++++++++++++++++++ example/main.ml | 15 +- example/map.html | 12 + 4 files changed, 671 insertions(+), 2 deletions(-) create mode 100644 example/leaflet.css create mode 100644 example/map.html diff --git a/example/dune b/example/dune index e36b142..80423a9 100644 --- a/example/dune +++ b/example/dune @@ -1,3 +1,7 @@ (executable (name main) - (modules main)) + (modules main) + (libraries leaflet) + (modes js) + (preprocess + (pps js_of_ocaml-ppx))) diff --git a/example/leaflet.css b/example/leaflet.css new file mode 100644 index 0000000..3385b5e --- /dev/null +++ b/example/leaflet.css @@ -0,0 +1,640 @@ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg, +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + } + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-tile { + will-change: opacity; + } +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + will-change: transform; + } +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline: 0; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-container a.leaflet-active { + outline: 2px solid orange; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a, +.leaflet-bar a:hover { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(/assets/img/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(/assets/img/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { + background-image: url(/assets/img/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.7); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover { + text-decoration: underline; + } +.leaflet-container .leaflet-control-attribution, +.leaflet-container .leaflet-control-scale { + font-size: 11px; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + font-size: 11px; + white-space: nowrap; + overflow: hidden; + -moz-box-sizing: border-box; + box-sizing: border-box; + + background: #fff; + background: rgba(255, 255, 255, 0.5); + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 19px; + line-height: 1.4; + } +.leaflet-popup-content p { + margin: 18px 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + padding: 4px 4px 0 0; + border: none; + text-align: center; + width: 18px; + height: 14px; + font: 16px/14px Tahoma, Verdana, sans-serif; + color: #c3c3c3; + text-decoration: none; + font-weight: bold; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999; + } +.leaflet-popup-scrolled { + overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } +.leaflet-oldie .leaflet-popup-tip-container { + margin-top: -1px; + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-clickable { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } diff --git a/example/main.ml b/example/main.ml index 16c9b9f..9b8e97d 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1 +1,14 @@ -let () = Format.printf "TODO@." +(* create map *) +let map = + let container_id = "map" in + Leaflet.Map.create container_id + +(* setup map *) +let () = + (* set osm layer *) + let osm_layer = Leaflet.Layer.create_tile_osm None in + Leaflet.Layer.add_to map osm_layer; + + (* set view *) + let latlng = Leaflet.Latlng.create 40.71 (-74.0) in + ignore @@ Leaflet.Map.set_view latlng ~zoom:(Some 13) map diff --git a/example/map.html b/example/map.html new file mode 100644 index 0000000..341173f --- /dev/null +++ b/example/map.html @@ -0,0 +1,12 @@ + + + + + + + +
+
+
+ + From f26ea6f5bbea0f851b4eae15cbe5b1a4c5222a53 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 16:16:37 +0200 Subject: [PATCH 64/99] make Map.create take Brr.El --- example/dune | 2 +- example/main.ml | 8 ++++++-- src/map.ml | 6 ++++-- src/map.mli | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/example/dune b/example/dune index 80423a9..1b81cc6 100644 --- a/example/dune +++ b/example/dune @@ -1,7 +1,7 @@ (executable (name main) (modules main) - (libraries leaflet) + (libraries brr leaflet) (modes js) (preprocess (pps js_of_ocaml-ppx))) diff --git a/example/main.ml b/example/main.ml index 9b8e97d..9e685c4 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1,7 +1,11 @@ (* create map *) let map = - let container_id = "map" in - Leaflet.Map.create container_id + let container = + match Brr.Document.find_el_by_id Brr.G.document (Jstr.of_string "map") with + | None -> failwith "map container not found" + | Some el -> el + in + Leaflet.Map.create container (* setup map *) let () = diff --git a/src/map.ml b/src/map.ml index 259efeb..8277a9a 100644 --- a/src/map.ml +++ b/src/map.ml @@ -6,8 +6,10 @@ let of_jv = Fun.id let to_jv = Fun.id -let create ?(options = Jv.null) container_id = - Jv.call Global.leaflet "map" [| Jv.of_string container_id; options |] +let create ?(options = Jv.null) container = + match Brr.El.at (Jstr.of_string "id") container with + | None -> failwith "container doesn't have id" + | Some id -> Jv.call Global.leaflet "map" [| Jv.of_jstr id; options |] let invalidate_size map = let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in diff --git a/src/map.mli b/src/map.mli index 96795cb..15c1f2b 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,7 +2,7 @@ type t -val create : ?options:Jv.t -> string -> t +val create : ?options:Jv.t -> Brr.El.t -> t val invalidate_size : t -> unit From 6141365dc842cba25034215fa5cf77133618d43a Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 22:42:28 +0200 Subject: [PATCH 65/99] add documentation, remove Map.as_target --- doc/index.mld | 14 ++------------ src/latlng.mli | 8 ++++++++ src/layer.ml | 1 - src/layer.mli | 14 ++++++++++++++ src/map.ml | 4 +--- src/map.mli | 23 ++++++++++++++++++++--- src/popup.mli | 5 +++++ 7 files changed, 50 insertions(+), 19 deletions(-) diff --git a/doc/index.mld b/doc/index.mld index c248edf..1676769 100644 --- a/doc/index.mld +++ b/doc/index.mld @@ -1,17 +1,7 @@ -{0 leaflet} +{0 Leaflet} -{{:https://TODO/leaflet} leaflet} is an {{:https://ocaml.org} OCaml} library/executable to TODO. - -{1:api API} +Leaflet is an [OCaml] bindings library for the {{:https://leafletjs.com} Leaflet} JavaScript library. {!modules: Leaflet } - -{1:private_api Private API} - -You shouldn't have to use any of these modules, they're used internally only. - -{!modules: -TODO -} diff --git a/src/latlng.mli b/src/latlng.mli index 9097890..120d165 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -2,14 +2,22 @@ type t +(** [create lat lng] is an object representing a geographical point with the + given latitude and longitude *) val create : float -> float -> t +(** [lat o] is the latitude of [o] *) val lat : t -> float +(** [lng o] is the longitude of [o] *) val lng : t -> float +(** [equals a b] is true iff [a] and [b] is at the same position (within a small + margin of error) *) val equals : t -> t -> bool +(** [of_jv jv] is [jv] as a [Latlng.t] *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : t -> Jv.t diff --git a/src/layer.ml b/src/layer.ml index 9808ebb..b1e8977 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -71,7 +71,6 @@ let create_marker : Latlng.t -> [ `Marker ] t = let create_tile_osm : string option -> [ `Tile ] t = fun url -> - (* see https://wiki.openstreetmap.org/wiki/Tile_servers *) let url = Option.value url ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" diff --git a/src/layer.mli b/src/layer.mli index b3816e6..d049182 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -8,32 +8,46 @@ type _ t = (** Basic layers *) +(** [add_to map layer] adds [layer] to [map] *) val add_to : Map.t -> _ t -> unit +(** [remove layer] removes [layer] from the map it is currently active on *) val remove : _ t -> unit +(** [remove_from map layer] removes [layer] from [map] *) val remove_from : Map.t -> _ t -> unit +(** [bind_popup popup layer] binds [popup] to [layer] *) val bind_popup : Brr.El.t -> _ t -> unit +(** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit +(** [open_popup layer] opens the popup bound to [layer] *) val open_popup : _ t -> unit +(** [close_popup layer] closes the popup bound to [layer] *) val close_popup : _ t -> unit +(** [get_popup layer] is the popup bound to [layer] *) val get_popup : _ t -> Popup.t +(** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : _ t -> Jv.t (** Geojson layers *) +(** [create_geojson geojson] is a new geojson layer *) val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t (** Marker layers *) +(** [create_marker latlng] is a new marker with the same position as latlng *) val create_marker : Latlng.t -> [ `Marker ] t (** Tile layers *) +(** [create_tile_osm Some(url)] is a new tile layer with tile server specified + by [url]. Tile server default to [openstreetmap.org]. See + {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : string option -> [ `Tile ] t diff --git a/src/map.ml b/src/map.ml index 8277a9a..bbd5da3 100644 --- a/src/map.ml +++ b/src/map.ml @@ -30,8 +30,6 @@ let set_view latlng ~zoom map = in () -let as_target map = Brr.Ev.target_of_jv map - let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in @@ -43,5 +41,5 @@ let get_center map = Latlng.of_jv @@ Jv.call map "getCenter" [||] let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int -let wrapped_latlng latlng map = +let wrap_latlng latlng map = Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] diff --git a/src/map.mli b/src/map.mli index 15c1f2b..d027da4 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,26 +2,43 @@ type t +(** [create container] creates a map on [container]. * To have a functional map + you will need to add a tile layer to it. *) val create : ?options:Jv.t -> Brr.El.t -> t +(** [invalidate_size map] checks if the map container size changed and updates + the map if so *) val invalidate_size : t -> unit +(** [set_view latlng Some(zoom) map] sets the view of the [map] (geographical + center and zoom) *) val set_view : Latlng.t -> zoom:int option -> t -> unit +(** [fit_world map] sets a map view that mostly contains the whole world with + the maximum zoom level possible *) val fit_world : t -> unit +(** [get_container map] is the HTML element that contains [map] *) val get_container : t -> Brr.El.t +(** [on event handler map] add an event listener on [map] for event [event] with + handler [handler] *) val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit +(** [get_center map] is the geographical center of the map view *) val get_center : t -> Latlng.t +(** [get_zoom map] is the current zoom level of the map view *) val get_zoom : t -> int -val wrapped_latlng : Latlng.t -> t -> Latlng.t - -val as_target : t -> Brr.Ev.target +(** [wrap_latlng latlng map] returns a new [Latlng.t] where lat and lng has been + wrapped according to the map's CRS's wrapLat and wrapLng properties, if they + are outside the CRS's bounds. By default this means longitude is wrapped + around the dateline so its value is between -180 and +180 degrees *) +val wrap_latlng : Latlng.t -> t -> Latlng.t +(** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t diff --git a/src/popup.mli b/src/popup.mli index ee5df35..9983c5c 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -2,12 +2,17 @@ type t +(** [set_latlng latlng] changes the popup position to the given point*) val set_latlng : Latlng.t -> unit +(** [set_content s] changes the popup content to [s]*) val set_content : string -> unit +(** [open_on map] * Adds the popup to [map] and closes the previous one. *) val open_on : Map.t -> unit +(** [close map] * closes the popup of [map]*) val close : Map.t -> unit +(** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t From 2f12dc381a828e5d9f8c2dcd2bd79da2638f134f Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 May 2022 23:02:04 +0200 Subject: [PATCH 66/99] add usage to readme --- .ocamlformat | 2 +- CHANGES.md | 4 +++- README.md | 11 +++++------ dune-project | 1 + leaflet.opam | 1 + 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index 1b64a37..cec2d50 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.21.0 +version=0.22.4 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/CHANGES.md b/CHANGES.md index d9cd2e7..4cff088 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1 +1,3 @@ -## unreleased +## 0.1 + +Initial release. diff --git a/README.md b/README.md index 4c297f0..ffa9b2e 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,12 @@ If you don't have `opam`, you can install it following the [how to install opam] If you can't or don't want to use `opam`, consult the [opam file] for build instructions. -## Quickstart +## Usage -```ocaml -let () = Format.printf "TODO@." -``` +Have a look at the [example] folder. +The documentation can be consulted via `odig doc leaflet`. -For more, have a look at the [example] folder, at the [documentation] or at the [test suite]. +You will also need [leaflet's files] (CSS and images). ## About @@ -35,9 +34,9 @@ leaflet's original code was taken from a [NGI0 funded project] [opam file]: ./leaflet.opam [test suite]: ./test -[documentation]: TODO/leaflet [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ [Leaflet]: https://leafletjs.com/ +[leaflet's files]: https://leafletjs.com/download.html [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ diff --git a/dune-project b/dune-project index 1c832fe..5afd2f1 100644 --- a/dune-project +++ b/dune-project @@ -10,6 +10,7 @@ (package (name leaflet) (depends + brr (ocaml (>= 4.08)) brr diff --git a/leaflet.opam b/leaflet.opam index b06ac7f..3568ea2 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -16,6 +16,7 @@ homepage: "https://forge.kumikode.org/kumikode/leaflet" bug-reports: "https://forge.kumikode.org/kumikode/leaflet/issues" depends: [ "dune" {>= "2.9"} + "brr" "ocaml" {>= "4.08"} "brr" "js_of_ocaml" From ea061ebe662d46da734aee0e890b8f71ad5cc698 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 18 Jun 2022 07:53:26 +0200 Subject: [PATCH 67/99] change map creation --- example/main.ml | 8 +------- src/map.ml | 11 +++++++---- src/map.mli | 11 ++++++++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/example/main.ml b/example/main.ml index 9e685c4..43b9fcd 100644 --- a/example/main.ml +++ b/example/main.ml @@ -1,11 +1,5 @@ (* create map *) -let map = - let container = - match Brr.Document.find_el_by_id Brr.G.document (Jstr.of_string "map") with - | None -> failwith "map container not found" - | Some el -> el - in - Leaflet.Map.create container +let map = Leaflet.Map.create_on "map" (* setup map *) let () = diff --git a/src/map.ml b/src/map.ml index bbd5da3..2f2db23 100644 --- a/src/map.ml +++ b/src/map.ml @@ -6,10 +6,13 @@ let of_jv = Fun.id let to_jv = Fun.id -let create ?(options = Jv.null) container = - match Brr.El.at (Jstr.of_string "id") container with - | None -> failwith "container doesn't have id" - | Some id -> Jv.call Global.leaflet "map" [| Jv.of_jstr id; options |] +let create_on ?(options = Jv.null) id = + Jv.call Global.leaflet "map" [| Jv.of_string id; options |] + +let create_from_div ?(options = Jv.null) container = + if Brr.El.has_tag_name Brr.El.Name.div container then + Jv.call Global.leaflet "map" [| Brr.El.to_jv container; options |] + else failwith "container is not a
" let invalidate_size map = let (_ : Jv.t) = Jv.call map "invalidateSize" [| Jv.true' |] in diff --git a/src/map.mli b/src/map.mli index d027da4..c1a7770 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,9 +2,14 @@ type t -(** [create container] creates a map on [container]. * To have a functional map - you will need to add a tile layer to it. *) -val create : ?options:Jv.t -> Brr.El.t -> t +(** [create id] creates a map on the
with DOM id [id]. To have a + functional map you will need to add a tile layer to it. *) +val create_on : ?options:Jv.t -> string -> t + +(** [create_from_div container] creates a map given [container], an instance of + a
HTML element. To have a functional map you will need to add a tile + layer to it. *) +val create_from_div : ?options:Jv.t -> Brr.El.t -> t (** [invalidate_size map] checks if the map container size changed and updates the map if so *) From 95f13b320b111a724aad626cf934d14f6d9acd30 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 18 Jun 2022 20:47:19 +0200 Subject: [PATCH 68/99] add js_of_ocaml to package dependency --- dune-project | 1 + example/dune | 4 +--- leaflet.opam | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dune-project b/dune-project index 5afd2f1..75ede85 100644 --- a/dune-project +++ b/dune-project @@ -11,6 +11,7 @@ (name leaflet) (depends brr + js_of_ocaml (ocaml (>= 4.08)) brr diff --git a/example/dune b/example/dune index 1b81cc6..b868e46 100644 --- a/example/dune +++ b/example/dune @@ -2,6 +2,4 @@ (name main) (modules main) (libraries brr leaflet) - (modes js) - (preprocess - (pps js_of_ocaml-ppx))) + (modes js)) diff --git a/leaflet.opam b/leaflet.opam index 3568ea2..de7dabf 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -17,6 +17,7 @@ bug-reports: "https://forge.kumikode.org/kumikode/leaflet/issues" depends: [ "dune" {>= "2.9"} "brr" + "js_of_ocaml" "ocaml" {>= "4.08"} "brr" "js_of_ocaml" From d1acabfdcde119e5f75117ea4b70e9ee984deff8 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 06:52:05 +0200 Subject: [PATCH 69/99] add of_jv, on, ?options for bind_popup --- src/layer.ml | 29 ++++++++++++++++++++++++++--- src/layer.mli | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index b1e8977..beef402 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -6,6 +6,12 @@ type _ t = | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t +type _ sub = + | Basic : [> `Basic ] sub + | Geojson : [> `Geojson ] sub + | Marker : [> `Marker ] sub + | Tile : [> `Tile ] sub + (** Basic layers *) let add_to : type kind. Map.t -> kind t -> unit = @@ -25,10 +31,10 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> kind t -> unit = - fun el -> function +let bind_popup : type kind. Brr.El.t -> ?options:Jv.t -> kind t -> unit = + fun el ?(options = Jv.null) -> function | Basic l | Geojson l | Marker l | Tile l -> - let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el |] in + let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el; options |] in () let unbind_popup : type kind. kind t -> unit = function @@ -53,6 +59,23 @@ let get_popup : type kind. kind t -> Popup.t = function let to_jv : type kind. kind t -> Jv.t = function | Basic l | Geojson l | Marker l | Tile l -> l +let of_jv : type kind. kind sub -> Jv.t -> kind t = + fun tag l -> + match tag with + | Basic -> Basic l + | Geojson -> Geojson l + | Marker -> Marker l + | Tile -> Tile l + +let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = + fun event handler layer -> + let name = Event.sub_to_string event in + let handler v = handler @@ Event.of_jv event v in + let (_ : Jv.t) = + Jv.call (to_jv layer) "on" [| Jv.of_string name; Jv.repr handler |] + in + () + (** Geojson layers *) let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = diff --git a/src/layer.mli b/src/layer.mli index d049182..309d1f5 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -6,6 +6,12 @@ type _ t = | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t +type _ sub = + | Basic : [> `Basic ] sub + | Geojson : [> `Geojson ] sub + | Marker : [> `Marker ] sub + | Tile : [> `Tile ] sub + (** Basic layers *) (** [add_to map layer] adds [layer] to [map] *) @@ -18,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> _ t -> unit +val bind_popup : Brr.El.t -> ?options:Jv.t -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit @@ -35,6 +41,13 @@ val get_popup : _ t -> Popup.t (** [to_jv o] is [o] as a {!Jv.t} *) val to_jv : _ t -> Jv.t +(** [of_jv tag o] is [o] as a [tag t] *) +val of_jv : 'a sub -> Jv.t -> 'a t + +(** [on event handler layer] add an event listener on [layer] for event [event] + with handler [handler] *) +val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit + (** Geojson layers *) (** [create_geojson geojson] is a new geojson layer *) From db88d3f670ee807bb3cda0d4b58e2662e2de32b7 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 07:57:38 +0200 Subject: [PATCH 70/99] add icon --- src/dune | 2 +- src/icon.ml | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/icon.mli | 21 +++++++++++++++++++++ src/point.ml | 3 +++ src/point.mli | 3 +++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/icon.ml create mode 100644 src/icon.mli diff --git a/src/dune b/src/dune index 4e2d45f..52d85ee 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup point) + (modules event global latlng layer map popup point icon) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/icon.ml b/src/icon.ml new file mode 100644 index 0000000..0073d68 --- /dev/null +++ b/src/icon.ml @@ -0,0 +1,47 @@ +(* BSD-2-Clause License *) + +type t = Jv.t + +type opt = + | Icon_retina_url of string + | Icon_size of Point.t + | Icon_anchor of Point.t + | Popup_anchor of Point.t + | Tooltip_anchor of Point.t + | Shadow_url of string + | Shadow_retina_url of string + | Shadow_size of Point.t + | Shadow_anchor of Point.t + | Class_name of string + | Cross_origin of string option + +let to_string = function + | Icon_retina_url _ -> "iconRetinaUrl" + | Icon_size _ -> "iconSize" + | Icon_anchor _ -> "iconAnchor" + | Popup_anchor _ -> "popupAnchor" + | Tooltip_anchor _ -> "tooltipAnchor" + | Shadow_url _ -> "shadowUrl" + | Shadow_retina_url _ -> "shadowRetinaUrl" + | Shadow_size _ -> "shadowSize" + | Shadow_anchor _ -> "shadowAnchor" + | Class_name _ -> "className" + | Cross_origin _ -> "crossOrigin" + +let to_jv = function + | Icon_size p + | Icon_anchor p + | Popup_anchor p + | Tooltip_anchor p + | Shadow_size p + | Shadow_anchor p -> + Point.to_jv p + | Icon_retina_url s | Shadow_url s | Shadow_retina_url s | Class_name s -> + Jv.of_string s + | Cross_origin o -> ( + match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) + +let create icon_url options = + let l = List.map (fun o -> (to_string o, to_jv o)) options in + let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + Jv.call Global.leaflet "icon" [| Jv.obj tab |] diff --git a/src/icon.mli b/src/icon.mli new file mode 100644 index 0000000..0d58709 --- /dev/null +++ b/src/icon.mli @@ -0,0 +1,21 @@ +(* BSD-2-Clause License *) + +type t + +(* type for icon option used to create an icon*) +type opt = + | Icon_retina_url of string + | Icon_size of Point.t + | Icon_anchor of Point.t + | Popup_anchor of Point.t + | Tooltip_anchor of Point.t + | Shadow_url of string + | Shadow_retina_url of string + | Shadow_size of Point.t + | Shadow_anchor of Point.t + | Class_name of string + | Cross_origin of string option + +(** [create icon_url options] Creates an icon instance with the given [options], + and the required `iconUrl` option set to [icon_url] *) +val create : string -> opt list -> t diff --git a/src/point.ml b/src/point.ml index 0191894..00fceb9 100644 --- a/src/point.ml +++ b/src/point.ml @@ -9,3 +9,6 @@ let of_jv point = let x = Jv.get point "x" |> Jv.to_int in let y = Jv.get point "y" |> Jv.to_int in { x; y } + +let to_jv point = + Jv.call Global.leaflet "point" [| Jv.of_int point.x; Jv.of_int point.y |] diff --git a/src/point.mli b/src/point.mli index 2ca4de2..a9b9430 100644 --- a/src/point.mli +++ b/src/point.mli @@ -7,3 +7,6 @@ type t = (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t + +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t From 96a7307bf331b1a37589cf0a2b8ac79086fde01e Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 08:16:21 +0200 Subject: [PATCH 71/99] add marker options --- src/icon.ml | 6 ++++-- src/icon.mli | 3 +++ src/layer.ml | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- src/layer.mli | 16 +++++++++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/icon.ml b/src/icon.ml index 0073d68..369c288 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -2,6 +2,8 @@ type t = Jv.t +let to_jv = Fun.id + type opt = | Icon_retina_url of string | Icon_size of Point.t @@ -28,7 +30,7 @@ let to_string = function | Class_name _ -> "className" | Cross_origin _ -> "crossOrigin" -let to_jv = function +let opt_to_jv = function | Icon_size p | Icon_anchor p | Popup_anchor p @@ -42,6 +44,6 @@ let to_jv = function match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) let create icon_url options = - let l = List.map (fun o -> (to_string o, to_jv o)) options in + let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in Jv.call Global.leaflet "icon" [| Jv.obj tab |] diff --git a/src/icon.mli b/src/icon.mli index 0d58709..df3b33e 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -2,6 +2,9 @@ type t +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t + (* type for icon option used to create an icon*) type opt = | Icon_retina_url of string diff --git a/src/layer.ml b/src/layer.ml index beef402..7f34d54 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -85,9 +85,52 @@ let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = (** Marker layers *) -let create_marker : Latlng.t -> [ `Marker ] t = - fun latlng -> - let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng |] in +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +let marker_opt_to_string : marker_opt -> string = function + | Icon _ -> "icon" + | Keyboard _ -> "keyboard" + | Title _ -> "title" + | Alt _ -> "alt" + | Z_index_offset _ -> "zIndexOffset" + | Opacity _ -> "opacity" + | Rise_on_hover _ -> "riseOnHover" + | Rise_offset _ -> "riseOffset" + | Pane _ -> "pane" + | Shadow_pane _ -> "shadowPane" + | Bubbling_mouse_events _ -> "bubblingMouseEvents" + | Auto_pan_on_focus _ -> "autoPanOnFocus" + +let marker_opt_to_jv = function + | Icon icon -> Icon.to_jv icon + | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b + -> + Jv.of_bool b + | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s + | Z_index_offset i | Rise_offset i -> Jv.of_int i + | Opacity f -> Jv.of_float f + +let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = + fun latlng options -> + let l = + Array.of_list + @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + in + let jv_t = + Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] + in Marker jv_t (** Tile layers *) diff --git a/src/layer.mli b/src/layer.mli index 309d1f5..9f85a0a 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -55,8 +55,22 @@ val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t (** Marker layers *) +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + (** [create_marker latlng] is a new marker with the same position as latlng *) -val create_marker : Latlng.t -> [ `Marker ] t +val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t (** Tile layers *) From 323891efef41974c0b9fe13924351935ca4ceb2a Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 09:17:23 +0200 Subject: [PATCH 72/99] add geojson options --- src/layer.ml | 36 +++++++++++++++++++++++++++++++++--- src/layer.mli | 15 +++++++++++++-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 7f34d54..b4261aa 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -78,9 +78,39 @@ let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = (** Geojson layers *) -let create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t = - fun ?(options = Jv.null) geojson -> - let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; options |] in +type geojson_opt = + | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Style of (Jv.t -> unit) + | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) + | Filter of (Jv.t -> bool) + | Coords_to_latlng of (Jv.t -> Latlng.t) + | Markers_inherit_options of bool + +let geojson_opt_to_string = function + | Point_to_layer _ -> "pointToLayer" + | Style _ -> "style" + | On_each_feature _ -> "onEachFeature" + | Filter _ -> "filter" + | Coords_to_latlng _ -> "coordsToLatLng" + | Markers_inherit_options _ -> "markersInheritOptions" + +let geojson_opt_to_jv = function + | Markers_inherit_options b -> Jv.of_bool b + | Point_to_layer f -> Jv.repr f + | Style f -> Jv.repr f + | On_each_feature f -> Jv.repr f + | Filter f -> Jv.repr f + | Coords_to_latlng f -> Jv.repr f + +let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = + fun geojson options -> + let l = + Array.of_list + @@ List.map + (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) + options + in + let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t (** Marker layers *) diff --git a/src/layer.mli b/src/layer.mli index 9f85a0a..204afab 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -50,11 +50,21 @@ val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit (** Geojson layers *) +(** type for geojson option, used to create geojson *) +type geojson_opt = + | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Style of (Jv.t -> unit) + | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) + | Filter of (Jv.t -> bool) + | Coords_to_latlng of (Jv.t -> Latlng.t) + | Markers_inherit_options of bool + (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : ?options:Jv.t -> Jv.t -> [ `Geojson ] t +val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t (** Marker layers *) +(** type for marker option, used to create marker *) type marker_opt = | Icon of Icon.t | Keyboard of bool @@ -69,7 +79,8 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -(** [create_marker latlng] is a new marker with the same position as latlng *) +(** [create_marker latlng options] is a new marker with the same position as + [latlng] and with options set to [options] *) val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t (** Tile layers *) From 9a0cec96c65e019ae4b3c03dbffd49f277c397eb Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 10:05:35 +0200 Subject: [PATCH 73/99] add popup options --- src/icon.ml | 4 ++-- src/icon.mli | 2 +- src/layer.ml | 19 ++++++++++++----- src/layer.mli | 2 +- src/popup.ml | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/popup.mli | 27 +++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 9 deletions(-) diff --git a/src/icon.ml b/src/icon.ml index 369c288..c40305d 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -45,5 +45,5 @@ let opt_to_jv = function let create icon_url options = let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in - let tab = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in - Jv.call Global.leaflet "icon" [| Jv.obj tab |] + let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + Jv.call Global.leaflet "icon" [| Jv.obj l |] diff --git a/src/icon.mli b/src/icon.mli index df3b33e..534c9d9 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -5,7 +5,7 @@ type t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t -(* type for icon option used to create an icon*) +(** type for icon option used to create an icon*) type opt = | Icon_retina_url of string | Icon_size of Point.t diff --git a/src/layer.ml b/src/layer.ml index b4261aa..fd2042c 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -31,10 +31,16 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> ?options:Jv.t -> kind t -> unit = - fun el ?(options = Jv.null) -> function - | Basic l | Geojson l | Marker l | Tile l -> - let (_ : Jv.t) = Jv.call l "bindPopup" [| Brr.El.to_jv el; options |] in +let bind_popup : type kind. Brr.El.t -> Popup.opt list -> kind t -> unit = + fun el options -> function + | Basic layer | Geojson layer | Marker layer | Tile layer -> + let l = + Array.of_list + @@ List.map (fun o -> (Popup.opt_to_string o, Popup.opt_to_jv o)) options + in + let (_ : Jv.t) = + Jv.call layer "bindPopup" [| Brr.El.to_jv el; Jv.obj l |] + in () let unbind_popup : type kind. kind t -> unit = function @@ -98,7 +104,10 @@ let geojson_opt_to_jv = function | Markers_inherit_options b -> Jv.of_bool b | Point_to_layer f -> Jv.repr f | Style f -> Jv.repr f - | On_each_feature f -> Jv.repr f + | On_each_feature f -> + (* we need to wrap the Jv.t *) + let f feature jv = jv |> of_jv Geojson |> f feature in + Jv.repr f | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f diff --git a/src/layer.mli b/src/layer.mli index 204afab..7eaabd2 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -24,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> ?options:Jv.t -> _ t -> unit +val bind_popup : Brr.El.t -> Popup.opt list -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit diff --git a/src/popup.ml b/src/popup.ml index 5447cd4..f7a1c69 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -21,3 +21,59 @@ let close map = () let of_jv = Fun.id + +type opt = + | Pane of string + | Offset of Point.t + | Max_width of int + | Min_width of int + | Max_height of int + | Auto_pan of bool + | Auto_pan_padding_top_left of Point.t + | Auto_pan_padding_bottom_right of Point.t + | Auto_pan_padding of Point.t + | Keep_in_view of bool + | Close_button of bool + | Auto_close of bool + | Close_on_escape_key of bool + | Close_on_click of bool + | Class_name of string + +let opt_to_string = function + | Pane _ -> "pane" + | Offset _ -> "offset" + | Max_width _ -> "maxWidth" + | Min_width _ -> "minWidth" + | Max_height _ -> "maxHeight" + | Auto_pan _ -> "autoPan" + | Auto_pan_padding_top_left _ -> "autoPanPaddingTopLeft" + | Auto_pan_padding_bottom_right _ -> "autoPanPaddingBottomRight" + | Auto_pan_padding _ -> "autoPanPadding" + | Keep_in_view _ -> "keepInView" + | Close_button _ -> "closeButton" + | Auto_close _ -> "autoClose" + | Close_on_escape_key _ -> "closeOnEscapeKey" + | Close_on_click _ -> "closeOnClick" + | Class_name _ -> "className" + +let opt_to_jv = function + | Offset p + | Auto_pan_padding_top_left p + | Auto_pan_padding_bottom_right p + | Auto_pan_padding p -> + Point.to_jv p + | Max_width i | Min_width i | Max_height i -> Jv.of_int i + | Auto_pan b + | Keep_in_view b + | Close_button b + | Auto_close b + | Close_on_escape_key b + | Close_on_click b -> + Jv.of_bool b + | Pane s | Class_name s -> Jv.of_string s + +let create options = + let l = + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options + in + Jv.call Global.leaflet "popup" [| Jv.obj l |] diff --git a/src/popup.mli b/src/popup.mli index 9983c5c..da7f27a 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -2,6 +2,24 @@ type t +(** type for popup option used to create an popup*) +type opt = + | Pane of string + | Offset of Point.t + | Max_width of int + | Min_width of int + | Max_height of int + | Auto_pan of bool + | Auto_pan_padding_top_left of Point.t + | Auto_pan_padding_bottom_right of Point.t + | Auto_pan_padding of Point.t + | Keep_in_view of bool + | Close_button of bool + | Auto_close of bool + | Close_on_escape_key of bool + | Close_on_click of bool + | Class_name of string + (** [set_latlng latlng] changes the popup position to the given point*) val set_latlng : Latlng.t -> unit @@ -16,3 +34,12 @@ val close : Map.t -> unit (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t + +(** [opt_to_string opt] is [opt] as {!string} *) +val opt_to_string : opt -> string + +(** [opt_to_jv opt] is [opt] as {!Jv.t} *) +val opt_to_jv : opt -> Jv.t + +(** [create options] is a new popup setup withs [options] *) +val create : opt list -> t From e7bac6c1cc10b251838e8242967fc2f094ea7454 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 20 Jun 2022 11:04:44 +0200 Subject: [PATCH 74/99] fix Point_to_layer --- src/layer.ml | 6 ++++-- src/layer.mli | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index fd2042c..b18c108 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -85,7 +85,7 @@ let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = (** Geojson layers *) type geojson_opt = - | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Point_to_layer of (Jv.t -> Latlng.t -> [ `Marker ] t) | Style of (Jv.t -> unit) | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) | Filter of (Jv.t -> bool) @@ -102,7 +102,9 @@ let geojson_opt_to_string = function let geojson_opt_to_jv = function | Markers_inherit_options b -> Jv.of_bool b - | Point_to_layer f -> Jv.repr f + | Point_to_layer f -> + (* the marker returned by `pointToLayer` is used internally by leaflet so we neet to unwrap it to a Jv.t *) + Jv.repr (fun geojsonpoint latlng -> to_jv @@ f geojsonpoint latlng) | Style f -> Jv.repr f | On_each_feature f -> (* we need to wrap the Jv.t *) diff --git a/src/layer.mli b/src/layer.mli index 7eaabd2..9c7a7cd 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -52,7 +52,7 @@ val on : 'a Event.sub -> ('a Event.t -> 'b) -> 'c t -> unit (** type for geojson option, used to create geojson *) type geojson_opt = - | Point_to_layer of (Jv.t -> Latlng.t -> unit) + | Point_to_layer of (Jv.t -> Latlng.t -> [ `Marker ] t) | Style of (Jv.t -> unit) | On_each_feature of (Jv.t -> [ `Geojson ] t -> unit) | Filter of (Jv.t -> bool) From 38d846cf29c5baf4f1999117bacb3ef6dac2b9ad Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 26 Jun 2022 04:08:53 +0200 Subject: [PATCH 75/99] better Layer.bind_popup and add Map.open/close_popup --- src/layer.ml | 12 +++--------- src/layer.mli | 2 +- src/map.ml | 6 ++++++ src/map.mli | 6 ++++++ src/popup.ml | 10 ++-------- src/popup.mli | 9 +++------ 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index b18c108..85a9ce8 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -31,16 +31,10 @@ let remove_from : type kind. Map.t -> kind t -> unit = let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () -let bind_popup : type kind. Brr.El.t -> Popup.opt list -> kind t -> unit = - fun el options -> function +let bind_popup : type kind. Popup.t -> kind t -> unit = + fun popup -> function | Basic layer | Geojson layer | Marker layer | Tile layer -> - let l = - Array.of_list - @@ List.map (fun o -> (Popup.opt_to_string o, Popup.opt_to_jv o)) options - in - let (_ : Jv.t) = - Jv.call layer "bindPopup" [| Brr.El.to_jv el; Jv.obj l |] - in + let (_ : Jv.t) = Jv.call layer "bindPopup" [| Popup.to_jv popup |] in () let unbind_popup : type kind. kind t -> unit = function diff --git a/src/layer.mli b/src/layer.mli index 9c7a7cd..e819d2e 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -24,7 +24,7 @@ val remove : _ t -> unit val remove_from : Map.t -> _ t -> unit (** [bind_popup popup layer] binds [popup] to [layer] *) -val bind_popup : Brr.El.t -> Popup.opt list -> _ t -> unit +val bind_popup : Popup.t -> _ t -> unit (** [unbind_popup layer] unbinds the popup bound to [layer] *) val unbind_popup : _ t -> unit diff --git a/src/map.ml b/src/map.ml index 2f2db23..235510c 100644 --- a/src/map.ml +++ b/src/map.ml @@ -46,3 +46,9 @@ let get_zoom map = Jv.call map "getZoom" [||] |> Jv.to_int let wrap_latlng latlng map = Latlng.of_jv @@ Jv.call map "wrapLatLng" [| Latlng.to_jv latlng |] + +let open_popup popup map = + ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] + +let close_popup popup map = + ignore @@ Jv.call map "closePopup" [| Popup.to_jv popup |] diff --git a/src/map.mli b/src/map.mli index c1a7770..db91af9 100644 --- a/src/map.mli +++ b/src/map.mli @@ -47,3 +47,9 @@ val of_jv : Jv.t -> t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t + +(* [open_popup popup map] opens [popup] on [map] *) +val open_popup : Popup.t -> t -> unit + +(* [close_popup popup map] closes [popup] on [map] *) +val close_popup : Popup.t -> t -> unit diff --git a/src/popup.ml b/src/popup.ml index f7a1c69..b2a5072 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -12,16 +12,10 @@ let set_content content = let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in () -let open_on map = - let (_ : Jv.t) = Jv.call popup "openOn" [| Map.to_jv map |] in - () - -let close map = - let (_ : Jv.t) = Jv.call (Map.to_jv map) "closePopup" [||] in - () - let of_jv = Fun.id +let to_jv = Fun.id + type opt = | Pane of string | Offset of Point.t diff --git a/src/popup.mli b/src/popup.mli index da7f27a..6391cee 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -26,15 +26,12 @@ val set_latlng : Latlng.t -> unit (** [set_content s] changes the popup content to [s]*) val set_content : string -> unit -(** [open_on map] * Adds the popup to [map] and closes the previous one. *) -val open_on : Map.t -> unit - -(** [close map] * closes the popup of [map]*) -val close : Map.t -> unit - (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t +(** [to_jv o] is [o] as {!Jv.t} *) +val to_jv : t -> Jv.t + (** [opt_to_string opt] is [opt] as {!string} *) val opt_to_string : opt -> string From 57ee0a2ca8f71324ee41296ac8fb8fe16dc98151 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 26 Jun 2022 05:07:45 +0200 Subject: [PATCH 76/99] better popups --- src/map.ml | 8 ++++++-- src/map.mli | 4 ++-- src/popup.ml | 41 +++++++++++++++++++++++++++++++++++------ src/popup.mli | 20 ++++++++++++++------ 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/map.ml b/src/map.ml index 235510c..9dec8d6 100644 --- a/src/map.ml +++ b/src/map.ml @@ -50,5 +50,9 @@ let wrap_latlng latlng map = let open_popup popup map = ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] -let close_popup popup map = - ignore @@ Jv.call map "closePopup" [| Popup.to_jv popup |] +let close_popup ~popup map = + ignore + @@ + match popup with + | None -> Jv.call map "closePopup" [||] + | Some popup -> Jv.call map "closePopup" [| Popup.to_jv popup |] diff --git a/src/map.mli b/src/map.mli index db91af9..d1bf3e4 100644 --- a/src/map.mli +++ b/src/map.mli @@ -51,5 +51,5 @@ val to_jv : t -> Jv.t (* [open_popup popup map] opens [popup] on [map] *) val open_popup : Popup.t -> t -> unit -(* [close_popup popup map] closes [popup] on [map] *) -val close_popup : Popup.t -> t -> unit +(* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) +val close_popup : popup:Popup.t option -> t -> unit diff --git a/src/popup.ml b/src/popup.ml index b2a5072..2792e23 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -2,16 +2,18 @@ type t = Jv.t -let popup = Jv.call Global.leaflet "popup" [||] - -let set_latlng latlng = +let set_latlng latlng popup = let (_ : Jv.t) = Jv.call popup "setLatLng" [| Latlng.to_jv latlng |] in () -let set_content content = +let set_content content popup = let (_ : Jv.t) = Jv.call popup "setContent" [| Jv.of_string content |] in () +let set_content_to_el el popup = + let (_ : Jv.t) = Jv.call popup "setContent" [| Brr.El.to_jv el |] in + () + let of_jv = Fun.id let to_jv = Fun.id @@ -66,8 +68,35 @@ let opt_to_jv = function Jv.of_bool b | Pane s | Class_name s -> Jv.of_string s -let create options = +let create content_opt ~latlng options = let l = Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in - Jv.call Global.leaflet "popup" [| Jv.obj l |] + let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in + let popup = + match latlng with + | None -> popup + | Some latlng -> + set_latlng latlng popup; + popup + in + match content_opt with + | None -> popup + | Some content -> + set_content content popup; + popup + +let create_from_el el ~latlng options = + let l = + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options + in + let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in + let popup = + match latlng with + | None -> popup + | Some latlng -> + set_latlng latlng popup; + popup + in + set_content_to_el el popup; + popup diff --git a/src/popup.mli b/src/popup.mli index 6391cee..dae1db8 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -20,11 +20,14 @@ type opt = | Close_on_click of bool | Class_name of string -(** [set_latlng latlng] changes the popup position to the given point*) -val set_latlng : Latlng.t -> unit +(** [set_latlng latlng popup] sets [popup] position to the given point*) +val set_latlng : Latlng.t -> t -> unit -(** [set_content s] changes the popup content to [s]*) -val set_content : string -> unit +(** [set_content s popup] sets [popup] content to [s]*) +val set_content : string -> t -> unit + +(** [set_content_to_el el s] sets [popup] content to [el]*) +val set_content_to_el : Brr.El.t -> t -> unit (** [of_jv jv] is [jv] as {!t} *) val of_jv : Jv.t -> t @@ -38,5 +41,10 @@ val opt_to_string : opt -> string (** [opt_to_jv opt] is [opt] as {!Jv.t} *) val opt_to_jv : opt -> Jv.t -(** [create options] is a new popup setup withs [options] *) -val create : opt list -> t +(** [create s latlng options] is a new popup setup with [options], position set + to [latlng] and content to [s] *) +val create : string option -> latlng:Latlng.t option -> opt list -> t + +(** [create_from_el el latlng options] is a new popup setup with [options], + position set to [latlng] and content to [el] *) +val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt list -> t From 6f1e93eab69e54fc62b0ca6070e3d75e096f20d6 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 24 Nov 2022 19:21:57 +0100 Subject: [PATCH 77/99] add Icon.create_div --- src/icon.ml | 20 ++++++++++++++++++++ src/icon.mli | 9 +++++++++ 2 files changed, 29 insertions(+) diff --git a/src/icon.ml b/src/icon.ml index c40305d..f8e1bb5 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -4,6 +4,8 @@ type t = Jv.t let to_jv = Fun.id +let of_jv = Fun.id + type opt = | Icon_retina_url of string | Icon_size of Point.t @@ -47,3 +49,21 @@ let create icon_url options = let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in Jv.call Global.leaflet "icon" [| Jv.obj l |] + +let create_div ~html ~bg_pos options = + let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in + let div_options = + let html = + match html with + | None -> [] + | Some html -> [ ("html", Jv.of_string html) ] + in + let bg_pos = + match bg_pos with + | None -> [] + | Some bg_pos -> [ ("bgPos", Point.to_jv bg_pos) ] + in + html @ bg_pos + in + let l = Array.of_list @@ div_options @ l in + Jv.call Global.leaflet "divIcon" [| Jv.obj l |] diff --git a/src/icon.mli b/src/icon.mli index 534c9d9..d7734dd 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -5,6 +5,9 @@ type t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t +(** [of_jv o] is [o] as {!Icon.t} *) +val of_jv : Jv.t -> t + (** type for icon option used to create an icon*) type opt = | Icon_retina_url of string @@ -22,3 +25,9 @@ type opt = (** [create icon_url options] Creates an icon instance with the given [options], and the required `iconUrl` option set to [icon_url] *) val create : string -> opt list -> t + +(** [create_div ~html ~bg_pos options] Creates an DivIcon instance with the + given [options], [bg_pos] is the optional relative position of the + background, in pixels [html] is custom HTML code to put inside the div + element, empty by default. *) +val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t From be85daf71b4d47d81ce0acbed46a479c5cc813cc Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 24 Nov 2022 19:22:18 +0100 Subject: [PATCH 78/99] more marker function --- src/layer.ml | 67 ++++++++++++++++++++++++++++++++++++--------------- src/layer.mli | 28 +++++++++++++++++---- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 85a9ce8..f98de08 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -118,7 +118,30 @@ let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t +(** Tile layers *) + +let create_tile_osm : string option -> [ `Tile ] t = + fun url -> + let url = + Option.value url + ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" + in + let jv_t = + Jv.call Global.leaflet "tileLayer" + [| Jv.of_string url + ; Jv.obj + [| ( "attribution" + , Jv.of_string + "© OpenStreetMap \ + contributors" ) + |] + |] + in + Tile jv_t + (** Marker layers *) +(* TODO make a Marker module? *) type marker_opt = | Icon of Icon.t @@ -168,24 +191,28 @@ let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = in Marker jv_t -(** Tile layers *) +let get_latlng : [ `Marker ] t -> Latlng.t = function + | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv -let create_tile_osm : string option -> [ `Tile ] t = - fun url -> - let url = - Option.value url - ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" - in - let jv_t = - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] - in - Tile jv_t +let set_latlng latlng : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in + () + +let set_z_index_offset z_index : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in + () + +let get_icon : [ `Marker ] t -> Icon.t = function + | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv + +let set_icon icon : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in + () + +let set_opacity opacity : [ `Marker ] t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in + () diff --git a/src/layer.mli b/src/layer.mli index e819d2e..84586d7 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,6 +62,13 @@ type geojson_opt = (** [create_geojson geojson] is a new geojson layer *) val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t +(** Tile layers *) + +(** [create_tile_osm Some(url)] is a new tile layer with tile server specified + by [url]. Tile server default to [openstreetmap.org]. See + {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) +val create_tile_osm : string option -> [ `Tile ] t + (** Marker layers *) (** type for marker option, used to create marker *) @@ -83,9 +90,20 @@ type marker_opt = [latlng] and with options set to [options] *) val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t -(** Tile layers *) +(** Returns the current geographical position of the marker. *) +val get_latlng : [ `Marker ] t -> Latlng.t -(** [create_tile_osm Some(url)] is a new tile layer with tile server specified - by [url]. Tile server default to [openstreetmap.org]. See - {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : string option -> [ `Tile ] t +(** Changes the marker position to the given point. *) +val set_latlng : Latlng.t -> [ `Marker ] t -> unit + +(** Changes the zIndex offset of the marker. *) +val set_z_index_offset : int -> [ `Marker ] t -> unit + +(** Returns the current icon used by the marker *) +val get_icon : [ `Marker ] t -> Icon.t + +(** Changes the marker icon. *) +val set_icon : Icon.t -> [ `Marker ] t -> unit + +(** Changes the opacity of the marker. *) +val set_opacity : int -> [ `Marker ] t -> unit From b3ec1bcfe1205bde2914863296923bf530499e84 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 01:58:10 +0100 Subject: [PATCH 79/99] fix doc --- src/map.mli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.mli b/src/map.mli index d1bf3e4..5d7a912 100644 --- a/src/map.mli +++ b/src/map.mli @@ -2,7 +2,7 @@ type t -(** [create id] creates a map on the
with DOM id [id]. To have a +(** [create_on id] creates a map on the
with DOM id [id]. To have a functional map you will need to add a tile layer to it. *) val create_on : ?options:Jv.t -> string -> t From 72949d06ad1a05a37a67b03d65ff380828a7daf9 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 01:59:30 +0100 Subject: [PATCH 80/99] update ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index cec2d50..c54116a 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.22.4 +version=0.24.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From 82fa7afc21472c5ea55661ba5c28ea64b1a7a1ac Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 31 Dec 2022 02:45:32 +0100 Subject: [PATCH 81/99] small popup change --- src/map.mli | 2 +- src/popup.ml | 4 ++-- src/popup.mli | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/map.mli b/src/map.mli index 5d7a912..ede2965 100644 --- a/src/map.mli +++ b/src/map.mli @@ -48,7 +48,7 @@ val of_jv : Jv.t -> t (** [to_jv o] is [o] as {!Jv.t} *) val to_jv : t -> Jv.t -(* [open_popup popup map] opens [popup] on [map] *) +(* [open_popup popup map] opens [popup] on [map]; Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability). *) val open_popup : Popup.t -> t -> unit (* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) diff --git a/src/popup.ml b/src/popup.ml index 2792e23..3960a81 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -68,7 +68,7 @@ let opt_to_jv = function Jv.of_bool b | Pane s | Class_name s -> Jv.of_string s -let create content_opt ~latlng options = +let create ~content ~latlng options = let l = Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in @@ -80,7 +80,7 @@ let create content_opt ~latlng options = set_latlng latlng popup; popup in - match content_opt with + match content with | None -> popup | Some content -> set_content content popup; diff --git a/src/popup.mli b/src/popup.mli index dae1db8..d099745 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -41,9 +41,9 @@ val opt_to_string : opt -> string (** [opt_to_jv opt] is [opt] as {!Jv.t} *) val opt_to_jv : opt -> Jv.t -(** [create s latlng options] is a new popup setup with [options], position set - to [latlng] and content to [s] *) -val create : string option -> latlng:Latlng.t option -> opt list -> t +(** [create ~content ~latlng options] is a new popup setup with [options], + position set to [latlng] and content to [s] *) +val create : content:string option -> latlng:Latlng.t option -> opt list -> t (** [create_from_el el latlng options] is a new popup setup with [options], position set to [latlng] and content to [el] *) From 2177dec31e76b6aa4c660aa528126eea6362e8c0 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 20:27:37 +0100 Subject: [PATCH 82/99] -> Latlng.create ~lat ~lng --- .ocamlformat | 2 +- example/main.ml | 2 +- src/latlng.ml | 2 +- src/latlng.mli | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ocamlformat b/.ocamlformat index c54116a..74ae9c5 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.24.1 +version=0.26.1 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/example/main.ml b/example/main.ml index 43b9fcd..4a90920 100644 --- a/example/main.ml +++ b/example/main.ml @@ -8,5 +8,5 @@ let () = Leaflet.Layer.add_to map osm_layer; (* set view *) - let latlng = Leaflet.Latlng.create 40.71 (-74.0) in + let latlng = Leaflet.Latlng.create ~lat:40.71 ~lng:(-74.0) in ignore @@ Leaflet.Map.set_view latlng ~zoom:(Some 13) map diff --git a/src/latlng.ml b/src/latlng.ml index 400200b..89cd3b8 100644 --- a/src/latlng.ml +++ b/src/latlng.ml @@ -2,7 +2,7 @@ type t = Jv.t -let create lat lng = +let create ~lat ~lng = Jv.call Global.leaflet "latLng" [| Jv.of_float lat; Jv.of_float lng |] let lat latlng = Jv.get latlng "lat" |> Jv.to_float diff --git a/src/latlng.mli b/src/latlng.mli index 120d165..3bff192 100644 --- a/src/latlng.mli +++ b/src/latlng.mli @@ -4,7 +4,7 @@ type t (** [create lat lng] is an object representing a geographical point with the given latitude and longitude *) -val create : float -> float -> t +val create : lat:float -> lng:float -> t (** [lat o] is the latitude of [o] *) val lat : t -> float From 4ef2368dc724eec58b7401d5d5f2cbcb1a24f0a8 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:07:41 +0100 Subject: [PATCH 83/99] move marker to separate module --- src/dune | 2 +- src/layer.ml | 77 ------------------------------------------------- src/layer.mli | 39 ------------------------- src/marker.ml | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/marker.mli | 38 ++++++++++++++++++++++++ 5 files changed, 117 insertions(+), 117 deletions(-) create mode 100644 src/marker.ml create mode 100644 src/marker.mli diff --git a/src/dune b/src/dune index 52d85ee..c29d930 100644 --- a/src/dune +++ b/src/dune @@ -1,6 +1,6 @@ (library (public_name leaflet) - (modules event global latlng layer map popup point icon) + (modules event global latlng layer map marker popup point icon) (private_modules global) (libraries brr) (js_of_ocaml diff --git a/src/layer.ml b/src/layer.ml index f98de08..e6ac275 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -139,80 +139,3 @@ let create_tile_osm : string option -> [ `Tile ] t = |] in Tile jv_t - -(** Marker layers *) -(* TODO make a Marker module? *) - -type marker_opt = - | Icon of Icon.t - | Keyboard of bool - | Title of string - | Alt of string - | Z_index_offset of int - | Opacity of float - | Rise_on_hover of bool - | Rise_offset of int - | Pane of string - | Shadow_pane of string - | Bubbling_mouse_events of bool - | Auto_pan_on_focus of bool - -let marker_opt_to_string : marker_opt -> string = function - | Icon _ -> "icon" - | Keyboard _ -> "keyboard" - | Title _ -> "title" - | Alt _ -> "alt" - | Z_index_offset _ -> "zIndexOffset" - | Opacity _ -> "opacity" - | Rise_on_hover _ -> "riseOnHover" - | Rise_offset _ -> "riseOffset" - | Pane _ -> "pane" - | Shadow_pane _ -> "shadowPane" - | Bubbling_mouse_events _ -> "bubblingMouseEvents" - | Auto_pan_on_focus _ -> "autoPanOnFocus" - -let marker_opt_to_jv = function - | Icon icon -> Icon.to_jv icon - | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b - -> - Jv.of_bool b - | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s - | Z_index_offset i | Rise_offset i -> Jv.of_int i - | Opacity f -> Jv.of_float f - -let create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t = - fun latlng options -> - let l = - Array.of_list - @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options - in - let jv_t = - Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] - in - Marker jv_t - -let get_latlng : [ `Marker ] t -> Latlng.t = function - | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv - -let set_latlng latlng : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in - () - -let set_z_index_offset z_index : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in - () - -let get_icon : [ `Marker ] t -> Icon.t = function - | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv - -let set_icon icon : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in - () - -let set_opacity opacity : [ `Marker ] t -> unit = function - | Marker marker -> - let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in - () diff --git a/src/layer.mli b/src/layer.mli index 84586d7..10cedc2 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -68,42 +68,3 @@ val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t by [url]. Tile server default to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : string option -> [ `Tile ] t - -(** Marker layers *) - -(** type for marker option, used to create marker *) -type marker_opt = - | Icon of Icon.t - | Keyboard of bool - | Title of string - | Alt of string - | Z_index_offset of int - | Opacity of float - | Rise_on_hover of bool - | Rise_offset of int - | Pane of string - | Shadow_pane of string - | Bubbling_mouse_events of bool - | Auto_pan_on_focus of bool - -(** [create_marker latlng options] is a new marker with the same position as - [latlng] and with options set to [options] *) -val create_marker : Latlng.t -> marker_opt list -> [ `Marker ] t - -(** Returns the current geographical position of the marker. *) -val get_latlng : [ `Marker ] t -> Latlng.t - -(** Changes the marker position to the given point. *) -val set_latlng : Latlng.t -> [ `Marker ] t -> unit - -(** Changes the zIndex offset of the marker. *) -val set_z_index_offset : int -> [ `Marker ] t -> unit - -(** Returns the current icon used by the marker *) -val get_icon : [ `Marker ] t -> Icon.t - -(** Changes the marker icon. *) -val set_icon : Icon.t -> [ `Marker ] t -> unit - -(** Changes the opacity of the marker. *) -val set_opacity : int -> [ `Marker ] t -> unit diff --git a/src/marker.ml b/src/marker.ml new file mode 100644 index 0000000..16a99c0 --- /dev/null +++ b/src/marker.ml @@ -0,0 +1,78 @@ +(** Marker layers *) +include Layer + +type t = [ `Marker ] Layer.t + +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +let marker_opt_to_string : marker_opt -> string = function + | Icon _ -> "icon" + | Keyboard _ -> "keyboard" + | Title _ -> "title" + | Alt _ -> "alt" + | Z_index_offset _ -> "zIndexOffset" + | Opacity _ -> "opacity" + | Rise_on_hover _ -> "riseOnHover" + | Rise_offset _ -> "riseOffset" + | Pane _ -> "pane" + | Shadow_pane _ -> "shadowPane" + | Bubbling_mouse_events _ -> "bubblingMouseEvents" + | Auto_pan_on_focus _ -> "autoPanOnFocus" + +let marker_opt_to_jv = function + | Icon icon -> Icon.to_jv icon + | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b + -> + Jv.of_bool b + | Title s | Alt s | Pane s | Shadow_pane s -> Jv.of_string s + | Z_index_offset i | Rise_offset i -> Jv.of_int i + | Opacity f -> Jv.of_float f + +let create_marker : Latlng.t -> marker_opt list -> t = + fun latlng options -> + let l = + Array.of_list + @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + in + let jv_t = + Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] + in + Marker jv_t + +let get_latlng : t -> Latlng.t = function + | Marker marker -> Jv.call marker "getLatLng" [||] |> Latlng.of_jv + +let set_latlng latlng : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setLatLng" [| Latlng.to_jv latlng |] in + () + +let set_z_index_offset z_index : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setZIndexOffset" [| Jv.of_int z_index |] in + () + +let get_icon : t -> Icon.t = function + | Marker marker -> Jv.call marker "getIcon" [||] |> Icon.of_jv + +let set_icon icon : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setIcon" [| Icon.to_jv icon |] in + () + +let set_opacity opacity : t -> unit = function + | Marker marker -> + let (_ : Jv.t) = Jv.call marker "setOpacity" [| Jv.of_int opacity |] in + () diff --git a/src/marker.mli b/src/marker.mli new file mode 100644 index 0000000..538ac95 --- /dev/null +++ b/src/marker.mli @@ -0,0 +1,38 @@ +type t = [ `Marker ] Layer.t + +(** type for marker option, used to create marker *) +type marker_opt = + | Icon of Icon.t + | Keyboard of bool + | Title of string + | Alt of string + | Z_index_offset of int + | Opacity of float + | Rise_on_hover of bool + | Rise_offset of int + | Pane of string + | Shadow_pane of string + | Bubbling_mouse_events of bool + | Auto_pan_on_focus of bool + +(** [create_marker latlng options] is a new marker with the same position as + [latlng] and with options set to [options] *) +val create_marker : Latlng.t -> marker_opt list -> t + +(** Returns the current geographical position of the marker. *) +val get_latlng : t -> Latlng.t + +(** Changes the marker position to the given point. *) +val set_latlng : Latlng.t -> t -> unit + +(** Changes the zIndex offset of the marker. *) +val set_z_index_offset : int -> t -> unit + +(** Returns the current icon used by the marker *) +val get_icon : t -> Icon.t + +(** Changes the marker icon. *) +val set_icon : Icon.t -> t -> unit + +(** Changes the opacity of the marker. *) +val set_opacity : int -> t -> unit From 6a58f6ff30cf204d752372a728646abddbe01872 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:08:10 +0100 Subject: [PATCH 84/99] add Icon.set_default_image_path --- src/icon.ml | 5 +++++ src/icon.mli | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/icon.ml b/src/icon.ml index f8e1bb5..4ed4972 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -67,3 +67,8 @@ let create_div ~html ~bg_pos options = in let l = Array.of_list @@ div_options @ l in Jv.call Global.leaflet "divIcon" [| Jv.obj l |] + +let set_default_image_path s = + let icon = Jv.get Global.leaflet "Icon" in + let icon_default = Jv.get icon "Default" in + Jv.set icon_default "imagePath" (Jv.of_string s) diff --git a/src/icon.mli b/src/icon.mli index d7734dd..451b51f 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -31,3 +31,6 @@ val create : string -> opt list -> t background, in pixels [html] is custom HTML code to put inside the div element, empty by default. *) val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t + +(** Sets the path of the default icon *) +val set_default_image_path : string -> unit From 65ee38b4ee9122ab85a7d2cc8ffc0f77ca0558b4 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 22:49:31 +0100 Subject: [PATCH 85/99] add tile_layer_opt; untested --- example/main.ml | 2 +- src/layer.ml | 73 +++++++++++++++++++++++++++++++++++++++---------- src/layer.mli | 22 +++++++++++++-- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/example/main.ml b/example/main.ml index 4a90920..abfe34a 100644 --- a/example/main.ml +++ b/example/main.ml @@ -4,7 +4,7 @@ let map = Leaflet.Map.create_on "map" (* setup map *) let () = (* set osm layer *) - let osm_layer = Leaflet.Layer.create_tile_osm None in + let osm_layer = Leaflet.Layer.create_tile_osm [] in Leaflet.Layer.add_to map osm_layer; (* set view *) diff --git a/src/layer.ml b/src/layer.ml index e6ac275..fa9dc0d 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -120,22 +120,65 @@ let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = (** Tile layers *) -let create_tile_osm : string option -> [ `Tile ] t = - fun url -> - let url = - Option.value url - ~default:"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" +type tile_layer_opt = + | Min_zoom of int + | Max_zoom of int + | Subdomains of string array + | Error_tile_url of string + | Zoom_offset of int + | Tms of bool + | Zoom_reverse of bool + | Detect_retina of bool + (* TODO allow string for those two + "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." + *) + | Cross_origin of bool + | Referrer_policy of bool + +let tile_layer_opt_to_string = function + | Min_zoom _ -> "minZoom" + | Max_zoom _ -> "maxZoom" + | Subdomains _ -> "subdomains" + | Error_tile_url _ -> "errorTileUrl" + | Zoom_offset _ -> "zoomOffset" + | Tms _ -> "tms" + | Zoom_reverse _ -> "zoomReverse" + | Detect_retina _ -> "detectRetina" + | Cross_origin _ -> "crossOrigin" + | Referrer_policy _ -> "referrerPolicy" + +let tile_layer_opt_to_jv = function + | Min_zoom o | Max_zoom o | Zoom_offset o -> Jv.of_int o + | Tms o + | Zoom_reverse o + | Detect_retina o + | Cross_origin o + | Referrer_policy o -> + Jv.of_bool o + | Error_tile_url o -> Jv.of_string o + | Subdomains o -> Jv.of_array Jv.of_string o + +let create_tile : + string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = + fun url ~attribution options -> + let arr = + Array.of_list + @@ ("attribution", Jv.of_string attribution) + :: List.map + (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) + options in let jv_t = - Jv.call Global.leaflet "tileLayer" - [| Jv.of_string url - ; Jv.obj - [| ( "attribution" - , Jv.of_string - "© OpenStreetMap \ - contributors" ) - |] - |] + Jv.call Global.leaflet "tileLayer" [| Jv.of_string url; Jv.obj arr |] in Tile jv_t + +let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = + fun options -> + let url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" in + let attribution = + "© OpenStreetMap \ + contributors" + in + create_tile url ~attribution options diff --git a/src/layer.mli b/src/layer.mli index 10cedc2..bd5513d 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -64,7 +64,23 @@ val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t (** Tile layers *) -(** [create_tile_osm Some(url)] is a new tile layer with tile server specified - by [url]. Tile server default to [openstreetmap.org]. See +type tile_layer_opt = + | Min_zoom of int + | Max_zoom of int + | Subdomains of string array + | Error_tile_url of string + | Zoom_offset of int + | Tms of bool + | Zoom_reverse of bool + | Detect_retina of bool + | Cross_origin of bool + | Referrer_policy of bool + +(** [create_tile url attribution opts] create a new tile layer *) +val create_tile : + string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t + +(** [create_tile_osm opts] create a new tile layer with tile server and + attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : string option -> [ `Tile ] t +val create_tile_osm : tile_layer_opt list -> [ `Tile ] t From 25f51e04178a973afe3687c368e1c74c3628a290 Mon Sep 17 00:00:00 2001 From: Swrup Date: Mon, 29 Jan 2024 23:05:24 +0100 Subject: [PATCH 86/99] cleanup Marker --- src/marker.ml | 11 +++++------ src/marker.mli | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/marker.ml b/src/marker.ml index 16a99c0..93ebd05 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -3,7 +3,7 @@ include Layer type t = [ `Marker ] Layer.t -type marker_opt = +type opt = | Icon of Icon.t | Keyboard of bool | Title of string @@ -17,7 +17,7 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -let marker_opt_to_string : marker_opt -> string = function +let opt_to_string : opt -> string = function | Icon _ -> "icon" | Keyboard _ -> "keyboard" | Title _ -> "title" @@ -31,7 +31,7 @@ let marker_opt_to_string : marker_opt -> string = function | Bubbling_mouse_events _ -> "bubblingMouseEvents" | Auto_pan_on_focus _ -> "autoPanOnFocus" -let marker_opt_to_jv = function +let opt_to_jv = function | Icon icon -> Icon.to_jv icon | Keyboard b | Rise_on_hover b | Bubbling_mouse_events b | Auto_pan_on_focus b -> @@ -40,11 +40,10 @@ let marker_opt_to_jv = function | Z_index_offset i | Rise_offset i -> Jv.of_int i | Opacity f -> Jv.of_float f -let create_marker : Latlng.t -> marker_opt list -> t = +let create : Latlng.t -> opt list -> t = fun latlng options -> let l = - Array.of_list - @@ List.map (fun o -> (marker_opt_to_string o, marker_opt_to_jv o)) options + Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] diff --git a/src/marker.mli b/src/marker.mli index 538ac95..ebb8096 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -1,7 +1,7 @@ type t = [ `Marker ] Layer.t (** type for marker option, used to create marker *) -type marker_opt = +type opt = | Icon of Icon.t | Keyboard of bool | Title of string @@ -15,9 +15,9 @@ type marker_opt = | Bubbling_mouse_events of bool | Auto_pan_on_focus of bool -(** [create_marker latlng options] is a new marker with the same position as - [latlng] and with options set to [options] *) -val create_marker : Latlng.t -> marker_opt list -> t +(** [create latlng options] is a new marker with the same position as [latlng] + and with options set to [options] *) +val create : Latlng.t -> opt list -> t (** Returns the current geographical position of the marker. *) val get_latlng : t -> Latlng.t From 85181f784a4baad6131c50bdc69e2849c2b96b84 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 00:20:36 +0100 Subject: [PATCH 87/99] add more options to tile_layer --- src/layer.ml | 57 ++++++++++++++++++++++++++++++++++++++++++++------- src/layer.mli | 13 ++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index fa9dc0d..ec9bb68 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -129,11 +129,25 @@ type tile_layer_opt = | Tms of bool | Zoom_reverse of bool | Detect_retina of bool - (* TODO allow string for those two - "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." - *) - | Cross_origin of bool + | (* TODO allow string for those two + "Whether the crossOrigin attribute will be added to the tiles. If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. Refer to CORS Settings for valid String values." + *) + Cross_origin of bool | Referrer_policy of bool + | (* GridLayer options *) + Tile_size of Point.t + | Opacity of float + | Update_when_idle of bool + | Update_when_zooming of bool + | Update_interval of int + | Z_index of int + | Bounds of (* LatLngBounds *) Latlng.t * Latlng.t + | Max_native_zoom of int + | Min_native_zoom of int + | No_wrap of bool + | Pane of string + | Class_name of string + | Keep_buffer of int let tile_layer_opt_to_string = function | Min_zoom _ -> "minZoom" @@ -146,17 +160,46 @@ let tile_layer_opt_to_string = function | Detect_retina _ -> "detectRetina" | Cross_origin _ -> "crossOrigin" | Referrer_policy _ -> "referrerPolicy" + | Tile_size _ -> "tileSize" + | Opacity _ -> "opacity" + | Update_when_idle _ -> "updateWhenIdle" + | Update_when_zooming _ -> "updateWhenZooming" + | Update_interval _ -> "updateInterval" + | Z_index _ -> "zIndex" + | Bounds _ -> "bounds" + | Max_native_zoom _ -> "maxNativeZoom" + | Min_native_zoom _ -> "minNativeZoom" + | No_wrap _ -> "noWrap" + | Pane _ -> "pane" + | Class_name _ -> "className" + | Keep_buffer _ -> "keepBuffer" let tile_layer_opt_to_jv = function - | Min_zoom o | Max_zoom o | Zoom_offset o -> Jv.of_int o + | Min_zoom o + | Max_zoom o + | Zoom_offset o + | Update_interval o + | Z_index o + | Keep_buffer o + | Min_native_zoom o + | Max_native_zoom o -> + Jv.of_int o | Tms o | Zoom_reverse o | Detect_retina o | Cross_origin o - | Referrer_policy o -> + | Referrer_policy o + | Update_when_idle o + | Update_when_zooming o + | No_wrap o -> Jv.of_bool o - | Error_tile_url o -> Jv.of_string o + | Error_tile_url o | Pane o | Class_name o -> Jv.of_string o | Subdomains o -> Jv.of_array Jv.of_string o + | Opacity o -> Jv.of_float o + | Tile_size o -> Point.to_jv o + | Bounds (a, b) -> + (* create the actual LatlngBounds from the pair *) + Jv.call Global.leaflet "latLngBounds" [| Latlng.to_jv a; Latlng.to_jv b |] let create_tile : string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = diff --git a/src/layer.mli b/src/layer.mli index bd5513d..5c28258 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -75,6 +75,19 @@ type tile_layer_opt = | Detect_retina of bool | Cross_origin of bool | Referrer_policy of bool + | Tile_size of Point.t + | Opacity of float + | Update_when_idle of bool + | Update_when_zooming of bool + | Update_interval of int + | Z_index of int + | Bounds of (* LatLngBounds *) Latlng.t * Latlng.t + | Max_native_zoom of int + | Min_native_zoom of int + | No_wrap of bool + | Pane of string + | Class_name of string + | Keep_buffer of int (** [create_tile url attribution opts] create a new tile layer *) val create_tile : From d7de66c1be07832877be897d2e1e286f5a1ef56e Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 00:48:37 +0100 Subject: [PATCH 88/99] add polyline layer --- src/layer.ml | 29 ++++++++++++++++++++--------- src/layer.mli | 5 +++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index ec9bb68..12c35c3 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -5,59 +5,61 @@ type _ t = | Geojson : Jv.t -> [> `Geojson ] t | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t + | Vector : Jv.t -> [> `Vector ] t type _ sub = | Basic : [> `Basic ] sub | Geojson : [> `Geojson ] sub | Marker : [> `Marker ] sub | Tile : [> `Tile ] sub + | Vector : [> `Vector ] sub (** Basic layers *) let add_to : type kind. Map.t -> kind t -> unit = fun map -> function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "addTo" [| Map.to_jv map |] in () let remove : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "remove" [||] in () let remove_from : type kind. Map.t -> kind t -> unit = fun map -> function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "removeFrom" [| Map.to_jv map |] in () let bind_popup : type kind. Popup.t -> kind t -> unit = fun popup -> function - | Basic layer | Geojson layer | Marker layer | Tile layer -> + | Basic layer | Geojson layer | Marker layer | Tile layer | Vector layer -> let (_ : Jv.t) = Jv.call layer "bindPopup" [| Popup.to_jv popup |] in () let unbind_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "unbindPopup" [||] in () let open_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "openPopup" [||] in () let close_popup : type kind. kind t -> unit = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> let (_ : Jv.t) = Jv.call l "closePopup" [||] in () let get_popup : type kind. kind t -> Popup.t = function - | Basic l | Geojson l | Marker l | Tile l -> + | Basic l | Geojson l | Marker l | Tile l | Vector l -> Jv.call l "getPopup" [||] |> Popup.of_jv let to_jv : type kind. kind t -> Jv.t = function - | Basic l | Geojson l | Marker l | Tile l -> l + | Basic l | Geojson l | Marker l | Tile l | Vector l -> l let of_jv : type kind. kind sub -> Jv.t -> kind t = fun tag l -> @@ -66,6 +68,7 @@ let of_jv : type kind. kind sub -> Jv.t -> kind t = | Geojson -> Geojson l | Marker -> Marker l | Tile -> Tile l + | Vector -> Vector l let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> 'c t -> unit = fun event handler layer -> @@ -225,3 +228,11 @@ let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = contributors" in create_tile url ~attribution options + +(* Vector Layers *) + +let create_polyline : Latlng.t list -> [ `Vector ] t = + fun l -> + let l = Jv.of_list Latlng.to_jv l in + let jv_t = Jv.call Global.leaflet "polyline" [| l |] in + Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 5c28258..1f34363 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -5,12 +5,14 @@ type _ t = | Geojson : Jv.t -> [> `Geojson ] t | Marker : Jv.t -> [> `Marker ] t | Tile : Jv.t -> [> `Tile ] t + | Vector : Jv.t -> [> `Vector ] t type _ sub = | Basic : [> `Basic ] sub | Geojson : [> `Geojson ] sub | Marker : [> `Marker ] sub | Tile : [> `Tile ] sub + | Vector : [> `Vector ] sub (** Basic layers *) @@ -97,3 +99,6 @@ val create_tile : attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) val create_tile_osm : tile_layer_opt list -> [ `Tile ] t + +(** [create_polyline l] create a polyline layer from [l] *) +val create_polyline : Latlng.t list -> [ `Vector ] t From 59e22333e788730df05a5a84dc38e66e07ba8152 Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 16:55:19 +0100 Subject: [PATCH 89/99] list -> array --- example/main.ml | 2 +- src/icon.ml | 10 +++++----- src/icon.mli | 4 ++-- src/layer.ml | 25 +++++++++++-------------- src/layer.mli | 8 ++++---- src/marker.ml | 6 ++---- src/marker.mli | 2 +- src/popup.ml | 8 ++------ src/popup.mli | 4 ++-- 9 files changed, 30 insertions(+), 39 deletions(-) diff --git a/example/main.ml b/example/main.ml index abfe34a..5fbe7c4 100644 --- a/example/main.ml +++ b/example/main.ml @@ -4,7 +4,7 @@ let map = Leaflet.Map.create_on "map" (* setup map *) let () = (* set osm layer *) - let osm_layer = Leaflet.Layer.create_tile_osm [] in + let osm_layer = Leaflet.Layer.create_tile_osm [||] in Leaflet.Layer.add_to map osm_layer; (* set view *) diff --git a/src/icon.ml b/src/icon.ml index 4ed4972..d59a69f 100644 --- a/src/icon.ml +++ b/src/icon.ml @@ -46,12 +46,12 @@ let opt_to_jv = function match o with Some s -> Jv.of_string s | None -> Jv.of_bool false ) let create icon_url options = - let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in - let l = Array.of_list @@ (("iconUrl", Jv.of_string icon_url) :: l) in + let l = Array.map (fun o -> (to_string o, opt_to_jv o)) options in + let l = Array.append [| ("iconUrl", Jv.of_string icon_url) |] l in Jv.call Global.leaflet "icon" [| Jv.obj l |] let create_div ~html ~bg_pos options = - let l = List.map (fun o -> (to_string o, opt_to_jv o)) options in + let l = Array.map (fun o -> (to_string o, opt_to_jv o)) options in let div_options = let html = match html with @@ -63,9 +63,9 @@ let create_div ~html ~bg_pos options = | None -> [] | Some bg_pos -> [ ("bgPos", Point.to_jv bg_pos) ] in - html @ bg_pos + html @ bg_pos |> Array.of_list in - let l = Array.of_list @@ div_options @ l in + let l = Array.append div_options l in Jv.call Global.leaflet "divIcon" [| Jv.obj l |] let set_default_image_path s = diff --git a/src/icon.mli b/src/icon.mli index 451b51f..f490910 100644 --- a/src/icon.mli +++ b/src/icon.mli @@ -24,13 +24,13 @@ type opt = (** [create icon_url options] Creates an icon instance with the given [options], and the required `iconUrl` option set to [icon_url] *) -val create : string -> opt list -> t +val create : string -> opt array -> t (** [create_div ~html ~bg_pos options] Creates an DivIcon instance with the given [options], [bg_pos] is the optional relative position of the background, in pixels [html] is custom HTML code to put inside the div element, empty by default. *) -val create_div : html:string option -> bg_pos:Point.t option -> opt list -> t +val create_div : html:string option -> bg_pos:Point.t option -> opt array -> t (** Sets the path of the default icon *) val set_default_image_path : string -> unit diff --git a/src/layer.ml b/src/layer.ml index 12c35c3..e001331 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -110,13 +110,10 @@ let geojson_opt_to_jv = function | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f -let create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t = +let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t = fun geojson options -> let l = - Array.of_list - @@ List.map - (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) - options + Array.map (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "geoJSON" [| geojson; Jv.obj l |] in Geojson jv_t @@ -205,21 +202,21 @@ let tile_layer_opt_to_jv = function Jv.call Global.leaflet "latLngBounds" [| Latlng.to_jv a; Latlng.to_jv b |] let create_tile : - string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t = + string -> attribution:string -> tile_layer_opt array -> [ `Tile ] t = fun url ~attribution options -> let arr = - Array.of_list - @@ ("attribution", Jv.of_string attribution) - :: List.map - (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) - options + Array.append + [| ("attribution", Jv.of_string attribution) |] + (Array.map + (fun o -> (tile_layer_opt_to_string o, tile_layer_opt_to_jv o)) + options ) in let jv_t = Jv.call Global.leaflet "tileLayer" [| Jv.of_string url; Jv.obj arr |] in Tile jv_t -let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = +let create_tile_osm : tile_layer_opt array -> [ `Tile ] t = fun options -> let url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" in let attribution = @@ -231,8 +228,8 @@ let create_tile_osm : tile_layer_opt list -> [ `Tile ] t = (* Vector Layers *) -let create_polyline : Latlng.t list -> [ `Vector ] t = +let create_polyline : Latlng.t array -> [ `Vector ] t = fun l -> - let l = Jv.of_list Latlng.to_jv l in + let l = Jv.of_array Latlng.to_jv l in let jv_t = Jv.call Global.leaflet "polyline" [| l |] in Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 1f34363..170ceb9 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,7 +62,7 @@ type geojson_opt = | Markers_inherit_options of bool (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : Jv.t -> geojson_opt list -> [ `Geojson ] t +val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t (** Tile layers *) @@ -93,12 +93,12 @@ type tile_layer_opt = (** [create_tile url attribution opts] create a new tile layer *) val create_tile : - string -> attribution:string -> tile_layer_opt list -> [ `Tile ] t + string -> attribution:string -> tile_layer_opt array -> [ `Tile ] t (** [create_tile_osm opts] create a new tile layer with tile server and attribution set to [openstreetmap.org]. See {:https://wiki.openstreetmap.org/wiki/Tile_servers} *) -val create_tile_osm : tile_layer_opt list -> [ `Tile ] t +val create_tile_osm : tile_layer_opt array -> [ `Tile ] t (** [create_polyline l] create a polyline layer from [l] *) -val create_polyline : Latlng.t list -> [ `Vector ] t +val create_polyline : Latlng.t array -> [ `Vector ] t diff --git a/src/marker.ml b/src/marker.ml index 93ebd05..7bf5f14 100644 --- a/src/marker.ml +++ b/src/marker.ml @@ -40,11 +40,9 @@ let opt_to_jv = function | Z_index_offset i | Rise_offset i -> Jv.of_int i | Opacity f -> Jv.of_float f -let create : Latlng.t -> opt list -> t = +let create : Latlng.t -> opt array -> t = fun latlng options -> - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let jv_t = Jv.call Global.leaflet "marker" [| Latlng.to_jv latlng; Jv.obj l |] in diff --git a/src/marker.mli b/src/marker.mli index ebb8096..a8c1237 100644 --- a/src/marker.mli +++ b/src/marker.mli @@ -17,7 +17,7 @@ type opt = (** [create latlng options] is a new marker with the same position as [latlng] and with options set to [options] *) -val create : Latlng.t -> opt list -> t +val create : Latlng.t -> opt array -> t (** Returns the current geographical position of the marker. *) val get_latlng : t -> Latlng.t diff --git a/src/popup.ml b/src/popup.ml index 3960a81..d3c077a 100644 --- a/src/popup.ml +++ b/src/popup.ml @@ -69,9 +69,7 @@ let opt_to_jv = function | Pane s | Class_name s -> Jv.of_string s let create ~content ~latlng options = - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in let popup = match latlng with @@ -87,9 +85,7 @@ let create ~content ~latlng options = popup let create_from_el el ~latlng options = - let l = - Array.of_list @@ List.map (fun o -> (opt_to_string o, opt_to_jv o)) options - in + let l = Array.map (fun o -> (opt_to_string o, opt_to_jv o)) options in let popup = Jv.call Global.leaflet "popup" [| Jv.obj l |] in let popup = match latlng with diff --git a/src/popup.mli b/src/popup.mli index d099745..f8dfc84 100644 --- a/src/popup.mli +++ b/src/popup.mli @@ -43,8 +43,8 @@ val opt_to_jv : opt -> Jv.t (** [create ~content ~latlng options] is a new popup setup with [options], position set to [latlng] and content to [s] *) -val create : content:string option -> latlng:Latlng.t option -> opt list -> t +val create : content:string option -> latlng:Latlng.t option -> opt array -> t (** [create_from_el el latlng options] is a new popup setup with [options], position set to [latlng] and content to [el] *) -val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt list -> t +val create_from_el : Brr.El.t -> latlng:Latlng.t option -> opt array -> t From 3b12978c1a73b01724764e3319f75fb4ad22ee3b Mon Sep 17 00:00:00 2001 From: Swrup Date: Tue, 30 Jan 2024 18:45:24 +0100 Subject: [PATCH 90/99] add cirecle marker --- src/layer.ml | 9 +++++++++ src/layer.mli | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/layer.ml b/src/layer.ml index e001331..8475a90 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -228,8 +228,17 @@ let create_tile_osm : tile_layer_opt array -> [ `Tile ] t = (* Vector Layers *) +(* TODO add options *) + let create_polyline : Latlng.t array -> [ `Vector ] t = fun l -> let l = Jv.of_array Latlng.to_jv l in let jv_t = Jv.call Global.leaflet "polyline" [| l |] in Vector jv_t + +let create_circle_marker : Latlng.t -> float -> [ `Vector ] t = + fun center radius -> + let center = Latlng.to_jv center in + let arr = [| ("radius", Jv.of_float radius) |] in + let jv_t = Jv.call Global.leaflet "circleMarker" [| center; Jv.obj arr |] in + Vector jv_t diff --git a/src/layer.mli b/src/layer.mli index 170ceb9..b2da3ae 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -102,3 +102,7 @@ val create_tile_osm : tile_layer_opt array -> [ `Tile ] t (** [create_polyline l] create a polyline layer from [l] *) val create_polyline : Latlng.t array -> [ `Vector ] t + +(** [create_circle_marker c r] create a cirecle marker layer with center [c] and + radius [r] *) +val create_circle_marker : Latlng.t -> float -> [ `Vector ] t From c1abfd7f5334304a8f65fbd93d4320705c6a2db5 Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 3 Jul 2024 11:19:26 +0200 Subject: [PATCH 91/99] close_popup: rm label --- src/map.ml | 2 +- src/map.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.ml b/src/map.ml index 9dec8d6..3c3ae0e 100644 --- a/src/map.ml +++ b/src/map.ml @@ -50,7 +50,7 @@ let wrap_latlng latlng map = let open_popup popup map = ignore @@ Jv.call map "openPopup" [| Popup.to_jv popup |] -let close_popup ~popup map = +let close_popup popup map = ignore @@ match popup with diff --git a/src/map.mli b/src/map.mli index ede2965..b50e841 100644 --- a/src/map.mli +++ b/src/map.mli @@ -52,4 +52,4 @@ val to_jv : t -> Jv.t val open_popup : Popup.t -> t -> unit (* [close_popup opt map] if [opt] is [Some popup] closes [popup] else closes previously opened popup *) -val close_popup : popup:Popup.t option -> t -> unit +val close_popup : Popup.t option -> t -> unit From de5fe018d51eb55b1386101addcbb4cf310f0d0e Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 3 Jul 2024 11:19:48 +0200 Subject: [PATCH 92/99] ocamlformat --- .ocamlformat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ocamlformat b/.ocamlformat index 74ae9c5..f948087 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.26.1 +version=0.26.2 assignment-operator=end-line break-cases=fit break-fun-decl=wrap From f2a594f75de0161c535c40d6d4b4e17e1403a76f Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 18 Jul 2024 10:36:27 +0200 Subject: [PATCH 93/99] create_geojson need a json object --- src/layer.ml | 2 +- src/layer.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layer.ml b/src/layer.ml index 8475a90..69b0f7d 100644 --- a/src/layer.ml +++ b/src/layer.ml @@ -110,7 +110,7 @@ let geojson_opt_to_jv = function | Filter f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f -let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t = +let create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t = fun geojson options -> let l = Array.map (fun o -> (geojson_opt_to_string o, geojson_opt_to_jv o)) options diff --git a/src/layer.mli b/src/layer.mli index b2da3ae..e01be64 100644 --- a/src/layer.mli +++ b/src/layer.mli @@ -62,7 +62,7 @@ type geojson_opt = | Markers_inherit_options of bool (** [create_geojson geojson] is a new geojson layer *) -val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t +val create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t (** Tile layers *) From 987d17766c52539ae2dc44d41a7bfabaef566f0e Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 8 Feb 2024 15:37:38 +0100 Subject: [PATCH 94/99] update leaflet.js --- src/leaflet.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/leaflet.js b/src/leaflet.js index 21f499c..a3bf693 100644 --- a/src/leaflet.js +++ b/src/leaflet.js @@ -1,6 +1,6 @@ /* @preserve - * Leaflet 1.7.1, a JS library for interactive maps. http://leafletjs.com - * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ -!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";function h(t){for(var i,e,n=1,o=arguments.length;n=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=O(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=N(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function kt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var Bt={ie:tt,ielt9:it,edge:et,webkit:nt,android:ot,android23:st,androidStock:at,opera:ht,chrome:ut,gecko:lt,safari:ct,phantom:_t,opera12:dt,win:pt,ie3d:mt,webkit3d:ft,gecko3d:gt,any3d:vt,mobile:yt,mobileWebkit:xt,mobileWebkit3d:wt,msPointer:Pt,pointer:Lt,touch:bt,mobileOpera:Tt,mobileGecko:Mt,retina:zt,passiveEvents:Ct,canvas:St,svg:Zt,vml:Et},At=Pt?"MSPointerDown":"pointerdown",It=Pt?"MSPointerMove":"pointermove",Ot=Pt?"MSPointerUp":"pointerup",Rt=Pt?"MSPointerCancel":"pointercancel",Nt={},Dt=!1;function jt(t,i,e,n){function o(t){Ut(t,r)}var s,r,a,h,u,l,c,_;function d(t){t.pointerType===(t.MSPOINTER_TYPE_MOUSE||"mouse")&&0===t.buttons||Ut(t,h)}return"touchstart"===i?(u=t,l=e,c=n,_=p(function(t){t.MSPOINTER_TYPE_TOUCH&&t.pointerType===t.MSPOINTER_TYPE_TOUCH&&Ri(t),Ut(t,l)}),u["_leaflet_touchstart"+c]=_,u.addEventListener(At,_,!1),Dt||(document.addEventListener(At,Wt,!0),document.addEventListener(It,Ht,!0),document.addEventListener(Ot,Ft,!0),document.addEventListener(Rt,Ft,!0),Dt=!0)):"touchmove"===i?(h=e,(a=t)["_leaflet_touchmove"+n]=d,a.addEventListener(It,d,!1)):"touchend"===i&&(r=e,(s=t)["_leaflet_touchend"+n]=o,s.addEventListener(Ot,o,!1),s.addEventListener(Rt,o,!1)),this}function Wt(t){Nt[t.pointerId]=t}function Ht(t){Nt[t.pointerId]&&(Nt[t.pointerId]=t)}function Ft(t){delete Nt[t.pointerId]}function Ut(t,i){for(var e in t.touches=[],Nt)t.touches.push(Nt[e]);t.changedTouches=[t],i(t)}var Vt=Pt?"MSPointerDown":Lt?"pointerdown":"touchstart",qt=Pt?"MSPointerUp":Lt?"pointerup":"touchend",Gt="_leaflet_";var Kt,Yt,Xt,Jt,$t,Qt,ti=fi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ii=fi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ei="webkitTransition"===ii||"OTransition"===ii?ii+"End":"transitionend";function ni(t){return"string"==typeof t?document.getElementById(t):t}function oi(t,i){var e,n=t.style[i]||t.currentStyle&&t.currentStyle[i];return n&&"auto"!==n||!document.defaultView||(n=(e=document.defaultView.getComputedStyle(t,null))?e[i]:null),"auto"===n?null:n}function si(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function ri(t){var i=t.parentNode;i&&i.removeChild(t)}function ai(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function hi(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function ui(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function li(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=pi(t);return 0this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,N(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e,n,o=A((i=i||{}).paddingTopLeft||i.padding||[0,0]),s=A(i.paddingBottomRight||i.padding||[0,0]),r=this.getCenter(),a=this.project(r),h=this.project(t),u=this.getPixelBounds(),l=u.getSize().divideBy(2),c=O([u.min.add(o),u.max.subtract(s)]);return c.contains(h)||(this._enforcingBounds=!0,e=a.subtract(h),n=A(h.x+e.x,h.y+e.y),(h.xc.max.x)&&(n.x=a.x-e.x,0c.max.y)&&(n.y=a.y-e.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[m(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Vi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Vi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){var i;this._loaded&&!Ui(t)&&("mousedown"!==(i=t.type)&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Pi(t.target||t.srcElement),this._fireDOMEvent(t,i))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){var n;if("click"===t.type&&((n=h({},t)).type="preclick",this._fireDOMEvent(n,n.type,e)),!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&Ri(t);var s,r={originalEvent:t};"keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type&&(s=o.getLatLng&&(!o._radius||o._radius<=10),r.containerPoint=s?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=s?o.getLatLng():this.layerPointToLatLng(r.layerPoint));for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,ci(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(p(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&_i(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Yi(t){return new Xi(t)}var Xi=S.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return ci(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(ri(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+m(this),n),this._layerControlInputs.push(i),i.layerId=m(t.layer),zi(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),$i=Xi.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=si("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=si("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Oi(s),zi(s,"click",Ni),zi(s,"click",o,this),zi(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";_i(this._zoomInButton,i),_i(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||ci(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||ci(this._zoomInButton,i)}});Ki.mergeOptions({zoomControl:!0}),Ki.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new $i,this.addControl(this.zoomControl))});var Qi=Xi.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=si("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=si("div",i,e)),t.imperial&&(this._iScale=si("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=si("div","leaflet-control-attribution"),Oi(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});Ki.mergeOptions({attributionControl:!0}),Ki.addInitHook(function(){this.options.attributionControl&&(new te).addTo(this)});Xi.Layers=Ji,Xi.Zoom=$i,Xi.Scale=Qi,Xi.Attribution=te,Yi.layers=function(t,i,e){return new Ji(t,i,e)},Yi.zoom=function(t){return new $i(t)},Yi.scale=function(t){return new Qi(t)},Yi.attribution=function(t){return new te(t)};var ie=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});ie.addTo=function(t,i){return t.addHandler(i,this),this};var ee,ne={Events:Z},oe=bt?"touchstart mousedown":"mousedown",se={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},re={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ae=E.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){c(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(zi(this._dragStartTarget,oe,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ae._dragging===this&&this.finishDrag(),Si(this._dragStartTarget,oe,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var i,e;!t._simulated&&this._enabled&&(this._moved=!1,li(this._element,"leaflet-zoom-anim")||ae._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ae._dragging=this)._preventOutline&&Pi(this._element),xi(),Xt(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=bi(this._element),this._startPoint=new k(i.clientX,i.clientY),this._parentScale=Ti(e),zi(document,re[t.type],this._onMove,this),zi(document,se[t.type],this._onUp,this))))},_onMove:function(t){var i,e;!t._simulated&&this._enabled&&(t.touches&&1i&&(e.push(t[n]),o=n);oi.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function de(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||Oe.prototype._containsPoint.call(this,t,!0)}});var Ne=Ce.extend({initialize:function(t,i){c(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=g(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c]))},_onCloseButtonClick:function(t){this._close(),Ni(t)},_getAnchor:function(){return A(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Ki.mergeOptions({closePopupOnClick:!0}),Ki.include({openPopup:function(t,i,e){return t instanceof tn||(t=new tn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Me.include({bindPopup:function(t,i){return t instanceof tn?(c(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new tn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Ni(t),i instanceof Be?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var en=Qe.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){Qe.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){Qe.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=Qe.prototype.getEvents.call(this);return bt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=si("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i,e=this._map,n=this._container,o=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=n.offsetWidth,h=n.offsetHeight,u=A(this.options.offset),l=this._getAnchor(),c="top"===r?(i=a/2,h):"bottom"===r?(i=a/2,0):(i="center"===r?a/2:"right"===r?0:"left"===r?a:s.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return N(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new R(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new k(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(ri(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){ci(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=a,t.onmousemove=a,it&&this.options.opacity<1&&mi(t,this.options.opacity),ot&&!st&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),p(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(p(this._tileReady,this,t,null,o)),vi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(mi(e.el,0),z(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(ci(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),it||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(p(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new k(this._wrapX?o(t.x,this._wrapX):t.x,this._wrapY?o(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new I(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var sn=on.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=c(this,i)).detectRetina&&zt&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),_n={_initContainer:function(){this._container=si("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(hn.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=cn("shape");ci(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=cn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ri(i),t.removeInteractiveTarget(i),delete this._layers[m(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i=i||(t._stroke=cn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=g(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e=e||(t._fill=cn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){hi(t._container)},_bringToBack:function(t){ui(t._container)}},dn=Et?cn:J,pn=hn.extend({getEvents:function(){var t=hn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=dn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=dn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ri(this._container),Si(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){var t,i,e;this._map._animatingZoom&&this._bounds||(hn.prototype._update.call(this),i=(t=this._bounds).getSize(),e=this._container,this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),vi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update"))},_initPath:function(t){var i=t._path=dn("path");t.options.className&&ci(i,t.options.className),t.options.interactive&&ci(i,"leaflet-interactive"),this._updateStyle(t),this._layers[m(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ri(t._path),t.removeInteractiveTarget(t._path),delete this._layers[m(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,$(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){hi(t._path)},_bringToBack:function(t){ui(t._path)}});function mn(t){return Zt||Et?new pn(t):null}Et&&pn.include(_n),Ki.include({getRenderer:function(t){var i=(i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&ln(t)||mn(t)}});var fn=Re.extend({initialize:function(t,i){Re.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=N(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});pn.create=dn,pn.pointsToPath=$,Ne.geometryToLayer=De,Ne.coordsToLatLng=We,Ne.coordsToLatLngs=He,Ne.latLngToCoords=Fe,Ne.latLngsToCoords=Ue,Ne.getFeature=Ve,Ne.asFeature=qe,Ki.mergeOptions({boxZoom:!0});var gn=ie.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){zi(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Si(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ri(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Xt(),xi(),this._startPoint=this._map.mouseEventToContainerPoint(t),zi(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=si("div","leaflet-zoom-box",this._container),ci(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new I(this._point,this._startPoint),e=i.getSize();vi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(ri(this._box),_i(this._container,"leaflet-crosshair")),Jt(),wi(),Si(document,{contextmenu:Ni,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){var i;1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(p(this._resetState,this),0),i=new R(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})))},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Ki.addInitHook("addHandler","boxZoom",gn),Ki.mergeOptions({doubleClickZoom:!0});var vn=ie.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Ki.addInitHook("addHandler","doubleClickZoom",vn),Ki.mergeOptions({dragging:!0,inertia:!st,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var yn=ie.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new ae(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),ci(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){_i(this._map._container,"leaflet-grab"),_i(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,i=this._map;i._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=N(this._map.options.maxBounds),this._offsetLimit=O(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,i.fire("movestart").fire("dragstart"),i.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var i,e;this._map.options.inertia&&(i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(e),this._times.push(i),this._prunePositions(i)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1 Date: Thu, 8 Feb 2024 15:58:52 +0100 Subject: [PATCH 95/99] use dune-site --- example/css_path.ml | 14 ++++ example/dune | 13 +++- example/map.html | 7 +- example/{main.ml => script.ml} | 4 + leaflet.opam | 2 - src/dune | 20 ++++- src/vendor/images/layers-2x.png | Bin 0 -> 1259 bytes src/vendor/images/layers.png | Bin 0 -> 696 bytes src/vendor/images/marker-icon-2x.png | Bin 0 -> 2464 bytes src/vendor/images/marker-icon.png | Bin 0 -> 1466 bytes src/vendor/images/marker-shadow.png | Bin 0 -> 618 bytes {example => src/vendor}/leaflet.css | 111 ++++++++++++++++----------- src/{ => vendor}/leaflet.js | 0 13 files changed, 119 insertions(+), 52 deletions(-) create mode 100644 example/css_path.ml rename example/{main.ml => script.ml} (72%) create mode 100644 src/vendor/images/layers-2x.png create mode 100644 src/vendor/images/layers.png create mode 100644 src/vendor/images/marker-icon-2x.png create mode 100644 src/vendor/images/marker-icon.png create mode 100644 src/vendor/images/marker-shadow.png rename {example => src/vendor}/leaflet.css (83%) rename src/{ => vendor}/leaflet.js (100%) diff --git a/example/css_path.ml b/example/css_path.ml new file mode 100644 index 0000000..96a5634 --- /dev/null +++ b/example/css_path.ml @@ -0,0 +1,14 @@ +(* get leaflet.css path from dune-site *) + +let dune_site = List.filter Sys.file_exists Mysites.Sites.css + +let lookup_file filename = + List.find_map + (fun dir -> + let filename' = Filename.concat dir filename in + if Sys.file_exists filename' then Some filename' else None ) + dune_site + +let leaflet_css = lookup_file "leaflet.css" |> Option.get + +let () = Format.printf "%s@." leaflet_css diff --git a/example/dune b/example/dune index b868e46..1e537ac 100644 --- a/example/dune +++ b/example/dune @@ -1,5 +1,14 @@ (executable - (name main) - (modules main) + (name css_path) + (modules css_path mysites) + (libraries dune-site)) + +(generate_sites_module + (module mysites) + (sites leaflet)) + +(executable + (name script) + (modules script) (libraries brr leaflet) (modes js)) diff --git a/example/map.html b/example/map.html index 341173f..053dd17 100644 --- a/example/map.html +++ b/example/map.html @@ -1,12 +1,15 @@ + - +
-
+ +
diff --git a/example/main.ml b/example/script.ml similarity index 72% rename from example/main.ml rename to example/script.ml index 5fbe7c4..4dfe92f 100644 --- a/example/main.ml +++ b/example/script.ml @@ -1,3 +1,7 @@ +(* this file will be compiled to js + you can then open map.html to see a simple page with a map loaded + by this script *) + (* create map *) let map = Leaflet.Map.create_on "map" diff --git a/leaflet.opam b/leaflet.opam index de7dabf..b06ac7f 100644 --- a/leaflet.opam +++ b/leaflet.opam @@ -16,8 +16,6 @@ homepage: "https://forge.kumikode.org/kumikode/leaflet" bug-reports: "https://forge.kumikode.org/kumikode/leaflet/issues" depends: [ "dune" {>= "2.9"} - "brr" - "js_of_ocaml" "ocaml" {>= "4.08"} "brr" "js_of_ocaml" diff --git a/src/dune b/src/dune index c29d930..e34b390 100644 --- a/src/dune +++ b/src/dune @@ -4,4 +4,22 @@ (private_modules global) (libraries brr) (js_of_ocaml - (javascript_files leaflet.js))) + (javascript_files vendor/leaflet.js))) + +(install + (section + (site + (leaflet css))) + (files + (vendor/leaflet.css as leaflet.css))) + +(install + (section + (site + (leaflet images))) + (files + (vendor/images/layers-2x.png as images/layers-2x.png) + (vendor/images/layers.png as images/layers.png) + (vendor/images/marker-icon-2x.png as images/marker-icon-2x.png) + (vendor/images/marker-icon.png as images/marker-icon.png) + (vendor/images/marker-shadow.png as images/marker-shadow.png))) diff --git a/src/vendor/images/layers-2x.png b/src/vendor/images/layers-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..200c333dca9652ac4cba004d609e5af4eee168c1 GIT binary patch literal 1259 zcmeAS@N?(olHy`uVBq!ia0y~yU@!q;4i*LmhWx_I2@DJ@n><|{Ln;`Pe)y|cT4BSrpMM7AKE|dn|XR+k!t#k(tv`Q zFW(sEd!8~#>$+9`f9l__#fF!KZ}B_rzo8eC{r}xGzO@x)!A}C+%Y(`<1s-2^LiGH- zNefThzU1_3Qe}!q>B&sRiQ8E#H9j`Wp1zeElOM1<_xPqG{7q&i{}sRA|NWDBa`yhi zf4~1}Z!&l?D{`K~v~Df`g0pk31-#L={QUP&^~BTfPt276eJZ4F#OLLkrWm<1w?G}$K(_Zg>&?>%7rSDWy?-oPVGDw+3f6ddKzommMznMtmE1m^mE;|X)^@3r5^M>q%(7WwwkhRUVZzX zFui*B_UL;{ERE{7ySzCa{A5c-^`03^s-Cnw)fD`#!?J7Jk{=GMTBd1ws=RS{H7RMA z+lH2N3m&&zxMt!%-Q)BVRe@_$r#$1#RlV@>f}~i)v%B7(D}^uiKE0`=J9&~rL}git za^vjh=XaOCc>eeO>kuD~_nyZSSrR*HoRZ?^jT=9HS|#-C z#I0=$9oqx1b}%c7@V%LR;e=gTTa&Q*O*Q|E%7{caZdK)_+ZJf zZ?&H!g%0t3zQ`e9eahh1=NZBi3YOTd+htU}IKfpW%e~b`fYbPb(yyJ0eX|!$;Jmtc zpGlI(Uq{=OPOf@MjvXyZfAUxkxkT|?T2R1T7_4W$NpIDXdncV=-Og(5O3XcC)5tQ> zz+Ah^=e$i`pnF#TudS&IcRlWTsKE8W$-*hoo%u=2$;`|LE*k2wcM@{W?B28Hj1!|( z?&`3_D`smL6xn7gD*L#dPAd}*D+qeymA_@1k^7b7fk)o?9(Qdv5?I?{*Qdo6H_a$Z zWx4ILe&t;!1-}-TBu7TxOI@rh@5%8t*~M7);;#tq)bxD@K>`uh2LySGU20__qc2Mz zz5e8&(8Q{b_nT$qIxJK3ZwNANm$G;z+!`QW&+ygqZIXsCQ=*b?Q`wxE@t%9{h$R(y z`}7A0eZ8=B>r+-n=MV*-1+Ej;cKH>13)vbyyUbGSW~KP1V^g_>mQb1#clPCv9d}vs ze&jIq>z1(p^?bgvyl$yv;Vr)mizp0?3uUtD~sA1FSi+%x^t@XE}h@-tYzk9 zqoeJq#fQ#h%zQM#GO;LXnVpKdkC%5qo68}Ws3tQNA+-xadlV-caB*y5$@NebP0l+XkKIZj$K literal 0 HcmV?d00001 diff --git a/src/vendor/images/layers.png b/src/vendor/images/layers.png new file mode 100644 index 0000000000000000000000000000000000000000..1a72e5784b2b456eac5d7670738db80697af3377 GIT binary patch literal 696 zcmeAS@N?(olHy`uVBq!ia0y~yV2}b~4i*Lm24?3LR|W>AdQTU}kP61$5aS9JMv;5A zx9={r3D-Qo$}jd-@Kme(q}h{gk8N9f^YEHSI?4X$wi&*^XXUqVf93n@6)G0|HB0O+ z{oGRd;!&;aKiPjre@~N1y8by_{oP(ApF5A&Z+bmlV3plXXQ4Q^(0Q+y~?G3 z!a`R6-Bzb}>nxoMS3g;|c>CL9(`O!9VDQ7}^1l9i({>+QJ4%7S^9P-Qtwc)jUmWjVlF-6H4cVyjqg@ zMm}=+(G^1+f9k%t3*NyNhGDITISixbZs=XtX?<#@#To^} zllR&yC7Q0b2+Ufee$_3@VyDHEwjITj6hhx>ORdzOd~VN~YpdKO9dmD=@;Ir&?!Ka0 ze9@!>sms1^+w^n(%oWF3dR*t__&0jzGw-8qqez~?-<4~x zU6bljyRxA4^qUU`2YDx)`}y=x*@+KtSBac>;qcY?zuAd~x7`1fA4n|jeLTA^%I{0R z&%u&I8&&`GCa_jieR-P2?K98qLyM^QzxM~_RzHi!*UqnACyylIHN^Rj+B6T>B0g6wD2rb>45pm~>lr(g1)bIG-PU&x&EkqfVSO*&yS z;hbgfS=;Jm?$a(hPCjqmxW%!3m-FO{289cX=kK>@-tIN=m|6E(zuA|q`_Fk#J#X4| z*0y{tG5mYrJM&be(p=rT6IlmmfW5UU2Hz<2n7J+mwrr-TRF?&V zs_)#7Uw`VB9X@~mmHni1?h{YB&A71m;5DZS7tY*$5wYNs%e3=LkK8nDKjS{>tX=Pg zt!M9fH?R8l@Bi^z&p&_vW!`i4?dR`v_g=Q2d_K5+tzXB6px$jMQ@2gtej$F@_2e0Q z9Xb!V_n&Z^e9@s{ZR~{2!982zCT(|`dj84V&nBH`ww%75u>873@7dlh=bfjXH|{(W z7d!Ji0|SF|NswPKgN%7_eosI1qqlQh)VQ0z2_?Q_-+JKUU7huPe~$OxD4((Q%=1rn z?q4@-&3bU7TsbLBvg!I5S2dYWD;2#S7ZU|h_he3U@wtzOHt*icIpHmL zy?Ai&|Ch$MFYn&^pnlOR%aGe&>)tMux+?e~{z}Q!-sv)H?Z4&ghKAqWlXPcq>ejrS z$BVzazm`65urEF{ge%(WbpDLf>%-W3W7Q8Z-diaxRrFdX{@IL*dsFs5{QGXyqWOP4-1PE)zwr(UqLCNG@BDShIb@BbQOH~rvz6x(1rM{&)h zCI2^1ie0}woOhbaNv}DX8hPC_CNKHouloIxr(aOX;V(s%tEQ{y7mEGo6BjSNdm(Vs z!BXu_x9&`h);d4=?!Ti)lNFxZ-a1{#+&m+>>+vSZ{Dx(nJA39omT)(Wd}d*OchY}> zS=Wlr9G}5lbce-J`;++A6P>4z=5$@YRO0(?M@{jf7aF}sW!InoesgvD`S0uR{y+7c zJM*Z^%fdw#&#l*lSVe4|v9FI;Blz0)M}eM4}1S7y|fO|lGIHmwo6)ysN) z@`Y2E&hx0QzQ6Ic0N5mtVH?#oTPjdTv<|H^U?6ohXl5NmKFtfVaU1XGt93HWL;;RCz(~i-B@2 ztMZwa3;7ji`<>cuYUsWYyyfT~aW>~)Ttdp0haa*^A7`rEIn48j^>mNb9mZLUU;Dgq zb(BBsvZ#Nx_Uel(roBAMoph#Zi{zHxs=z<2V(tqsuD&`oda+X07I6J*oa%H2;&Oq~}6b8UMv1o^cHB zw@!+h7H6D zE$XK?O<(fKWT9kaoQA9NCob2O4UaD6IrQb)Yuwtmc1m82EZ4gF#as5z)n(u0^CphP zQoO8O{?ujuQ*uXBbiS=f+M{6qXZNIC-#wKX9$WmgkWlOGG%UQt>8v8C#bLHj^{?#p zq^}Oqw=ccclsgm}$Rb#}qSsU0T>Y|%q3Of?gq$MZT@r_@Zu{PyecS50-wK8AYV-e2 zfB!+nf3KYzTfhAMRX%I(>aI5GIrFb~>*ZDV4V`!wuLxajKX3Ps*sJFZ{dk2L|LmL? zzat=TpVAF?U;l!InHzU3j`scCuEl+urt8mrgm91(dc6j+tP z6A`%Mx>-aj?~J8<#TLO+mYPp{qlT&iN z&a1S3<*O-TZj{@!u_4N6X2lKeSu#n_P@}6L{b6Jl@&cjG~%U8!&Dx}z( zrMAAcayuD$-&lEawocKa4aqJsJ&X3~rhP8ov`9`;z3BX#j-a~m>C=zc{$M|Ob;m?a ziOFe4?k@Rq<_XD> zB4=;4Zhd?AM&|77+xND~`rPKZmAu(>+oP1++ovkt{rkN7+x4_tFaL!ukK6nGo$YfQ z^*v9n8!cmLEqlSVG%sR-0gvk$*DRbW z{m-p)*DZrjd!y_xaa_#o*4U(@uKo4!Pp!ij7T!1}%l>}rjh7!Q-(N81zW?~clRw*E z{?k)GYWmiy#bRlmL;oJl&J$aiudgm)F0-iHas2Qk`y1cI?%sa8bcrAT(b;!%I<0P9 z{GTy@w!r#Jyj6z3I9)}Su6`_XYb*QXS!FV5bHD9z{itSs)R*aqqTRyE=Ymg+ZNB$v zHnpZ&)$hNave^Ci{e>)>+mm|UX)=F2arlas*Y!VZ^`gp;W=x!PmHFb<*?e}lzMCE0 zvRk9d-y7$jUC*^W@geu4@I-OlYNyz3uMQ~hJ@ZAvR^;ZhPs}lPSAO%o7BSQa zbpPGC@q~NNuAHs@aeMx#hPkYYE#J1MVCVaHeA;*K{uFcFvg=QSSx&=`UA`hqVtqd? zdYU5{zPVBEP0{7r*yQI8{Cgfe_xwDKZM9d}j|Vzyjy`R7nLK@io8wY#kL`E7Jf<68x9vugLJO(0z-KZ&Qdg!24aAb07_69#wwGGo2xYnJYN`~G6Y z{f5WJTvyi~d3Pw}=hJ5XJrB~|HdTa{+%+rHYo0wvW<#>j?DETdO_@vH{3w)qU%ji; z_NZx&{M3G{ii77TKhyiAxALr4;M%-PCKi?|B^8>h(u}9Bzu_-jd+e)R*D9HVSAKyF zecrkG`QJvbip||uzVh)2I2K)AknA*Z-`f1(ke>{yQhV!uK44yNk^b+!z|FQq$H>U% z4;rj)&CipZ6`-=U+SoNLchL;9^D}-vc+R=`7mwnv#>0hg<$|tQStOh|DXSMGs-QM%v9#OT6aOo!0u!OS>mk{4v*^-gU{kUv-=DI!X3RTGs59 zrms7aq`qxvdDNrlbwOV>GmT$cCUm!OcDu!Xn-2~CQ?8YY{CTrg$>;Sw`KWyp56!-# zvTn<7$3qHR4xXKK)bzH)nQ1H9&39e2*J8I>_;hw(^Yq=jSu~fmADQ`g-w!kW*($3f zq`R`zS+DL4=#y?Q`_N(ZtLBi%<=QzX-b%(U=MFlvzxDbXmD0JBS)OidXsr40A^42_ zgQZVg7!FDwD~idOcvfy#ai6Y&gUYVfn=F;xwLJ0PR(xmSKH_ux;D=dz-;~^0xZPL! z1ozroz7KYO?cK)hC-BfMm|Z;L!tIi4FB=3m3Vm8)$!*y6sqlWqio>o2PxU5+TD=Tg zTYBn%ncKVvzMt<;x^8t&I-EsdU*;9>P2#^cg&*=|96!BiOWgcbr%qb!*P729?QZ?6 zRrA<$=6|mncDLWmyzk*RUeFH>vO3!Qi?h`T=KR)_2Cros(q` zrr!L0L#TAiV);U2p+@gxZ`B_y65O@-44>dO5ph1@TNmwv1>fy$%wBo$+&WgT#8pop z)W1KvrsG3JiO}O;u{)0M6cpu=b+0}4U()?P(=nGF;+fwCy{@FkvLxKGX3gAtJaCcS qX{9?EN|FMnBE=+YEB(x$$D3}plVUPRyu-l2z~JfX=d#Wzp$P!`FXGq$ literal 0 HcmV?d00001 diff --git a/src/vendor/images/marker-shadow.png b/src/vendor/images/marker-shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..9fd2979532a19a15b824ce763c76e04a8dafadfb GIT binary patch literal 618 zcmeAS@N?(olHy`uVBq!ia0y~yV9*3%4i*Lm2ByptwG0eQhMq2tAr*{oFSYhPb`W5> zz-9dRf4!`+aT{;(+DlW`OuKvh(cD`Fe?o50tvmGJPyYYkI}^-Pj=%i->5t$_?z+Eg z<0t)EHE)aXMy2F{nEjj_T;IYwdK?Rnnaqjf{1)D-;#kNmzt4GE;O+QxK@S+5(^AaU z7N=aDb)V1U?7Vn^%sUpxJr3q=Te918=e*elN$zhlHIzdXC1oeM8Mbg5Nj2o3WOPw+ zpMOwu*&gweJLb*OS~P7Ar@rLmS*ayg8lq+dZ0+?Zm6nX!yo^w|MJ60@P{_ADQggak&v`^0oPSK8g z6Zm$gzJVJ145{rKZ=dn?y=(KrV#&L&JR6VjWuMu>*SMBLWeLMd-$OHax6Mdiqt~NQ zs^Y#(?6|a*=efdFwcBoGHo3%{*nZNbWKCU{!`kM%S>CBD4~8GC3UcaXD%fwav8F%f z=oGOgmCmZ50aHZd{ Date: Sun, 29 Sep 2024 09:28:50 +0200 Subject: [PATCH 96/99] Map.on: make handler type be (.. -> unit) --- src/map.ml | 2 +- src/map.mli | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.ml b/src/map.ml index 3c3ae0e..146055d 100644 --- a/src/map.ml +++ b/src/map.ml @@ -33,7 +33,7 @@ let set_view latlng ~zoom map = in () -let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit = +let on : type kind. kind Event.sub -> (kind Event.t -> unit) -> t -> unit = fun event handler map -> let name = Event.sub_to_string event in let handler v = handler @@ Event.of_jv event v in diff --git a/src/map.mli b/src/map.mli index b50e841..4b8db43 100644 --- a/src/map.mli +++ b/src/map.mli @@ -28,7 +28,7 @@ val get_container : t -> Brr.El.t (** [on event handler map] add an event listener on [map] for event [event] with handler [handler] *) -val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit +val on : 'a Event.sub -> ('a Event.t -> unit) -> t -> unit (** [get_center map] is the geographical center of the map view *) val get_center : t -> Latlng.t From 4265cdce9209cb1dece064392d8545c6d9764b88 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sun, 15 Dec 2024 06:58:09 +0100 Subject: [PATCH 97/99] ocamlformat --- .ocamlformat | 2 +- example/css_path.ml | 14 ---------- example/dune | 29 ++++++++++++++------- example/{map.html => index.html} | 4 +-- example/server.ml | 44 ++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 26 deletions(-) rename example/{map.html => index.html} (68%) create mode 100644 example/server.ml diff --git a/.ocamlformat b/.ocamlformat index f948087..eb9f4e0 100644 --- a/.ocamlformat +++ b/.ocamlformat @@ -1,4 +1,4 @@ -version=0.26.2 +version=0.27.0 assignment-operator=end-line break-cases=fit break-fun-decl=wrap diff --git a/example/css_path.ml b/example/css_path.ml index 96a5634..e69de29 100644 --- a/example/css_path.ml +++ b/example/css_path.ml @@ -1,14 +0,0 @@ -(* get leaflet.css path from dune-site *) - -let dune_site = List.filter Sys.file_exists Mysites.Sites.css - -let lookup_file filename = - List.find_map - (fun dir -> - let filename' = Filename.concat dir filename in - if Sys.file_exists filename' then Some filename' else None ) - dune_site - -let leaflet_css = lookup_file "leaflet.css" |> Option.get - -let () = Format.printf "%s@." leaflet_css diff --git a/example/dune b/example/dune index 1e537ac..b7b1c0c 100644 --- a/example/dune +++ b/example/dune @@ -1,14 +1,25 @@ -(executable - (name css_path) - (modules css_path mysites) - (libraries dune-site)) - -(generate_sites_module - (module mysites) - (sites leaflet)) - (executable (name script) (modules script) (libraries brr leaflet) (modes js)) + +(executable + (name server) + (modules content server css_path mysites) + (libraries dune-site tiny_httpd)) + +(generate_sites_module + (module mysites) + (sites leaflet)) + +(rule + (with-stdout-to + content.ml + (progn + (echo "let index_html = {|") + (cat index.html) + (echo "|}") + (echo "let script_js = {|") + (cat script.bc.js) + (echo "|}")))) diff --git a/example/map.html b/example/index.html similarity index 68% rename from example/map.html rename to example/index.html index 053dd17..4ba93c9 100644 --- a/example/map.html +++ b/example/index.html @@ -4,12 +4,12 @@ - +
-
+
diff --git a/example/server.ml b/example/server.ml new file mode 100644 index 0000000..755e2ab --- /dev/null +++ b/example/server.ml @@ -0,0 +1,44 @@ +let read_file file = In_channel.with_open_bin file In_channel.input_all + +let leaflet_css = + (* get leaflet.css path from dune-site *) + let dune_site = List.filter Sys.file_exists Mysites.Sites.css in + let lookup_file filename = + List.find_map + (fun dir -> + let filename' = Filename.concat dir filename in + if Sys.file_exists filename' then Some filename' else None ) + dune_site + in + let path = + match lookup_file "leaflet.css" with + | None -> + Printf.eprintf + "File 'leaflet.css' not found.\n\ + It should have been installed with dune-site.\n\ + Did you run `dune build @install`?\n"; + exit 1 + | Some o -> o + in + read_file path + +let script_js = Content.script_js + +let index_html = Content.index_html + +module S = Tiny_httpd + +let () = + let server = S.create () in + S.add_route_handler server + S.Route.(exact "leaflet.css" @/ return) + (fun _req -> S.Response.make_string (Ok leaflet_css)); + S.add_route_handler server + S.Route.(exact "script.js" @/ return) + (fun _req -> S.Response.make_string (Ok script_js)); + S.add_route_handler server + S.Route.(return) + (fun _req -> S.Response.make_string (Ok index_html)); + + Printf.printf "listening on http://%s:%d/\n%!" (S.addr server) (S.port server); + match S.run server with Ok () -> () | Error e -> raise e From a099b05592e2f04349ed095c96f54881814964c9 Mon Sep 17 00:00:00 2001 From: Swrup Date: Thu, 19 Mar 2026 22:01:05 +0100 Subject: [PATCH 98/99] better readme; rm empty test/ --- README.md | 22 +++++++++++++--------- test/dune | 3 --- test/test.ml | 1 - 3 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 test/dune delete mode 100644 test/test.ml diff --git a/README.md b/README.md index ffa9b2e..a43ea72 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # leaflet -`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library. +`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library (v1.9.4). ## Installation @@ -16,27 +16,31 @@ If you can't or don't want to use `opam`, consult the [opam file] for build inst ## Usage -Have a look at the [example] folder. -The documentation can be consulted via `odig doc leaflet`. +The library use `dune-site` to install [leaflet's files] (CSS and images). -You will also need [leaflet's files] (CSS and images). +Have a look at the [example] folder. +It use [tiny_httpd] to provide a simple web page with a map that use [OpenStreetMap] tiles: +```sh +dune build @install +dune exec example/server.exe +``` ## About -leaflet's original code was taken from a [NGI0 funded project] +This library started off from the code of a [NGI0 funded project] - [LICENSE] - [CHANGELOG] [CHANGELOG]: ./CHANGES.md -[example]: ./example [LICENSE]: ./LICENSE.md [opam file]: ./leaflet.opam -[test suite]: ./test - [how to install opam]: https://opam.ocaml.org/doc/Install.html [OCaml]: https://ocaml.org [opam]: https://opam.ocaml.org/ [Leaflet]: https://leafletjs.com/ -[leaflet's files]: https://leafletjs.com/download.html +[Leaflet's files]: ./src/vendor/ [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ +[tiny_httpd]: https://github.com/c-cube/tiny_httpd +[example]: ./example/ +[OpenStreetMap]: https://www.openstreetmap.org diff --git a/test/dune b/test/dune deleted file mode 100644 index f929c11..0000000 --- a/test/dune +++ /dev/null @@ -1,3 +0,0 @@ -(test - (name test) - (modules test)) diff --git a/test/test.ml b/test/test.ml deleted file mode 100644 index 29ef5f9..0000000 --- a/test/test.ml +++ /dev/null @@ -1 +0,0 @@ -let () = assert true (* TODO *) From 9a6659c9125f186d1ab5494ad5b9c4a71de76080 Mon Sep 17 00:00:00 2001 From: Swrup Date: Sat, 23 Nov 2024 09:51:13 +0100 Subject: [PATCH 99/99] version 0.2 --- CHANGES.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 4cff088..0c40b06 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,11 @@ +## 0.2 + +- use leaflet.js v1.9.4 +- some small breaking changes +- add more bindings +- use dune-site to "install" css and images files +- provide example + ## 0.1 Initial release.