This emacs lisp code adds geo location (latitude / longitude) link type to org-mode.
Geo location links can be opened with any web service or osm.el.
Also, you can freely customize the results when exporting geo location links.
Example of export results:
https://misohena.github.io/org-geolink/example-js.html
(with-eval-after-load "org"
(require 'org-geolink))
Customize default map service as you like:
- [[geo:36.2893,137.64785]]
- [[geo:36.2893,137.64785;z=18]]
- [[geo:36.2893,137.64785][Oku-hotaka-dake]]
When exporting as HTML, the output is as follows:
<ul class="org-ul">
<li><a href="https://www.openstreetmap.org/#map=15/36.2893/137.64785" target="_blank" rel="noopener" data-geolink="36.2893,137.64785">36.2893,137.64785</a></li>
<li><a href="https://www.openstreetmap.org/#map=18/36.2893/137.64785" target="_blank" rel="noopener" data-geolink="36.2893,137.64785;z=18">36.2893,137.64785</a></li>
<li><a href="https://www.openstreetmap.org/#map=15/36.2893/137.64785" target="_blank" rel="noopener" data-geolink="36.2893,137.64785">Oku-hotaka-dake</a></li>
</ul>
The syntax of the path part is the same as the geo URI Scheme (rfc5870, Wikipedia). However, CRS conversion is not supported.
More Examples:
https://raw.githubusercontent.com/misohena/org-geolink/master/example.org
Type C-c C-o
on geo link.
The variable org-geolink-follow-function
allows you to customize how locations are opened. In addition to the web browser, you can also open a location using the browse-url geo protocol handler or osm.el.
If you are using osm.el, you can open the location currently displayed in the osm buffer with a map service registered with org-geolink.
(with-eval-after-load 'osm
(define-key osm-mode-map (kbd \"O\")
#'org-geolink-open-osm-el-location-by-selected-web-service))
{{{PATH}}}
- Original path string.
{{{CONTENTS}}}
- Description of link or result of expanding org-geolink-contents-template.
{{{URL}}}
- Result of expanding org-geolink-url-template.
{{{1}}}
- First coordinate number (Latitude).
{{{2}}}
- Second coordinate number (Longitude).
{{{3}}}
- Third coordinate number (Optional).
{{{
pname}}}
- Value of link parameter ( ; pname = pvalue ).
{{{
pname:
fmt}}}
(if pvalue (format fmt pvalue) "")
.
Template to use when creating a link HTML.
- Default
<a href="{{{URL}}}" target="_blank" rel="noopener" data-geolink="{{{PATH}}}">{{{CONTENTS}}}</a>
- In-Buffer Setting
#+GEOLINK_HTML_TEMPLATE:
string
Link text to use if no description is specified.
- Default
- ~”{{{1}}},{{{2}}}”~
- In-Buffer Setting
#+GEOLINK_CONTENTS_TEMPLATE:
string
Template to use when creating a URL.
Specify in a format like ~”https://www.openstreetmap.org/#map={{{z}}}/{{{1}}}/{{{2}}}”~ .
nil means to use the default map service.
- Default
- nil (Use org-geolink-map-service-default )
Default map service. Specify ID symbol defined in org-geolink-map-services-user and org-geolink-map-services
- Default
- osm
- In-Buffer Setting
#+GEOLINK_MAP:
map-id- Predefined map services
-
ID osm Open Street Map apple Apple Maps google Goole Maps jgsi The Geospatial Information Authority of Japan
Alist of user defined map services.
- Default
- nil
- Example
-
(setq org-geolink-map-services-user '((ex-map-1 (name . "Example Map 1") (url . "https://www.example.com/type1/#map={{{z}}}/{{{1}}}/{{{2}}}")) (ex-map-2 (name . "Example Map 2") (url . "https://www.example.com/type2/lat={{{1}}}&lng={{{2}}}&z={{{z}}}"))))
Default path parameters alist.
- Default
- ’((“z” . “15”))
- In-Buffer Setting
#+GEOLINK_DEFAULT_PARAMS:
key=value;key=value=;…
The following CSS inserts an earth emoji right after the geolink:
a[data-geolink]::after {
content: "\1f310";
}
See demo page: https://misohena.github.io/org-geolink/example-js.html
Org-mode source code: https://raw.githubusercontent.com/misohena/org-geolink/master/example-js.org
The following example replaces a geolink with an embedded map. Replaces only the links with ;style=map
with the Leaflet map. You can also specify ;map-width=
and ;map-height=
.
Settings:
(require 'org-geolink)
(defconst my-geolink-html-template-default
"<a href=\"{{{URL}}}\" target=\"_blank\" rel=\"noopener\" data-geolink=\"{{{PATH}}}\">{{{CONTENTS}}}</a>")
(defconst my-geolink-html-template-for-map
"<script>
(function(){
const div=document.createElement('div');
div.style.width = '{{{map-width}}}px';
div.style.height = '{{{map-height}}}px';
div.style.display = 'inline-block';
document.currentScript.parentNode.insertBefore(div, document.currentScript);
const map = L.map(div).setView([{{{1}}},{{{2}}}],{{{z}}});
const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{
attribution: '© <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors, <a href=\"http://creativecommons.org/licenses/by-sa/2.0/\">CC-BY-SA</a>',
maxZoom: 19
});
tileLayer.addTo(map);
})();
</script>
")
(setf (alist-get "map-width" org-geolink-default-params nil nil #'equal) "200")
(setf (alist-get "map-height" org-geolink-default-params nil nil #'equal) "200")
(defun my-geolink-html-template (params)
(if (equal (cdr (assoc "style" params)) "map")
(org-geolink-expand-template my-geolink-html-template-for-map params)
(org-geolink-expand-template my-geolink-html-template-default params)))
(setq org-geolink-html-template #'my-geolink-html-template)
Org-mode source:
#+HTML_HEAD: <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
#+HTML_HEAD: <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
Normal Link: [[geo:36.2893,137.64785][Oku-hotaka-dake]]
Map [[geo:36.2893,137.64785;style=map]] or [[geo:36.2893,137.64785;z=18;style=map]]
[[geo:36.2893,137.64785;z=18;style=map;map-width=400;map-height=300]]
Header-free HTML template:
(defconst my-geolink-html-template-for-map
"<script>
(function(){
const currentScript = document.currentScript;
function createMap(){
const div=document.createElement('div');
div.style.width = '{{{map-width}}}px';
div.style.height = '{{{map-height}}}px';
div.style.display = 'inline-block';
currentScript.parentNode.insertBefore(div, currentScript);
const map = L.map(div).setView([{{{1}}},{{{2}}}],{{{z}}});
const tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{attribution: '© <a href=\"http://osm.org/copyright\">OpenStreetMap</a> contributors, <a href=\"http://creativecommons.org/licenses/by-sa/2.0/\">CC-BY-SA</a>', maxZoom: 19});
tileLayer.addTo(map);
}
if(window.L){
createMap();
}
else{
let scr = Array.prototype.find.call(document.head.querySelectorAll('script[src]'), (scr)=>scr.src.includes('leaflet.js'));
if(scr){
const onloadOld = scr.onload;
scr.onload = ()=>{if(onloadOld){onloadOld();} createMap();};
}
else{
const ls = document.createElement('link');
ls.rel='stylesheet';
ls.href='https://unpkg.com/leaflet@1.7.1/dist/leaflet.css';
ls.crossOrigin='';
ls.integrity='sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==';
document.head.appendChild(ls);
scr = document.createElement('script');
scr.src = 'https://unpkg.com/leaflet@1.7.1/dist/leaflet.js';
scr.crossOrigin='';
scr.integrity='sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==';
scr.onload = createMap;
document.head.appendChild(scr);
}
}
})();
</script>
")