Add Geospatial plugin (#7406)
* Add XLSX import spec for demo real estate spreadsheets * Fix fieldname * Improve map pin * RealEstate demo: Set lat, long, price fields to be numeric * Clean up Flickr demo * Update geomap widget to refresh properly * Add Leaflet MasterCluster plugin * Setup the marker cluster plugin * Rearrange real estate demo * Reduce default cluster radius * Beginnings of real estate demo * Fix interpretation of HTTP status codes * Real estate demo: Make columns hideable * Real estate demo: sortability * Real estate demo: search and limit * Fix typo * Fix lat long transposition * Fix startup ordering * Add geolookup operator * Real Estate Demo: Add support for computed columns * Real estate demo: Increase result limit * Remove demo data * Track map pan and zoom state in a state tiddler * WIP * Use geojson extension for geojson file * Use geojson extensions for another geojson file * Split demo from the geospatial plugin into its own edition * Add build targets required by ./bin/site-build.sh... ... when building the geospatial edition as the main edition, making it easier to find on Vercel * CI Fixes * Fix default tab * Rearranging geospatial plugin vs. edition * More refactoring between demo and plugin * Start of plugin docs * Display GeoJSON properties on click * Fix layer lookup demo * Restore XLSX Utils plugin and dependencies * Cleanup docs * Remove 5.2.8 release note * Remove 5.2.8 release note * Docs update * Fix minor refreshing bug for geomap widget * Docs updates * Add jsonset operator * Add geonearestpoint operator * jsonset: support for other data types and documentation * Add logo * Add link to preview build * jsonset: add support for assigning JSON strings * Fix nonstandard initialisation code for fill/parameter/slot widgets * Introduce testcase widget so that we can reuse testcases as documentation examples There's still a bit to do: adding tabs to the source panel of the testcase display, and tweaking the CSS. * Update logo * Testcasewidget: Add tabs for switching between source tiddlers * Testcase appearance tweaks * Switch to fluid-fixed layout * Docs for the testcase-transclude and testcase-view widgets * Split docs into separate tabs * Extend testcase-view to be able to view other fields * Extend default testcase template to show all fields of payload tiddlers * Add some geomap examples * Fix testcase rounded corners * Add a geomap layer demo * Add favicon * Switch from building the geospatial plugin as the main build back to tw5.com To make it easier to get to the documentation for the new features * Remove obsolete comment * Remove geospatial plugin from tw5.com build * Fix build link * Add note about core enhancements included in this branch * Refactor data widget implementation To avoid code duplication * Integrate test cases with the docs * Remove erroneously pasted docs material * Remove erroneously copied olc-encode tests within old-decode test case * Refactor compound tiddler handling into data widget And add some tests for the data widget * Default test case template tweaks * Move Flickr macros into geospatial plugin from the demo edition * FlickrDemo: Simplify UI * FlickrMacros: Use a template to define photo tiddler fields * Remove geospatial plugin from prerelease default tiddlers * Extend Flickr helpers to support photoTiddlerTemplate parameter * Update modification times of doc tiddlers So that they are at the top of the recent tab * Update 5.3.0 release note * Remove custom CI step for this branch * Restore standard sitetitle * Flickr macro docs * Rename $:/tags/GeoLayer to $:/tags/GeoFeature And make sure that it works with all GeoJSON features, not just polygons * More test data (from leaflet.js) * Captions should be transcluded, not viewed raw * Make HTTP handler use wiki of widget that sent the message * Switch testcase widget to use an intrinsic template Makes things much simpler * Complete Flickr demos * Extend geonearestpoint operator to work with feature collections * Extend realestate demo to show data on nearest volcano * Flickr macros: fix pagination after first page Make sure that the widget we create to run the actions also has access to the event handlers attached to the rootwidget. * Real estate demo: Fix nearest volcano * Testcase docs update * Testcase template: put title at the top and remove header row * Docs correction * New geonearestpoint test case * Make test cases editable * Test case default template: Always put "Output" tab first * Initial Commit * HttpClient object shouldn't need to know about events * Add support for cancelling HTTP requests * Make the number of outstanding HTTP requests available in a state tiddler * Add a network activity button Click it to cancel outstanding requests * WIP * Fix typo Thanks @btheado Co-authored-by: btheado <brian.theado@gmail.com> * Data widget: parse carriage returns in compound tiddlers * Fix crash when cancelling more than one HTTP request Thanks @saqimtiaz * Further fixes to cancelling outstanding HTTP requests * Don't have data widget rendering its own JSON Making the data widget render its raw JSON (introduced in683ec33004
) was a bad idea as it messes up the innerwiki use of the data widget. Instead we use the testcase widget with a special template to render the raw JSON of the payload of a testcase, thus giving us a way to test the data widget * Fix missed docs update * Introduce geolayer widget for specifying layers for geomap * Fix breaking tests * Remove docs references to obsolete widgets * Tests for geounion, geointersect and geodifference * Support for multiple base layers * Make the layers control visible which allows the base layer to be chosen, and individual overlay layers to be hidden * Add tiddlers tagged $:/tags/GeoBaseLayer to define some useful map base layers * Add geobaselayer widget to define base layers * Add a satellite base layer and another terrain base layer * Add a note where to get more base layers * Docs update * Geomap widget: fix default base layer rendering * Add startPosition and layersPanel attributes to geomap widget * Update geolayer widget docs with missing attributes * Add interactive demos for geounion, geodifference, geointersection * Open geofeature and geomarker maps on the bounds of their content * Move settings from demo into plugin Because now the Flickr macros are part of the plugin * Icon for geospatial plugin * Fix missing body * Flickr Demo typo * Docs update * Add support for draggable markers * Removed accidentally committed file * Remove unwanted log * Add support for tm-request-geolocation message * Fix typo * Fix bug when fitting to non-extistent bounds * Update main wiki greeting * Use "Flickr helpers" instead of "Flickr macros" * File renames for05d3271603
* Fix testcase widget example Thanks @btheado * Fix testcase widget refreshing * Fix failing tests from03b6413c7a
* Docs: Clarify that template must be in the payload * Testcase widget: Exclude tab state tiddlers See https://github.com/Jermolene/TiddlyWiki5/pull/7406#discussion_r1327971965 Thanks @btheado * Remove obsolete setquerystring operator Instead we have the query- parameters to the http request message * Remove obsolete change to --setfield command * Fix tiddler name typo * Initial Commit * Add note to preview build * Fix whitespace and indenting Thanks @pmario * Fix crash with unset $tiddler attribute on <$data> widget Thanks @CodaCodr * Remove Stamen baselayers They have stopped making them available for free - see https://maps.stamen.com/stadia-partnership/ * Disable test that won't run in browser CI * Disable broken tests * Update olc-encode.tid (#7885) Correct spelling * Don't duplicate "description" field in test cases * Use different background colours for nested testcase widgets * Extend the testcase widget to run tests * Add testcases to control panel * Add a view template body template to render testcase tiddlers * Test edition should display testcases * Whitespace fixes * Make testcase tiddler tempalte link to itself * Styling tweaks * Docs improvements * Styling tweaks * Run the new tw5.com testcases in the test edition * Update data widget to display its content in JSON * Add testcase convenience procedure * Clearer testcases for data widget, and docs tweaks * Don't expect our intentionally failing test to pass * Extend testcase default template so that the display format can be chosen It is selected by setting the variable "displayFormat" * DataWidget docs typo * Mark Geospatial plugin as experimental * Update to Leaflet v1.9.4 * Remove unneeded template Left over from when the testcase widget was first implemented * Don't hide the volcanoes of the world data set * Update Flickr demo docs * Fix subtle typo that was preventing popups from working correctly * Go back to hiding the volcanoes of the world by default Too much data for a small device now that the markers are displayed correctly * Clarify docs for tm-request-location * Update modified testcase from master * Prepare for merging --------- Co-authored-by: btheado <brian.theado@gmail.com> Co-authored-by: Drevarr <drevarr@gmail.com>
@ -393,6 +393,17 @@ node $TW5_BUILD_TIDDLYWIKI \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/highlight/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
# /plugins/tiddlywiki/geospatial/index.html Demo wiki with geospatial plugin
|
||||
# /plugins/tiddlywiki/geospatial/empty.html Empty wiki with geospatial plugin
|
||||
node $TW5_BUILD_TIDDLYWIKI \
|
||||
./editions/geospatialdemo \
|
||||
--verbose \
|
||||
--load $TW5_BUILD_OUTPUT/build.tid \
|
||||
--output $TW5_BUILD_OUTPUT \
|
||||
--rendertiddler $:/core/save/all plugins/tiddlywiki/geospatial/index.html text/plain \
|
||||
--rendertiddler $:/core/save/empty plugins/tiddlywiki/geospatial/empty.html text/plain \
|
||||
|| exit 1
|
||||
|
||||
######################################################
|
||||
#
|
||||
# Language editions
|
||||
|
4
editions/geospatialdemo/tiddlers/DefaultTiddlers.tid
Normal file
@ -0,0 +1,4 @@
|
||||
title: $:/DefaultTiddlers
|
||||
|
||||
HelloThere
|
||||
$:/plugins/tiddlywiki/geospatial
|
14
editions/geospatialdemo/tiddlers/Features.tid
Normal file
@ -0,0 +1,14 @@
|
||||
title: GeoFeatures
|
||||
tags: $:/tags/GeospatialDemo
|
||||
|
||||
This is a list of all the tiddlers containing ~GeoJSON feature collections in this wiki (identified by the tag <<tag "$:/tags/GeoFeature">>). A ~GeoJSON feature collection is a list of features, each of which consists of a geometry and associated metadata.
|
||||
|
||||
<ul>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoFeature]sort[caption]]">
|
||||
<li>
|
||||
<$link>
|
||||
<$transclude field="caption"><$view field="title"/></$view>
|
||||
</$link>
|
||||
</li>
|
||||
</$list>
|
||||
</ul>
|
27
editions/geospatialdemo/tiddlers/Flickr Demo.tid
Normal file
@ -0,0 +1,27 @@
|
||||
title: Flickr Demo
|
||||
caption: Flickr
|
||||
tags: $:/tags/GeospatialDemo
|
||||
|
||||
! Retrieve Geotagged Flickr Photos
|
||||
|
||||
This demo will not work until you have set a Flickr API key in the [[Geospatial plugin settings|$:/plugins/tiddlywiki/geospatial/settings]].
|
||||
|
||||
<$button>
|
||||
<$macrocall $name="flickr-get-album-items" albumID={{$:/config/flickr-param/album-id}}/>
|
||||
Get Flickr album
|
||||
</$button> <$edit-text tiddler="$:/config/flickr-param/album-id" tag="input"/> (parameter should be an album ID, e.g. 72157630297432522)
|
||||
|
||||
<$button>
|
||||
<$macrocall $name="flickr-get-interesting-items"/>
|
||||
Get Flickr interesting items
|
||||
</$button>
|
||||
|
||||
<$button>
|
||||
<$macrocall $name="flickr-get-photos-of-user-items" userID={{$:/config/flickr-param/user-id}}/>
|
||||
Get Flickr photos of user
|
||||
</$button> <$edit-text tiddler="$:/config/flickr-param/user-id" tag="input"/> (parameter should be a user ID, e.g. 35468148136@N01)
|
||||
|
||||
<$button>
|
||||
<$macrocall $name="flickr-get-group-items" groupID={{$:/config/flickr-param/group-id}}/>
|
||||
Get Flickr group
|
||||
</$button> <$edit-text tiddler="$:/config/flickr-param/group-id" tag="input"/> (parameter should be an group ID, e.g. 22075379@N00)
|
BIN
editions/geospatialdemo/tiddlers/Geospatial Plugin Logo.png
Normal file
After Width: | Height: | Size: 509 KiB |
@ -0,0 +1,2 @@
|
||||
title: Geospatial Plugin Logo
|
||||
type: image/png
|
37
editions/geospatialdemo/tiddlers/HelloThere.tid
Normal file
@ -0,0 +1,37 @@
|
||||
title: HelloThere
|
||||
|
||||
//The latest build of the Geospatial Plugin can be found at:// https://tiddlywiki5-git-geospatial-plugin-jermolene.vercel.app/plugins/tiddlywiki/geospatial/index.html
|
||||
|
||||
!! Introduction
|
||||
|
||||
{{$:/plugins/tiddlywiki/geospatial/readme}}
|
||||
|
||||
!! Prerequisites
|
||||
|
||||
This demo requires that the API keys needed to access external services be obtained by the end user and manually configured. These keys are stored in the browser and so only need to be set up once. See the ''Settings'' tab of [[the plugin|$:/plugins/tiddlywiki/geospatial]] for details.
|
||||
|
||||
!! Demos
|
||||
|
||||
* Visit the ~GeoFeatures and ~GeoMarkers tabs to see the data loaded into this wiki
|
||||
* Click on a link to a layer or marker to open the corresponding tiddler that includes a map
|
||||
* Use the Flickr tab to retrieve geotagged photographs from Flickr
|
||||
* Visit a ~GeoMarker tiddler and use the "Call ~TravelTime" button to calculate an isochrone from that location using the ~TravelTime API
|
||||
|
||||
! Map Showing All Features and Markers
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
startPosition="bounds"
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoBaseLayer]]">
|
||||
<$geobaselayer title=<<currentTiddler>>/>
|
||||
</$list>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoMarker]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}} name={{!!caption}}/>
|
||||
</$list>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoFeature]]">
|
||||
<$geolayer json={{!!text}} color={{!!color}} name={{!!caption}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
|
||||
<<tabs tabsList:"[all[tiddlers+shadows]tag[$:/tags/GeospatialDemo]]" default:"GeoMarkers">>
|
53
editions/geospatialdemo/tiddlers/Markers.tid
Normal file
@ -0,0 +1,53 @@
|
||||
title: GeoMarkers
|
||||
tags: $:/tags/GeospatialDemo
|
||||
|
||||
|
||||
|
||||
\procedure onsuccess()
|
||||
<$action-setfield
|
||||
$tiddler="CurrentLocation"
|
||||
tags="$:/tags/GeoMarker"
|
||||
timestamp=<<timestamp>>
|
||||
lat=<<latitude>>
|
||||
long=<<longitude>>
|
||||
alt=<<altitude>>
|
||||
accuracy=<<accuracy>>
|
||||
altitudeAccuracy=<<altitudeAccuracy>>
|
||||
heading=<<heading>>
|
||||
speed=<<speed>>
|
||||
/>
|
||||
\end
|
||||
\procedure onerror()
|
||||
<$action-setfield
|
||||
$tiddler="CurrentLocation"
|
||||
$field="text"
|
||||
$value=<<error>>
|
||||
/>
|
||||
\end
|
||||
\procedure onclick()
|
||||
<$action-sendmessage
|
||||
$message="tm-request-geolocation"
|
||||
actionsSuccess=<<onsuccess>>
|
||||
actionsError=<<onerror>>
|
||||
/>
|
||||
\end
|
||||
|
||||
This is a list of all the tiddlers containing ~GeoJSON markers in this wiki (identified by the tag <<tag "$:/tags/GeoMarker">>). A ~GeoJSON marker identifies a location via latitude and longitude (and optional altitude) and may also contain associated metadata in JSON format.
|
||||
|
||||
Click this button to create a marker from the current location. Your browser will ask for permission before granting the request. On some browsers it takes a couple of seconds for the location to appear.
|
||||
|
||||
<$button actions=<<onclick>>>
|
||||
Request location
|
||||
</$button>
|
||||
|
||||
{{CurrentLocation}}
|
||||
|
||||
<ul>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoMarker]sort[caption]]">
|
||||
<li>
|
||||
<$link>
|
||||
<$view field="caption"><$view field="title"/></$view>
|
||||
</$link>
|
||||
</li>
|
||||
</$list>
|
||||
</ul>
|
3
editions/geospatialdemo/tiddlers/SiteSubtitle.tid
Normal file
@ -0,0 +1,3 @@
|
||||
title: $:/SiteSubtitle
|
||||
|
||||
Geographic Data Features for ~TiddlyWiki
|
3
editions/geospatialdemo/tiddlers/SiteTitle.tid
Normal file
@ -0,0 +1,3 @@
|
||||
title: $:/SiteTitle
|
||||
|
||||
[img width=200 [Geospatial Plugin Logo]]<br>Geospatial Plugin
|
@ -0,0 +1,6 @@
|
||||
title: $:/plugins/geospatial/demo/ViewTemplateBodyFilters
|
||||
tags: $:/tags/ViewTemplateBodyFilter
|
||||
list-before: $:/config/ViewTemplateBodyFilters/stylesheet
|
||||
|
||||
[tag[$:/tags/GeoFeature]then[ui/geofeature]]
|
||||
[tag[$:/tags/GeoMarker]then[ui/geomarker]]
|
@ -0,0 +1,9 @@
|
||||
title: cities/LimehouseTownHall
|
||||
tags: $:/tags/GeoMarker
|
||||
caption: Limehouse Town Hall
|
||||
lat: 51.51216651476898
|
||||
long: -0.03138562132137639
|
||||
alt: 0
|
||||
|
||||
This is Limehouse Town Hall!
|
||||
|
9
editions/geospatialdemo/tiddlers/cities/Motovun.tid
Normal file
@ -0,0 +1,9 @@
|
||||
title: cities/Motovun
|
||||
tags: $:/tags/GeoMarker
|
||||
icon: Motovun Jack.svg
|
||||
caption: Motovun
|
||||
lat: 45.336453407749225
|
||||
long: 13.828231379455806
|
||||
alt: 0
|
||||
|
||||
This is Motovun!
|
8
editions/geospatialdemo/tiddlers/cities/NewYork.tid
Normal file
@ -0,0 +1,8 @@
|
||||
title: cities/NewYork
|
||||
tags: $:/tags/GeoMarker
|
||||
caption: New York
|
||||
lat: 40.712778
|
||||
long: -74.006111
|
||||
alt: 0
|
||||
|
||||
This is New York!
|
8
editions/geospatialdemo/tiddlers/cities/Oxford.tid
Normal file
@ -0,0 +1,8 @@
|
||||
title: cities/Oxford
|
||||
tags: $:/tags/GeoMarker
|
||||
caption: Oxford
|
||||
lat: 51.751944
|
||||
long: -1.257778
|
||||
alt: 0
|
||||
|
||||
This is Oxford!
|
8
editions/geospatialdemo/tiddlers/cities/Toronto.tid
Normal file
@ -0,0 +1,8 @@
|
||||
title: cities/Toronto
|
||||
tags: $:/tags/GeoMarker
|
||||
caption: Toronto
|
||||
lat: 43.651070
|
||||
long: -79.347015
|
||||
alt: 0
|
||||
|
||||
This is Toronto!
|
8
editions/geospatialdemo/tiddlers/cities/Winchester.tid
Normal file
@ -0,0 +1,8 @@
|
||||
title: cities/Winchester
|
||||
tags: $:/tags/GeoMarker
|
||||
caption: Winchester
|
||||
lat: 51.0632
|
||||
long: -1.308
|
||||
alt: 0
|
||||
|
||||
This is Winchester!
|
@ -0,0 +1,5 @@
|
||||
title: $:/config/flickr-param/
|
||||
|
||||
album-id: 72157630297432522
|
||||
user-id: 35468148136@N01
|
||||
group-id: 22075379@N00
|
4
editions/geospatialdemo/tiddlers/default-import-spec.tid
Normal file
@ -0,0 +1,4 @@
|
||||
title: $:/config/plugins/tiddlywiki/xlsx-utils/default-import-spec
|
||||
type: text/vnd.tiddlywiki
|
||||
|
||||
$:/_importspec/RealEstate/
|
BIN
editions/geospatialdemo/tiddlers/favicon.png
Normal file
After Width: | Height: | Size: 36 KiB |
2
editions/geospatialdemo/tiddlers/favicon.png.meta
Normal file
@ -0,0 +1,2 @@
|
||||
title: $:/favicon.ico
|
||||
type: image/png
|
@ -0,0 +1,5 @@
|
||||
title: $:/geospatialdemo/features/canada-census-subdivision-millesime
|
||||
caption: Canada Census Subdivisions Millesime
|
||||
type: application/json
|
||||
tags: $:/tags/GeoFeature
|
||||
color: #f8f
|
109
editions/geospatialdemo/tiddlers/features/denver-bikerental.tid
Normal file
@ -0,0 +1,109 @@
|
||||
title: $:/geospatialdemo/features/denver/bikerental
|
||||
caption: Denver bike rentals as ~GeoJSON points
|
||||
tags: $:/tags/GeoFeature
|
||||
type: application/json
|
||||
color: blue
|
||||
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9998241,
|
||||
39.7471494
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 51
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9983545,
|
||||
39.7502833
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 52
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9963919,
|
||||
39.7444271
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 54
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9960754,
|
||||
39.7498956
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 55
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9933717,
|
||||
39.7477264
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 57
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9913392,
|
||||
39.7432392
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 58
|
||||
},
|
||||
{
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
-104.9788452,
|
||||
39.6933755
|
||||
]
|
||||
},
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is a B-Cycle Station. Come pick up a bike and pay by the hour. What a deal!"
|
||||
},
|
||||
"id": 74
|
||||
}
|
||||
]
|
||||
}
|
63
editions/geospatialdemo/tiddlers/features/denver-campus.tid
Normal file
@ -0,0 +1,63 @@
|
||||
title: $:/geospatialdemo/features/denver/campus
|
||||
caption: Denver Auraria West Campus as ~GeoJSON multipolygons
|
||||
tags: $:/tags/GeoFeature
|
||||
type: application/json
|
||||
color: purple
|
||||
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "This is the Auraria West Campus",
|
||||
"style": {
|
||||
"weight": 2,
|
||||
"color": "#999",
|
||||
"opacity": 1,
|
||||
"fillColor": "#B0DE5C",
|
||||
"fillOpacity": 0.8
|
||||
}
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
[-105.00432014465332, 39.74732195489861],
|
||||
[-105.00715255737305, 39.74620006835170],
|
||||
[-105.00921249389647, 39.74468219277038],
|
||||
[-105.01067161560059, 39.74362625960105],
|
||||
[-105.01195907592773, 39.74290029616054],
|
||||
[-105.00989913940431, 39.74078835902781],
|
||||
[-105.00758171081543, 39.74059036160317],
|
||||
[-105.00346183776855, 39.74059036160317],
|
||||
[-105.00097274780272, 39.74059036160317],
|
||||
[-105.00062942504881, 39.74072235994946],
|
||||
[-105.00020027160645, 39.74191033368865],
|
||||
[-105.00071525573731, 39.74276830198601],
|
||||
[-105.00097274780272, 39.74369225589818],
|
||||
[-105.00097274780272, 39.74461619742136],
|
||||
[-105.00123023986816, 39.74534214278395],
|
||||
[-105.00183105468751, 39.74613407445653],
|
||||
[-105.00432014465332, 39.74732195489861]
|
||||
],[
|
||||
[-105.00361204147337, 39.74354376414072],
|
||||
[-105.00301122665405, 39.74278480127163],
|
||||
[-105.00221729278564, 39.74316428375108],
|
||||
[-105.00283956527711, 39.74390674342741],
|
||||
[-105.00361204147337, 39.74354376414072]
|
||||
]
|
||||
],[
|
||||
[
|
||||
[-105.00942707061768, 39.73989736613708],
|
||||
[-105.00942707061768, 39.73910536278566],
|
||||
[-105.00685214996338, 39.73923736397631],
|
||||
[-105.00384807586671, 39.73910536278566],
|
||||
[-105.00174522399902, 39.73903936209552],
|
||||
[-105.00041484832764, 39.73910536278566],
|
||||
[-105.00041484832764, 39.73979836621592],
|
||||
[-105.00535011291504, 39.73986436617916],
|
||||
[-105.00942707061768, 39.73989736613708]
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
56
editions/geospatialdemo/tiddlers/features/denver-freebus.tid
Normal file
@ -0,0 +1,56 @@
|
||||
title: $:/geospatialdemo/features/denver/freebus
|
||||
caption: Denver free bus routes as ~GeoJSON linestrings
|
||||
tags: $:/tags/GeoFeature
|
||||
type: application/json
|
||||
color: green
|
||||
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[-105.00341892242432, 39.75383843460583],
|
||||
[-105.0008225440979, 39.751891803969535]
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"popupContent": "This is a free bus line that will take you across downtown.",
|
||||
"underConstruction": false
|
||||
},
|
||||
"id": 1
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[-105.0008225440979, 39.751891803969535],
|
||||
[-104.99820470809937, 39.74979664004068]
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"popupContent": "This is a free bus line that will take you across downtown.",
|
||||
"underConstruction": true
|
||||
},
|
||||
"id": 2
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[-104.99820470809937, 39.74979664004068],
|
||||
[-104.98689651489258, 39.741052354709055]
|
||||
]
|
||||
},
|
||||
"properties": {
|
||||
"popupContent": "This is a free bus line that will take you across downtown.",
|
||||
"underConstruction": false
|
||||
},
|
||||
"id": 3
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
title: $:/geospatialdemo/features/denver/lightrail
|
||||
caption: Denver light rail stops as ~GeoJSON points
|
||||
tags: $:/tags/GeoFeature
|
||||
type: application/json
|
||||
color: red
|
||||
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "18th & California Light Rail Stop"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-104.98999178409576, 39.74683938093904]
|
||||
}
|
||||
},{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"popupContent": "20th & Welton Light Rail Stop"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [-104.98689115047453, 39.747924136466565]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
title: $:/geospatialdemo/features/harvard-volcanoes-of-the-world
|
||||
caption: Harvard Volcanoes of the World
|
||||
type: application/json
|
||||
tags: $:/tags/GeoFeature/Hidden
|
||||
color: #f88
|
54
editions/geospatialdemo/tiddlers/features/us-states.geojson
Normal file
@ -0,0 +1,5 @@
|
||||
title: $:/geospatialdemo/features/us-states
|
||||
caption: US State Boundaries
|
||||
type: application/json
|
||||
tags: $:/tags/GeoFeature
|
||||
color: #88f
|
@ -0,0 +1,99 @@
|
||||
title: real-estate-demo
|
||||
caption: Real Estate Demo
|
||||
tags: $:/tags/GeospatialDemo
|
||||
|
||||
\define default-display-filter() [<currentTiddler>get<fieldname>]
|
||||
\define default-limit() 10
|
||||
|
||||
This is a list of all the tiddlers containing ~GeoJSON markers in this wiki (identified by the tag <<tag "$:/tags/GeoMarker">>) viewed as both a map and a table.
|
||||
|
||||
<$let
|
||||
schema={{real-estate-demo/schema}}
|
||||
>
|
||||
<div>
|
||||
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
|
||||
<$let
|
||||
config={{{ [<schema>jsonget[columns],<index>,[name]addprefix[$:/config/geospatial/demo/real-estate-demo/columns/]] }}}
|
||||
>
|
||||
<div>
|
||||
<$checkbox tiddler=<<config>> field="visible" checked="yes" unchecked="no" default="yes">
|
||||
<$text text={{{ [<schema>jsonget[columns],<index>,[caption]] }}}/>
|
||||
</$checkbox>
|
||||
</div>
|
||||
</$let>
|
||||
</$list>
|
||||
</div>
|
||||
<div>
|
||||
Sorting by
|
||||
<$select tiddler="$:/config/geospatial/demo/real-estate-demo/sort-field" default="title">
|
||||
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
|
||||
<option value={{{ [<schema>jsonget[columns],<index>,[name]] }}}>
|
||||
<$text text={{{ [<schema>jsonget[columns],<index>,[caption]] }}}/>
|
||||
</option>
|
||||
</$list>
|
||||
</$select>
|
||||
<$checkbox tiddler="$:/config/geospatial/demo/real-estate-demo/sort-order" field="text" checked="reverse" unchecked="normal" default="normal">
|
||||
Reverse sort order
|
||||
</$checkbox>
|
||||
</div>
|
||||
<div>
|
||||
Search: <$edit-text tiddler="$:/config/geospatial/demo/real-estate-demo/search" tag="input"/>
|
||||
</div>
|
||||
<div>
|
||||
Limit: <$edit-text tiddler="$:/config/geospatial/demo/real-estate-demo/limit" tag="input" placeholder=<<default-limit>>/>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
|
||||
<$let
|
||||
config={{{ [<schema>jsonget[columns],<index>,[name]addprefix[$:/config/geospatial/demo/real-estate-demo/columns/]] }}}
|
||||
>
|
||||
<$list filter="[<config>get[visible]else[yes]match[yes]]" variable="ignore">
|
||||
<th>
|
||||
<$text text={{{ [<schema>jsonget[columns],<index>,[caption]] }}}/>
|
||||
</th>
|
||||
</$list>
|
||||
</$let>
|
||||
</$list>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<$let
|
||||
sortField={{{ [[$:/config/geospatial/demo/real-estate-demo/sort-field]get[text]else[title]] }}}
|
||||
sortOrder={{{ [[$:/config/geospatial/demo/real-estate-demo/sort-order]get[text]else[normal]] }}}
|
||||
limit={{{ [[$:/config/geospatial/demo/real-estate-demo/limit]get[text]] :else[<default-limit>] }}}
|
||||
>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoMarker]search:*{$:/config/geospatial/demo/real-estate-demo/search}nsort<sortField>order<sortOrder>limit<limit>]">
|
||||
<$let
|
||||
rowTiddler=<<currentTiddler>>
|
||||
>
|
||||
<$setmultiplevariables
|
||||
$names="[<schema>jsonindexes[variables]sort[]]"
|
||||
$values="[<schema>jsonindexes[variables]sort[]] :map[<schema>jsonget[variables],<currentTiddler>] :map[subfilter<currentTiddler>]"
|
||||
>
|
||||
<tr>
|
||||
<$list filter="[<schema>jsonindexes[columns]]" variable="index">
|
||||
<$let
|
||||
config={{{ [<schema>jsonget[columns],<index>,[name]addprefix[$:/config/geospatial/demo/real-estate-demo/columns/]] }}}
|
||||
>
|
||||
<$list filter="[<config>get[visible]else[yes]match[yes]]" variable="ignore">
|
||||
<td>
|
||||
<$let
|
||||
fieldname={{{ [<schema>jsonget[columns],<index>,[name]] }}}
|
||||
displayFilter={{{ [<schema>jsonget[columns],<index>,[display]] :else[<default-display-filter>] }}}
|
||||
>
|
||||
<$text text={{{ [subfilter<displayFilter>] }}}/>
|
||||
</$let>
|
||||
</td>
|
||||
</$list>
|
||||
</$let>
|
||||
</$list>
|
||||
</tr>
|
||||
</$setmultiplevariables>
|
||||
</$let>
|
||||
</$list>
|
||||
</$let>
|
||||
</tbody>
|
||||
</table>
|
||||
</$let>
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"columns": [
|
||||
{"name": "address", "caption": "Address", "type": "string"},
|
||||
{"name": "broker", "caption": "Broker", "type": "string"},
|
||||
{"name": "city", "caption": "City", "type": "string"},
|
||||
{"name": "lat", "caption": "Latitude", "type": "number"},
|
||||
{"name": "long", "caption": "Longitude", "type": "number"},
|
||||
{"name": "price", "caption": "Price", "type": "number"},
|
||||
{"name": "salesagent", "caption": "Sales Agent", "type": "string"},
|
||||
{"name": "state", "caption": "State", "type": "string"},
|
||||
{"name": "title", "caption": "Title", "type": "string"},
|
||||
{"name": "zipcode", "caption": "Zip Code", "type": "string"},
|
||||
{"name": "census-province", "caption": "Census Province", "type": "string", "display": "[<census-data>jsonget[0],[prov_name_en],[0]]"},
|
||||
{"name": "census-division", "caption": "Census Division", "type": "string", "display": "[<census-data>jsonget[0],[cd_name_en],[0]]"},
|
||||
{"name": "census-subdivision", "caption": "Census Subdivision", "type": "string", "display": "[<census-data>jsonget[0],[csd_name_en],[0]]"},
|
||||
{"name": "nearest-volcano", "caption": "Nearest Volcano", "type": "string", "display": "[{$:/geospatialdemo/features/harvard-volcanoes-of-the-world}geonearestpoint<coords>]"}
|
||||
],
|
||||
"variables": {
|
||||
"coords": "[<rowTiddler>] :map[geopoint{!!long},{!!lat}]",
|
||||
"census-data": "[<rowTiddler>] :map[geopoint{!!long},{!!lat}geolookup{$:/geospatialdemo/features/canada-census-subdivision-millesime}]"
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
title: real-estate-demo/schema
|
||||
type: application/json
|
||||
|
@ -0,0 +1,5 @@
|
||||
import-spec-role: row
|
||||
list: $:/_importspec/RealEstate/PropertiesRow/Field/long $:/_importspec/RealEstate/PropertiesRow/Field/lat $:/_importspec/RealEstate/PropertiesRow/Field/price $:/_importspec/RealEstate/PropertiesRow/Field/broker $:/_importspec/RealEstate/PropertiesRow/Field/salesagent $:/_importspec/RealEstate/PropertiesRow/Field/zipcode $:/_importspec/RealEstate/PropertiesRow/Field/state $:/_importspec/RealEstate/PropertiesRow/Field/city $:/_importspec/RealEstate/PropertiesRow/Field/tags $:/_importspec/RealEstate/PropertiesRow/Field/title $:/_importspec/RealEstate/PropertiesRow/Field/address
|
||||
tags:
|
||||
title: $:/_importspec/RealEstate/PropertiesRow
|
||||
type: text/vnd.tiddlywiki
|
@ -0,0 +1,7 @@
|
||||
import-field-column: Address
|
||||
import-field-name: address
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/address
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-field-column: Broker
|
||||
import-field-name: broker
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/broker
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-field-column: City
|
||||
import-field-name: city
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/city
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,8 @@
|
||||
import-field-column: Latitude
|
||||
import-field-name: lat
|
||||
import-field-type: number
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/lat
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,8 @@
|
||||
import-field-column: Longitude
|
||||
import-field-name: long
|
||||
import-field-type: number
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/long
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,8 @@
|
||||
import-field-column: Price
|
||||
import-field-name: price
|
||||
import-field-type: number
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/price
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-field-column: Sales Agent
|
||||
import-field-name: salesagent
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/salesagent
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-field-column: State
|
||||
import-field-name: state
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/state
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-spec-role: field
|
||||
import-field-name: tags
|
||||
import-field-type: string
|
||||
import-field-source: constant
|
||||
import-field-value: $:/tags/GeoMarker
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/tags
|
||||
type: text/vnd.tiddlywiki
|
@ -0,0 +1,8 @@
|
||||
import-field-column: Address
|
||||
import-field-name: title
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
import-field-skip-tiddler-if-blank: yes
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/title
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-field-column: Zip Code
|
||||
import-field-name: zipcode
|
||||
import-field-source: column
|
||||
import-spec-role: field
|
||||
title: $:/_importspec/RealEstate/PropertiesRow/Field/zipcode
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
import-sheet-name: Final Day 1 and 2
|
||||
import-spec-role: sheet
|
||||
list: [[$:/_importspec/RealEstate/PropertiesRow]]
|
||||
tags:
|
||||
title: $:/_importspec/RealEstate/PropertiesSheet
|
||||
type: text/vnd.tiddlywiki
|
||||
|
@ -0,0 +1,7 @@
|
||||
caption: Real Estate Listing Demo
|
||||
import-spec-role: workbook
|
||||
list: [[$:/_importspec/RealEstate/PropertiesSheet]]
|
||||
tags:
|
||||
title: $:/_importspec/RealEstate/
|
||||
type: text/vnd.tiddlywiki
|
||||
|
2
editions/geospatialdemo/tiddlers/sidebarlayout.tid
Normal file
@ -0,0 +1,2 @@
|
||||
title: $:/themes/tiddlywiki/vanilla/options/sidebarlayout
|
||||
text: fluid-fixed
|
39
editions/geospatialdemo/tiddlers/ui/geofeature.tid
Normal file
@ -0,0 +1,39 @@
|
||||
title: ui/geofeature
|
||||
|
||||
\define create-intersection()
|
||||
<$let
|
||||
intersectLayer={{{ =[<currentTiddler>get[text]] =[<otherFeature>get[text]] +[geointersect[]] }}}
|
||||
>
|
||||
<$action-createtiddler $basetitle="$:/temp/_IsochroneLayer" text={{{ [<intersectLayer>] }}} tags="$:/tags/GeoFeature" caption={{{ [<captionThisFeature>addsuffix[ intersected with ]addsuffix<captionOtherFeature>] }}}/>
|
||||
</$let>
|
||||
\end
|
||||
|
||||
!! Mapped
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
startPosition="bounds"
|
||||
>
|
||||
<$geolayer json={{!!text}} color={{!!color}}/>
|
||||
</$geomap>
|
||||
|
||||
!! Intersect with other features
|
||||
|
||||
<$let
|
||||
captionThisFeature={{{ [<currentTiddler>get[caption]else<currentTiddler>] }}}
|
||||
>
|
||||
<ul>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoFeature]sort[caption]] -[<currentTiddler>]" variable="otherFeature">
|
||||
<$let
|
||||
captionOtherFeature={{{ [<otherFeature>get[caption]else<otherFeature>] }}}
|
||||
>
|
||||
<li>
|
||||
<$link to=<<otherFeature>>><$transclude tiddler=<<otherFeature>> field="caption"><$view tiddler=<<otherFeature>> field="title"/></$transclude></$link>
|
||||
<$button actions=<<create-intersection>>>
|
||||
Create intersection
|
||||
</$button>
|
||||
</li>
|
||||
</$let>
|
||||
</$list>
|
||||
</ul>
|
||||
</$let>
|
128
editions/geospatialdemo/tiddlers/ui/geomarker.tid
Normal file
@ -0,0 +1,128 @@
|
||||
title: ui/geomarker
|
||||
|
||||
\define default-traveltime-time() 5400
|
||||
|
||||
\define completion-actions()
|
||||
<$action-log/>
|
||||
<$action-setfield $tiddler="$:/temp/_StatusCode" text=<<status>>/>
|
||||
<$action-setfield $tiddler="$:/temp/_StatusText" text=<<statusText>>/>
|
||||
<$action-setfield $tiddler="$:/temp/_Error" text=<<error>>/>
|
||||
<$action-setfield $tiddler="$:/temp/_Result" text=<<data>>/>
|
||||
<$action-setfield $tiddler="$:/temp/_Headers" text=<<headers>>/>
|
||||
<$list filter="[<status>compare:number:gteq[200]compare:number:lteq[299]]" variable="ignore">
|
||||
<$action-createtiddler $basetitle="$:/temp/_IsochroneLayer" text={{{ [<data>] }}} tags="$:/tags/GeoFeature" caption={{{ [<currentTiddler>get[caption]else<currentTiddler>addprefix[Travel time from ]] }}}/>
|
||||
</$list>
|
||||
\end
|
||||
|
||||
\define progress-actions()
|
||||
<$action-log message="In progress-actions"/>
|
||||
<$action-log/>
|
||||
\end
|
||||
|
||||
\define payload-source()
|
||||
\rules only transcludeinline transcludeblock filteredtranscludeinline filteredtranscludeblock
|
||||
{
|
||||
"departure_searches": [
|
||||
{
|
||||
"id": "My first isochrone",
|
||||
"coords": {
|
||||
"lat": {{!!lat}},
|
||||
"lng": {{!!long}}
|
||||
},
|
||||
"departure_time": "2023-02-27T08:00:00Z",
|
||||
"travel_time": {{{ [[$:/config/plugins/geospatial/traveltime/time]get[text]else<default-traveltime-time>] }}},
|
||||
"transportation": {
|
||||
"type": "driving"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
\end
|
||||
|
||||
\define get-traveltime-actions()
|
||||
<$wikify name="payload" text=<<payload-source>>>
|
||||
<$action-log $message="Making payload"/>
|
||||
<$action-log/>
|
||||
<$action-sendmessage
|
||||
$message="tm-http-request"
|
||||
url="https://api.traveltimeapp.com/v4/time-map"
|
||||
method="POST"
|
||||
header-accept="application/geo+json"
|
||||
header-Content-Type="application/json"
|
||||
password-header-X-Api-Key="traveltime-secret-key"
|
||||
password-header-X-Application-Id="traveltime-application-id"
|
||||
body=<<payload>>
|
||||
var-currentTiddler=<<currentTiddler>>
|
||||
bind-status="$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/status"
|
||||
bind-progress="$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/progress"
|
||||
oncompletion=<<completion-actions>>
|
||||
onprogress=<<progress-actions>>
|
||||
/>
|
||||
</$wikify>
|
||||
\end
|
||||
|
||||
!! Mapped
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
startPosition="bounds"
|
||||
>
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$geomap>
|
||||
|
||||
!! Distance to other markers
|
||||
|
||||
<$let
|
||||
thisLocation={{{ [geopoint{!!long},{!!lat}] }}}
|
||||
>
|
||||
<ul>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoMarker]sort[caption]] -[<currentTiddler>]">
|
||||
<li>
|
||||
<$link><$view field="caption"><$view field="title"/></$view></$link>
|
||||
--
|
||||
<$let
|
||||
otherLocation={{{ [geopoint{!!long},{!!lat}] }}}
|
||||
>
|
||||
<$text text={{{ [geodistance<thisLocation>,<otherLocation>,[miles]fixed[0]] }}}/> miles
|
||||
</$let>
|
||||
</li>
|
||||
</$list>
|
||||
</ul>
|
||||
</$let>
|
||||
|
||||
!! GeoFeature Lookups
|
||||
|
||||
<$let
|
||||
thisLocation={{{ [geopoint{!!long},{!!lat}] }}}
|
||||
>
|
||||
<ul>
|
||||
<$list filter="[all[shadows+tiddlers]tag[$:/tags/GeoFeature]sort[caption]]">
|
||||
<li>
|
||||
<$text text={{{ [<currentTiddler>get[caption]] :else[<currentTiddler>] }}}/> --
|
||||
<$text text={{{ [<thisLocation>geolookup{!!text}] }}}/>
|
||||
</li>
|
||||
</$list>
|
||||
</ul>
|
||||
</$let>
|
||||
|
||||
!! Travel Time
|
||||
|
||||
<$button actions=<<get-traveltime-actions>>>
|
||||
Call ~TravelTime
|
||||
</$button>
|
||||
|
||||
Maximum time: <$edit-text tiddler="$:/config/plugins/geospatial/traveltime/time" default=<<default-traveltime-time>> tag="input"/> seconds
|
||||
|
||||
|Status |<$text text={{$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/status}}/> |
|
||||
|Progress |<$text text={{$:/temp/plugins/tiddlywiki/geospatial/demo/traveltime/progress}}/> |
|
||||
|Status Code |<$text text={{$:/temp/_StatusCode}}/> |
|
||||
|Status Text |<$text text={{$:/temp/_StatusText}}/> |
|
||||
|Error |<$text text={{$:/temp/_Error}}/> |
|
||||
|
||||
<$list filter="[<currentTiddler>has[photo-url]]" variable="ignore">
|
||||
|
||||
!! Photo
|
||||
|
||||
<img src={{!!photo-url}}/>
|
||||
|
||||
</$list>
|
23
editions/geospatialdemo/tiddlywiki.info
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"description": "Demo of the geospatial plugin for TiddlyWiki",
|
||||
"plugins": [
|
||||
"tiddlywiki/geospatial",
|
||||
"tiddlywiki/jszip",
|
||||
"tiddlywiki/xlsx-utils",
|
||||
"tiddlywiki/codemirror"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
"tiddlywiki/snowwhite"
|
||||
],
|
||||
"includeWikis": [
|
||||
],
|
||||
"build": {
|
||||
"index": [
|
||||
"--render","$:/core/save/all","index.html","text/plain"],
|
||||
"favicon": [],
|
||||
"static": [],
|
||||
"empty": [],
|
||||
"encrypted": []
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
title: Data/ImportCompound
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
description: Importing a compound payload tiddler and adding custom fields
|
||||
|
||||
title: Description
|
||||
text: Importing a compound payload tiddler and adding custom fields
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
|
||||
<$data $compound-tiddler="Compound" custom="Alpha"/>
|
||||
</$testcase>
|
||||
+
|
||||
title: Compound
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
|
||||
title: Payload Tiddler
|
||||
tags: Alpha Beta Gamma
|
||||
|
||||
This is a payload tiddler from a compound tiddler
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><div><div>[{"title":"Payload Tiddler","tags":"Alpha Beta Gamma","text":"This is a payload tiddler from a compound tiddler","custom":"Alpha"}]</div></div></p>
|
@ -0,0 +1,28 @@
|
||||
title: Data/ImportFilter
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
description: Importing a payload filter and adding custom fields
|
||||
|
||||
title: Description
|
||||
text: Importing a payload filter and adding custom fields
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
|
||||
<$data $filter="[tag[Definitions]]" custom="Alpha"/>
|
||||
</$testcase>
|
||||
+
|
||||
title: HelloThere
|
||||
tags: Definitions
|
||||
|
||||
This is the tiddler HelloThere
|
||||
+
|
||||
title: AnotherDefinition
|
||||
tags: Definitions
|
||||
|
||||
This is the tiddler AnotherDefinition
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><div><div>[{"title":"AnotherDefinition","tags":"Definitions","text":"This is the tiddler AnotherDefinition","custom":"Alpha"},{"title":"HelloThere","tags":"Definitions","text":"This is the tiddler HelloThere","custom":"Alpha"}]</div></div></p>
|
@ -0,0 +1,23 @@
|
||||
title: Data/ImportTiddler
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
description: Importing a payload tiddler and adding custom fields
|
||||
|
||||
title: Description
|
||||
text: Importing a payload tiddler and adding custom fields
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
|
||||
<$data $tiddler="HelloThere" custom="Alpha"/>
|
||||
</$testcase>
|
||||
+
|
||||
title: HelloThere
|
||||
tags: Definitions
|
||||
|
||||
This is the tiddler HelloThere
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><div><div>[{"title":"HelloThere","tags":"Definitions","text":"This is the tiddler HelloThere","custom":"Alpha"}]</div></div></p>
|
18
editions/test/tiddlers/tests/data/data-widget/Simple.tid
Normal file
@ -0,0 +1,18 @@
|
||||
title: Data/Simple
|
||||
type: text/vnd.tiddlywiki-multiple
|
||||
tags: [[$:/tags/wiki-test-spec]]
|
||||
description: Standalone data widget to create individual tiddlers
|
||||
|
||||
title: Description
|
||||
text: Standalone data widget to create individual tiddlers
|
||||
+
|
||||
title: Output
|
||||
|
||||
\whitespace trim
|
||||
<$testcase template="$:/core/ui/testcases/RawJSONTemplate">
|
||||
<$data title="Epsilon" text="Theta"/>
|
||||
</$testcase>
|
||||
+
|
||||
title: ExpectedResult
|
||||
|
||||
<p><div><div>[{"title":"Epsilon","text":"Theta"}]</div></div></p>
|
@ -1,7 +1,8 @@
|
||||
{
|
||||
"description": "TiddlyWiki core tests",
|
||||
"plugins": [
|
||||
"tiddlywiki/jasmine"
|
||||
"tiddlywiki/jasmine",
|
||||
"tiddlywiki/geospatial"
|
||||
],
|
||||
"themes": [
|
||||
"tiddlywiki/vanilla",
|
||||
|
@ -20,4 +20,4 @@ title: Address
|
||||
14 Carrot Street, Vegetabletown
|
||||
+
|
||||
title: ExpectedResult
|
||||
text: <p>Good morning, my <a class="tc-tiddlylink tc-tiddlylink-resolves" href="#Name">name</a> is Robert Rabbit and I <a class="tc-tiddlylink tc-tiddlylink-resolves" href="#Address">live in</a> 14 Carrot Street, Vegetabletown</p>
|
||||
text: <p>Good morning, my <a class="tc-tiddlylink tc-tiddlylink-resolves" href="#Name">name</a> is Robert Rabbit and I <a class="tc-tiddlylink tc-tiddlylink-resolves" href="#Address">live in</a> 14 Carrot Street, Vegetabletown</p>
|
@ -0,0 +1,2 @@
|
||||
title: $:/tags/GeoBaseLayer
|
||||
list: $:/plugins/tiddlywiki/geospatial/baselayers/openstreetmap $:/plugins/tiddlywiki/geospatial/baselayers/esri-world-imagery $:/plugins/tiddlywiki/geospatial/baselayers/opentopomap $:/plugins/tiddlywiki/geospatial/baselayers/stamen-terrain $:/plugins/tiddlywiki/geospatial/baselayers/stamen-watercolor
|
@ -0,0 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/baselayers/esri-world-imagery
|
||||
caption: ESRI World Imagery
|
||||
tags: $:/tags/GeoBaseLayer
|
||||
tiles-url: https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}
|
||||
max-zoom: 18
|
||||
|
||||
Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community
|
@ -0,0 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/baselayers/openstreetmap
|
||||
caption: OpenStreetMap
|
||||
tags: $:/tags/GeoBaseLayer
|
||||
tiles-url: https://tile.openstreetmap.org/{z}/{x}/{y}.png
|
||||
max-zoom: 19
|
||||
|
||||
© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>
|
7
plugins/tiddlywiki/geospatial/baselayers/opentopomap.tid
Normal file
@ -0,0 +1,7 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/baselayers/opentopomap
|
||||
caption: OpenTopoMap
|
||||
tags: $:/tags/GeoBaseLayer
|
||||
tiles-url: https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png
|
||||
max-zoom: 17
|
||||
|
||||
Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://viewfinderpanoramas.org">SRTM</a> | Map style: © <a href="https://opentopomap.org">OpenTopoMap</a> (<a href="https://creativecommons.org/licenses/by-sa/3.0/">CC-BY-SA</a>)
|
3
plugins/tiddlywiki/geospatial/docs.tid
Normal file
@ -0,0 +1,3 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs
|
||||
|
||||
<<tabs tabsList:"[all[tiddlers+shadows]tag[$:/tags/GeospatialDocs]]" default:"$:/plugins/tiddlywiki/geospatial/docs/geomap" class:"tc-vertical">>
|
141
plugins/tiddlywiki/geospatial/docs/flickr.tid
Normal file
@ -0,0 +1,141 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/flickr-helpers
|
||||
caption: Flickr helpers
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! Flickr Helpers
|
||||
|
||||
!!! Photo Tiddlers
|
||||
|
||||
The procedures that retrieve photos from Flickr create a separate tiddler for each retrieved photo. The field values of these photo tiddlers are specified through a photo tiddler template that specifies a filter expression for each field that is to be included.
|
||||
|
||||
A [[default photo tiddler template|$:/plugins/tiddlywiki/geospatial/procedures/Flickr/DefaultPhotoTemplate]] is used if one is not specified. The default template makes the following assignments:
|
||||
|
||||
|!Field |!Description |
|
||||
|title |Set to "Flickr Photo " appended with Flickr's ID for the photograph |
|
||||
|tags |`$:/tags/GeoMarker` and `$:/tags/FlickrPhoto` |
|
||||
|caption |The title of the photograph |
|
||||
|lat |The latitude of the image (blank for non-geocoded photographs) |
|
||||
|long |The longitude of the image (blank for non-geocoded photographs) |
|
||||
|alt |0 |
|
||||
|photo-url |The URL of the "large" image size of the photograph (longest side will be a maximum of 1024px) |
|
||||
|icon-url |The URL of the "small thumbnail" image size of the photograph (cropped to a square of maximum size 75px) |
|
||||
|
||||
The photo tiddler template can reference the following variables. See [[Flickr's documentation|https://www.flickr.com/services/api/misc.urls.html]] to learn how these values can be combined to construct URLs to access photographs.
|
||||
|
||||
|!Variable |!Description |
|
||||
|photoData |Raw JSON data returned from Flickr API |
|
||||
|photoFarm |Flickr photo farm associated with the photograph |
|
||||
|photoServer | Flickr server associated with the photograph |
|
||||
|photoID |Flickr photo ID for the photograph |
|
||||
|photoSecret |The URL secret associated with the photograph |
|
||||
|
||||
!!! `flickr-get-photos-of-user-items` procedure
|
||||
|
||||
Retrieves photographs of a particular user, identified by their user ID.
|
||||
|
||||
|!Parameter |!Description |
|
||||
|userID |ID of the user of whom to retrieve photos (eg 35468148136@N01) |
|
||||
|photoTiddlerTemplate |Optional title of tiddler specifying field values for the created photo tiddlers |
|
||||
|
||||
For example:
|
||||
|
||||
<$testcase>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
<$data title="Description" text="Get photographs of user"/>
|
||||
<$data title="Output" text="""<$button>
|
||||
<$transclude $variable="flickr-get-photos-of-user-items" userID="35468148136@N01"/>
|
||||
Click to get photos of user
|
||||
</$button>
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/FlickrPhoto]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
</$testcase>
|
||||
|
||||
!!! `flickr-get-group-items` procedure
|
||||
|
||||
Retrieves photographs from a group, identified by the group ID.
|
||||
|
||||
|!Parameter |!Description |
|
||||
|groupID |ID of the group from which to retrieve photos (eg 22075379@N00) |
|
||||
|photoTiddlerTemplate |Optional title of tiddler specifying field values for the created photo tiddlers |
|
||||
|
||||
For example:
|
||||
|
||||
<$testcase>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
<$data title="Description" text="Get photographs from group"/>
|
||||
<$data title="Output" text="""<$button>
|
||||
<$transclude $variable="flickr-get-group-items" groupID="22075379@N00"/>
|
||||
Click to get photos from group
|
||||
</$button>
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/FlickrPhoto]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
</$testcase>
|
||||
|
||||
!!! `flickr-get-album-items` procedure
|
||||
|
||||
Retrieves photographs from an album, identified by the album ID.
|
||||
|
||||
|!Parameter |!Description |
|
||||
|albumID |ID of the album from which to retrieve photos (eg 72157630297432522) |
|
||||
|photoTiddlerTemplate |Optional title of tiddler specifying field values for the created photo tiddlers |
|
||||
|
||||
For example:
|
||||
|
||||
<$testcase>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
<$data title="Description" text="Get photographs from album"/>
|
||||
<$data title="Output" text="""<$button>
|
||||
<$transclude $variable="flickr-get-album-items" albumID="72157630297432522"/>
|
||||
Click to get photos from album
|
||||
</$button>
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/FlickrPhoto]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
</$testcase>
|
||||
|
||||
!!! `flickr-get-interesting-items` procedure
|
||||
|
||||
Retrieves Flickr's current list of the 500 most "interesting" photographs.
|
||||
|
||||
|!Parameter |!Description |
|
||||
|photoTiddlerTemplate |Optional title of tiddler specifying field values for the created photo tiddlers |
|
||||
|
||||
For example:
|
||||
|
||||
<$testcase>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
<$data title="Description" text="Get interesting photographs"/>
|
||||
<$data title="Output" text="""<$button>
|
||||
<$transclude $variable="flickr-get-interesting-items"/>
|
||||
Click to get interesting photos
|
||||
</$button>
|
||||
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/FlickrPhoto]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
</$testcase>
|
20
plugins/tiddlywiki/geospatial/docs/geobaselayer.tid
Normal file
@ -0,0 +1,20 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geobaselayer
|
||||
caption: geobaselayer widget
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `<$geobaselayer>` widget
|
||||
|
||||
The `<$geobaselayer>` widget is used inside the `<$geomap>` widget to define the base layers to display on the map.
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
|!Attribute |!Description |
|
||||
|''title'' |Optional title of a tiddler that defines the base layer through the fields ''caption'', ''tiles-url'', ''max-zoom'' and ''text'' (the text field defines the attribution string for the base layer) |
|
||||
|''name'' |Optional name for the base layer |
|
||||
|''tiles-url'' |Optional templated tile server URL for the base layer |
|
||||
|''max-zoom'' |Optional maximum zoom level for the base layer |
|
||||
|''attribution'' |Optional attribution text for the base layer |
|
||||
|
||||
The base layer will only work if all four of the required items ''name'', ''tiles-url'', ''max-zoom'' and ''attribution'' must be provided, either through the base layer tiddler specified in the title attribute, or explicitly via their own attributes.
|
||||
|
||||
See https://leaflet-extras.github.io/leaflet-providers/preview/ for a collection of compatible base layers.
|
20
plugins/tiddlywiki/geospatial/docs/geodifference.tid
Normal file
@ -0,0 +1,20 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geodifference
|
||||
caption: geodifference operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geodifference` operator
|
||||
|
||||
The `geodifference` operator calculates the difference between two or more [[GeoJSON Polygon Features|GeoJSON Polygon Feature]].
|
||||
|
||||
Each input list item is interpreted as a [[GeoJSON Polygon Feature Collection]] containing polygons.
|
||||
|
||||
```
|
||||
[geodifference[]]
|
||||
```
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geodifference-interactive"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
14
plugins/tiddlywiki/geospatial/docs/geodistance.tid
Normal file
@ -0,0 +1,14 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geodistance
|
||||
caption: geodistance operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geodistance` operator
|
||||
|
||||
The `geodistance` operator calculates the distance between two points in [[GeoJSON Point Feature]] format. The points are specified as two operands. An optional third operand specifies the units as `miles`, `kilometers`, `degrees` or `radians` (defaults to `miles`).
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geodistance"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
20
plugins/tiddlywiki/geospatial/docs/geointersect.tid
Normal file
@ -0,0 +1,20 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geointersect
|
||||
caption: geointersect operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geointersect` operator
|
||||
|
||||
The `geointersect` operator calculates the intersection between two or more [[GeoJSON Polygon Features|GeoJSON Polygon Feature]].
|
||||
|
||||
Each input list item is interpreted as a [[GeoJSON Polygon Feature Collection]] containing polygons.
|
||||
|
||||
```
|
||||
[geointersect[]]
|
||||
```
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geointersect-interactive"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
24
plugins/tiddlywiki/geospatial/docs/geolayer.tid
Normal file
@ -0,0 +1,24 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geolayer
|
||||
caption: geolayer widget
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `<$geolayer>` widget
|
||||
|
||||
The `<$geolayer>` widget is used inside the `<$geomap>` widget to indicate the layers and markers to display.
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
|!Attribute |!Description |
|
||||
|''json'' |Optional GeoJSON Feature Collection to be rendered |
|
||||
|''name'' |Optional name to be displayed for this layer |
|
||||
|''color'' |Optional CSS colour for this layer |
|
||||
|''lat'' |Optional latitude of marker if json attribute missing |
|
||||
|''long'' |Optional longitude of marker if json attribute missing |
|
||||
|''alt'' |Optional altitude of marker if json attribute missing |
|
||||
|''draggable'' |Set to "yes" to make the marker draggable |
|
||||
|''updateActions'' |Optional actions when the marker is dragged other otherwise modified. The variables ''lat'' and ''long'' contain the new coordinates of the marker |
|
||||
|
||||
Note that the `<$geolayer>` widget can be used in one of two modes:
|
||||
|
||||
* With the ''json'' attibute specifying the layer to be drawn
|
||||
* With the ''lat'', ''long'' and optional ''alt'' attributes specifying a marker to be drawn
|
92
plugins/tiddlywiki/geospatial/docs/geolocation.tid
Normal file
@ -0,0 +1,92 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geolocation
|
||||
caption: tm-request-geolocation message
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `tm-request-geolocation` message
|
||||
|
||||
The `tm-request-geolocation` message requests the location of the device on which TiddlyWiki is running. Browsers will request permission from the user before returning the location.
|
||||
|
||||
The following parameters are supported:
|
||||
|
||||
|!Parameters |!Description |
|
||||
|''actionsSuccess'' |Action string that is invoked if the request succeeds. See below for the variable values that are made available to the action string |
|
||||
|''actionsError'' |Action string that is invoked if the request fails. See below for the variable values that are made available to the action string |
|
||||
|''accuracy'' |Optional value "low" or "high", defaults to "high". Note that higher accuracy can be significantly slower |
|
||||
|''timeout'' |Optional timeout value in milliseconds after which requests are automatically aborted. Defaults to infinity, meaning that requests do not timeout |
|
||||
|''maximumAge'' |An optional positive value indicating the maximum age in milliseconds of a possible cached position that is acceptable to return. If set to 0, it means that the device cannot use a cached position and must attempt to retrieve the real current position |
|
||||
|
||||
The following variables are made available to the action strings passed in the ''actionsSuccess'' parameter:
|
||||
|
||||
|!Name |!Description |
|
||||
|''timestamp'' |Date and time at which the location was retrieved, in TiddlyWiki YYYYMMDDHHMMSSmmm format |
|
||||
|''latitude'' |The latitude of the position in decimal degrees |
|
||||
|''longitude'' |The longitude of the position in decimal degrees |
|
||||
|''altitude'' |The altitude of the position in meters, relative to sea level. This value can be null if the implementation cannot provide the data |
|
||||
|''accuracy'' |A number representing the accuracy of the latitude and longitude properties, expressed in meters |
|
||||
|''altitudeAccuracy'' |A number representing the accuracy of the altitude expressed in meters. This value can be null |
|
||||
|''heading'' |A number representing the direction towards which the device is facing. This value, specified in degrees, indicates how far off from heading true north the device is. 0 degrees represents true north, and the direction is determined clockwise (which means that east is 90 degrees and west is 270 degrees). If speed is 0, heading is NaN. If the device is unable to provide heading information, this value is null |
|
||||
|''speed'' |A number representing the velocity of the device in meters per second. This value can be null |
|
||||
|
||||
Note that Safari appears to provide obfuscated values for some items for privacy reasons.
|
||||
|
||||
The following variables are made available to the action strings passed in the ''actionsError'' parameter:
|
||||
|
||||
|!Name |!Description |
|
||||
|''error'' |Message associated with the error |
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data
|
||||
title="Description"
|
||||
text="Retrieve current location"
|
||||
/>
|
||||
<$data
|
||||
title="Output"
|
||||
text="""
|
||||
\procedure onsuccess()
|
||||
<$action-setfield
|
||||
$tiddler="CurrentLocation"
|
||||
tags="$:/tags/GeoMarker"
|
||||
timestamp=<<timestamp>>
|
||||
lat=<<latitude>>
|
||||
long=<<longitude>>
|
||||
alt=<<altitude>>
|
||||
accuracy=<<accuracy>>
|
||||
altitudeAccuracy=<<altitudeAccuracy>>
|
||||
heading=<<heading>>
|
||||
speed=<<speed>>
|
||||
/>
|
||||
\end
|
||||
\procedure onerror()
|
||||
<$action-setfield
|
||||
$tiddler="CurrentLocation"
|
||||
$field="text"
|
||||
$value=<<error>>
|
||||
/>
|
||||
\end
|
||||
\procedure onclick()
|
||||
<$action-sendmessage
|
||||
$message="tm-request-geolocation"
|
||||
actionsSuccess=<<onsuccess>>
|
||||
actionsError=<<onerror>>
|
||||
/>
|
||||
\end
|
||||
<$button actions=<<onclick>> style="background: red; color: white; font-size: 18pt;">
|
||||
Click this button to request current location
|
||||
</$button>
|
||||
Your browser will ask for permission before granting the request. On some system it may take a couple of seconds for the location to appear.
|
||||
<hr>
|
||||
{{CurrentLocation}}
|
||||
{{CurrentLocation||$:/core/ui/TiddlerFields}}
|
||||
<hr>
|
||||
<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoMarker]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
16
plugins/tiddlywiki/geospatial/docs/geolookup.tid
Normal file
@ -0,0 +1,16 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geolookup
|
||||
caption: geolookup operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geolookup` operator
|
||||
|
||||
The `geolookup` operator identifies the polygon(s) within a [[GeoJSON Polygon Feature]] that correspond to a particular point, and returns the JSON properties of that polygon.
|
||||
|
||||
Each input list item is interpreted as a [[GeoJSON Point Feature]] and the operand is interpreted as a [[GeoJSON Polygon Feature Collection]].
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geolookup"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
122
plugins/tiddlywiki/geospatial/docs/geomap.tid
Normal file
@ -0,0 +1,122 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geomap
|
||||
caption: geomap widget
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `<$geomap>` widget
|
||||
|
||||
The `<$geomap>` widget displays an interactive map using [[Leaflet.js|https://leafletjs.com/]]. `<$geolayer>` and `<$geobaselayer>` widgets inside the `<$geomap>` widget are used to indicate the overlay layers and markers to display, and the base map layer to be used.
|
||||
|
||||
The following attributes are supported:
|
||||
|
||||
|!Attribute |!Description |
|
||||
|''state'' |The title of a state tiddler used to track the state of the map in the `zoom`, `long` and `lat` fields |
|
||||
|''startPosition'' |Optional starting position for the map: "world" (the default) shows the entire map, "bounds" zooms to the bounds of the loaded layes |
|
||||
|''layersPanel'' |Optional starting status for the layers panel: "collapsed" (the default) causes the layers panel to initially be shown collapsed, "open" causes the layers panel to initially be shown opened |
|
||||
|
||||
If no base layers are defined by `<$geobaselayer>` widgets within the `<$geomap>` widget then all the available base layers will be loaded by the equivalent of the following code:
|
||||
|
||||
```
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoBaseLayer]]">
|
||||
<$geobaselayer title=<<currentTiddler>>/>
|
||||
</$list>
|
||||
```
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data
|
||||
title="Description"
|
||||
text="Map with state preservation"
|
||||
/>
|
||||
<$data
|
||||
title="Output"
|
||||
text="""<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
/>
|
||||
"""/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
||||
|
||||
<$testcase>
|
||||
<$data
|
||||
title="Description"
|
||||
text="Map with geomarker"
|
||||
/>
|
||||
<$data
|
||||
title="Oxford"
|
||||
tags="$:/tags/GeoMarker"
|
||||
caption="Oxford"
|
||||
lat="51.751944"
|
||||
long="-1.257778"
|
||||
alt="0"
|
||||
text="""This is Oxford!"""/>
|
||||
<$data title="Output" text="""<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoMarker]]">
|
||||
<$geolayer lat={{!!lat}} long={{!!long}} alt={{!!alt}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
||||
|
||||
<$testcase>
|
||||
<$data
|
||||
title="Description"
|
||||
text="Map with geofeature"
|
||||
/>
|
||||
<$data
|
||||
title="Layer"
|
||||
tags="$:/tags/GeoFeature"
|
||||
type="application/json"
|
||||
color="red"
|
||||
text="""{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "An example geofeature feature",
|
||||
"properties": {
|
||||
"custom": "A custom property of this feature"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[-90,35],
|
||||
[-90,30],
|
||||
[-85,30],
|
||||
[-85,35],
|
||||
[-90,35]
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}"""/>
|
||||
<$data title="Output" text="""<$geomap
|
||||
state=<<qualify "$:/state/demo-map">>
|
||||
>
|
||||
<$list filter="[all[tiddlers+shadows]tag[$:/tags/GeoFeature]]">
|
||||
<$geolayer json={{!!text}} color={{!!color}}/>
|
||||
</$list>
|
||||
</$geomap>
|
||||
"""/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/widgets/geomap"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/widgets/geomap-refresh"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/widgets/geomap-draggable-marker"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
19
plugins/tiddlywiki/geospatial/docs/geonearestpoint.tid
Normal file
@ -0,0 +1,19 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geonearestpoint
|
||||
caption: geonearestpoint operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geonearestpoint` operator
|
||||
|
||||
The `geonearestpoint` operator determines the point in a list that is nearest to a target point. Each input list item is interpreted as a [[GeoJSON Feature]] comprising the candidate points. The target point is specified as the first operand in [[GeoJSON Point Feature]] format.
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geonearestpoint"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geonearestpoint2"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
22
plugins/tiddlywiki/geospatial/docs/geopoint.tid
Normal file
@ -0,0 +1,22 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geopoint
|
||||
caption: geopoint operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geopoint` operator
|
||||
|
||||
The `geopoint` operator converts separate latitude, longitude and (optionally) altitude numbers into a [[GeoJSON Point Feature]] that can be used with other geospatial primitives.
|
||||
|
||||
The coordinates are specified as two or three operands:
|
||||
|
||||
```
|
||||
[geopoint<latitude>,<longitude>,<attitude>]
|
||||
```
|
||||
|
||||
Any operands that cannot be interpreted as a valid number will be interpreted as the value zero.
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geopoint"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
20
plugins/tiddlywiki/geospatial/docs/geounion.tid
Normal file
@ -0,0 +1,20 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/geounion
|
||||
caption: geounion operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `geounion` operator
|
||||
|
||||
The `geounion` operator calculates the union between two or more [[GeoJSON Polygon Features|GeoJSON Polygon Feature]].
|
||||
|
||||
Each input list item is interpreted as a [[GeoJSON Polygon Feature Collection]] containing polygons.
|
||||
|
||||
```
|
||||
[geounion[]]
|
||||
```
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/geounion-interactive"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
14
plugins/tiddlywiki/geospatial/docs/olc-decode.tid
Normal file
@ -0,0 +1,14 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/olc-decode
|
||||
caption: olc-decode operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `olc-decode` operator
|
||||
|
||||
The `olc-decode` operator converts an [[OpenLocationCode|https://github.com/google/open-location-code]] shortcut into the [[GeoJSON Point Feature]] at its centre or the [[GeoJSON Polygon Feature]] representing the bounds of the area identified by the input code.
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/olc-decode"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
14
plugins/tiddlywiki/geospatial/docs/olc-encode.tid
Normal file
@ -0,0 +1,14 @@
|
||||
title: $:/plugins/tiddlywiki/geospatial/docs/olc-encode
|
||||
caption: olc-encode operator
|
||||
tags: $:/tags/GeospatialDocs
|
||||
|
||||
!! `olc-encode` operator
|
||||
|
||||
The `olc-encode` operator converts separate latitude and longitude numbers into an [[OpenLocationCode|https://github.com/google/open-location-code]] shortcut code with a specified length (defaults to 11 characters).
|
||||
|
||||
!! Examples
|
||||
|
||||
<$testcase>
|
||||
<$data $compound-tiddler="$:/plugins/tiddlywiki/geospatial/tests/operators/olc-encode"/>
|
||||
<$data $tiddler="$:/plugins/tiddlywiki/geospatial"/>
|
||||
</$testcase>
|
26
plugins/tiddlywiki/geospatial/files/leaflet.js/LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2010-2024, Volodymyr Agafonkin
|
||||
Copyright (c) 2010-2011, CloudMade
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
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.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
plugins/tiddlywiki/geospatial/files/leaflet.js/images/layers.png
Normal file
After Width: | Height: | Size: 696 B |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 618 B |
14512
plugins/tiddlywiki/geospatial/files/leaflet.js/leaflet-src.js
Normal file
661
plugins/tiddlywiki/geospatial/files/leaflet.js/leaflet.css
Normal file
@ -0,0 +1,661 @@
|
||||
/* 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 {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
.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;
|
||||
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 {
|
||||
-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-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;
|
||||
}
|
||||
svg.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-offset: 1px;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a {
|
||||
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,
|
||||
.leaflet-bar a:focus {
|
||||
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(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/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;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover,
|
||||
.leaflet-control-attribution a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-attribution-flag {
|
||||
display: inline !important;
|
||||
vertical-align: baseline !important;
|
||||
width: 1em;
|
||||
height: 0.6669em;
|
||||
}
|
||||
.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;
|
||||
white-space: nowrap;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
text-shadow: 1px 1px #fff;
|
||||
}
|
||||
.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 24px 13px 20px;
|
||||
line-height: 1.3;
|
||||
font-size: 13px;
|
||||
font-size: 1.08333em;
|
||||
min-height: 1px;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 17px 0;
|
||||
margin: 1.3em 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-top: -1px;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
pointer-events: auto;
|
||||
|
||||
-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;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font: 16px/24px Tahoma, Verdana, sans-serif;
|
||||
color: #757575;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover,
|
||||
.leaflet-container a.leaflet-popup-close-button:focus {
|
||||
color: #585858;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.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-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-interactive {
|
||||
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;
|
||||
}
|
||||
|
||||
/* Printing */
|
||||
|
||||
@media print {
|
||||
/* Prevent printers from removing background-images of controls. */
|
||||
.leaflet-control {
|
||||
-webkit-print-color-adjust: exact;
|
||||
print-color-adjust: exact;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"tiddlers": [
|
||||
{
|
||||
"file": "leaflet.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.js",
|
||||
"module-type": "library"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "leaflet.css",
|
||||
"fields": {
|
||||
"type": "text/css",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.css",
|
||||
"tags": "[[$:/tags/Stylesheet]]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "images/layers-2x.png",
|
||||
"fields": {
|
||||
"type": "image/png",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet/images/layers-2x.png"
|
||||
}
|
||||
},
|
||||
{
|
||||
"file": "LICENSE",
|
||||
"fields": {
|
||||
"type": "text/plain",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.js/LICENSE"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
Copyright 2012 David Leaver
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,60 @@
|
||||
.marker-cluster-small {
|
||||
background-color: rgba(181, 226, 140, 0.6);
|
||||
}
|
||||
.marker-cluster-small div {
|
||||
background-color: rgba(110, 204, 57, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-medium {
|
||||
background-color: rgba(241, 211, 87, 0.6);
|
||||
}
|
||||
.marker-cluster-medium div {
|
||||
background-color: rgba(240, 194, 12, 0.6);
|
||||
}
|
||||
|
||||
.marker-cluster-large {
|
||||
background-color: rgba(253, 156, 115, 0.6);
|
||||
}
|
||||
.marker-cluster-large div {
|
||||
background-color: rgba(241, 128, 23, 0.6);
|
||||
}
|
||||
|
||||
/* IE 6-8 fallback colors */
|
||||
.leaflet-oldie .marker-cluster-small {
|
||||
background-color: rgb(181, 226, 140);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-small div {
|
||||
background-color: rgb(110, 204, 57);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-medium {
|
||||
background-color: rgb(241, 211, 87);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-medium div {
|
||||
background-color: rgb(240, 194, 12);
|
||||
}
|
||||
|
||||
.leaflet-oldie .marker-cluster-large {
|
||||
background-color: rgb(253, 156, 115);
|
||||
}
|
||||
.leaflet-oldie .marker-cluster-large div {
|
||||
background-color: rgb(241, 128, 23);
|
||||
}
|
||||
|
||||
.marker-cluster {
|
||||
background-clip: padding-box;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.marker-cluster div {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
margin-left: 5px;
|
||||
margin-top: 5px;
|
||||
|
||||
text-align: center;
|
||||
border-radius: 15px;
|
||||
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.marker-cluster span {
|
||||
line-height: 30px;
|
||||
}
|
14
plugins/tiddlywiki/geospatial/files/leaflet.markercluster/MarkerCluster.css
Executable file
@ -0,0 +1,14 @@
|
||||
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
|
||||
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
|
||||
}
|
||||
|
||||
.leaflet-cluster-spider-leg {
|
||||
/* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
|
||||
-webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
|
||||
-moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
|
||||
-o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
|
||||
transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"tiddlers": [
|
||||
{
|
||||
"file": "leaflet.markercluster.js",
|
||||
"fields": {
|
||||
"type": "application/javascript",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.markercluster.js",
|
||||
"module-type": "library"
|
||||
},
|
||||
"prefix": "(function() {var L = require('$:/plugins/tiddlywiki/geospatial/leaflet.js');",
|
||||
"suffix": "\n})();"
|
||||
},
|
||||
{
|
||||
"file": "MarkerCluster.css",
|
||||
"fields": {
|
||||
"type": "text/css",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.MarkerCluster.css",
|
||||
"tags": "[[$:/tags/Stylesheet]]"
|
||||
},
|
||||
"prefix": "",
|
||||
"suffix": ""
|
||||
},
|
||||
{
|
||||
"file": "MarkerCluster.Default.css",
|
||||
"fields": {
|
||||
"type": "text/css",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.MarkerCluster.Default.css",
|
||||
"tags": "[[$:/tags/Stylesheet]]"
|
||||
},
|
||||
"prefix": "",
|
||||
"suffix": ""
|
||||
},
|
||||
{
|
||||
"file": "MIT-LICENCE.txt",
|
||||
"fields": {
|
||||
"type": "text/plain",
|
||||
"title": "$:/plugins/tiddlywiki/geospatial/leaflet.markercluster/LICENSE"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
202
plugins/tiddlywiki/geospatial/files/open-location-code/LICENSE
Normal file
@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -0,0 +1,695 @@
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* Convert locations to and from short codes.
|
||||
*
|
||||
* Open Location Codes are short, 10-11 character codes that can be used instead
|
||||
* of street addresses. The codes can be generated and decoded offline, and use
|
||||
* a reduced character set that minimises the chance of codes including words.
|
||||
*
|
||||
* Codes are able to be shortened relative to a nearby location. This means that
|
||||
* in many cases, only four to seven characters of the code are needed.
|
||||
* To recover the original code, the same location is not required, as long as
|
||||
* a nearby location is provided.
|
||||
*
|
||||
* Codes represent rectangular areas rather than points, and the longer the
|
||||
* code, the smaller the area. A 10 character code represents a 13.5x13.5
|
||||
* meter area (at the equator. An 11 character code represents approximately
|
||||
* a 2.8x3.5 meter area.
|
||||
*
|
||||
* Two encoding algorithms are used. The first 10 characters are pairs of
|
||||
* characters, one for latitude and one for longitude, using base 20. Each pair
|
||||
* reduces the area of the code by a factor of 400. Only even code lengths are
|
||||
* sensible, since an odd-numbered length would have sides in a ratio of 20:1.
|
||||
*
|
||||
* At position 11, the algorithm changes so that each character selects one
|
||||
* position from a 4x5 grid. This allows single-character refinements.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Encode a location, default accuracy:
|
||||
* var code = OpenLocationCode.encode(47.365590, 8.524997);
|
||||
*
|
||||
* Encode a location using one stage of additional refinement:
|
||||
* var code = OpenLocationCode.encode(47.365590, 8.524997, 11);
|
||||
*
|
||||
* Decode a full code:
|
||||
* var coord = OpenLocationCode.decode(code);
|
||||
* var msg = 'Center is ' + coord.latitudeCenter + ',' + coord.longitudeCenter;
|
||||
*
|
||||
* Attempt to trim the first characters from a code:
|
||||
* var shortCode = OpenLocationCode.shorten('8FVC9G8F+6X', 47.5, 8.5);
|
||||
*
|
||||
* Recover the full code from a short code:
|
||||
* var code = OpenLocationCode.recoverNearest('9G8F+6X', 47.4, 8.6);
|
||||
* var code = OpenLocationCode.recoverNearest('8F+6X', 47.4, 8.6);
|
||||
*/
|
||||
(function(root, factory) {
|
||||
/* global define, module */
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['b'], function(b) {
|
||||
return (root.returnExportsGlobal = factory(b));
|
||||
});
|
||||
} else if (typeof module === 'object' && module.exports) {
|
||||
// Node. Does not work with strict CommonJS, but
|
||||
// only CommonJS-like environments that support module.exports,
|
||||
// like Node.
|
||||
module.exports = factory(require('b'));
|
||||
} else {
|
||||
// Browser globals
|
||||
root.OpenLocationCode = factory();
|
||||
}
|
||||
}(this, function() {
|
||||
var OpenLocationCode = {};
|
||||
|
||||
/**
|
||||
* Provides a normal precision code, approximately 14x14 meters.
|
||||
* @const {number}
|
||||
*/
|
||||
OpenLocationCode.CODE_PRECISION_NORMAL = 10;
|
||||
|
||||
/**
|
||||
* Provides an extra precision code, approximately 2x3 meters.
|
||||
* @const {number}
|
||||
*/
|
||||
OpenLocationCode.CODE_PRECISION_EXTRA = 11;
|
||||
|
||||
// A separator used to break the code into two parts to aid memorability.
|
||||
var SEPARATOR_ = '+';
|
||||
|
||||
// The number of characters to place before the separator.
|
||||
var SEPARATOR_POSITION_ = 8;
|
||||
|
||||
// The character used to pad codes.
|
||||
var PADDING_CHARACTER_ = '0';
|
||||
|
||||
// The character set used to encode the values.
|
||||
var CODE_ALPHABET_ = '23456789CFGHJMPQRVWX';
|
||||
|
||||
// The base to use to convert numbers to/from.
|
||||
var ENCODING_BASE_ = CODE_ALPHABET_.length;
|
||||
|
||||
// The maximum value for latitude in degrees.
|
||||
var LATITUDE_MAX_ = 90;
|
||||
|
||||
// The maximum value for longitude in degrees.
|
||||
var LONGITUDE_MAX_ = 180;
|
||||
|
||||
// The max number of digits to process in a plus code.
|
||||
var MAX_DIGIT_COUNT_ = 15;
|
||||
|
||||
// Maximum code length using lat/lng pair encoding. The area of such a
|
||||
// code is approximately 13x13 meters (at the equator), and should be suitable
|
||||
// for identifying buildings. This excludes prefix and separator characters.
|
||||
var PAIR_CODE_LENGTH_ = 10;
|
||||
|
||||
// First place value of the pairs (if the last pair value is 1).
|
||||
var PAIR_FIRST_PLACE_VALUE_ = Math.pow(
|
||||
ENCODING_BASE_, (PAIR_CODE_LENGTH_ / 2 - 1));
|
||||
|
||||
// Inverse of the precision of the pair section of the code.
|
||||
var PAIR_PRECISION_ = Math.pow(ENCODING_BASE_, 3);
|
||||
|
||||
// The resolution values in degrees for each position in the lat/lng pair
|
||||
// encoding. These give the place value of each position, and therefore the
|
||||
// dimensions of the resulting area.
|
||||
var PAIR_RESOLUTIONS_ = [20.0, 1.0, .05, .0025, .000125];
|
||||
|
||||
// Number of digits in the grid precision part of the code.
|
||||
var GRID_CODE_LENGTH_ = MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_;
|
||||
|
||||
// Number of columns in the grid refinement method.
|
||||
var GRID_COLUMNS_ = 4;
|
||||
|
||||
// Number of rows in the grid refinement method.
|
||||
var GRID_ROWS_ = 5;
|
||||
|
||||
// First place value of the latitude grid (if the last place is 1).
|
||||
var GRID_LAT_FIRST_PLACE_VALUE_ = Math.pow(
|
||||
GRID_ROWS_, (GRID_CODE_LENGTH_ - 1));
|
||||
|
||||
// First place value of the longitude grid (if the last place is 1).
|
||||
var GRID_LNG_FIRST_PLACE_VALUE_ = Math.pow(
|
||||
GRID_COLUMNS_, (GRID_CODE_LENGTH_ - 1));
|
||||
|
||||
// Multiply latitude by this much to make it a multiple of the finest
|
||||
// precision.
|
||||
var FINAL_LAT_PRECISION_ = PAIR_PRECISION_ *
|
||||
Math.pow(GRID_ROWS_, (MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_));
|
||||
|
||||
// Multiply longitude by this much to make it a multiple of the finest
|
||||
// precision.
|
||||
var FINAL_LNG_PRECISION_ = PAIR_PRECISION_ *
|
||||
Math.pow(GRID_COLUMNS_, (MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_));
|
||||
|
||||
// Minimum length of a code that can be shortened.
|
||||
var MIN_TRIMMABLE_CODE_LEN_ = 6;
|
||||
|
||||
/**
|
||||
@return {string} Returns the OLC alphabet.
|
||||
*/
|
||||
OpenLocationCode.getAlphabet = function() {
|
||||
return CODE_ALPHABET_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if a code is valid.
|
||||
*
|
||||
* To be valid, all characters must be from the Open Location Code character
|
||||
* set with at most one separator. The separator can be in any even-numbered
|
||||
* position up to the eighth digit.
|
||||
*
|
||||
* @param {string} code The string to check.
|
||||
* @return {boolean} True if the string is a valid code.
|
||||
*/
|
||||
var isValid = OpenLocationCode.isValid = function(code) {
|
||||
if (!code || typeof code !== 'string') {
|
||||
return false;
|
||||
}
|
||||
// The separator is required.
|
||||
if (code.indexOf(SEPARATOR_) == -1) {
|
||||
return false;
|
||||
}
|
||||
if (code.indexOf(SEPARATOR_) != code.lastIndexOf(SEPARATOR_)) {
|
||||
return false;
|
||||
}
|
||||
// Is it the only character?
|
||||
if (code.length == 1) {
|
||||
return false;
|
||||
}
|
||||
// Is it in an illegal position?
|
||||
if (code.indexOf(SEPARATOR_) > SEPARATOR_POSITION_ ||
|
||||
code.indexOf(SEPARATOR_) % 2 == 1) {
|
||||
return false;
|
||||
}
|
||||
// We can have an even number of padding characters before the separator,
|
||||
// but then it must be the final character.
|
||||
if (code.indexOf(PADDING_CHARACTER_) > -1) {
|
||||
// Short codes cannot have padding
|
||||
if (code.indexOf(SEPARATOR_) < SEPARATOR_POSITION_) {
|
||||
return false;
|
||||
}
|
||||
// Not allowed to start with them!
|
||||
if (code.indexOf(PADDING_CHARACTER_) == 0) {
|
||||
return false;
|
||||
}
|
||||
// There can only be one group and it must have even length.
|
||||
var padMatch = code.match(new RegExp('(' + PADDING_CHARACTER_ + '+)', 'g'));
|
||||
if (padMatch.length > 1 || padMatch[0].length % 2 == 1 ||
|
||||
padMatch[0].length > SEPARATOR_POSITION_ - 2) {
|
||||
return false;
|
||||
}
|
||||
// If the code is long enough to end with a separator, make sure it does.
|
||||
if (code.charAt(code.length - 1) != SEPARATOR_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If there are characters after the separator, make sure there isn't just
|
||||
// one of them (not legal).
|
||||
if (code.length - code.indexOf(SEPARATOR_) - 1 == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strip the separator and any padding characters.
|
||||
code = code.replace(new RegExp('\\' + SEPARATOR_ + '+'), '')
|
||||
.replace(new RegExp(PADDING_CHARACTER_ + '+'), '');
|
||||
// Check the code contains only valid characters.
|
||||
for (var i = 0, len = code.length; i < len; i++) {
|
||||
var character = code.charAt(i).toUpperCase();
|
||||
if (character != SEPARATOR_ && CODE_ALPHABET_.indexOf(character) == -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if a code is a valid short code.
|
||||
*
|
||||
* @param {string} code The string to check.
|
||||
* @return {boolean} True if the string can be produced by removing four or
|
||||
* more characters from the start of a valid code.
|
||||
*/
|
||||
var isShort = OpenLocationCode.isShort = function(code) {
|
||||
// Check it's valid.
|
||||
if (!isValid(code)) {
|
||||
return false;
|
||||
}
|
||||
// If there are less characters than expected before the SEPARATOR.
|
||||
if (code.indexOf(SEPARATOR_) >= 0 &&
|
||||
code.indexOf(SEPARATOR_) < SEPARATOR_POSITION_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines if a code is a valid full Open Location Code.
|
||||
*
|
||||
* @param {string} code The string to check.
|
||||
* @return {boolean} True if the code represents a valid latitude and
|
||||
* longitude combination.
|
||||
*/
|
||||
var isFull = OpenLocationCode.isFull = function(code) {
|
||||
if (!isValid(code)) {
|
||||
return false;
|
||||
}
|
||||
// If it's short, it's not full.
|
||||
if (isShort(code)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Work out what the first latitude character indicates for latitude.
|
||||
var firstLatValue = CODE_ALPHABET_.indexOf(
|
||||
code.charAt(0).toUpperCase()) * ENCODING_BASE_;
|
||||
if (firstLatValue >= LATITUDE_MAX_ * 2) {
|
||||
// The code would decode to a latitude of >= 90 degrees.
|
||||
return false;
|
||||
}
|
||||
if (code.length > 1) {
|
||||
// Work out what the first longitude character indicates for longitude.
|
||||
var firstLngValue = CODE_ALPHABET_.indexOf(
|
||||
code.charAt(1).toUpperCase()) * ENCODING_BASE_;
|
||||
if (firstLngValue >= LONGITUDE_MAX_ * 2) {
|
||||
// The code would decode to a longitude of >= 180 degrees.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode a location into an Open Location Code.
|
||||
*
|
||||
* @param {number} latitude The latitude in signed decimal degrees. It will
|
||||
* be clipped to the range -90 to 90.
|
||||
* @param {number} longitude The longitude in signed decimal degrees. Will be
|
||||
* normalised to the range -180 to 180.
|
||||
* @param {?number} codeLength The length of the code to generate. If
|
||||
* omitted, the value OpenLocationCode.CODE_PRECISION_NORMAL will be used.
|
||||
* For a more precise result, OpenLocationCode.CODE_PRECISION_EXTRA is
|
||||
* recommended.
|
||||
* @return {string} The code.
|
||||
* @throws {Exception} if any of the input values are not numbers.
|
||||
*/
|
||||
var encode = OpenLocationCode.encode = function(latitude,
|
||||
longitude, codeLength) {
|
||||
latitude = Number(latitude);
|
||||
longitude = Number(longitude);
|
||||
if (typeof codeLength == 'undefined') {
|
||||
codeLength = OpenLocationCode.CODE_PRECISION_NORMAL;
|
||||
} else {
|
||||
codeLength = Math.min(MAX_DIGIT_COUNT_, Number(codeLength));
|
||||
}
|
||||
if (isNaN(latitude) || isNaN(longitude) || isNaN(codeLength)) {
|
||||
throw new Error('ValueError: Parameters are not numbers');
|
||||
}
|
||||
if (codeLength < 2 ||
|
||||
(codeLength < PAIR_CODE_LENGTH_ && codeLength % 2 == 1)) {
|
||||
throw new Error('IllegalArgumentException: Invalid Open Location Code length');
|
||||
}
|
||||
// Ensure that latitude and longitude are valid.
|
||||
latitude = clipLatitude(latitude);
|
||||
longitude = normalizeLongitude(longitude);
|
||||
// Latitude 90 needs to be adjusted to be just less, so the returned code
|
||||
// can also be decoded.
|
||||
if (latitude == 90) {
|
||||
latitude = latitude - computeLatitudePrecision(codeLength);
|
||||
}
|
||||
var code = '';
|
||||
|
||||
// Compute the code.
|
||||
// This approach converts each value to an integer after multiplying it by
|
||||
// the final precision. This allows us to use only integer operations, so
|
||||
// avoiding any accumulation of floating point representation errors.
|
||||
|
||||
// Multiply values by their precision and convert to positive.
|
||||
// Force to integers so the division operations will have integer results.
|
||||
// Note: JavaScript requires rounding before truncating to ensure precision!
|
||||
var latVal =
|
||||
Math.floor(Math.round((latitude + LATITUDE_MAX_) * FINAL_LAT_PRECISION_ * 1e6) / 1e6);
|
||||
var lngVal =
|
||||
Math.floor(Math.round((longitude + LONGITUDE_MAX_) * FINAL_LNG_PRECISION_ * 1e6) / 1e6);
|
||||
|
||||
// Compute the grid part of the code if necessary.
|
||||
if (codeLength > PAIR_CODE_LENGTH_) {
|
||||
for (var i = 0; i < MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_; i++) {
|
||||
var latDigit = latVal % GRID_ROWS_;
|
||||
var lngDigit = lngVal % GRID_COLUMNS_;
|
||||
var ndx = latDigit * GRID_COLUMNS_ + lngDigit;
|
||||
code = CODE_ALPHABET_.charAt(ndx) + code;
|
||||
// Note! Integer division.
|
||||
latVal = Math.floor(latVal / GRID_ROWS_);
|
||||
lngVal = Math.floor(lngVal / GRID_COLUMNS_);
|
||||
}
|
||||
} else {
|
||||
latVal = Math.floor(latVal / Math.pow(GRID_ROWS_, GRID_CODE_LENGTH_));
|
||||
lngVal = Math.floor(lngVal / Math.pow(GRID_COLUMNS_, GRID_CODE_LENGTH_));
|
||||
}
|
||||
// Compute the pair section of the code.
|
||||
for (var i = 0; i < PAIR_CODE_LENGTH_ / 2; i++) {
|
||||
code = CODE_ALPHABET_.charAt(lngVal % ENCODING_BASE_) + code;
|
||||
code = CODE_ALPHABET_.charAt(latVal % ENCODING_BASE_) + code;
|
||||
latVal = Math.floor(latVal / ENCODING_BASE_);
|
||||
lngVal = Math.floor(lngVal / ENCODING_BASE_);
|
||||
}
|
||||
|
||||
// Add the separator character.
|
||||
code = code.substring(0, SEPARATOR_POSITION_) +
|
||||
SEPARATOR_ +
|
||||
code.substring(SEPARATOR_POSITION_);
|
||||
|
||||
|
||||
// If we don't need to pad the code, return the requested section.
|
||||
if (codeLength >= SEPARATOR_POSITION_) {
|
||||
return code.substring(0, codeLength + 1);
|
||||
}
|
||||
// Pad and return the code.
|
||||
return code.substring(0, codeLength) +
|
||||
Array(SEPARATOR_POSITION_ - codeLength + 1).join(PADDING_CHARACTER_) + SEPARATOR_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes an Open Location Code into its location coordinates.
|
||||
*
|
||||
* Returns a CodeArea object that includes the coordinates of the bounding
|
||||
* box - the lower left, center and upper right.
|
||||
*
|
||||
* @param {string} code The code to decode.
|
||||
* @return {OpenLocationCode.CodeArea} An object with the coordinates of the
|
||||
* area of the code.
|
||||
* @throws {Exception} If the code is not valid.
|
||||
*/
|
||||
var decode = OpenLocationCode.decode = function(code) {
|
||||
// This calculates the values for the pair and grid section separately, using
|
||||
// integer arithmetic. Only at the final step are they converted to floating
|
||||
// point and combined.
|
||||
if (!isFull(code)) {
|
||||
throw new Error('IllegalArgumentException: ' +
|
||||
'Passed Open Location Code is not a valid full code: ' + code);
|
||||
}
|
||||
// Strip the '+' and '0' characters from the code and convert to upper case.
|
||||
code = code.replace('+', '').replace(/0/g, '').toLocaleUpperCase('en-US');
|
||||
|
||||
// Initialise the values for each section. We work them out as integers and
|
||||
// convert them to floats at the end.
|
||||
var normalLat = -LATITUDE_MAX_ * PAIR_PRECISION_;
|
||||
var normalLng = -LONGITUDE_MAX_ * PAIR_PRECISION_;
|
||||
var gridLat = 0;
|
||||
var gridLng = 0;
|
||||
// How many digits do we have to process?
|
||||
var digits = Math.min(code.length, PAIR_CODE_LENGTH_);
|
||||
// Define the place value for the most significant pair.
|
||||
var pv = PAIR_FIRST_PLACE_VALUE_;
|
||||
// Decode the paired digits.
|
||||
for (var i = 0; i < digits; i += 2) {
|
||||
normalLat += CODE_ALPHABET_.indexOf(code.charAt(i)) * pv;
|
||||
normalLng += CODE_ALPHABET_.indexOf(code.charAt(i + 1)) * pv;
|
||||
if (i < digits - 2) {
|
||||
pv /= ENCODING_BASE_;
|
||||
}
|
||||
}
|
||||
// Convert the place value to a float in degrees.
|
||||
var latPrecision = pv / PAIR_PRECISION_;
|
||||
var lngPrecision = pv / PAIR_PRECISION_;
|
||||
// Process any extra precision digits.
|
||||
if (code.length > PAIR_CODE_LENGTH_) {
|
||||
// Initialise the place values for the grid.
|
||||
var rowpv = GRID_LAT_FIRST_PLACE_VALUE_;
|
||||
var colpv = GRID_LNG_FIRST_PLACE_VALUE_;
|
||||
// How many digits do we have to process?
|
||||
digits = Math.min(code.length, MAX_DIGIT_COUNT_);
|
||||
for (var i = PAIR_CODE_LENGTH_; i < digits; i++) {
|
||||
var digitVal = CODE_ALPHABET_.indexOf(code.charAt(i));
|
||||
var row = Math.floor(digitVal / GRID_COLUMNS_);
|
||||
var col = digitVal % GRID_COLUMNS_;
|
||||
gridLat += row * rowpv;
|
||||
gridLng += col * colpv;
|
||||
if (i < digits - 1) {
|
||||
rowpv /= GRID_ROWS_;
|
||||
colpv /= GRID_COLUMNS_;
|
||||
}
|
||||
}
|
||||
// Adjust the precisions from the integer values to degrees.
|
||||
latPrecision = rowpv / FINAL_LAT_PRECISION_;
|
||||
lngPrecision = colpv / FINAL_LNG_PRECISION_;
|
||||
}
|
||||
// Merge the values from the normal and extra precision parts of the code.
|
||||
var lat = normalLat / PAIR_PRECISION_ + gridLat / FINAL_LAT_PRECISION_;
|
||||
var lng = normalLng / PAIR_PRECISION_ + gridLng / FINAL_LNG_PRECISION_;
|
||||
// Multiple values by 1e14, round and then divide. This reduces errors due
|
||||
// to floating point precision.
|
||||
return new CodeArea(
|
||||
Math.round(lat * 1e14) / 1e14, Math.round(lng * 1e14) / 1e14,
|
||||
Math.round((lat + latPrecision) * 1e14) / 1e14,
|
||||
Math.round((lng + lngPrecision) * 1e14) / 1e14,
|
||||
Math.min(code.length, MAX_DIGIT_COUNT_));
|
||||
};
|
||||
|
||||
/**
|
||||
* Recover the nearest matching code to a specified location.
|
||||
*
|
||||
* Given a valid short Open Location Code this recovers the nearest matching
|
||||
* full code to the specified location.
|
||||
*
|
||||
* @param {string} shortCode A valid short code.
|
||||
* @param {number} referenceLatitude The latitude to use for the reference
|
||||
* location.
|
||||
* @param {number} referenceLongitude The longitude to use for the reference
|
||||
* location.
|
||||
* @return {string} The nearest matching full code to the reference location.
|
||||
* @throws {Exception} if the short code is not valid, or the reference
|
||||
* position values are not numbers.
|
||||
*/
|
||||
OpenLocationCode.recoverNearest = function(
|
||||
shortCode, referenceLatitude, referenceLongitude) {
|
||||
if (!isShort(shortCode)) {
|
||||
if (isFull(shortCode)) {
|
||||
return shortCode.toUpperCase();
|
||||
} else {
|
||||
throw new Error(
|
||||
'ValueError: Passed short code is not valid: ' + shortCode);
|
||||
}
|
||||
}
|
||||
referenceLatitude = Number(referenceLatitude);
|
||||
referenceLongitude = Number(referenceLongitude);
|
||||
if (isNaN(referenceLatitude) || isNaN(referenceLongitude)) {
|
||||
throw new Error('ValueError: Reference position are not numbers');
|
||||
}
|
||||
// Ensure that latitude and longitude are valid.
|
||||
referenceLatitude = clipLatitude(referenceLatitude);
|
||||
referenceLongitude = normalizeLongitude(referenceLongitude);
|
||||
|
||||
// Clean up the passed code.
|
||||
shortCode = shortCode.toUpperCase();
|
||||
// Compute the number of digits we need to recover.
|
||||
var paddingLength = SEPARATOR_POSITION_ - shortCode.indexOf(SEPARATOR_);
|
||||
// The resolution (height and width) of the padded area in degrees.
|
||||
var resolution = Math.pow(20, 2 - (paddingLength / 2));
|
||||
// Distance from the center to an edge (in degrees).
|
||||
var halfResolution = resolution / 2.0;
|
||||
|
||||
// Use the reference location to pad the supplied short code and decode it.
|
||||
var codeArea = decode(
|
||||
encode(referenceLatitude, referenceLongitude).substr(0, paddingLength)
|
||||
+ shortCode);
|
||||
// How many degrees latitude is the code from the reference? If it is more
|
||||
// than half the resolution, we need to move it north or south but keep it
|
||||
// within -90 to 90 degrees.
|
||||
if (referenceLatitude + halfResolution < codeArea.latitudeCenter &&
|
||||
codeArea.latitudeCenter - resolution >= -LATITUDE_MAX_) {
|
||||
// If the proposed code is more than half a cell north of the reference location,
|
||||
// it's too far, and the best match will be one cell south.
|
||||
codeArea.latitudeCenter -= resolution;
|
||||
} else if (referenceLatitude - halfResolution > codeArea.latitudeCenter &&
|
||||
codeArea.latitudeCenter + resolution <= LATITUDE_MAX_) {
|
||||
// If the proposed code is more than half a cell south of the reference location,
|
||||
// it's too far, and the best match will be one cell north.
|
||||
codeArea.latitudeCenter += resolution;
|
||||
}
|
||||
|
||||
// How many degrees longitude is the code from the reference?
|
||||
if (referenceLongitude + halfResolution < codeArea.longitudeCenter) {
|
||||
codeArea.longitudeCenter -= resolution;
|
||||
} else if (referenceLongitude - halfResolution > codeArea.longitudeCenter) {
|
||||
codeArea.longitudeCenter += resolution;
|
||||
}
|
||||
|
||||
return encode(
|
||||
codeArea.latitudeCenter, codeArea.longitudeCenter, codeArea.codeLength);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove characters from the start of an OLC code.
|
||||
*
|
||||
* This uses a reference location to determine how many initial characters
|
||||
* can be removed from the OLC code. The number of characters that can be
|
||||
* removed depends on the distance between the code center and the reference
|
||||
* location.
|
||||
*
|
||||
* @param {string} code The full code to shorten.
|
||||
* @param {number} latitude The latitude to use for the reference location.
|
||||
* @param {number} longitude The longitude to use for the reference location.
|
||||
* @return {string} The code, shortened as much as possible that it is still
|
||||
* the closest matching code to the reference location.
|
||||
* @throws {Exception} if the passed code is not a valid full code or the
|
||||
* reference location values are not numbers.
|
||||
*/
|
||||
OpenLocationCode.shorten = function(
|
||||
code, latitude, longitude) {
|
||||
if (!isFull(code)) {
|
||||
throw new Error('ValueError: Passed code is not valid and full: ' + code);
|
||||
}
|
||||
if (code.indexOf(PADDING_CHARACTER_) != -1) {
|
||||
throw new Error('ValueError: Cannot shorten padded codes: ' + code);
|
||||
}
|
||||
code = code.toUpperCase();
|
||||
var codeArea = decode(code);
|
||||
if (codeArea.codeLength < MIN_TRIMMABLE_CODE_LEN_) {
|
||||
throw new Error(
|
||||
'ValueError: Code length must be at least ' +
|
||||
MIN_TRIMMABLE_CODE_LEN_);
|
||||
}
|
||||
// Ensure that latitude and longitude are valid.
|
||||
latitude = Number(latitude);
|
||||
longitude = Number(longitude);
|
||||
if (isNaN(latitude) || isNaN(longitude)) {
|
||||
throw new Error('ValueError: Reference position are not numbers');
|
||||
}
|
||||
latitude = clipLatitude(latitude);
|
||||
longitude = normalizeLongitude(longitude);
|
||||
// How close are the latitude and longitude to the code center.
|
||||
var range = Math.max(
|
||||
Math.abs(codeArea.latitudeCenter - latitude),
|
||||
Math.abs(codeArea.longitudeCenter - longitude));
|
||||
for (var i = PAIR_RESOLUTIONS_.length - 2; i >= 1; i--) {
|
||||
// Check if we're close enough to shorten. The range must be less than 1/2
|
||||
// the resolution to shorten at all, and we want to allow some safety, so
|
||||
// use 0.3 instead of 0.5 as a multiplier.
|
||||
if (range < (PAIR_RESOLUTIONS_[i] * 0.3)) {
|
||||
// Trim it.
|
||||
return code.substring((i + 1) * 2);
|
||||
}
|
||||
}
|
||||
return code;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clip a latitude into the range -90 to 90.
|
||||
*
|
||||
* @param {number} latitude
|
||||
* @return {number} The latitude value clipped to be in the range.
|
||||
*/
|
||||
var clipLatitude = function(latitude) {
|
||||
return Math.min(90, Math.max(-90, latitude));
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the latitude precision value for a given code length.
|
||||
* Lengths <= 10 have the same precision for latitude and longitude, but
|
||||
* lengths > 10 have different precisions due to the grid method having
|
||||
* fewer columns than rows.
|
||||
* @param {number} codeLength
|
||||
* @return {number} The latitude precision in degrees.
|
||||
*/
|
||||
var computeLatitudePrecision = function(codeLength) {
|
||||
if (codeLength <= 10) {
|
||||
return Math.pow(ENCODING_BASE_, Math.floor(codeLength / -2 + 2));
|
||||
}
|
||||
return Math.pow(ENCODING_BASE_, -3) / Math.pow(GRID_ROWS_, codeLength - 10);
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize a longitude into the range -180 to 180, not including 180.
|
||||
*
|
||||
* @param {number} longitude
|
||||
* @return {number} Normalized into the range -180 to 180.
|
||||
*/
|
||||
var normalizeLongitude = function(longitude) {
|
||||
while (longitude < -180) {
|
||||
longitude = longitude + 360;
|
||||
}
|
||||
while (longitude >= 180) {
|
||||
longitude = longitude - 360;
|
||||
}
|
||||
return longitude;
|
||||
};
|
||||
|
||||
/**
|
||||
* Coordinates of a decoded Open Location Code.
|
||||
*
|
||||
* The coordinates include the latitude and longitude of the lower left and
|
||||
* upper right corners and the center of the bounding box for the area the
|
||||
* code represents.
|
||||
* @param {number} latitudeLo
|
||||
* @param {number} longitudeLo
|
||||
* @param {number} latitudeHi
|
||||
* @param {number} longitudeHi
|
||||
* @param {number} codeLength
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
var CodeArea = OpenLocationCode.CodeArea = function(
|
||||
latitudeLo, longitudeLo, latitudeHi, longitudeHi, codeLength) {
|
||||
return new OpenLocationCode.CodeArea.fn.Init(
|
||||
latitudeLo, longitudeLo, latitudeHi, longitudeHi, codeLength);
|
||||
};
|
||||
CodeArea.fn = CodeArea.prototype = {
|
||||
Init: function(
|
||||
latitudeLo, longitudeLo, latitudeHi, longitudeHi, codeLength) {
|
||||
/**
|
||||
* The latitude of the SW corner.
|
||||
* @type {number}
|
||||
*/
|
||||
this.latitudeLo = latitudeLo;
|
||||
/**
|
||||
* The longitude of the SW corner in degrees.
|
||||
* @type {number}
|
||||
*/
|
||||
this.longitudeLo = longitudeLo;
|
||||
/**
|
||||
* The latitude of the NE corner in degrees.
|
||||
* @type {number}
|
||||
*/
|
||||
this.latitudeHi = latitudeHi;
|
||||
/**
|
||||
* The longitude of the NE corner in degrees.
|
||||
* @type {number}
|
||||
*/
|
||||
this.longitudeHi = longitudeHi;
|
||||
/**
|
||||
* The number of digits in the code.
|
||||
* @type {number}
|
||||
*/
|
||||
this.codeLength = codeLength;
|
||||
/**
|
||||
* The latitude of the center in degrees.
|
||||
* @type {number}
|
||||
*/
|
||||
this.latitudeCenter = Math.min(
|
||||
latitudeLo + (latitudeHi - latitudeLo) / 2, LATITUDE_MAX_);
|
||||
/**
|
||||
* The longitude of the center in degrees.
|
||||
* @type {number}
|
||||
*/
|
||||
this.longitudeCenter = Math.min(
|
||||
longitudeLo + (longitudeHi - longitudeLo) / 2, LONGITUDE_MAX_);
|
||||
},
|
||||
};
|
||||
CodeArea.fn.Init.prototype = CodeArea.fn;
|
||||
|
||||
return OpenLocationCode;
|
||||
}));
|
1
plugins/tiddlywiki/geospatial/files/open-location-code/openlocationcode.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(e,r){"function"==typeof define&&define.amd?define(["b"],function(t){return e.returnExportsGlobal=r()}):"object"==typeof module&&module.exports?module.exports=r(require("b")):e.OpenLocationCode=r()}(this,function(){var e={CODE_PRECISION_NORMAL:10,CODE_PRECISION_EXTRA:11},r="23456789CFGHJMPQRVWX",t=r.length,n=Math.pow(t,4),o=Math.pow(t,3),i=[20,1,.05,.0025,125e-6],a=Math.pow(5,4),u=Math.pow(4,4),f=o*Math.pow(5,5),h=o*Math.pow(4,5);e.getAlphabet=function(){return r};var l=e.isValid=function(e){if(!e||"string"!=typeof e)return!1;if(-1==e.indexOf("+"))return!1;if(e.indexOf("+")!=e.lastIndexOf("+"))return!1;if(1==e.length)return!1;if(e.indexOf("+")>8||e.indexOf("+")%2==1)return!1;if(e.indexOf("0")>-1){if(e.indexOf("+")<8)return!1;if(0==e.indexOf("0"))return!1;var t=e.match(new RegExp("(0+)","g"));if(t.length>1||t[0].length%2==1||t[0].length>6)return!1;if("+"!=e.charAt(e.length-1))return!1}if(e.length-e.indexOf("+")-1==1)return!1;for(var n=0,o=(e=e.replace(new RegExp("\\++"),"").replace(new RegExp("0+"),"")).length;n<o;n++){var i=e.charAt(n).toUpperCase();if("+"!=i&&-1==r.indexOf(i))return!1}return!0},d=e.isShort=function(e){return!!l(e)&&(e.indexOf("+")>=0&&e.indexOf("+")<8)},s=e.isFull=function(e){if(!l(e))return!1;if(d(e))return!1;if(r.indexOf(e.charAt(0).toUpperCase())*t>=180)return!1;if(e.length>1&&r.indexOf(e.charAt(1).toUpperCase())*t>=360)return!1;return!0},p=e.encode=function(n,o,i){if(n=Number(n),o=Number(o),i=void 0===i?e.CODE_PRECISION_NORMAL:Math.min(15,Number(i)),isNaN(n)||isNaN(o)||isNaN(i))throw new Error("ValueError: Parameters are not numbers");if(i<2||i<10&&i%2==1)throw new Error("IllegalArgumentException: Invalid Open Location Code length");n=g(n),o=C(o),90==n&&(n-=M(i));var a="",u=Math.floor(Math.round((n+90)*f*1e6)/1e6),l=Math.floor(Math.round((o+180)*h*1e6)/1e6);if(i>10)for(var d=0;d<5;d++){a=r.charAt(4*(u%5)+l%4)+a,u=Math.floor(u/5),l=Math.floor(l/4)}else u=Math.floor(u/Math.pow(5,5)),l=Math.floor(l/Math.pow(4,5));for(d=0;d<5;d++)a=r.charAt(l%t)+a,a=r.charAt(u%t)+a,u=Math.floor(u/t),l=Math.floor(l/t);return a=a.substring(0,8)+"+"+a.substring(8),i>=8?a.substring(0,i+1):a.substring(0,i)+Array(8-i+1).join("0")+"+"},c=e.decode=function(e){if(!s(e))throw new Error("IllegalArgumentException: Passed Open Location Code is not a valid full code: "+e);e=e.replace("+","").replace(/0/g,"").toLocaleUpperCase("en-US");for(var i=-90*o,l=-180*o,d=0,p=0,c=Math.min(e.length,10),g=n,M=0;M<c;M+=2)i+=r.indexOf(e.charAt(M))*g,l+=r.indexOf(e.charAt(M+1))*g,M<c-2&&(g/=t);var C=g/o,O=g/o;if(e.length>10){var x=a,E=u;c=Math.min(e.length,15);for(M=10;M<c;M++){var m=r.indexOf(e.charAt(M));d+=Math.floor(m/4)*x,p+=m%4*E,M<c-1&&(x/=5,E/=4)}C=x/f,O=E/h}var N=i/o+d/f,b=l/o+p/h;return new w(Math.round(1e14*N)/1e14,Math.round(1e14*b)/1e14,Math.round(1e14*(N+C))/1e14,Math.round(1e14*(b+O))/1e14,Math.min(e.length,15))};e.recoverNearest=function(e,r,t){if(!d(e)){if(s(e))return e.toUpperCase();throw new Error("ValueError: Passed short code is not valid: "+e)}if(r=Number(r),t=Number(t),isNaN(r)||isNaN(t))throw new Error("ValueError: Reference position are not numbers");r=g(r),t=C(t);var n=8-(e=e.toUpperCase()).indexOf("+"),o=Math.pow(20,2-n/2),i=o/2,a=c(p(r,t).substr(0,n)+e);return r+i<a.latitudeCenter&&a.latitudeCenter-o>=-90?a.latitudeCenter-=o:r-i>a.latitudeCenter&&a.latitudeCenter+o<=90&&(a.latitudeCenter+=o),t+i<a.longitudeCenter?a.longitudeCenter-=o:t-i>a.longitudeCenter&&(a.longitudeCenter+=o),p(a.latitudeCenter,a.longitudeCenter,a.codeLength)},e.shorten=function(e,r,t){if(!s(e))throw new Error("ValueError: Passed code is not valid and full: "+e);if(-1!=e.indexOf("0"))throw new Error("ValueError: Cannot shorten padded codes: "+e);e=e.toUpperCase();var n=c(e);if(n.codeLength<6)throw new Error("ValueError: Code length must be at least 6");if(r=Number(r),t=Number(t),isNaN(r)||isNaN(t))throw new Error("ValueError: Reference position are not numbers");r=g(r),t=C(t);for(var o=Math.max(Math.abs(n.latitudeCenter-r),Math.abs(n.longitudeCenter-t)),a=i.length-2;a>=1;a--)if(o<.3*i[a])return e.substring(2*(a+1));return e};var g=function(e){return Math.min(90,Math.max(-90,e))},M=function(e){return e<=10?Math.pow(t,Math.floor(e/-2+2)):Math.pow(t,-3)/Math.pow(5,e-10)},C=function(e){for(;e<-180;)e+=360;for(;e>=180;)e-=360;return e},w=e.CodeArea=function(r,t,n,o,i){return new e.CodeArea.fn.Init(r,t,n,o,i)};return w.fn=w.prototype={Init:function(e,r,t,n,o){this.latitudeLo=e,this.longitudeLo=r,this.latitudeHi=t,this.longitudeHi=n,this.codeLength=o,this.latitudeCenter=Math.min(e+(t-e)/2,90),this.longitudeCenter=Math.min(r+(n-r)/2,180)}},w.fn.Init.prototype=w.fn,e});
|