Compare commits

..

No commits in common. "8e88bbaf67e827296068e410739ffd0c80c8562a" and "df486e8a6579d39e2c9552094beb00023391b579" have entirely different histories.

26 changed files with 112 additions and 217 deletions

View file

@ -1,4 +1,4 @@
version=0.27.0 version=0.26.1
assignment-operator=end-line assignment-operator=end-line
break-cases=fit break-cases=fit
break-fun-decl=wrap break-fun-decl=wrap

View file

@ -1,11 +1,3 @@
## 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 ## 0.1
Initial release. Initial release.

View file

@ -1,6 +1,6 @@
# leaflet # leaflet
`leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library (v1.9.4). `leaflet` is an [OCaml] bindings library for the [Leaflet] JavaScript library.
## Installation ## Installation
@ -16,31 +16,27 @@ If you can't or don't want to use `opam`, consult the [opam file] for build inst
## Usage ## Usage
The library use `dune-site` to install [leaflet's files] (CSS and images).
Have a look at the [example] folder. Have a look at the [example] folder.
It use [tiny_httpd] to provide a simple web page with a map that use [OpenStreetMap] tiles: The documentation can be consulted via `odig doc leaflet`.
```sh
dune build @install You will also need [leaflet's files] (CSS and images).
dune exec example/server.exe
```
## About ## About
This library started off from the code of a [NGI0 funded project] leaflet's original code was taken from a [NGI0 funded project]
- [LICENSE] - [LICENSE]
- [CHANGELOG] - [CHANGELOG]
[CHANGELOG]: ./CHANGES.md [CHANGELOG]: ./CHANGES.md
[example]: ./example
[LICENSE]: ./LICENSE.md [LICENSE]: ./LICENSE.md
[opam file]: ./leaflet.opam [opam file]: ./leaflet.opam
[test suite]: ./test
[how to install opam]: https://opam.ocaml.org/doc/Install.html [how to install opam]: https://opam.ocaml.org/doc/Install.html
[OCaml]: https://ocaml.org [OCaml]: https://ocaml.org
[opam]: https://opam.ocaml.org/ [opam]: https://opam.ocaml.org/
[Leaflet]: https://leafletjs.com/ [Leaflet]: https://leafletjs.com/
[Leaflet's files]: ./src/vendor/ [leaflet's files]: https://leafletjs.com/download.html
[NGI0 funded project]: https://nlnet.nl/project/openEngiadina/ [NGI0 funded project]: https://nlnet.nl/project/openEngiadina/
[tiny_httpd]: https://github.com/c-cube/tiny_httpd
[example]: ./example/
[OpenStreetMap]: https://www.openstreetmap.org

View file

@ -1,20 +1,35 @@
(lang dune 2.9) (lang dune 2.9)
(using dune_site 0.1)
;uncomment when fixed: https://github.com/ocaml/dune/issues/9661 (implicit_transitive_deps false)
;(implicit_transitive_deps false)
(name leaflet) (name leaflet)
(generate_opam_files false) (license BSD-2-Clause)
(authors "pukkamustard <pukkamustard@posteo.net>" "swrup <swrup@protonmail.com>" "Léo Andrès <contact@ndrs.fr>")
(maintainers "swrup <swrup@protonmail.com>")
(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)
(documentation TODO/leaflet)
(generate_opam_files true)
(package (package
(name leaflet) (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 (depends
(ocaml
(>= 4.08))
brr brr
js_of_ocaml js_of_ocaml
dune-site (ocaml
(tiny_httpd :with-test) (>= 4.08))))
)
(sites (share css) (share images)))

View file

View file

@ -1,25 +1,5 @@
(executable (executable
(name script) (name main)
(modules script) (modules main)
(libraries brr leaflet) (libraries brr leaflet)
(modes js)) (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 "|}"))))

View file

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- dune-site should have installed leaflet.css
you can use css_path.ml to get it's path -->
<link href="leaflet.css" rel="stylesheet">
<script type="text/javascript" src="script.js" defer="defer"></script>
</head>
<body>
<main>
<!-- don't forget to set a size! -->
<div id="map" style="height: 700px; width: 700px"></div>
</main>
</body>
</html>

View file

@ -45,10 +45,7 @@
} }
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ /* .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 img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg { .leaflet-container .leaflet-overlay-pane svg,
max-width: none !important;
max-height: none !important;
}
.leaflet-container .leaflet-marker-pane img, .leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img, .leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img, .leaflet-container .leaflet-tile-pane img,
@ -56,15 +53,8 @@
.leaflet-container .leaflet-tile { .leaflet-container .leaflet-tile {
max-width: none !important; max-width: none !important;
max-height: none !important; max-height: none !important;
width: auto;
padding: 0;
} }
.leaflet-container img.leaflet-tile {
/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */
mix-blend-mode: plus-lighter;
}
.leaflet-container.leaflet-touch-zoom { .leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y; -ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y; touch-action: pan-x pan-y;
@ -176,6 +166,9 @@
/* zoom and fade animations */ /* zoom and fade animations */
.leaflet-fade-anim .leaflet-tile {
will-change: opacity;
}
.leaflet-fade-anim .leaflet-popup { .leaflet-fade-anim .leaflet-popup {
opacity: 0; opacity: 0;
-webkit-transition: opacity 0.2s linear; -webkit-transition: opacity 0.2s linear;
@ -190,10 +183,9 @@
-ms-transform-origin: 0 0; -ms-transform-origin: 0 0;
transform-origin: 0 0; transform-origin: 0 0;
} }
svg.leaflet-zoom-animated { .leaflet-zoom-anim .leaflet-zoom-animated {
will-change: transform; will-change: transform;
} }
.leaflet-zoom-anim .leaflet-zoom-animated { .leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); -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); -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
@ -259,11 +251,14 @@ svg.leaflet-image-layer.leaflet-interactive path {
.leaflet-container { .leaflet-container {
background: #ddd; background: #ddd;
outline-offset: 1px; outline: 0;
} }
.leaflet-container a { .leaflet-container a {
color: #0078A8; color: #0078A8;
} }
.leaflet-container a.leaflet-active {
outline: 2px solid orange;
}
.leaflet-zoom-box { .leaflet-zoom-box {
border: 2px dotted #38f; border: 2px dotted #38f;
background: rgba(255,255,255,0.5); background: rgba(255,255,255,0.5);
@ -272,10 +267,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
/* general typography */ /* general typography */
.leaflet-container { .leaflet-container {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
font-size: 12px;
font-size: 0.75rem;
line-height: 1.5;
} }
@ -285,7 +277,8 @@ svg.leaflet-image-layer.leaflet-interactive path {
box-shadow: 0 1px 5px rgba(0,0,0,0.65); box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px; border-radius: 4px;
} }
.leaflet-bar a { .leaflet-bar a,
.leaflet-bar a:hover {
background-color: #fff; background-color: #fff;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
width: 26px; width: 26px;
@ -302,8 +295,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
background-repeat: no-repeat; background-repeat: no-repeat;
display: block; display: block;
} }
.leaflet-bar a:hover, .leaflet-bar a:hover {
.leaflet-bar a:focus {
background-color: #f4f4f4; background-color: #f4f4f4;
} }
.leaflet-bar a:first-child { .leaflet-bar a:first-child {
@ -356,12 +348,12 @@ svg.leaflet-image-layer.leaflet-interactive path {
border-radius: 5px; border-radius: 5px;
} }
.leaflet-control-layers-toggle { .leaflet-control-layers-toggle {
background-image: url(images/layers.png); background-image: url(/assets/img/layers.png);
width: 36px; width: 36px;
height: 36px; height: 36px;
} }
.leaflet-retina .leaflet-control-layers-toggle { .leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png); background-image: url(/assets/img/layers-2x.png);
background-size: 26px 26px; background-size: 26px 26px;
} }
.leaflet-touch .leaflet-control-layers-toggle { .leaflet-touch .leaflet-control-layers-toggle {
@ -393,8 +385,6 @@ svg.leaflet-image-layer.leaflet-interactive path {
} }
.leaflet-control-layers label { .leaflet-control-layers label {
display: block; display: block;
font-size: 13px;
font-size: 1.08333em;
} }
.leaflet-control-layers-separator { .leaflet-control-layers-separator {
height: 0; height: 0;
@ -403,8 +393,8 @@ svg.leaflet-image-layer.leaflet-interactive path {
} }
/* Default icon URLs */ /* Default icon URLs */
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ .leaflet-default-icon-path {
background-image: url(images/marker-icon.png); background-image: url(/assets/img/marker-icon.png);
} }
@ -412,27 +402,23 @@ svg.leaflet-image-layer.leaflet-interactive path {
.leaflet-container .leaflet-control-attribution { .leaflet-container .leaflet-control-attribution {
background: #fff; background: #fff;
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.7);
margin: 0; margin: 0;
} }
.leaflet-control-attribution, .leaflet-control-attribution,
.leaflet-control-scale-line { .leaflet-control-scale-line {
padding: 0 5px; padding: 0 5px;
color: #333; color: #333;
line-height: 1.4;
} }
.leaflet-control-attribution a { .leaflet-control-attribution a {
text-decoration: none; text-decoration: none;
} }
.leaflet-control-attribution a:hover, .leaflet-control-attribution a:hover {
.leaflet-control-attribution a:focus {
text-decoration: underline; text-decoration: underline;
} }
.leaflet-attribution-flag { .leaflet-container .leaflet-control-attribution,
display: inline !important; .leaflet-container .leaflet-control-scale {
vertical-align: baseline !important; font-size: 11px;
width: 1em;
height: 0.6669em;
} }
.leaflet-left .leaflet-control-scale { .leaflet-left .leaflet-control-scale {
margin-left: 5px; margin-left: 5px;
@ -445,11 +431,14 @@ svg.leaflet-image-layer.leaflet-interactive path {
border-top: none; border-top: none;
line-height: 1.1; line-height: 1.1;
padding: 2px 5px 1px; padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap; white-space: nowrap;
overflow: hidden;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; box-sizing: border-box;
background: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px #fff; background: #fff;
background: rgba(255, 255, 255, 0.5);
} }
.leaflet-control-scale-line:not(:first-child) { .leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777; border-top: 2px solid #777;
@ -485,22 +474,17 @@ svg.leaflet-image-layer.leaflet-interactive path {
border-radius: 12px; border-radius: 12px;
} }
.leaflet-popup-content { .leaflet-popup-content {
margin: 13px 24px 13px 20px; margin: 13px 19px;
line-height: 1.3; line-height: 1.4;
font-size: 13px;
font-size: 1.08333em;
min-height: 1px;
} }
.leaflet-popup-content p { .leaflet-popup-content p {
margin: 17px 0; margin: 18px 0;
margin: 1.3em 0;
} }
.leaflet-popup-tip-container { .leaflet-popup-tip-container {
width: 40px; width: 40px;
height: 20px; height: 20px;
position: absolute; position: absolute;
left: 50%; left: 50%;
margin-top: -1px;
margin-left: -20px; margin-left: -20px;
overflow: hidden; overflow: hidden;
pointer-events: none; pointer-events: none;
@ -511,7 +495,6 @@ svg.leaflet-image-layer.leaflet-interactive path {
padding: 1px; padding: 1px;
margin: -10px auto 0; margin: -10px auto 0;
pointer-events: auto;
-webkit-transform: rotate(45deg); -webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg); -moz-transform: rotate(45deg);
@ -528,21 +511,24 @@ svg.leaflet-image-layer.leaflet-interactive path {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
padding: 4px 4px 0 0;
border: none; border: none;
text-align: center; text-align: center;
width: 24px; width: 18px;
height: 24px; height: 14px;
font: 16px/24px Tahoma, Verdana, sans-serif; font: 16px/14px Tahoma, Verdana, sans-serif;
color: #757575; color: #c3c3c3;
text-decoration: none; text-decoration: none;
font-weight: bold;
background: transparent; background: transparent;
} }
.leaflet-container a.leaflet-popup-close-button:hover, .leaflet-container a.leaflet-popup-close-button:hover {
.leaflet-container a.leaflet-popup-close-button:focus { color: #999;
color: #585858;
} }
.leaflet-popup-scrolled { .leaflet-popup-scrolled {
overflow: auto; overflow: auto;
border-bottom: 1px solid #ddd;
border-top: 1px solid #ddd;
} }
.leaflet-oldie .leaflet-popup-content-wrapper { .leaflet-oldie .leaflet-popup-content-wrapper {
@ -555,6 +541,9 @@ svg.leaflet-image-layer.leaflet-interactive path {
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; -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); 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-zoom,
.leaflet-oldie .leaflet-control-layers, .leaflet-oldie .leaflet-control-layers,
@ -589,7 +578,7 @@ svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: none; pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4); box-shadow: 0 1px 3px rgba(0,0,0,0.4);
} }
.leaflet-tooltip.leaflet-interactive { .leaflet-tooltip.leaflet-clickable {
cursor: pointer; cursor: pointer;
pointer-events: auto; pointer-events: auto;
} }
@ -649,13 +638,3 @@ svg.leaflet-image-layer.leaflet-interactive path {
margin-left: -12px; margin-left: -12px;
border-right-color: #fff; border-right-color: #fff;
} }
/* Printing */
@media print {
/* Prevent printers from removing background-images of controls. */
.leaflet-control {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
}

View file

@ -1,7 +1,3 @@
(* 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 *) (* create map *)
let map = Leaflet.Map.create_on "map" let map = Leaflet.Map.create_on "map"

12
example/map.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<link href="leaflet.css" rel="stylesheet">
<script type="text/javascript" src="main.bc.js" defer="defer"></script>
</head>
<body>
<main>
<div id="map" style="height: 100%"></div>
</main>
</body>
</html>

View file

@ -1,44 +0,0 @@
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

View file

@ -1,6 +1,5 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0" opam-version: "2.0"
name: "leaflet"
version: "0.2"
synopsis: "Bindings for the Leaflet JavaScript library" synopsis: "Bindings for the Leaflet JavaScript library"
description: description:
"leaflet is an OCaml bindings library for the Leaflet JavaScript library." "leaflet is an OCaml bindings library for the Leaflet JavaScript library."
@ -13,14 +12,13 @@ authors: [
license: "BSD-2-Clause" license: "BSD-2-Clause"
tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"] tags: ["leaflet" "javascript" "bindings" "interactive" "map" "openstreetmap"]
homepage: "https://git.zapashcanon.fr/swrup/leaflet" homepage: "https://git.zapashcanon.fr/swrup/leaflet"
doc: "TODO/leaflet"
bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues" bug-reports: "https://git.zapashcanon.fr/swrup/leaflet/issues"
depends: [ depends: [
"dune" {>= "2.9"} "dune" {>= "2.9"}
"ocaml" {>= "4.08"}
"brr" "brr"
"js_of_ocaml" "js_of_ocaml"
"dune-site" "ocaml" {>= "4.08"}
"tiny_httpd" {with-test}
"odoc" {with-doc} "odoc" {with-doc}
] ]
build: [ build: [

View file

@ -4,22 +4,4 @@
(private_modules global) (private_modules global)
(libraries brr) (libraries brr)
(js_of_ocaml (js_of_ocaml
(javascript_files vendor/leaflet.js))) (javascript_files 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)))

View file

@ -110,7 +110,7 @@ let geojson_opt_to_jv = function
| Filter f -> Jv.repr f | Filter f -> Jv.repr f
| Coords_to_latlng f -> Jv.repr f | Coords_to_latlng f -> Jv.repr f
let create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t = let create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t =
fun geojson options -> fun geojson options ->
let l = let l =
Array.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

View file

@ -62,7 +62,7 @@ type geojson_opt =
| Markers_inherit_options of bool | Markers_inherit_options of bool
(** [create_geojson geojson] is a new geojson layer *) (** [create_geojson geojson] is a new geojson layer *)
val create_geojson : Brr.Json.t -> geojson_opt array -> [ `Geojson ] t val create_geojson : Jv.t -> geojson_opt array -> [ `Geojson ] t
(** Tile layers *) (** Tile layers *)

6
src/leaflet.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -33,7 +33,7 @@ let set_view latlng ~zoom map =
in in
() ()
let on : type kind. kind Event.sub -> (kind Event.t -> unit) -> t -> unit = let on : type kind. kind Event.sub -> (kind Event.t -> 'b) -> t -> unit =
fun event handler map -> fun event handler map ->
let name = Event.sub_to_string event in let name = Event.sub_to_string event in
let handler v = handler @@ Event.of_jv event v in let handler v = handler @@ Event.of_jv event v in

View file

@ -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 (** [on event handler map] add an event listener on [map] for event [event] with
handler [handler] *) handler [handler] *)
val on : 'a Event.sub -> ('a Event.t -> unit) -> t -> unit val on : 'a Event.sub -> ('a Event.t -> 'b) -> t -> unit
(** [get_center map] is the geographical center of the map view *) (** [get_center map] is the geographical center of the map view *)
val get_center : t -> Latlng.t val get_center : t -> Latlng.t

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 B

File diff suppressed because one or more lines are too long

3
test/dune Normal file
View file

@ -0,0 +1,3 @@
(test
(name test)
(modules test))

1
test/test.ml Normal file
View file

@ -0,0 +1 @@
let () = assert true (* TODO *)