├── .eslintrc.json ├── .github └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── .stylelintrc.json ├── conf.json ├── docs ├── api │ ├── classes.list.html │ ├── docs │ │ └── web │ │ │ └── img │ │ │ ├── GitHub-Mark-Light-32px.png │ │ │ ├── logo70.png │ │ │ └── olturf-example-screenshot.png │ ├── external-ol.control.Control.html │ ├── external-ol.control.html │ ├── external-ol.html │ ├── externals.list.html │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ ├── img │ │ ├── glyphicons-halflings-white.png │ │ └── glyphicons-halflings.png │ ├── index.html │ ├── namespaces.list.html │ ├── olturf.Toolbar.html │ ├── olturf.html │ ├── olturf.toolbars.html │ ├── quicksearch.html │ ├── scripts │ │ ├── docstrap.lib.js │ │ ├── fulltext-search-ui.js │ │ ├── fulltext-search.js │ │ ├── lunr.min.js │ │ ├── prettify │ │ │ ├── Apache-License-2.0.txt │ │ │ ├── jquery.min.js │ │ │ ├── lang-css.js │ │ │ └── prettify.js │ │ ├── sunlight.js │ │ └── toc.js │ └── styles │ │ ├── darkstrap.css │ │ ├── prettify-tomorrow.css │ │ ├── site.cerulean.css │ │ ├── site.cosmo.css │ │ ├── site.cyborg.css │ │ ├── site.darkly.css │ │ ├── site.darkstrap.css │ │ ├── site.dibs-bootstrap.css │ │ ├── site.flatly.css │ │ ├── site.journal.css │ │ ├── site.lumen.css │ │ ├── site.paper.css │ │ ├── site.readable.css │ │ ├── site.sandstone.css │ │ ├── site.simplex.css │ │ ├── site.slate.css │ │ ├── site.spacelab.css │ │ ├── site.superhero.css │ │ ├── site.united.css │ │ ├── site.yeti.css │ │ ├── sunlight.dark.css │ │ └── sunlight.default.css ├── home.css ├── index.html └── web │ ├── css │ ├── github.css │ └── olturf.css │ ├── demos.html │ ├── img │ ├── GitHub-Mark-Light-32px.png │ ├── logo70.png │ └── olturf-example-screenshot.png │ ├── index.html │ ├── js │ └── example.js │ ├── multiple.html │ ├── standard.html │ └── start.html ├── jest.config.js ├── license.txt ├── package-lock.json ├── package.json ├── readme.md ├── rollup.config.js ├── src ├── css │ ├── along.css │ ├── area.css │ ├── bearing.css │ ├── bezier.css │ ├── buffer.css │ ├── center-of-mass.css │ ├── center.css │ ├── centroid.css │ ├── circle.css │ ├── collect.css │ ├── combine.css │ ├── concave.css │ ├── control.css │ ├── convex.css │ ├── destination.css │ ├── difference.css │ ├── distance.css │ ├── envelope.css │ ├── explode.css │ ├── flip.css │ ├── form.css │ ├── hex-grid.css │ ├── inside.css │ ├── intersect.css │ ├── isolines.css │ ├── kinks.css │ ├── line-distance.css │ ├── line-slice-along.css │ ├── main.css │ ├── midpoint.css │ ├── nearest.css │ ├── planepoint.css │ ├── point-grid.css │ ├── point-on-line.css │ ├── point-on-surface.css │ ├── popup.css │ ├── random.css │ ├── sample.css │ ├── simplify.css │ ├── square-grid.css │ ├── square.css │ ├── tag.css │ ├── tesselate.css │ ├── tin.css │ ├── triangle-grid.css │ ├── union.css │ └── within.css └── js │ ├── along.js │ ├── area.js │ ├── bearing.js │ ├── bezier.js │ ├── buffer.js │ ├── center-of-mass.js │ ├── center.js │ ├── centroid.js │ ├── circle.js │ ├── collect.js │ ├── combine.js │ ├── concave.js │ ├── control.js │ ├── controls.js │ ├── convex.js │ ├── destination.js │ ├── difference.js │ ├── distance.js │ ├── envelope.js │ ├── explode.js │ ├── flip.js │ ├── form.js │ ├── handler.js │ ├── hex-grid.js │ ├── inside.js │ ├── intersect.js │ ├── isolines.js │ ├── kinks.js │ ├── line-distance.js │ ├── line-slice-along.js │ ├── main.js │ ├── midpoint.js │ ├── nearest.js │ ├── planepoint.js │ ├── point-grid.js │ ├── point-on-line.js │ ├── point-on-surface.js │ ├── popup.js │ ├── random.js │ ├── sample.js │ ├── simplify.js │ ├── square-grid.js │ ├── square.js │ ├── tag.js │ ├── tesselate.js │ ├── tin.js │ ├── toolbars.js │ ├── triangle-grid.js │ ├── union.js │ ├── utils.js │ └── within.js └── test ├── index.css ├── index.html └── test.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "google", 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly" 11 | }, 12 | "parserOptions": { 13 | "ecmaVersion": 2018, 14 | "sourceType": "module" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: ["push", "pull_request"] 4 | 5 | jobs: 6 | 7 | build: 8 | name: Build 9 | runs-on: ubuntu-latest 10 | steps: 11 | 12 | - uses: actions/checkout@v2 13 | - name: Use Node.js 16.x 14 | uses: actions/setup-node@v2 15 | with: 16 | node-version: 16.x 17 | - name: npm install, npm test 18 | run: | 19 | npm install 20 | npm test 21 | - name: Coveralls 22 | uses: coverallsapp/github-action@master 23 | with: 24 | github-token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v2 13 | with: 14 | node-version: 16.x 15 | - run: npm ci 16 | - run: npm test 17 | 18 | publish-npm: 19 | needs: build 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v2 23 | - uses: actions/setup-node@v2 24 | with: 25 | node-version: 16.x 26 | registry-url: https://registry.npmjs.org/ 27 | - run: npm ci 28 | - run: npm publish 29 | env: 30 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .nyc_output/ 2 | /coverage/ 3 | /dist/ 4 | /node_modules/ 5 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "ignoreFiles": ["docs/web/css/github.css"] 4 | } 5 | -------------------------------------------------------------------------------- /conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "opts": 3 | { 4 | "destination": "docs/api", 5 | "readme": "readme.md", 6 | "recurse": true 7 | }, 8 | 9 | "plugins": 10 | [ 11 | "plugins/markdown" 12 | ], 13 | 14 | "source": 15 | { 16 | "include": 17 | [ 18 | "src" 19 | ], 20 | 21 | "includePattern": ".+\\.js(doc)?$", 22 | "excludePattern": "(^|\\/|\\\\)_" 23 | }, 24 | 25 | "tags": 26 | { 27 | "allowUnknownTags": true, 28 | "dictionaries": 29 | [ 30 | "jsdoc" 31 | ] 32 | }, 33 | 34 | "templates": 35 | { 36 | "includeDate": false, 37 | "systemName": "olturf" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /docs/api/docs/web/img/GitHub-Mark-Light-32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/docs/web/img/GitHub-Mark-Light-32px.png -------------------------------------------------------------------------------- /docs/api/docs/web/img/logo70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/docs/web/img/logo70.png -------------------------------------------------------------------------------- /docs/api/docs/web/img/olturf-example-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/docs/web/img/olturf-example-screenshot.png -------------------------------------------------------------------------------- /docs/api/external-ol.control.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | olturf Namespace: control 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 71 | 72 | 73 |
74 |
75 | 76 | 77 |
78 | 79 |
80 | 81 | 82 |

Namespace: control

83 |
84 | 85 |
86 | 87 |

88 | ol. 89 | 90 | control 91 |

92 | 93 | 94 |
95 | 96 | 97 |
98 |
99 | 100 | 101 |

ol control namespace

102 | 103 | 104 | 105 |
106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
See:
140 |
141 | 144 |
145 | 146 | 147 | 148 |
149 | 150 | 151 | 152 | 153 |
154 | 155 | 156 | 157 | 158 | 159 | 160 |

Classes

161 | 162 |
163 |
Control
164 |
165 |
166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 |
180 | 181 |
182 | 183 | 184 | 185 | 186 |
187 |
188 | 189 |
190 | 191 | 192 |
193 | 194 |
195 | 196 | 197 |
198 |
199 | 200 | 201 | 215 | 216 | 217 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 309 | 310 | 311 | 312 | -------------------------------------------------------------------------------- /docs/api/external-ol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | olturf External: ol 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 71 | 72 | 73 |
74 |
75 | 76 | 77 |
78 | 79 |
80 | 81 | 82 |

External: ol

83 |
84 | 85 |
86 | 87 |

88 | ol 89 |

90 | 91 | 92 |
93 | 94 | 95 |
96 |
97 | 98 | 99 |

ol main namespace

100 | 101 | 102 | 103 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 |
See:
138 |
139 | 142 |
143 | 144 | 145 | 146 |
147 | 148 | 149 | 150 | 151 |
152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |

Namespaces

163 | 164 |
165 |
control
166 |
167 |
168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 |
178 | 179 |
180 | 181 | 182 | 183 | 184 |
185 |
186 | 187 |
188 | 189 | 190 |
191 | 192 |
193 | 194 | 195 |
196 |
197 | 198 | 199 | 213 | 214 | 215 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 307 | 308 | 309 | 310 | -------------------------------------------------------------------------------- /docs/api/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /docs/api/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /docs/api/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /docs/api/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /docs/api/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /docs/api/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/api/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/api/scripts/fulltext-search-ui.js: -------------------------------------------------------------------------------- 1 | window.SearcherDisplay = (function($) { 2 | /** 3 | * This class provides support for displaying quick search text results to users. 4 | */ 5 | function SearcherDisplay() { } 6 | 7 | SearcherDisplay.prototype.init = function() { 8 | this._displayQuickSearch(); 9 | }; 10 | 11 | /** 12 | * This method creates the quick text search entry in navigation menu and wires all required events. 13 | */ 14 | SearcherDisplay.prototype._displayQuickSearch = function() { 15 | var quickSearch = $(document.createElement("iframe")), 16 | body = $("body"), 17 | self = this; 18 | 19 | quickSearch.attr("src", "quicksearch.html"); 20 | quickSearch.css("width", "0px"); 21 | quickSearch.css("height", "0px"); 22 | 23 | body.append(quickSearch); 24 | 25 | $(window).on("message", function(msg) { 26 | var msgData = msg.originalEvent.data; 27 | 28 | if (msgData.msgid != "docstrap.quicksearch.done") { 29 | return; 30 | } 31 | 32 | var results = msgData.results || []; 33 | 34 | self._displaySearchResults(results); 35 | }); 36 | 37 | function startSearch() { 38 | var searchTerms = $('#search-input').prop("value"); 39 | if (searchTerms) { 40 | quickSearch[0].contentWindow.postMessage({ 41 | "searchTerms": searchTerms, 42 | "msgid": "docstrap.quicksearch.start" 43 | }, "*"); 44 | } 45 | } 46 | 47 | $('#search-input').on('keyup', function(evt) { 48 | if (evt.keyCode != 13) { 49 | return; 50 | } 51 | startSearch(); 52 | return false; 53 | }); 54 | $('#search-submit').on('click', function() { 55 | startSearch(); 56 | return false; 57 | }); 58 | }; 59 | 60 | /** 61 | * This method displays the quick text search results in a modal dialog. 62 | */ 63 | SearcherDisplay.prototype._displaySearchResults = function(results) { 64 | var resultsHolder = $($("#searchResults").find(".modal-body")), 65 | fragment = document.createDocumentFragment(), 66 | resultsList = document.createElement("ul"); 67 | 68 | resultsHolder.empty(); 69 | 70 | for (var idx = 0; idx < results.length; idx++) { 71 | var result = results[idx], 72 | item = document.createElement("li"), 73 | link = document.createElement("a"); 74 | 75 | link.href = result.id; 76 | link.innerHTML = result.title; 77 | 78 | item.appendChild(link) 79 | resultsList.appendChild(item); 80 | } 81 | 82 | fragment.appendChild(resultsList); 83 | resultsHolder.append(fragment); 84 | 85 | $("#searchResults").modal({"show": true}); 86 | }; 87 | 88 | return new SearcherDisplay(); 89 | })($); 90 | -------------------------------------------------------------------------------- /docs/api/scripts/fulltext-search.js: -------------------------------------------------------------------------------- 1 | window.Searcher = (function() { 2 | function Searcher() { 3 | this._index = lunr(function () { 4 | this.field('title', {boost: 10}) 5 | this.field('body') 6 | this.ref('id') 7 | }) ; 8 | 9 | this._indexContent = undefined; 10 | } 11 | 12 | Searcher.prototype.init = function() { 13 | var self = this; 14 | 15 | $("script[type='text/x-docstrap-searchdb']").each(function(idx, item) { 16 | self._indexContent = JSON.parse(item.innerHTML); 17 | 18 | for (var entryId in self._indexContent) { 19 | self._index.add(self._indexContent[entryId]); 20 | } 21 | }); 22 | }; 23 | 24 | Searcher.prototype.search = function(searchTerm) { 25 | var results = [], 26 | searchResults = this._index.search(searchTerm); 27 | 28 | for (var idx = 0; idx < searchResults.length; idx++) { 29 | results.push(this._indexContent[searchResults[idx].ref]) 30 | } 31 | 32 | return results; 33 | }; 34 | 35 | return new Searcher(); 36 | })(); -------------------------------------------------------------------------------- /docs/api/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([ 2 | ["pln", /^[\t\n\f\r ]+/, null, " \t\r\n "] 3 | ], [ 4 | ["str", /^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/, null], 5 | ["str", /^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/, null], 6 | ["lang-css-str", /^url\(([^"')]*)\)/i], 7 | ["kwd", /^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i, null], 8 | ["lang-css-kw", /^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i], 9 | ["com", /^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], 10 | ["com", /^(?:<\!--|--\>)/], 11 | ["lit", /^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i], 12 | ["lit", /^#[\da-f]{3,6}/i], 13 | ["pln", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i], 14 | ["pun", /^[^\s\w"']+/] 15 | ]), ["css"]); 16 | PR.registerLangHandler(PR.createSimpleLexer([], [ 17 | ["kwd", /^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i] 18 | ]), ["css-kw"]); 19 | PR.registerLangHandler(PR.createSimpleLexer([], [ 20 | ["str", /^[^"')]+/] 21 | ]), ["css-str"]); -------------------------------------------------------------------------------- /docs/api/scripts/toc.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var navbarHeight; 3 | var initialised = false; 4 | var navbarOffset; 5 | 6 | function elOffset($el) { 7 | return $el.offset().top - (navbarHeight + navbarOffset); 8 | } 9 | 10 | function scrollToHash(duringPageLoad) { 11 | var elScrollToId = location.hash.replace(/^#/, ''); 12 | var $el; 13 | 14 | function doScroll() { 15 | var offsetTop = elOffset($el); 16 | window.scrollTo(window.pageXOffset || window.scrollX, offsetTop); 17 | } 18 | 19 | if (elScrollToId) { 20 | $el = $(document.getElementById(elScrollToId)); 21 | 22 | if (!$el.length) { 23 | $el = $(document.getElementsByName(elScrollToId)); 24 | } 25 | 26 | if ($el.length) { 27 | if (duringPageLoad) { 28 | $(window).one('scroll', function() { 29 | setTimeout(doScroll, 100); 30 | }); 31 | } else { 32 | setTimeout(doScroll, 0); 33 | } 34 | } 35 | } 36 | } 37 | 38 | function init(opts) { 39 | if (initialised) { 40 | return; 41 | } 42 | initialised = true; 43 | navbarHeight = $('.navbar').height(); 44 | navbarOffset = opts.navbarOffset; 45 | 46 | // some browsers move the offset after changing location. 47 | // also catch external links coming in 48 | $(window).on("hashchange", scrollToHash.bind(null, false)); 49 | $(scrollToHash.bind(null, true)); 50 | } 51 | 52 | $.catchAnchorLinks = function(options) { 53 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 54 | init(opts); 55 | }; 56 | 57 | $.fn.toc = function(options) { 58 | var self = this; 59 | var opts = $.extend({}, jQuery.fn.toc.defaults, options); 60 | 61 | var container = $(opts.container); 62 | var tocs = []; 63 | var headings = $(opts.selectors, container); 64 | var headingOffsets = []; 65 | var activeClassName = 'active'; 66 | var ANCHOR_PREFIX = "__anchor"; 67 | var maxScrollTo; 68 | var visibleHeight; 69 | var headerHeight = 10; // so if the header is readable, its counted as shown 70 | init(); 71 | 72 | var scrollTo = function(e) { 73 | e.preventDefault(); 74 | var target = $(e.target); 75 | if (target.prop('tagName').toLowerCase() !== "a") { 76 | target = target.parent(); 77 | } 78 | var elScrollToId = target.attr('href').replace(/^#/, '') + ANCHOR_PREFIX; 79 | var $el = $(document.getElementById(elScrollToId)); 80 | 81 | var offsetTop = Math.min(maxScrollTo, elOffset($el)); 82 | 83 | $('body,html').animate({ scrollTop: offsetTop }, 400, 'swing', function() { 84 | location.hash = '#' + elScrollToId; 85 | }); 86 | 87 | $('a', self).removeClass(activeClassName); 88 | target.addClass(activeClassName); 89 | }; 90 | 91 | var calcHadingOffsets = function() { 92 | maxScrollTo = $("body").height() - $(window).height(); 93 | visibleHeight = $(window).height() - navbarHeight; 94 | headingOffsets = []; 95 | headings.each(function(i, heading) { 96 | var anchorSpan = $(heading).prev("span"); 97 | var top = 0; 98 | if (anchorSpan.length) { 99 | top = elOffset(anchorSpan); 100 | } 101 | headingOffsets.push(top > 0 ? top : 0); 102 | }); 103 | } 104 | 105 | //highlight on scroll 106 | var timeout; 107 | var highlightOnScroll = function(e) { 108 | if (!tocs.length) { 109 | return; 110 | } 111 | if (timeout) { 112 | clearTimeout(timeout); 113 | } 114 | timeout = setTimeout(function() { 115 | var top = $(window).scrollTop(), 116 | highlighted; 117 | for (var i = headingOffsets.length - 1; i >= 0; i--) { 118 | var isActive = tocs[i].hasClass(activeClassName); 119 | // at the end of the page, allow any shown header 120 | if (isActive && headingOffsets[i] >= maxScrollTo && top >= maxScrollTo) { 121 | return; 122 | } 123 | // if we have got to the first heading or the heading is the first one visible 124 | if (i === 0 || (headingOffsets[i] + headerHeight >= top && (headingOffsets[i - 1] + headerHeight <= top))) { 125 | // in the case that a heading takes up more than the visible height e.g. we are showing 126 | // only the one above, highlight the one above 127 | if (i > 0 && headingOffsets[i] - visibleHeight >= top) { 128 | i--; 129 | } 130 | $('a', self).removeClass(activeClassName); 131 | if (i >= 0) { 132 | highlighted = tocs[i].addClass(activeClassName); 133 | opts.onHighlight(highlighted); 134 | } 135 | break; 136 | } 137 | } 138 | }, 50); 139 | }; 140 | if (opts.highlightOnScroll) { 141 | $(window).bind('scroll', highlightOnScroll); 142 | $(window).bind('load resize', function() { 143 | calcHadingOffsets(); 144 | highlightOnScroll(); 145 | }); 146 | } 147 | 148 | return this.each(function() { 149 | //build TOC 150 | var el = $(this); 151 | var ul = $('
'); 152 | 153 | headings.each(function(i, heading) { 154 | var $h = $(heading); 155 | 156 | var anchor = $('').attr('id', opts.anchorName(i, heading, opts.prefix) + ANCHOR_PREFIX).insertBefore($h); 157 | 158 | var span = $('') 159 | .text(opts.headerText(i, heading, $h)); 160 | 161 | //build TOC item 162 | var a = $('') 163 | .append(span) 164 | .attr('href', '#' + opts.anchorName(i, heading, opts.prefix)) 165 | .bind('click', function(e) { 166 | scrollTo(e); 167 | el.trigger('selected', $(this).attr('href')); 168 | }); 169 | 170 | span.addClass(opts.itemClass(i, heading, $h, opts.prefix)); 171 | 172 | tocs.push(a); 173 | 174 | ul.append(a); 175 | }); 176 | el.html(ul); 177 | 178 | calcHadingOffsets(); 179 | }); 180 | }; 181 | 182 | 183 | jQuery.fn.toc.defaults = { 184 | container: 'body', 185 | selectors: 'h1,h2,h3', 186 | smoothScrolling: true, 187 | prefix: 'toc', 188 | onHighlight: function() {}, 189 | highlightOnScroll: true, 190 | navbarOffset: 0, 191 | anchorName: function(i, heading, prefix) { 192 | return prefix+i; 193 | }, 194 | headerText: function(i, heading, $heading) { 195 | return $heading.text(); 196 | }, 197 | itemClass: function(i, heading, $heading, prefix) { 198 | return prefix + '-' + $heading[0].tagName.toLowerCase(); 199 | } 200 | 201 | }; 202 | 203 | })(jQuery); 204 | -------------------------------------------------------------------------------- /docs/api/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Menlo, Monaco, Consolas, monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/home.css: -------------------------------------------------------------------------------- 1 | /* Move down content because we have a fixed navbar that is 50px tall */ 2 | body { 3 | padding-top: 50px; 4 | padding-bottom: 20px; 5 | margin-bottom: 60px; 6 | } 7 | 8 | .footer { 9 | position: absolute; 10 | bottom: 0; 11 | left: 0; 12 | width: 100%; 13 | height: 60px; 14 | } 15 | 16 | .intro-header { 17 | padding-top: 50px; 18 | padding-bottom: 50px; 19 | text-align: center; 20 | color: #f8f8f8; 21 | background-size: cover; 22 | } 23 | 24 | .intro-message { 25 | position: relative; 26 | padding-top: 20%; 27 | padding-bottom: 20%; 28 | } 29 | 30 | .intro-message > img { 31 | display: inline-block; 32 | } 33 | 34 | .intro-message > h1 { 35 | margin: 0; 36 | color: #000; 37 | font-size: 5em; 38 | } 39 | 40 | .intro-divider { 41 | width: 100%; 42 | border-top: 1px solid #f8f8f8; 43 | border-bottom: 1px solid rgba(0 0 0 / 20%); 44 | } 45 | 46 | .intro-message > h3 { 47 | color: #000; 48 | } 49 | 50 | @media (max-width: 767px) { 51 | .intro-message { 52 | padding-bottom: 15%; 53 | } 54 | 55 | .intro-message > h1 { 56 | font-size: 3em; 57 | } 58 | 59 | ul.intro-social-buttons > li { 60 | display: block; 61 | margin-bottom: 20px; 62 | padding: 0; 63 | } 64 | 65 | ul.intro-social-buttons > li:last-child { 66 | margin-bottom: 0; 67 | } 68 | 69 | .intro-divider { 70 | width: 100%; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | OpenLayers Turf | Portal 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 | 28 |

OpenLayers Turf

29 |

30 | A Javascript library that provides a 31 | Turf 32 | toolbar for 33 | OpenLayers 34 |

35 |
36 | 44 |
45 |
46 |
47 |
48 |
49 | 50 |
51 |
52 |

© 2016 Daniel Pulido <dpmcmlxxvi@gmail.com>

53 |
54 |
55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/web/css/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | } 14 | 15 | .hljs-comment, 16 | .hljs-quote { 17 | color: #998; 18 | font-style: italic; 19 | } 20 | 21 | .hljs-keyword, 22 | .hljs-selector-tag, 23 | .hljs-subst { 24 | color: #333; 25 | font-weight: bold; 26 | } 27 | 28 | .hljs-number, 29 | .hljs-literal, 30 | .hljs-variable, 31 | .hljs-template-variable, 32 | .hljs-tag .hljs-attr { 33 | color: #008080; 34 | } 35 | 36 | .hljs-string, 37 | .hljs-doctag { 38 | color: #d14; 39 | } 40 | 41 | .hljs-title, 42 | .hljs-section, 43 | .hljs-selector-id { 44 | color: #900; 45 | font-weight: bold; 46 | } 47 | 48 | .hljs-subst { 49 | font-weight: normal; 50 | } 51 | 52 | .hljs-type, 53 | .hljs-class .hljs-title { 54 | color: #458; 55 | font-weight: bold; 56 | } 57 | 58 | .hljs-tag, 59 | .hljs-name, 60 | .hljs-attribute { 61 | color: #000080; 62 | font-weight: normal; 63 | } 64 | 65 | .hljs-regexp, 66 | .hljs-link { 67 | color: #009926; 68 | } 69 | 70 | .hljs-symbol, 71 | .hljs-bullet { 72 | color: #990073; 73 | } 74 | 75 | .hljs-built_in, 76 | .hljs-builtin-name { 77 | color: #0086b3; 78 | } 79 | 80 | .hljs-meta { 81 | color: #999; 82 | font-weight: bold; 83 | } 84 | 85 | .hljs-deletion { 86 | background: #fdd; 87 | } 88 | 89 | .hljs-addition { 90 | background: #dfd; 91 | } 92 | 93 | .hljs-emphasis { 94 | font-style: italic; 95 | } 96 | 97 | .hljs-strong { 98 | font-weight: bold; 99 | } 100 | -------------------------------------------------------------------------------- /docs/web/css/olturf.css: -------------------------------------------------------------------------------- 1 | /* Move down content because we have a fixed navbar that is 50px tall */ 2 | body { 3 | padding-top: 50px; 4 | padding-bottom: 20px; 5 | } 6 | 7 | .olturf-github-logo > li > a { 8 | padding: 9px 15px; 9 | } 10 | 11 | .ol-control button { 12 | height: 1.5em; 13 | width: 1.5em; 14 | } 15 | -------------------------------------------------------------------------------- /docs/web/img/GitHub-Mark-Light-32px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/web/img/GitHub-Mark-Light-32px.png -------------------------------------------------------------------------------- /docs/web/img/logo70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/web/img/logo70.png -------------------------------------------------------------------------------- /docs/web/img/olturf-example-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpmcmlxxvi/olturf/1f45937c1ea3afc63d6a938497ae8f9a2fe9766f/docs/web/img/olturf-example-screenshot.png -------------------------------------------------------------------------------- /docs/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | OpenLayers Turf | Home 11 | 12 | 17 | 22 | 27 | 28 | 34 | 35 | 36 | 37 | 71 | 72 |
73 |
74 |
75 | 76 |
77 |
78 |
79 |

OpenLayers Turf

80 |
81 |
82 |

83 | A Javascript library that provides a 84 | Turf 85 | toolbar for 86 | OpenLayers 87 |

88 |

89 | Download » 95 | 96 |

97 |
98 |
99 | 100 |
101 | 102 |
103 |
104 |

Goal

105 |

106 | The main goal of olturf is to provide a easy-to-use 107 | library that combines the mapping capabilities of OpenLayers with 108 | the geospatial analysis tools of Turf. 109 |

110 |
111 |
112 |

Features

113 |

114 | An out-of-the-box solution to display an OpenLayers toolbar with 115 | access to Turf commands and popup forms and messages to provide 116 | inputs and outputs. 117 |

118 |
119 |
120 |

Configurable

121 |

122 | The user can control the styling of the toolbar and its controls by 123 | provding custom style sheets, as well a custom handler if the 124 | default handler is not sufficient. 125 |

126 |
127 |
128 |
129 |
130 |

Example

131 |

132 | The following example contains the standard toolbar which has 133 | controls for all of the currently supported Turf commands. 134 |

135 |
136 |
137 |
138 |
139 | 140 |
141 |
142 |
143 |

© 2016 Daniel Pulido <dpmcmlxxvi@gmail.com>

144 |

145 | Source code is released under the 146 | MIT 147 | license. Documentation is released under the 148 | 149 | CC BY 4.0 150 | 151 | license. Icons are from 152 | OSGeo 153 | and released under the 154 | 155 | CC BY 3.0 156 | 157 | license. 158 |

159 |
160 |
161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /docs/web/js/example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description Create ol map 3 | * @param {string} id ol.Map DOM id 4 | * @return {ol.Map} OpenLayers map. 5 | */ 6 | function createMap(id) { // eslint-disable-line no-unused-vars 7 | // ================================================== 8 | // Create map 9 | // -------------------------------------------------- 10 | 11 | const select = new ol.interaction.Select({ 12 | condition: ol.events.condition.click, 13 | }); 14 | const controls = ol.control.defaults(); 15 | const interactions = ol.interaction.defaults().extend([select]); 16 | const layers = [new ol.layer.Tile({ 17 | source: new ol.source.Stamen({layer: 'watercolor'}), 18 | })]; 19 | const view = new ol.View({ 20 | center: [-8161939, 6095025], 21 | zoom: 8, 22 | }); 23 | const map = new ol.Map({ 24 | controls: controls, 25 | interactions: interactions, 26 | layers: layers, 27 | target: id, 28 | view: view, 29 | }); 30 | 31 | // ================================================== 32 | // Add data to map 33 | // -------------------------------------------------- 34 | 35 | // Add polygons 36 | const polygons = new ol.layer.Vector({ 37 | source: new ol.source.Vector({ 38 | format: new ol.format.GeoJSON(), 39 | url: 'https://openlayers.org/en/latest/examples/data/geojson/polygon-samples.geojson', 40 | }), 41 | }); 42 | map.addLayer(polygons); 43 | 44 | // Add lines 45 | const lines = new ol.layer.Vector({ 46 | source: new ol.source.Vector({ 47 | format: new ol.format.GeoJSON(), 48 | url: 'https://openlayers.org/en/latest/examples/data/geojson/line-samples.geojson', 49 | }), 50 | }); 51 | map.addLayer(lines); 52 | 53 | // Add points 54 | const points = new ol.layer.Vector({ 55 | source: new ol.source.Vector({ 56 | format: new ol.format.GeoJSON(), 57 | url: 'https://openlayers.org/en/latest/examples/data/geojson/point-samples.geojson', 58 | }), 59 | }); 60 | map.addLayer(points); 61 | 62 | return map; 63 | } 64 | -------------------------------------------------------------------------------- /docs/web/multiple.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | OpenLayers Turf example with two toolbars 7 | 8 | 13 | 18 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/web/standard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OpenLayers Turf example 6 | 7 | 12 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/tmp/jest_rs", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | // clearMocks: false, 19 | 20 | // Indicates whether the coverage information should be collected while 21 | // executing the test 22 | // collectCoverage: false, 23 | 24 | // An array of glob patterns indicating a set of files for which coverage 25 | // information should be collected 26 | // collectCoverageFrom: null, 27 | 28 | // The directory where Jest should output its coverage files 29 | coverageDirectory: 'coverage', 30 | 31 | // An array of regexp pattern strings used to skip coverage collection 32 | // coveragePathIgnorePatterns: [ 33 | // "/node_modules/" 34 | // ], 35 | 36 | // A list of reporter names that Jest uses when writing coverage reports 37 | // coverageReporters: [ 38 | // "json", 39 | // "text", 40 | // "lcov", 41 | // "clover" 42 | // ], 43 | 44 | // An object that configures minimum threshold enforcement for coverage 45 | // results 46 | // coverageThreshold: null, 47 | 48 | // A path to a custom dependency extractor 49 | // dependencyExtractor: null, 50 | 51 | // Make calling deprecated APIs throw helpful error messages 52 | // errorOnDeprecated: false, 53 | 54 | // Force coverage collection from ignored files using an array of glob 55 | // patterns 56 | // forceCoverageMatch: [], 57 | 58 | // A path to a module which exports an async function that is triggered once 59 | // before all test suites 60 | // globalSetup: null, 61 | 62 | // A path to a module which exports an async function that is triggered once 63 | // after all test suites 64 | // globalTeardown: null, 65 | 66 | // A set of global variables that need to be available in all test 67 | // environments 68 | // globals: {}, 69 | 70 | // An array of directory names to be searched recursively up from the 71 | // requiring module's location 72 | // moduleDirectories: [ 73 | // "node_modules" 74 | // ], 75 | 76 | // An array of file extensions your modules use 77 | // moduleFileExtensions: [ 78 | // "js", 79 | // "json", 80 | // "jsx", 81 | // "ts", 82 | // "tsx", 83 | // "node" 84 | // ], 85 | 86 | // A map from regular expressions to module names that allow to stub out 87 | // resources with a single module 88 | // moduleNameMapper: {}, 89 | 90 | // An array of regexp pattern strings, matched against all module paths before 91 | // considered 'visible' to the module loader 92 | // modulePathIgnorePatterns: [], 93 | 94 | // Activates notifications for test results 95 | // notify: false, 96 | 97 | // An enum that specifies notification mode. Requires { notify: true } 98 | // notifyMode: "failure-change", 99 | 100 | // A preset that is used as a base for Jest's configuration 101 | preset: 'jest-puppeteer', 102 | 103 | // Run tests from one or more projects 104 | // projects: null, 105 | 106 | // Use this configuration option to add custom reporters to Jest 107 | // reporters: undefined, 108 | 109 | // Automatically reset mock state between every test 110 | // resetMocks: false, 111 | 112 | // Reset the module registry before running each individual test 113 | // resetModules: false, 114 | 115 | // A path to a custom resolver 116 | // resolver: null, 117 | 118 | // Automatically restore mock state between every test 119 | // restoreMocks: false, 120 | 121 | // The root directory that Jest should scan for tests and modules within 122 | // rootDir: null, 123 | 124 | // A list of paths to directories that Jest should use to search for files in 125 | // roots: [ 126 | // "" 127 | // ], 128 | 129 | // Allows you to use a custom runner instead of Jest's default test runner 130 | // runner: "jest-runner", 131 | 132 | // The paths to modules that run some code to configure or set up the testing 133 | // environment before each test 134 | // setupFiles: [], 135 | 136 | // A list of paths to modules that run some code to configure or set up the 137 | // testing framework before each test 138 | // setupFilesAfterEnv: [], 139 | 140 | // A list of paths to snapshot serializer modules Jest should use for snapshot 141 | // testing 142 | // snapshotSerializers: [], 143 | 144 | // The test environment that will be used for testing 145 | // testEnvironment: "jest-environment-jsdom", 146 | 147 | // Options that will be passed to the testEnvironment 148 | // testEnvironmentOptions: {}, 149 | 150 | // Adds a location field to test results 151 | // testLocationInResults: false, 152 | 153 | // The glob patterns Jest uses to detect test files 154 | // testMatch: [ 155 | // "**/__tests__/**/*.[jt]s?(x)", 156 | // "**/?(*.)+(spec|test).[tj]s?(x)" 157 | // ], 158 | 159 | // An array of regexp pattern strings that are matched against all test paths, 160 | // matched tests are skipped 161 | // testPathIgnorePatterns: [ 162 | // "/node_modules/" 163 | // ], 164 | 165 | // The regexp pattern or array of patterns that Jest uses to detect test files 166 | // testRegex: [], 167 | 168 | // This option allows the use of a custom results processor 169 | // testResultsProcessor: null, 170 | 171 | // This option allows use of a custom test runner 172 | // testRunner: "jasmine2", 173 | 174 | // This option sets the URL for the jsdom environment. It is reflected in 175 | // properties such as location.href 176 | // testURL: "http://localhost", 177 | 178 | // Setting this value to "fake" allows the use of fake timers for functions 179 | // such as "setTimeout" 180 | // timers: "real", 181 | 182 | // A map from regular expressions to paths to transformers 183 | // transform: null, 184 | 185 | // An array of regexp pattern strings that are matched against all source file 186 | // paths, matched files will skip transformation 187 | // transformIgnorePatterns: [ 188 | // "/node_modules/" 189 | // ], 190 | 191 | // An array of regexp pattern strings that are matched against all modules 192 | // before the module loader will automatically return a mock for them 193 | // unmockedModulePathPatterns: undefined, 194 | 195 | // Indicates whether each individual test should be reported during the run 196 | // verbose: null, 197 | 198 | // An array of regexp patterns that are matched against all source file paths 199 | // before re-running tests in watch mode 200 | // watchPathIgnorePatterns: [], 201 | 202 | // Whether to use watchman for file crawling 203 | // watchman: true, 204 | }; 205 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Daniel Pulido 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "olturf", 3 | "version": "0.8.1", 4 | "description": "A Turf toolbar for OpenLayers.", 5 | "author": { 6 | "name": "Daniel Pulido", 7 | "email": "dpmcmlxxvi@gmail.com" 8 | }, 9 | "license": "MIT", 10 | "main": "dist/olturf.js", 11 | "module": "src/js/main.js", 12 | "unpkg": "dist/olturf.min.js", 13 | "jsdelivr": "dist/olturf.min.js", 14 | "scripts": { 15 | "build": "run-s lint bundle docs", 16 | "bundle": "run-s bundle:js bundle:css", 17 | "bundle:css": "run-s bundle:css:*", 18 | "bundle:css:cat": "shx cat src/css/*.css > dist/olturf.css", 19 | "bundle:css:min": "cleancss -o dist/olturf.min.css -O2 src/css/*.css", 20 | "bundle:js": "rollup --silent -c", 21 | "docs": "run-s docs:clean docs:build docs:mkdir docs:copy", 22 | "docs:build": "jsdoc -t ./node_modules/ink-docstrap/template -c conf.json", 23 | "docs:clean": "shx rm -rf docs/api", 24 | "docs:copy": "shx cp docs/web/img/* docs/api/docs/web/img/", 25 | "docs:mkdir": "shx mkdir -p docs/api/docs/web/img/", 26 | "lint": "run-s lint:md lint:css lint:html lint:js", 27 | "lint:css": "stylelint 'src/css/*.css' 'docs/*.css' 'docs/web/css/*.css'", 28 | "lint:html": "run-s lint:html:pretty lint:html:hint", 29 | "lint:html:hint": "htmlhint 'docs/*.html' 'docs/web/*.html'", 30 | "lint:html:pretty": "prettier --check 'docs/*.html' 'docs/web/*.html'", 31 | "lint:js": "eslint '*.js' 'docs/web/js/*.js' 'src/js/*.js'", 32 | "lint:md": "remark -q .", 33 | "prepare": "npm run build", 34 | "test": "run-s test:clean test:lint test:run test:coverage", 35 | "test:clean": "shx rm -rf coverage .nyc_output", 36 | "test:coverage": "nyc report --reporter=lcov", 37 | "test:lint": "run-s test:lint:*", 38 | "test:lint:css": "stylelint 'test/*.css'", 39 | "test:lint:html": "run-s test:lint:html:*", 40 | "test:lint:html:hint": "htmlhint 'test/*.html'", 41 | "test:lint:html:pretty": "prettier --check 'test/*.html'", 42 | "test:lint:js": "eslint 'test/*.js'", 43 | "test:run": "jest" 44 | }, 45 | "files": [ 46 | "src/**/*.*", 47 | "dist/*.*" 48 | ], 49 | "homepage": "https://github.com/dpmcmlxxvi/olturf", 50 | "repository": { 51 | "type": "git", 52 | "url": "git+https://github.com/dpmcmlxxvi/olturf.git" 53 | }, 54 | "bugs": { 55 | "url": "https://github.com/dpmcmlxxvi/olturf/issues" 56 | }, 57 | "keywords": [ 58 | "turf", 59 | "openlayers", 60 | "toolbar" 61 | ], 62 | "devDependencies": { 63 | "clean-css-cli": "^5.5.2", 64 | "coveralls": "^3.1.1", 65 | "eslint": "^8.8.0", 66 | "eslint-config-google": "^0.14.0", 67 | "htmlhint": "^1.1.2", 68 | "ink-docstrap": "^1.3.2", 69 | "jest": "^27.4.7", 70 | "jest-puppeteer": "^6.1.0", 71 | "jquery": "^3.6.0", 72 | "jsdoc": "^3.6.10", 73 | "npm-run-all": "^4.1.5", 74 | "nyc": "^15.1.0", 75 | "prettier": "^2.5.1", 76 | "puppeteer": "^13.1.3", 77 | "puppeteer-to-istanbul": "^1.4.0", 78 | "remark-cli": "^10.0.1", 79 | "remark-preset-lint-markdown-style-guide": "^5.1.2", 80 | "rollup": "^2.67.0", 81 | "rollup-plugin-commonjs": "^10.1.0", 82 | "rollup-plugin-node-resolve": "^5.2.0", 83 | "rollup-plugin-terser": "^7.0.2", 84 | "shx": "^0.3.4", 85 | "stylelint": "^14.3.0", 86 | "stylelint-config-standard": "^24.0.0" 87 | }, 88 | "remarkConfig": { 89 | "plugins": [ 90 | "remark-preset-lint-markdown-style-guide" 91 | ] 92 | }, 93 | "nyc": { 94 | "include": [ 95 | "**/olturf.js" 96 | ] 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # OpenLayers Turf 2 | 3 | [![build](https://github.com/dpmcmlxxvi/olturf/actions/workflows/build.yml/badge.svg)](https://github.com/dpmcmlxxvi/olturf/actions) 4 | [![coverage](https://img.shields.io/coveralls/dpmcmlxxvi/olturf.svg)](https://coveralls.io/r/dpmcmlxxvi/olturf?branch=master) 5 | [![codacy](https://app.codacy.com/project/badge/Grade/c8c1b0c8b3c842df96a08276fe3cb69a)](https://www.codacy.com/gh/dpmcmlxxvi/olturf/dashboard?utm_source=github.com&utm_medium=referral&utm_content=dpmcmlxxvi/olturf&utm_campaign=Badge_Grade) 6 | [![npm](https://badge.fury.io/js/olturf.svg)](https://badge.fury.io/js/olturf) 7 | 8 | [OpenLayers Turf](https://github.com/dpmcmlxxvi/olturf) (olturf) is a 9 | [Turf](http://turfjs.org/) toolbar for [OpenLayers](http://openlayers.org/). 10 | The toolbar provides the following features: 11 | 12 | - **Customizable** commands to display 13 | - **Forms** to collect command inputs 14 | - **Popups** to display numerical outputs 15 | - **Input** features are selected in the map 16 | - **Output** features are displayed in the map 17 | 18 | Instead of displaying all the Turf commands available, individual commands can 19 | be selected or a subset of pre-defined groups can be displayed. The following 20 | groups are available `aggregation`, `classification`, `data`, `grids`, 21 | `interpolation`, `measurement`, `misc`, `joins`, `transformation`. 22 | 23 | ![](docs/web/img/olturf-example-screenshot.png) 24 | 25 | ## GETTING STARTED 26 | 27 | A toolbar can be added to an OpenLayers map by adding its dependencies 28 | 29 | ```html 30 | 32 | 33 | 34 | 35 | 36 | 37 | ``` 38 | 39 | then creating an instance and adding it to the map 40 | 41 | ```javascript 42 | const toolbar = new olturf.Toolbar(); 43 | const map = new ol.Map({...}); 44 | map.addControl(toolbar); 45 | ``` 46 | 47 | ## DOCUMENTATION 48 | 49 | The following help is available at the olturf 50 | [website](http://dpmcmlxxvi.github.io/olturf): 51 | 52 | - [Introduction](http://dpmcmlxxvi.github.io/olturf/web/) 53 | - [Getting Started](http://dpmcmlxxvi.github.io/olturf/web/start.html) 54 | - [Examples](http://dpmcmlxxvi.github.io/olturf/web/demos.html) 55 | - [API](http://dpmcmlxxvi.github.io/olturf/api/) 56 | 57 | ## BUILD 58 | 59 | To build and test the library locally: 60 | 61 | ```shell 62 | npm install 63 | npm test 64 | ``` 65 | 66 | The bundled library and stylesheet are at `dist/olturf.min.js` and 67 | `dist/olturf.min.css`. 68 | 69 | ## LICENSE 70 | 71 | Copyright (c) 2016 Daniel Pulido 72 | 73 | Source code is released under the [MIT License](http://opensource.org/licenses/MIT). 74 | Documentation is released under the [CC BY 4.0](http://creativecommons.org/licenses/by-sa/4.0/). 75 | Icons are from [OSGeo](http://trac.osgeo.org/osgeo/wiki) and released under the 76 | [CC BY 3.0](http://creativecommons.org/licenses/by-sa/3.0/). 77 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from 'rollup-plugin-commonjs'; 2 | import pkg from './package.json'; 3 | import resolve from 'rollup-plugin-node-resolve'; 4 | import {terser} from 'rollup-plugin-terser'; 5 | 6 | const banner = `\ 7 | /** 8 | * ${pkg.name} v${pkg.version} 9 | * ${pkg.description} 10 | * 11 | * @author ${pkg.author.name} <${pkg.author.email}> 12 | * @license ${pkg.license} 13 | * @preserve 14 | */ 15 | `; 16 | 17 | const build = (filename, plugins) => ({ 18 | input: pkg.module, 19 | output: { 20 | banner: banner, 21 | file: filename, 22 | format: 'umd', 23 | name: 'olturf', 24 | }, 25 | plugins, 26 | }); 27 | 28 | export default [ 29 | build('dist/olturf.js', [commonjs(), resolve()]), 30 | build('dist/olturf.min.js', [commonjs(), resolve(), terser()]), 31 | ]; 32 | -------------------------------------------------------------------------------- /src/css/along.css: -------------------------------------------------------------------------------- 1 | .olturf-along { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFQSURBVEiJ3ZWxTsJQFIb/U2oiE6mDi4kOTCT6DjI5uTQhOunIzsA7SFgdcFMnStJSfQB4CljooAmJmBjSCZJyOC40IVivYC+D3vXe/P/35dzcSyKCbS5jq+n/osBUbRaLRdOyrHJmJ1MFAI64Nh6PG51OZ6alwLKscnYvW8+f5ncBIOgG9cXW7boFpLpFpYvSS+G8cJg7yAEAwmGI3lMPHPGPwSJy2W63m0qDRCKiV8/zjtY9rxwyR1wbdAezcBgiHIYIusGUI65tAqQ0YGZv8jG56T/3RwA4HrK2AsMwKkR012q2KpuErlVg2/Y+gGvTNE9+Gw4oZiAiVSJ6dBznLU1BokFMz8zHacKBbwxEpArgwff9UdqCLwYx/Xw+T00PJBjopAdWDHTTAysGC/p7XfTAksGC/oqItNEDSwYicgag4bruu84C5XOtY/39P/kTb06L2sdZq7MAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/area.css: -------------------------------------------------------------------------------- 1 | .olturf-area { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAiElEQVRIiWNgoCewicr7jw1T1YKmBVtQMF0sIAcTbQE5eIRagCusqWoBseoH1gJSkh7JFpAKSM4HQxeEhgf/heHAoIB/1GCHhgf/RbHg8vXzfy9fP/83ICDgPzXYA2fBxMn9/7CxkTXjUoPMxmkBLoxsATGYZAuQXUcTC0jFGBbQAlM9Pw0IAAB5nYPLMYssKQAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/bearing.css: -------------------------------------------------------------------------------- 1 | .olturf-bearing { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABlUlEQVRIic2TzysEYRjHXxelcHRRioPCycHa3fd5NwcXKe1a7+68z1pSRMb7LCVnFycHSe7uzk7+BbVJccLZRcqvyOzrsEYjBvvubnzrW08z834+T80MY5aJ5/NtPEuzgyO5VltGOFzqUY6FK0AyUeVOW0EiqbluxlhD8FpMyibI0S4gGUAyQtHBkJTNFcMBV7reIEeAepgxxmLphX7I0SkgGa7oAXLkWm3uR6DrAOoLQDKg6JgregIkw5GKQs73VgX3k8ivdgpFl+WtdUng0mafXG+sCTyqKAOor8tb6/s4kpfIuImqwXxsrUU4tOe/SHD0fkwutAPSOaA+rAoekcuxMogMKH0bzy7N+PfijrvBUT9bf/cgCwBKv7xvXnH1I5/UIlTAJ7UApDtrgSrcfCv4KdHUcg8gGeEsTlhDvsuAWukDJBNNu4N1ETDGGEwVOqwOymza85saT5ZqMcts2vsgODkreidnRS+ZTJpazH8n2N7ZKn01Bw+HPROcQwVhDQp+04oFwe3qIqi0nwT1qNU/8+/yCqPLom9B4CXCAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/bezier.css: -------------------------------------------------------------------------------- 1 | .olturf-bezier { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAARoSURBVEiJnVNLbJRVGD33Mf+8/mGGKZ2+aGZogQohQqS8tCqYoNIFCysDhCAaFyQaI8qCYEKiGxeGhcEnGCwkVaQWfIAhAgtNpkkRi8FQSSltaSlQGGinnaHz+u/9XAwdKFAtPZub3Pvdc77v3HsYEeF+hMPhmTaX2MoYrwDIAMimiS5b6eyPVppOHj58+NYDl8YBu1cgHA7PtbnETtK0IrRshs0T8AhiAAi4PZBAtCMaH74yZOeSd+ks/axIHzcdZnN9fX2KMcbWr18d0FoUHjz4QxvdIc4LhMNhr3CwrtnLq3zBxSHOJINWGtrSUEpBq9yqMgpDV2KI9caswd7BRHJwxMk4y5AiN5MsKwRXRLiSyVhrmw40/SVHu5cu/lnJ3FJ3RU0lJ6IcudLQWoM05VZFIBDMYg/MYo+cvrjcpy0NlVV2aZdgnNkBoP/ctVl9p/v2AniCERHWrq1bYZiOo8u3POeSdpnv9vbN22je04xsMjshvx0eB6pfqwZpQuv+00mVoiW5CSSvDS2dkSPXOt9t27E2lC4oRfmi8gkJRHZFcg/LGfwzCnCjPfq0BABhEwGbywAR5exQGtcvXEfiRgLBpUG0fNUCK2lNaIJRcINLkHZKAGCM2TFKrjVURuH8sfOoeLYCvX/0omReCUJPhvCwLz0epJSCMebgAJBJWo29rT3xUWs6mzvh9Dthc9ow2DOI8uryRyIHgGRsZIQR+iQA+L3+I0M3BxHri0EYApdaLmHBugXoONGB4NIgCIRbnbdwsyMaH7occ0pDpt0BU/sr/Wbh7AC7nzw1lELsckwS8ZN3c7AhvFEI9qVhOly+oA9moYmu3zphBsz48LUhQ0hxyspk6yWzH7UsKwChFgop3p82K1AWfCpkZzynE++P4+KJ9hErrbZ9903jp2OSXFdXt1k4xBfVm6rZmYYz0Jb1N2n2kV3ajzQ0NAzf3+mdcP4kDVk9pdTLE9F4NpNIp5SFdxoPNH4L3JPk2tpau8t0dVe9WFWSSqSoJ9LT2tTYtGgifq9Zt2YVoGdywjmfb1pk9+7d+eDkk+x0O7d7ij1eb5kXF76+kCJFm8cjjOxnCxnwIYAlALBl1djz5v17AOAUAe/lBRhjG20um+yOdGcB/HLo0KEz4wkw4GNu89Q4PRXg3AEuHGDCAKkMiBQKKjegt3X78yoTc+UFtKWXDXQN7ACw2spY7/6PKzXuqY9DGlPHbBrOMpTM2wqnbx6EcONi5JUa9qj/O2cBI2/pC+Dclt9zeKtQMudtGO5ypBPd6PlzGwZ6vr/7Bo+Ke8nNomdQNOt1SLsfVnoA/f/sAqkkAExeYBRTileg6LE3wIUDWqUR7diLVPxi/nzSArGrv6Js/g7Erh6H4Z6OgtAaXGvbib6zH4ypm/wEpFEQfBmFlZvQGXkVw/2/43r75w+U8cnyF4TCcHrngDEBf/Clh5IDk52A4azNWTS/u+VNRDv3QVsj49ZN7pvuYyvB8QkIVf/RRDs03voX8NULXlemglsAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/buffer.css: -------------------------------------------------------------------------------- 1 | .olturf-buffer { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAATdEVYdFRpdGxlAHNlbGVjdCByYWRpdXNsCnYvAAAAGHRFWHRBdXRob3IAUm9iZXJ0IFN6Y3plcGFuZWtfVrEIAAAAGHRFWHRDcmVhdGlvbiBUaW1lADIwMTEtMDQtMjDcNDpxAAAAUnRFWHRDb3B5cmlnaHQAQ0MgQXR0cmlidXRpb24tU2hhcmVBbGlrZSBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8zLjAvXoNavAAAA3ZJREFUSImtlV1oHFUUgL+ZbNgoW3cb+0u3bsqChQUzkGYyQfMg1lISjWZBdpNQaUhpixBoUBRBUSToi29tSkUpTV6KD8I85KcIMRS3LY4jbQeDiQ/psnR3TCOm2fq3k033+rBp3Z9ssg85cB/uueec755z7z1XEkJQKoqq1QDtQINlGsOKqplAAJi0TKNPUbX9gG2ZxsMy5xKRK+hfB94HPGvzFwEVOLs27weuK6r2zGYA6VEGiqrJwGlgxDKNfzdzVFStF5gAMpZpONVkcAY4Djy1WXAAyzQuW6aRBoYVVXu3mgz2AeLLwVsfPVzNnhSVy/e/M+SSS96vP7188CjwgmUav5bauNYOVLFM4ybAjVHp5KGXO2RXbe2mWaxmszJTk93AUWDdMsnkb8ujw0NAVcEBXLW1CJAt05gCjiiqdmg9wHPA91VF3FgagNfKNgGcA1a3AGAAx9YDjALRjTzf+8yNsyIT8AsO+B0CfkGDH+p9RWbj5B9jGaAN2AckKgGcFZnDRyIApJIJbs7GuZu8ByLHjm3tnJ2Mnt+/Z9f84tL9D8Lh8Fe6rmcKAdfJ168iIODPX+XW1lag9bE+nU6TSqVIJpNvxeNxZ2Zmxu1yuSaAw4WAno1eIsABv0MqmSgKDuD1evF6vQSDQSmRSEg1NTX3HMcZLLSRAY+iaqc3AgT8AtuOr7tm2zZDQ0P/3Lp9e25pOR3Sdf3nUsAycEJRtVOVAA1+8jVfRy5dvMBvCws37txNrSwu3V8uXZfXWu6bwFXIP//VbLbIqN4HiBzpdLoM0N3bxzaP56Vd9dvPWaZR1vulwv9AUbVPPj42F9zje9BT2ou++aGdV994h1AohG3bXLp4ge7ePoLBIPPz8wwPD//lOE67ruvXighCiMejsbnl7cbmloXG5paOQr0Qgkgkcn5kZCQXj8dFf3//3+0dr3wbiURysVhM2LYtYrGYiEajf3Z1dbUV+kmlP5qiagcBL7ATeB74EbgS2Lv7VFNT0+eSJLl+mZ2dmJuP/7T76e3xep/vi4GBAU+lTMoABaAQ0EO+V33oefKJE3t37jgjyfKD3/9Yevbqd1OLAOFwuM3tdl+pBKkIKJVwOFzndrsnHMcZLL2KG0GqBlSxgSLI9PQ04+Pjd7YMUAjp7Oz0jI2NbW0GhZC6urrRTCZzXNf1a/8Bf22h7chkjC8AAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/center-of-mass.css: -------------------------------------------------------------------------------- 1 | .olturf-center-of-mass { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdFRpdGxlAEdJUyBpY29uIHRoZW1lIDAuMXda8RoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAASdEVYdENyZWF0aW9uIFRpbWUAMjAxMTFlNGMAAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAACoUlEQVRIie1UTUhUURg933tv3nszTwdnREmjTYZjILYJI3HjKhqj0LFxMlP7WcRI0q5NIG0qXJXKgBSESVLDGAhtIsWIaaWLsh9SUmZA8QdManxvnqPe26axQcfJRbXyrD645zvncLj3EuccW0FE5PXWVjASHETMwrkgceJfB54OvOPpFjKAUvler1fmAj9vVZVbmk1zOJzODUkUSRRFzC8sIBb7QZJkGdENY4AYDQeDwdldG7jdbiU3z/GxsLBw38kT7iyXq2Qb2e/3b87Zds0E0TIRDTHGYqIoFoBwgDOeZcTjHaWHS3vb29uZlFxw5ObcdrlKCi5fvKJlSlTZVolwZxh373Soc/NzBdPTUxcYY7CqVtjtdmwwhoHnoe4vk5+zAXRKv6opt9qUqz6vz5ZONDV5Eq2trQCAQCCw7UzxNdh6HvbcIKIuCQBsmnqzuvqUVdOyMibfOoc7w2m5RUWHYLNasz0+T7kEACQI+/Pz8mlH9RSxZEV/Qk6Ogy1/X3JIAMAYc2raztUna0itKl01qVBkGbQhqAIAEDA6NT21q/u9m/QAEF81iRGtCgCgm/F7I69HVjItGIaB5pZmHK84ZtZ6avjE5AQSicSO3NmZGTURT4Q330FTS+OnsrIjB896vKosywAAXdcx/uE9xsZGVyKRiCyryltdN0KqIhdLklQlW+SitmvXNafTuSlumia6A1364uLC477eJ/7fBk1NGhfYA1VRThcXu/BtaWk9Eo2qiiK/ievGI9NcezE4OBhLTdrQ6PNbLJaOmjO1NofTSdFohA0Nv1oF+LO+3v5LnHNOW7+W+npPFSOhSOB8mXPhZTAYzFhd3bm6o5pqvS+Kom19bX3UWDO7Q/2h8eT5NoO/DeGfqu8Z7BnsGfwfg58EuxP0AMkiuQAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/center.css: -------------------------------------------------------------------------------- 1 | .olturf-center { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAC20lEQVRIic2Uz08TQRTHBw96UP8C/wcTE6OJcPEmiVm2uzvdzu7ObEst1B5MpJEiChKI0MKaeNGDCUEwkR8VCt5qKq0SD7X80ARjoASJSfdGQ6GIHOR5gYYfLQV64SXfw06+8z5v3uwbhPJHmSBw5ZIk3cZYsEiyhDmRu4IQKivgP1pgjM9aZIuD6spv992atYZG30pT86PMk5bmjNtTm1EpWWUONmaRLQxjfOlYySsrK89pVEnWN3jXotFxME3zgHiez4kydUNjqkkZ7VM19QVzsBFWTRNMpz8tssXR0tJyZg+AKORZ29PWbL7EuwHGuAE8z0MqlYLJqUkYCg7CwGA/jI2NQjQ6DpGPEXB7atetNuu93a25xnRtPZmcL1r5DmBH+fwTE59B1ZVU7s50u/Z+KDi4Vazy/SoEME0TXLXO1Sqx6jpCCCG7Q5+KxaKHtuY4JzBNE+p9D1Yw4W4hhBBiOv2VSHwtaM53B8W8j5saV0RR5LdbRIcGBvsLtijfSYp5vb66jCRJlQghhCSbdKPG7Vo9bMPCwgKERkPgD7Rv9L3p3YrGorC0tFTQa1Osm+Xl5Rdzf5Kmqz86jcDG7k3JZBKGR97Bw0bfmo1YN1k1GxdkwaMw8lyvZt9dNc7s7OzsnuSLi4tQ572f1Zjt5Z45oJSeV5n61ulyZDu7AllfQ/2KTKx/dbv2wWrlyZ5qtkMmsofqWjYUGtmKfYrB696efxpT/qi60oMKPSuCwN0UZOGOKIoixvhCsReAE7mr1K59sTv1GUrJK45wl4vtOR2B/biCGCSuGArkEzFIHPtxxYkBxCBxb7cXWgfaoD3YAdPzMzA5NwXtwQ5oHWgDb7cXiEHiJwYohgL+4QB0hQzoChmwnE7Dcjqd+/YPB0AxFCgJsJMsH6ArZJQOmJqbziXer5nkt9IBkUSk4OSH4+HSAbu1k3j/+ukF7J+BcDwMkUTkwCycGHDUQfsPOfOjEiyix5sAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/centroid.css: -------------------------------------------------------------------------------- 1 | .olturf-centroid { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADc0lEQVRIiaWU729TVRjHz/ZCTdDwB/g/mJiIJg5eGELiEnfX9t7b29t777nt5n64FxJZWMcUXBSNwy3xjQZ9w91INjZ0Y4aEsXDXWqqkbGRp1hunHXXIeoGkgfUHtqXdvr4A6qotde2TPMlJzvc5n+d5znkOIeWtwWZjmjiOe4fnbVZO4HiGZV4lhDRU0P8/43n+OatgdSuq88/u9zpT/QOezeMnPkx8PHgi0d3TlZAUMUnddNYqWCnP8y/v6vDm5ubnZcUZ6evvTXm9CzBN8z9usViKrlApI1PJVKgyJsnS19RNp2mbskhV5VerYHUPDg42lgBEpzjy6WefpMsdvBMwvDAMi8WCWCyGpRtLmDo/iXOTE5idvQCvdwFX9Cvo7ul6aHfY39/ZmtepKj+MRH6vmvlTwFMvp7961Q9JdcaKd6a65B+nzk9uV8v8314JYJomOrrak61s6xuEEEJcbvWGz+d9Zmt2U4FpmujzHN3kReZtQgghVFX+WFy8XlFc7g6qaT86PrDJsqzlSYuUqXOTExVbVK6Satpez5EEx3HNhBBCOAf3Zmd3R/JZAWtra5i5MIMvhj7PjJ0d3fb6vFhfX6+odTjtuaamppeKL0lWJePU8FBmZ1AkEsEP09/j2IAn5RDtOdpGF2yCrcdJxa/UNhrq6GxPh8PhksOj0SiO9H6Qlqnjm5I5UBRlj0Sl8fYOd/rUl0NpT3/fpiDas6pLnrfbLWJJNk9MEIUeRZXTMzPT276ffNBGz2zJ1PmXpDrPkErfis3GvGUTbO+yLMvyPP9itR+AYZnXFJf8s6tdXVYU8TtGZF6pFlPVAmNkv18jwYBGUMn9GgkGxsj+mgB+jQSvje/F8sV9CF06gJX5QygAWJk/hNClA1i+uA/XxvfCr5FgbRVoBCuXD8LQGRh6Cwy9BQWguDZ0BiuXDyKgEdQMuLN6GulkBLdCJ/Hgrh8FAA/u+nErdBLpZAR3Vk/XBzB0BrfDI8hv5ZDLpxDfmEMun0J+K4fb4REYOlMv4HE78oUs4htzMPQWxDfmkC9ki3t1AQJaA1b9Eh4VMsjm7iP227fI5u7jUSGDVb+EgNZQH+Bm8DAS8SUYeivuRSdQAHAvOgFDb0UivoSbwcP1AX45+wICo43Fd18A/pmD0cbH+7UCyg1ZCWDHsNVWwS4m+W8fje20SGRe3gAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/circle.css: -------------------------------------------------------------------------------- 1 | .olturf-circle { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAwOC0xMi0xMlguO78AAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAACWklEQVRIibWVMUtbYRSGn3OTS0hqqUIjFQrqH7CkmOBgIjgJpUu3m9s9xSEGdPEXFFoDaQbRxaXEbEKHLg6CxqGYQqj+AztIW2raYpvBeE+Hm0ht741Xi+/0wfnO+3K+c873iqpykwj7BabsQsZBpwWSCkkAgbpC3UC2tiulnSAC8ncFaXt2QMUsG6oTIFUVGuEzowHQDjkJURKgliPyTvQ0X6ssNwMLpLOFSUSrIButvtbi+9XVX15J47lcLHoSfQ76BBWrtl7avVQgbc8OgLkvjj7bqZbfBik/Y+UfqSErcDrmV4nRPaiYZZCNoOQA7l3ZcHO9YYDbUEN1otXXWgxK3kWrr7VoqE5M2YWMr4CDToNU/d68F9wcqbocPgICSRUaVyXvQoWGdEbZU0Ah2R3F6yB8ZjS0l8BNovtE9XbISVyXpB1yEgJ1XwGFuruh14MoCe0lYCBboNZ4Lhe7Krmbo5bL4SXe2eTJp3OvReW4VinNBSHOFrOTghSBlM+VPUXnz39T0dM8mPsZK78ZZJsFKQ4NDKXu3OonHAoz82AGRx029zdpn7X5/vNb6qh5VDyfolpluYmKpYaspO3Cq17P1Yml4v2DRCNRzLDJ8N1hRuOjmGGTaCRKvH8QIHXBD2rrpd20PTumYpZjJ5EPGXvO87uOEbHghJAR8q2wG/vHD7q4zHDuP/yyPf94gZH4iGf+4ddDXr554e9oHcfydS27aNP8cczQ7Xue8c/Hn4AelhkEa9tr5+el7BIAC+sLF+7c+FfxPxXs8ccOHHw88Gr6nm+TL0PQRfsNt8H8Kgp1SDQAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/collect.css: -------------------------------------------------------------------------------- 1 | .olturf-collect { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFiSURBVEiJY/z//z8DLQETTU2nhwUss2bNevH3719xig1iYvz759//vMzMzGnI4ozTpk37HxERRqn5DCtWrGJgYWL8/+ff/xxkS6gaRNaKLIwsTIxTpk+fnkUTC4S5mTAsYaGmBciWHL3/Z8r06dOpZwEXJwfDuks/kIUYWZgYJ1HNAj9/P4YHDx4w/PjxEy528OAhZqrGwb9/qKUCIyMj9kheWRZDlgVKSooMGhrqcMzHx4dpwbsn9xg+vnjE8OruNbIsQQcoFnx69Yxhc2seg75nOMOO/kqqWAKP5JVlMQwfnj9kUDK1Y3DNqmNgYGBg2NCYwcAvIccQ3rWEcgvCu5YwfPvwhmF1ZTzD2sYMhmfXLzKEtC1gEJJRosQDqEHEJSDCENq+kOHe6UMMgY2zKDYcwwKYJQKS8gx8YlIUG47VAgYGBorCHB2wMDMzv1yxYhXF9QE2wMzM/JJxtE4ecAsAO8JvNCGaP0kAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/combine.css: -------------------------------------------------------------------------------- 1 | .olturf-combine { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABXElEQVRIid2VP2uDQBiHM+QbuYoajZCPEA5KPISMouIfSBfXI0O+QZYM3tApY8RVpJ8gGKhDIWQIZJNiwLdLU0IajdoWmv7gN/o8eHfvXafzXwIf/TVebQGLNEZSbSpjN+WQfpSxm0qqTVmkMW14nxEEr8tjk4iKlRE/KGiUQLg5AI0SIH5QiIqV8dgkguB1G4FP4bFJhs40W633EG/zL12t9zB0phmPTdIYziKNERWrFH4uERUru1iu25FUmxI/KKrgpxI/KCTVpo0EMnZTGiU34fE2BxolIGM3bSTgkH4MN4dagnBzAA7px6ug3sjYsUiDy/axAz/yByzSrn5kzBZA/KCWoHIPygRPzy8wGE/g26eoTBBvc/DmS3h4nJVKas1BlSB6fQNvvoTBeALED6DVJFcJzpfLmC2gjx2ouIvaC05lkdb89r1/QdmgXWtvZOyasP/Oi9ZWcL95BwBW4rRT0YJCAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/concave.css: -------------------------------------------------------------------------------- 1 | .olturf-concave { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAUdEVYdFRpdGxlAHNlbGVjdCBwb2x5Z29u55zSuQAAABh0RVh0QXV0aG9yAFJvYmVydCBTemN6ZXBhbmVrX1axCAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDExLTA0LTIw3DQ6cQAAAFJ0RVh0Q29weXJpZ2h0AENDIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMy4wL16DWrwAAAPUSURBVEiJrZNtaBt1HMc/edplWdeWrXS6ZXYlCK64XJEmqThXR5UxsY7M2m6dVYsUfAhSENSBm9CK696IlBSxIkN8yAuFm7bbBKGoFPQ8cdxSG3XEtqw97epMU7sul5qcL5qWpA/pivvCvbjf0+f//d39cVd5t7qrvMPuKu9hwzD4v4+7ynvIXeXduPBuMgwD0ePbBwSBB1VFvso6JXp8ZuA1YA54FbhDVeQ4gFX0+PYABwBRVWRD9PhOAN+qivzNOhgfA7cDTcCeheEAVmA3cKeqyEYm9h3wkejxdauK3LnGye8B4kAnMKgqcioDWZQV2ABMLAR62i7WT88Y2/+csp/69C3HqbRhwlkyu2z4wM+lFDp2cKz2ivTsycnDGWAx4FEV+atsQAj4bCGQ+neudd8jD5utNhvKpSTHT8c4+ugmnmksyAHcKE7QeBS0SxcPZYV3AyeBRYAZaAFqFwIGmK02GwAe9wY+6SphajpNOg2Dv85x/PQUqRTsv9fOzh12jPkZC5oB+pauyAt8v2wHGZVutfBSayHaRIpXOmM837wZi2XlWlWRw0B4KWAjsOavuX2bhXNnSvPWiB6fCKRURR7MBrSqipzI1/jymwJ60kyZ06DcqVPmNNjlhC3Fy0qPAdeAHEC36PGdUBVZWw2gJ83UPtQAwPjYKD9FhrkyNgFGmpLNB+k639idTCZ/LNzkmJlN6Gp2rxXYD9jzOShzzl+R6upqoHoxHo/HGR8fZ2xs7LmRkZHr4XDYYbVavwa+zAaQsbWqyp0642OjOcMBioqKKCoqwuVymUZHR61mi+VafPqf17NrzMBdQLHo8TnyOdC04RVzmqbR0dExG4lEvrg8PDqtTf41mQNQFTkJNAO/ZK7+Mu1yMr/zFXTm/XeIxWI9oVCoMW0Y54E/ljpAVeQ3gHrgsgnSQ7/dyBmypRgw0sTjcZbqSNPT2Gy2F+6reeCsqsgvqoo8nZ03GYaR0yB1FX74tuR6wl0+xZGaEeLXbWh/O1CG76ehqY2Kigo0TaOn512am5/E5XIRjUYJBoOzuq4fkCRpIC8AIPM97lYV+QfR4/sccOy8bVvJ4/WPiTU1Nab29vZELBZ7TxCElkAgUJAFmdF1/WA2ZEXASvL7/S2VlZVdJpPJGolEekOhUIPf798rCMKFfBDzWoOzpIbDYcfQ0NDVRCLRAiBJ0oCu6weDweBMNBrF5XIRCAQKBEG44Pf7967XgV0QhHO6rrdJkhReklvVyU0DbuIAOZD+/n76+vp+v2WAbEhdXV1Bb2/vrXWQDbHb7R8kEomnJEka+A80He5eVGttWgAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/control.css: -------------------------------------------------------------------------------- 1 | .olturf-control { 2 | background-color: #fff; 3 | background-color: rgba(255 255 255 / 40%); 4 | float: left; 5 | padding: 1px; 6 | } 7 | -------------------------------------------------------------------------------- /src/css/convex.css: -------------------------------------------------------------------------------- 1 | .olturf-convex { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAWdEVYdFRpdGxlAHNlbGVjdCByZWN0YW5nbGUlXhwlAAAAGHRFWHRBdXRob3IAUm9iZXJ0IFN6Y3plcGFuZWtfVrEIAAAAGHRFWHRDcmVhdGlvbiBUaW1lADIwMTEtMDQtMjDcNDpxAAAAUnRFWHRDb3B5cmlnaHQAQ0MgQXR0cmlidXRpb24tU2hhcmVBbGlrZSBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8zLjAvXoNavAAAAx1JREFUSIm1lU9oHGUYxn/f7OzMsqYklF4sC2lZEFmsoAUNpbCH6qGBUFbTbFCoHhIwZQ4RsTdBWNRbKSXF0iJiQEg2Jh+amFxK8FCwWluQYPe0NqW7A57WhSTuzGTm87B/Ot1s4kbjA3P43md4n/d9n/ebEUop/k/oACOjw58Bk0AMWKxtuaOxuGEDvf/mPDc7fy6bfeOlmZn5+3pD6EMCrS+fz2+ExPvaiun6fMG48EzN3foZ0LVG7G5b8v+E6enpTSCAxojmZudPMVMnf/rauO5ve+MKtF0zNCAgiOjRm6++7b7XzkWE/1xL4PzIm2XgKIC/7Y2ffG1Q06PRf6x02/O0e7eWx4EdAr6KXAIuao1Snm0SCrpKDqBHo+zR6QQ8Ie90lXF/8FoCc7Pzpw46+64edMKlT00cV6M/oTiecOhPKI4l4HD7oobQ9KB+D0IedILjapx5fQSAcukR9wsPeVz6A1TAkUNnubqcvea67i/Ar8ADKWWNugcXmxdtTw/6E/XPycDAADDQilerVcrlMqVSaWJ9fX1zbW0truv6D8AZ9uPB8YRDufRoR7y3t5dUKkU6nRZCCF3X9ZLjOJPwxAMNWh7s2YFtP+zI2bZNLpfbKhQK3zmOk5JSrkHLA7ry4FiC+sw74MsvPqdSqdxYWFh4v42aoHXRQh4ICLY976k3D/cBKqBare4QGH3rXQzDGMtkMqfbqM4eRPTozXu3loM7K98Sfo4c2qBcrk/Stm0+yX1EsVgkmUxiWVaPaZorYZGmB0IpxUh2+LHn+ieklH/uNqZsNnttcHBwIp1Oi1wut1WpVG4YhjFmWVZPMpmkWCwyNTW14TjO2Xg8/pvnec/n8/kfhVKK89nhy0JgEWivKOGfE0J8DAQE2snmOfCVOvHCi38BRqHwQA/wA99TY9Fo9LplWUZIxPUDTxeauJKf+eYD0e0vM5PJvByJRO42VjElpdxsxE+bprnSqRMp5e39CMRM0/zecZzJ5iqGuF1FuhboooCnRFZXV1laWvr9wATCIkNDQz2Li4sH20FYJBaLfVWr1d6RUt7+GyKBjgDfZ+b/AAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/destination.css: -------------------------------------------------------------------------------- 1 | .olturf-destination { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAXdEVYdFRpdGxlAHNob3J0ZXN0IGRpc3RhbmNlgQo2JgAAABh0RVh0QXV0aG9yAFJvYmVydCBTemN6ZXBhbmVrX1axCAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDExLTAzLTA4fQ7oeAAAAFJ0RVh0Q29weXJpZ2h0AENDIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMy4wL16DWrwAAASBSURBVEiJrZVbaBxVGMf/35nZmd3sJmk2JmkuTWLaQGuvxta2BvahRRGL1RfBglpvKCo+aMGK0CgrVh+qLwYUCn3rg1YfRBEs0eqS9EZTUhq0ppf0sr1k40622Wxm53LO58NsIpGkZaEHzszHnPn+v/Od/5kzxMwop6V64kI3IocjlXVrjWhNKBSuDOtGzNTMGPRwDJoRg25GoRlREBH0MsVJNyKHaltWbaxpWRkjzQRpRqmbIC0EEgZI6AARAC4PoOnGq1V17VtrmpbHCAJEBCIBIq1010GaDhIhQGiAUhDlAIQW2lXX9mA1AIBmLhQMEpVmLQChgTQTEKK8CgCAhBYEs9aVAuZSrAClwHAAJcsDEIlJzykgZEYDMVaBMCswK0BJgPzgZUVgJaGneuIh3Yg+K/TQ88p3+33XvgJwXyJpXf8/wC3mX7w23Pdb25rHGzRDAKwg3QL0sAZiCSg/qIcVAILyHdDJL1YfDFc2bIu3dlVLz4Y7leHxi8cu+07hdWbVl0hac/Zx/0f13VrIPEBCq2AlHQA5EQq3LFn7ZEO4qgEoGQ4iSNcGHf2krXfJhh1vVdYtBUsH7DvwbAuZkf6JycyFrO9OdyeSVuZOS5fqiW+Jt679vnH5lkWzAAC+W4AAie2x+zrALMGltdRCESxenqhpXrm1Qzciv6d64t13sWeokL1aZN8BpBNMVDpQXhGisr4zEjjvB51l0JVCRVW9aF392IpFizt/OLa3NT2QbHxpPvVE0rJ81z5w+9Y5n6UL9mcANoSdS8vggQuWHlh5YCXB7IOVhBGpwuJlm2o7urY3kxD7Uj3xyHwQ6RWHpTs9O3v2XSjfhvCKk4esyyeLwUAAgfQAWapmZgfZkyASZxJJy54PoOlGi6abOiuJU39n8WbvabD0IHyn8N7YyB/pqcwlydIFZqvw5ghM3ByZ8JzCngVdINKV8r2BPy189t15vPFEO5gVRCJp2b5T2JA++/NN5RVLVbhzcllJFHI3comkNbCQvvScr34auFj48sdRfLpzBVa1VwYfWsmk3LG9bX959kRLyKyYk5j/54qdGR3MMKv3FxLv6upuk3rn7ipThve93I77m6IAgOKUVfzvqGDVrBvhOYmeU8DYpVNp351elUhaLgCsWb9xNxE2M+Nb1nBOk/Q2a7wNjP2vrLv5gjnF+1ltrrbz4yqbHh4jZkaqJy6MSNW1joeeajp45Dp+OT2OxriBqBy3L2Wp90bOSLHGNkMsBfgBYjwCYDWCo3SPY4a+PtffnweAox83fQgSOwCc8N3pd2cAXdUNyw43dm6u9SUjfSuLocHjtweuVHwzdKviNsAdAEUIPMokLoNhAvwOFJ45M3jiyILGA4EHWsh8NFbTXAsA+cz5af/G2YmV9f7O13ov/jpf0rr1D+8CxNNDg8f77yQ+CyASbULT2SlMIHv1zIjvFTclkpazUNLQqZOf3014pokS4NGKRY2UG7uQ973iB3cSL7fN/DLHvWIek+OjNoDD90p8FuA5heeuDfedVdKPAWi+l4B/AfJCR40J0MXMAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/difference.css: -------------------------------------------------------------------------------- 1 | .olturf-difference { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAbklEQVRIie3VsQnAIBCFYWcXZ3hyReDAFXSHTBIsrW0ubUJEUJIm3sFff5VPY357RD4DkNmIfO4CAKQUng6AKLAS4ELKlqNcexWwHGU/6i0FFgA25umhe4xdCxjJcuw/KgUWAFpjN5ILqf//fnkneT8msJ9jSPUAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/distance.css: -------------------------------------------------------------------------------- 1 | .olturf-distance { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAwOC0xMi0xMlguO78AAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAAAk0lEQVRIie2WTQqDMBSEJ5p7+XuAgLV6nFJ6mCK9iwsXXqbPceWqkYRaqUJm9REm+XjJJook9ky06+lBEARBEAQHEWgAuLYXWRbkPalYR9zKANA9XzFIom4qGcZehrEXYwx/wXVTCck/vEFWJLSxT8fW/xDkZUob+3Rsfe8rWpvGFW/B2jSu6AXut8c3+51Rp/9VzIHnftsVKYakAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/envelope.css: -------------------------------------------------------------------------------- 1 | .olturf-envelope { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA60lEQVRIie2TPQ6CQBCFvYWX8Ah7DRJn7rBY0FppIhjmCvQmxlCTcIGNIrZoTyct5bMSDVIYfhKjTvIVO8X7tpg3Gn3FqKmeK9alYhv9oEs11fOHgHU5odm4rw9PaDZWrMsngY2+whsz/4KfEAx9pkMX7TfH8ixFQoaF0QQJGcuzVGsBCRkncLDYLLHaujieUxyyBKuti8VmCSdwQEKmtYCF4e3W8EOBHwquRYFrUVRvb7cGC7c/fxauwpoEfijdBUl2rILrpJdTd0G8j5HneSORiboLnrkH1/efK6h3IDIR4n380oXWgneLdgPkrIVRqRRKGQAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/explode.css: -------------------------------------------------------------------------------- 1 | .olturf-explode { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABhklEQVRIieWVvYrCQBSFQ/AB9l1sxYSEFFa2kmJJCAg2IiExhYU2goNbKYykWsEieQaDbbDYaiuJRTqxUAwIKRRytzHgTxITXYtlD5xu5nwzd+bOEMR/EJz8sjkXgwt8Pc9KqsmJmlvkG0dO1FxWUs0CX88/tSia7uQoUUaMoPjIsALTdmC23IFpO4AMK2AExadEGdF0J5cpOBQlyqjS7PvTxQbmq8ONp4sNVJp9nxJllDm8wNfzjKDEhp9DGEHxr8pFEARBvJ0cKVZSTWRYQVJ4aGRYASup5nVG4qFwouaatnM3fL46gGk7wImaexFAkuSeJMl9HKDIN46z5S4VYLbcQZFvHCODdH20xhjDtcu1Fjy1g1AYY/C88Y3bwy4gw0oFiDuDRMDXN4ZSVYNnblEiwPPGMJj04L31EQtJ1QdJgO32EwaTHpSqGiDDgoc6OQpAnK7webnawy6Uay3I/BalAYTGGCc9ZukBcb4DSF+iXwXENVqUdX20zpL9yK+Vad7LAX9XP2247FgA1I+DAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/flip.css: -------------------------------------------------------------------------------- 1 | .olturf-flip { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAD1klEQVRIib3V708TdxwH8Lo92COeb/sHTPZgD5bswRKe7MkSl9hSoLX3ve/VgnSUSrC1rBSz4FW6tFzvSn94Nw4LLhASCrpMqibtanEazJZMY4Y4cUtgjs01PjGWFcWO9x61OaBlLDH7Jp8Hl3zv/bq77+e+X53u/xhJNZaRZblxz0nQHaDD9K1D8UNv/GdAURSMqoniLgS6AxbJYuOi3B0ikRIbYUuMyLwkEVK0RqyXTWHTB/sG1pZs2xCTaHqHldgl15irOPD1AELZEMS8CDEvIpgJone6d8sata6zEXaW5/nX/hUoFwxVJBgPfkQl+ngkP7I1/8t1xL+NV8O1kJATYFft61yUm9oXUEHcsZ6X6jV1M/Mgi8SNBIScgP7ZfrTL7c+ISF6wErvZlmh7euqrU1tCTgCV6Iae17+9L6D0exM6ZTvyD+cxfH0YYl6Ec9RZolG6QATysWnG9Lreq28wD5k/JBFSdE+6YYvbNpkwQ/cFLC81I5D6DJcW5yDmRfjTftAI/aNW9xwRj7xPhghPhghv4k1v1gzXe/UNvpgPs9lWzGZbIc2YMXwljNm7FyDmRfSl+kBFuloJIkOE13v1DZX7uRB3mAtxh+s+PR2kB7kIh96JXsg5BXJOQfRaFNK8VO0Yz5QHnikPHKMOEJG8oIP0oE6n0zFhhjpkR8katf615ycKnQ3BnezC+YUvMX0nBfmmXO2USvFzPGiElkwhU2Ml3DXuLmV/+gbhbBh7Ioqi4P6iER0JCn6Orxl+LM4hLH9ekmW5URuu3hqFmBcRuBqoj1QWuRbCz/HoSFDcXzRibcmGQWVg40TS9VwbXqm6iLaLtIg2vFww4MZ3LehWO1ErfE9EC2gRbfjKAyOoxKJrpAP9Ux50j3dvBa4GqsH+tB/OpLPoTDqLdtn+nA2zfzNh5t2aQLlgwOqyEavLxur1xmMD5m+1VMt7jsI346sCx8eOrxOBfGGRLLZKVf+dncDaz0bELjCIXWTww+2WXfiz35rgkCm0b2CNWYtUoO/V7SJtwML3zbDLNvhmfDgWp8gvtODXh0Y8WTEiPd+KnhEWnomebbsriZBy3bNiJ/D0URNsURahbAj+tB+u8U44lKM4OkzhOt+F05dOb1vY7nOd8CZObtY9tGqtQSpjRtdI27bteWcJOQEnJ0/AO0bw6J6t9qFVDygXDJjOmNEeo/BM9sCf9iOYCULICThz+Qz6Un3oSHAIpxg8WWnadp7sQuoB5YIBhZUmTFwx49Mki0/OUtAIgVuliF+04N6Pzbvm10RUNf6noih4lZVUY5ma6/Gqxz8JrRbcNYv5ygAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/form.css: -------------------------------------------------------------------------------- 1 | .olturf-form { 2 | background-color: #fff; 3 | background-color: rgba(255 255 255 / 40%); 4 | border-radius: 4px; 5 | display: inline-block; 6 | left: 2.5em; 7 | padding: 2px; 8 | top: 2.5em; 9 | } 10 | 11 | .olturf-form-table { 12 | background-color: #00a088; 13 | background-color: rgba(0 60 136 / 50%); 14 | border-radius: 2px; 15 | } 16 | 17 | .olturf-form-header { 18 | color: #d3d3d3; 19 | padding: 2px; 20 | text-align: right; 21 | white-space: nowrap; 22 | } 23 | 24 | .olturf-form-data { 25 | padding: 2px; 26 | text-align: left; 27 | } 28 | 29 | .olturf-form-input, 30 | .olturf-form-select { 31 | background-color: #fff; 32 | border: 1px solid #bbb; 33 | border-radius: 3px; 34 | box-sizing: border-box; 35 | color: #000; 36 | line-height: normal; 37 | padding: 4px; 38 | text-align: center; 39 | width: 100px; 40 | } 41 | 42 | .olturf-form-select { 43 | text-align-last: center; 44 | } 45 | -------------------------------------------------------------------------------- /src/css/hex-grid.css: -------------------------------------------------------------------------------- 1 | .olturf-hex-grid { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdFRpdGxlAEdJUyBpY29uIHRoZW1lIDAuMXda8RoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAwOC0xMi0xMlguO78AAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAACu0lEQVRIidWVz0obURSHf3PvTMZRxzEhJoIBGzCKmVBctIsUKi76AK5Kn8CFcV/oSzQLoZpVF30AV6VQhJJFAhWzUhAlaSQuEpyMHfzLzL13urIkJE5Ci4We5ZzD950z91yu5Ps+HjPIo9L/hUAOSm5ubiYppVlCyIosyyue5z1RFKUuhCgyxr5RSstra2vVIIZ0fwaFQmHU87xnlNIXiqK8Yow9J4SEIpGINzU1NR4OhyVd13F5eYmLiwvfsqxr27apEILLslzxPO+r7/slIcT39fX1q54JJElqhkIhnXOOiYkJpNNpRCIRABjp7EhVVUSjUSmVSo3f3t6iXq+j0Wi8ZIwtE0JAKXUATPYIGGN6NpuFZVl+q9USpVKJMsYC/y+lFJqm8Wg0inA4TA3DQLFYNDprus4gHo8jHo9LpmnSSqUCTdOwuLjYF76/vw9N05BOp2lQEw9uUSqVQr1eB+e8J+c4Ds7PzzE/Px/EDhboug7DMHB2dtaTOzg4wMLCAmQ5cAmDBQAwNzeHarV7C1utFu7u7jA7OzsQPlAQi8V+QwHA930cHh7CNE0QMtwdHVjVOcXp6SlUVcX09PRQ8KEEiUQCjuPAtm0cHR0hk8kMDe8SEEKujo+PmRCiu4AQJJNJlMtlxGIxGIbRAxlK4Hne05OTk/Lu7u61bdtdRclkEkKIB+8EALTbbezt7d0QQpzO77/3bGNj4weA5a2trTelUulDIpEYMU1zRFEUqKoKzjk0TeuCuq6LRqMhqtXqjeu6Pznnec75x84aqd+Dk8/nJ8fGxt5LkvR6aWlpdGZmBjs7O1hdXQUAWJaFWq1202w2KSHks+u6+VwuV+w3WV/BfWxvb2cppZ8Mw4hbljWWyWRErVbr6jaXy7UfBAwSAEChUFB8339LCHkH4EtQt38k+Nv4/9/kRxf8Aov8Kt80gIHgAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/inside.css: -------------------------------------------------------------------------------- 1 | .olturf-inside { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAOnSURBVEiJtZVPaNtWHMd/sp70rMS1uyxM++tLlAaUeJeGHZaMNeQ08BgVxsmpYrBBB6OXpjn0MsNOzWHbYYOWlRXvsiQkZoQwekjSyyCXZGNx4jqp+yeaIRVtXf+RozzpydphFbhuqrlb9gNdfnrfz/f9nh5fMa7rwv9ZqN2FyWSSp5TGMcaDDMMMEEJEjLHuuu4mIWQNIbQ4OztrteqYdiZIJBL9CKEpSZLC75861d3X13eso6MDisViJbe1ZeZyObNQKFQppZNzc3NbL2QwPj5+hmXZT1VVFd4dGhIRxx1rfl8tl3cdx7Gz2Syk02nTcZzvp6enf2zLIJFI9GOML6dSKeEVUezGweBxAIBGo+FYlmVYBwdVx3GIt94wDEilUiYh5Kw3SeB58GQyySOEplRVFbq6uoIe3LYso1apaGa9/qAZDgAQCoVAVVUBITSVTCZ5XwNKaVySpHAsFgMcDL4EAOBQahq12v3fbxaEH35eeuOP7TuhVl0sFgNJksKU0rivAcZ4UJZlgWVZhDiuEwDA3N9/fOlapudKZqnXRCHxSmap99K1TE+rVpZlAWM86GvAMMxANBoFlmWx17tXvA/bd4vh8xMXAh/G48z5iQuB7bvFcFF/iJu10WgUGIYZ8DUghIiiKAKLEOf19h6WUDgScTnu7xbHcRCORNy9B6WnDERRBEKI+E9HpOu6DpRSGwCg4bqNk/29VWLWGzdWVqBUKsGNlRUgZr0xOHCi2qzVdR0wxrqvgeu6m5qmAbVtk9p2ndp2jQGACfX0LX23UP7m668a+m6hPKGevsW0aDVNA9d1NwF8ooIQspbL5d4bGRkRatXqntfvees1c/Jj5fbzdAAAuVzOJISs+U6AEFrc2dlxl5eXBT9Ya2WzWSgUClWE0KKvgeM4n5imOTQzM9O3vr7+zH0/rAzDgHQ6bVJKJ73gO/SIFEU5Y9v2t6urq97xSmNjY9ujo6Om3869LGoOvGcMFEUZPh4WLlcqVvO3YxYWFh7l83lGlmUhGo2CKIqg6zpomgZtp6miKMNvvv7y9Ytn3+6s7C7AxasYLMq4PM9/zrLs1X/zP0CHwUX3F3hsG8BxnfsuE/hsfn7ei9/Mk6ftQofB87fL8OVPomHRwAeZTObXFwG2FruxsTHcFRGuf3Hu5FPwA/u/wwEAUJB30h+9U+x8lc7CzXv0SOEAAGzvCfm3/J/BJI8I/91i95HCAZ7cIkVRhoO8kz6wWPUo4QAAfwH7avNlAy/YaQAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/intersect.css: -------------------------------------------------------------------------------- 1 | .olturf-intersect { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAg0lEQVRIie3WOwrAIBAEUM8u1pYjdoKdtd4hJwmW1mk2bX7EVRJIQGFaX+HuoBDMo3zK0kVqifIpc+8X0kWa5qUp0kUawEcBa00GQNs8CgCgUtwuA6gCOrRt8e0mXwGcAOCN5aNAT4npEPlA7+MNoAocqwQAWWvOY/mvlhxAF/D2d2QFJ6oxfy6NLhIAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/isolines.css: -------------------------------------------------------------------------------- 1 | .olturf-isolines { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAJdEVYdFRpdGxlAGRlbVKoAMYAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAxMi0wNC0yNZ221GMAAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAAE1UlEQVRIiZWVS2wbVRSGvxmPx297YieO0yTugzRFVSRoC6jQQhFCZYOEkBAgIVGxQSzYoe5YsEPsEKoQsGGJKKsCqoDykChFpUBb0QdJaZs6cWLHsWPHY3vec1lMSYgMfZzd/Pec/9M9Z+690vczXcFdhCt0dOdPTK/Khdp3tO0rOH6LdHgKTd2Npu5CU/cAEgDSnQK67iw182tWrNMIHABmW+doGgt9ubnIPu7PfkQ0VEC5nXHTPkPVOE7X/atvLRHOYDpLxEIKQkDTNgFoWKc4v/Iqe4eO/T/Ax6LU+ZiGdXKjqRJmLJ5iLJ6ioGbIh7febAZcXm3w/sx5WrZJwzpF173x3wDDK3NNfw/TW9/+cDTBo/lRisk0AMKXsBdtWldczFoIa1hHHlLJraaoyyZKBGQp3A9YsU9zQ/8QHxuAXCTKvqFRJtIDCFtCvxzFXlKwFn26lyRsN8F8u42600bb64Et02kJtKKCIqU2ArrudWb1DxA4hCSJJ0Y2M5XJIUkSZkll9WwCzwgaYpZu0LVt5tttPOGjTZjYvs+FVh3fBc05SFjOrANcoXNNfxeBQyyk8Mz4BJviSbyOTOvXBFYlHMzGNLErFZqNBuV2GyHDwL4O6qDLydoipusCUJBfAggAAsE1/Qi230CWJJ4tTlKIxbGXFVZ+SOO74Pd6OPU67uoqLdNkUdeRFJ/BJzvEihZX2k1OVEoAaOoeVLe4Dli1z6I7FwHYnx+lEIvjdWRWfkzhu+C2Wljz88GMDINKp4M67JA7oBPWPK60m3xamsYXgkgox/b04bW2K/8MFiASCrErOwxA+3wC35IQto29EPxN9V6PZbvDwCNdUlMGtvD5vHydM/VqYCbF2am9TSSUR43GAs3HoWWdBWB7aoCQJOHpMsZ8GITAnJtD+D7LvR7tgSaFxzooSY+K0eVoaZpl0wBAIsS9mbdIKBPBeUlpAaDjzOATnMCkogJgNxQQYFer+IbBitXDfbBKfjLI+2l5gW8XS7jCByCubGZb6vWbdxBEonGSmWwAEKxfRT5BgW/JeO02Tr1O0zTpbl1Gu2n+S73CVwuzAIRljc2JQxTiTwMhAGRZZnBkfH0GsdDI2kfV6AXbVQys8hKG61Lz2xT2BPp8T+f4YmA+Gn+OYuIQITmxVi9JEsNj21AjsXWAKg+SCu9Edy5T7umYdo3o0AKQp6LrZA7oyGFBx3X4ZHYaX8hMZg6Tjz7Fv0MC8pu2EI0nN+gywGDkcRpGmcvLJ/m99jNyxMUcbSJv65C4xwLgi/JV2o7F9vQbfeYAuZFx4qlMny4bjsA0dlFpz9FzWvzWWMLzBO4DVXIHdAAutupcajVIhneQjx7sM8nmN5HK5Pp0AHml6wEqo/EXAPijWWO16+ALARJ0PYcvy9cB2Jp8DdYu5yC03DCZbP4/zddaBFBMvAyA5Xl8U5oDwEfw2Y0ZOq6Npu4mo963oTiTzTMwNMKtYg2QDE+SjTwMwLHr1+i4DicqJa7qLQDG4s9vKEwPDJLNb7ql+QYAwI70m0hSGCfkcmT6HCeXygAklC1okYfW8lJajtzw2G3N+wDZyF6mtHeIZMCJ2Wt6MfkKAGE1wmBhnMHCOHcafS9aMXEIkFiIHkU4IdL+forxF1HUCPGbz+XdxN+cyycVMShqOgAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/kinks.css: -------------------------------------------------------------------------------- 1 | .olturf-kinks { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAACVklEQVRIie2UwWvTcBTHM8aQgQNR8DC97S8Qwd28CIOhWAsDL+vBgwiCSKEg3rxYdhCRHYZxgitYGHUlrU1+W375/dJupLCutWARRyzCMFuXOvUSxW3N8jxo0i5pM6f15hcehOT3vp+X917CMD7ChB/HFAGmCEQqxP3O/pEWJCFgAzBF6a4D5nHmQssb0K4DRFEYdgBEKBwmFyFuCBM04XlQiPdOKTGmUU4OqBvqjSc2IJt7saXM9GyXkwPqtw+j95WZnu3S3NFV0EdO2rksy/aJJDMmEkHCFFmYIvAAion+tZ2Ni2DWA/B1fdzuPywtJcCsBzzxOnN82a4WE0FvmRm0BexsXrlnJ3+vXXUOyjlun3FDD0KtGgYqRC27WldYIhEkDyD/vNewTXb1oJMgyTyY9QAYWgjUShRyi0m34c8ggo4JmkCIG2o7nJVEv9ZaqSTzTnKp8LS96a9qRZIZY1m2z3f6rS0ytBAQOdPJFHKLScimrlkdq22nfPyIUauGoVSY7mhcKkxDrRqGhh6Ez2/PP/otY2cT8KzZyfhN+SEYWmjfsCvpE0VfY/feukPOpZzrL2vXPWuaf8bs+QI69VatRMHQQlBcbrZq6/1ND+DAFrk3IZ8a+dTQg45BeWXKAWxWb3sAB7eIIq11b/c+Xr67W7vU/FJfTTqAdTXiASgxxvQFuPVOOD2sxBhTr5x7vDp/Kiu/vNVs3dyoZd9XYoylV85OVtHgmUMB3MKEf+D8USU+8ldm7SRKfMQGLFD+TtcBHMcdE6mQF6mgpHF6sOuA//rn+gHQQduJqSP5sgAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/line-distance.css: -------------------------------------------------------------------------------- 1 | .olturf-line-distance { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAcUlEQVRIiWNgGAUjC9hE5f2nqRl0sYAaeGAtoCh8qGTGKKABCA0P/gvDgUEB/6jBDg0P/otiweXr5/9evn7+b0BAwH9qsAfOgomT+/9hYyNrxqUGmY3TAlwY2QJiMMkWILuOJhaQijEsoAWmen4aEAAAa1lIy4I8OMcAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/line-slice-along.css: -------------------------------------------------------------------------------- 1 | .olturf-line-slice-along { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGGSURBVEiJY/z//z8DLQETTU0fFhawEKMoJCzk4d/ff+UIqWNiYXq5dvVaCZItsMiwmM/IyFhPSN2RSUfE0cVwWhAYGOgsayb7Z1LlpIMnZpxI/Pv7L0GHMLEwvUQXY8SWTN3d3bl5+Xkfawdo875/8H7dw5MPUzZu3PiZoA3YLMUmyMPHUyeoIMjOxMzE8uz8M/ffv38zkmM4VgsCAwMVGBgYchVtFLnu7Lvz5e+fv2Xbtm37RK4FGHHAzMY8VdpQmvXT808M399/f25gYDCHXMMZGNB84O/vb8fExOQgpS/Fcu/AvW+/f/5Oqa+v/0cVCxobG5lY2VnnKDsocz27+OzPv3//DmzcuPEQJYajWHDhwoUUTkFOSV5JXoYnZ5/8/vvrbzalhsMt8PLy4mNmYe5ScVLhuX/k/jcGBobJ69evf0A1Czg4OOT+M/xnf3X91b/3D97//PLpSxM1DIdbsG7duiuM/xm1X998vY7hH0P8zp07v1LLAqw5mZpg6NcHoxYMvAUAfCmMafgSSToAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/main.css: -------------------------------------------------------------------------------- 1 | /* csslint known-properties:false */ 2 | 3 | .olturf-toolbar { 4 | background-color: initial; 5 | left: 2.5em; 6 | padding: initial; 7 | top: 0.5em; 8 | } 9 | 10 | .olturf-toolbar:hover { 11 | background-color: initial; 12 | } 13 | -------------------------------------------------------------------------------- /src/css/midpoint.css: -------------------------------------------------------------------------------- 1 | .olturf-midpoint { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAB9ElEQVRIie2Tz0vbYBjHH6WH3fxHevTYQxAJpG9C0MZ6kF48eCrkj4iCh/4B7vbqQKEHdxAshXRgCJOAB6sGOkRB7EQhRIwBm5jw3aEYN7Y52uoOY1944IXnefnw/PgS/bNijOW1ea0+q82G2rxWZ4zlX6OWiIgEQciV5kq+vqqnyx+Xoa/qaWmu5AuCkBulNpOqqlplqRLUPtXwFJWlSqCqqjZK7d8DvPmIiN54yf/1kwRByEmSpEmSpP1xOYNKFMU8k5lfXiwH5cVywGTmi6L4ektSZpR6daWaPt1wdaWaKjNK/aU/9gYVLE6OzQm/C4uTY29QgYqsGBrbRmYSY9tAkRXDlwAWJ2d/cwKHO5No7xZw3JxGAuC4OY32bgGHO5PY35yAxckZrgNOOGpOwW0pcE0ZrikjAbK321Jw1JyCzQlD7cDmhKvOGsLgFBdtA7fXe0gA3F7v4aJtIAxOcdVZ6wOIBr8imxNcU8HlSQ1xGiF6vIfXbSB6vEecRrg8qcE1lWfAoOoD+uOIkx68bgOuKcPrNhAnvSw3EsDmY+hYC4iTB/QiH1+/vEcv8hEnD+hYC7D52GiAM0fHnXcAt6Xi5nwLCYCb8y24LRV33gHOHH00wOcP72Cvj2d3nwDPPlgf7+eHBfzKZD8AvjPbcB0M4ORvbQgnY/H2T5IAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/nearest.css: -------------------------------------------------------------------------------- 1 | .olturf-nearest { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAALdEVYdFRpdGxlAHRvdWNozKhkvwAAABh0RVh0QXV0aG9yAFJvYmVydCBTemN6ZXBhbmVrX1axCAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDEyLTA0LTI2BL+F2QAAAFJ0RVh0Q29weXJpZ2h0AENDIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMy4wL16DWrwAAAGgSURBVEiJ1ZQtTytREIafdwu7SypYddUVJISQYDZQheNHkBowrSwShSL8gEqQ1IAhSATyuqvKLQiShpBc0YQEwVfSUNqwg6DLV1vR7SJ45TmTec7MvGdkZnyH/hfkPjzjjKWd+G9e7oTHNCIbZDhLD5CXc+KSm/AIgSZGbapi7VQA/1aVw2NZwjfjRnD1+MQlQGLAn4L8oEPRxBpiErjFOEUQRRwvHlgbwEkKCDoUzaGIKCFWgCwQYrQW2lTjuMQVmFgDSrO/2QCoNyhg7GMccmBRHJe4ggG6n9+z6seDxBXI2DZRrjdY7x6VZWx/jUsMuBtnN+iAiZ0YeDfObu9Dvuknx0p7Bj0a2KJPPue9BUsVa6UCePM5lABMlIMOwGvPRwb08fl6d6BDAfrO4GRFOTMmh0k0SL0VbMnJZFg24zYyKvUGhe5NX58PDahdkMPBB04dCKOIfYn7QT4fCnCel4tHaMaNBIIjIg6/fv/EgJbPtIym4IqI43CGKpvvi2skwHlernyyJmpei8u57j4fVW+A6yzOryZnaSWO9fN30QtrfZ6HZ1VNSwAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/planepoint.css: -------------------------------------------------------------------------------- 1 | .olturf-planepoint { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdFRpdGxlAEdJUyBpY29uIHRoZW1lIDAuMXda8RoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAwOC0xMi0xMlguO78AAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAADGElEQVRIia2VX0hTURjAv3PP2JyuQpdoEimZUUKm9RAYYmgKzb0kJcHqxYGQTq3RnWWQ/1J0kxkZlKH2ICrtgn/CiS9ZK/ChMrS3QI0mhH+w5sg/996dnR50Muf8t/U9ft+5v9/hO/d8B1FKIdBQqVSRUqlUjxDKAACsUquVgwMDCwBAKKXDgiCYmYDpALAOzwQADACQnp6uXC9hhFCmVCrVByVY3/l2DAYhlBGUANZ3vlNdEqRgI04lJobKZDLcYDKd9ORsNtvCfxGcSEiQFxQUHKutqZmYn58XvWvBtojExcWFFBYVxRrr66d84QBAghJQSofPJCWFmRsbf8zMzAg+ZTeldDioFgmCYH7T3+/5m7wPfOMeoJyiynwgpBwwrht4VtEejNBfMEBIOWtg4ylx1e/1I7WuKl99u2JSravK35x7NOGdWxNgXGcyGv+srvKR2dqywTRNYfhOcIQQAkIaWMO9425RbEvTlNI0TSl1i2Iba2DjgZDyTesppZCap5fLQ7E9Kjo6fHZ21iG4xGsfO5re+8Iv3iiJDwuTvyZuej5EJltEEone01a1rspvq5Fn2KVp7lyPPKxsv5qbq+js7Fx2ieILh9R5/0tLi4gQQpdu6UsZzDxOSUmRfx0dXaGM++i7V02O3dqJvKdplrbss0qVcy45+SzT3d29bLdPL0owpoQQMVwZobyp0Sg4jluampqqtHU0Ne4GB/C5aPwKr7VaB3gAAK1WG3rwgOIIa2BjFApFbElxscLhcMC03b4UtkCa9wLfIvjQ9eQbUNRltVp5AIDMrCxobW2Fy9lZAADQ29PzlxfFu4ODT/m9CpDvg5Oap48IkTM/i0uKFTExMRv58fFxsHDc97ftxtN0H6/UllExYjH/drldDziOW/LkCCHQ19e3JK4sF+4H7lcAABDN/3o+Nzc/OzY2tiYdGXG7RHHU1tU8vB/4tgKLxUJ4UdD29PasOJ1OGBoa4nl+WbdfOICfM/COKwUPxzHGSS5CPg29rL0QiGDHcY0l+BBrYEGCcVQg8F0FwOBqk9E0CRhXByr4B2XGW/k9xrM6AAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/point-grid.css: -------------------------------------------------------------------------------- 1 | .olturf-point-grid { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAK4SURBVEiJ7VU9TBNhGH6+u16vLXJwtbW2xLahISQmxlhMINDExIWFSRNQCSHqgAwyMMHOzmDCX0KURhYaBjfDgDElUYIEz6UhUCGRtI2FAlau1x53nwNQpYBAACef7cn3/nzv++Z9HxKLxSh24XQ6STweP1fO4IJx4QkIpfR4qzPAUNiz/v7+PG9vbz/Azz4DSkGSSXDz8xgVhAYuEgEXiYBZWcFLQuynreB3AkoxyvM3uNlZFCWTuOJ0oqajw3XV44HD7YZIKYrt9oZ4KIRUOIytxUW8IETIu2saXhFSqivKvgT5Gbw2Gm8KLldVTWenQfT5jvyRvLqKuCQhNjOjfpcksq0olAIMdJ3hios1TVHAEBJ5KMsfAID09fVRoijgJAn3AoG2zzw/uBcsYLW2TaVSf+XvE4lBwrJgWDbPv01PI1tejmddXTszMCwswOrz4ZLTedoWgzUawbDsPi56PGDjcQA7pYGm0yj1ek8d/CgUORwgm5sAADIIWASL5cH9sTHDeSVQZRnjzc1aSy43bNB7e7e2JAlTqdSJen4iTimUxkYAGGYoz4NyHOS1tfMqAGomA8LzAAADAGgOBzaWl4GKikMdcuk00okE3gwMqBv19eAEAeaSEsiVlQBzcFfXl5ZARRHA7h6ECDGqZnNDidtdGujuNlhsNqxHo1gOh/WlyUlNk+VtnZAozWQWNeAHA1xmOe4aazJdv9vTk98bNZvFl2BQj05MyKlMZvw5pVmS1wNK8c7rvS03NX0CAPA8+GCw5s7c3EfOagVw8Na8dbl8Wmtr1GKzQdc0kKGhp7dGRoYFvx+s2VxwiwjBo1xuVq2thVpdDbWqCi253PRe8MPwmNKvqt+PtMmEn6KIrCyHxLo6sGZz3uZwPfhjcY4Fx0EvKwO12/GE0nTh87/Xg/+aXIgLn8Ev5ZpuTngdnFsAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/point-on-line.css: -------------------------------------------------------------------------------- 1 | .olturf-point-on-line { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAJ+SURBVEiJ3ZVfSFNRHMe/95x7t927uZUlmlMUdMGCIEUKjf5JZK6n89RD9h5EJQWRvvVeIL4kioGv1SYLkoJgPkgaQUWSljBFhXRO5zC9Tu+f00uNmpsbt3zpC+fld+/v++H7O5xzBM459lJkT93/C4C420fGWDWhZNw0TFchZkQkseDTYFnBAGqjfRX1FY7K45WF+GOke6Q0s5YTwBhrtTvtjSWHS8TRntFtY9uw5QMQkcQKAgQCAbviUvprz9c6Z0dnN03DfDQ4OHgnHyArNFtRdsod7nK3W5IlrEyv6Ck1dd+KeVYAY6wawN2aczXOaCS6YRpm59DQ0JpVwI4RURvt89Z5JXVFhZpQV5PJZI9VcyAjAWOslUikyVvvFaPD0Q1tS7seiUT0fwIIBAJ2KtF+X7NPiX2JcX1LnwiHw8//xhz4bUSyU+4oKivyeLweTD2eSnGdX8vVdLLt5gUCoQsc/pzOAiZN8PY0QBCEq5IiiTMjMxqAF8Fg8H2uXgKhq6R4n7/sYDFEUYRICSilcCsOxJPfoes6FpcT/ngi2ZUekambjYnpRG/8a3xB29Ju75qbw19VXgqXIsNhkyBSCgFA26Wz8FUegkuRUVVeCnD40wlCodASgBs/V15J4s4z6rBJYM0n8PrtJ0xMzwPIcxfl0n63C3PfYrh88TQSyTWcaTgKp2wHAFBC0NJ4DAc8Lox9nNi767rhSC1amuqsJQCAdXUT8wtL4JxjW9PSCX4pHBnDqzcfIFh5k09duZW16cmDe9ANA73PXmL43TgAi3uQS+tqCg8HQvgcnUvXrAEETGY7ZJ3dA1hcXv3jP0ubbIK3Q8BkZj3T3ARv/wHTUNux2OINBwAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/point-on-surface.css: -------------------------------------------------------------------------------- 1 | .olturf-point-on-surface { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAACEklEQVRIic2Tv0sbYRjH3yJiwcG1i0snt25O4r/QKeDd1rlCQW+WKKgxuYPL+77f580ruDnIKRkLgeAoHDbaoYNmcpAMJcGhUCi1PB1M0pBcchdd+sIz3Mvd5/Pc80OIF54gCBYBnBMRJ8WL4MaYNQAP4+BExEJKOTct2Fq7oLU+ngTuC4joHsB6VlEYhqsA7tLAAH4Q0QcxcDlRZK2dVUrtA/iTBtdaXxDRWyGEEAkvjIistUvGmEaGrH8T0VYURTP9zACsE9H9OJFS6tMjc2qtiagppVxOrKuUcm6CiNMExphDz/PmUxvYEwFoZxEA+F4ul99nGQ4hhBCe580bYw570HHRFXwG8CYzXEq5TETNtBIB+Km1/pgZHEXRDBFtdScgsRQ9gTGmYa1dygwXQojuzE5s4iMzK6X2rbWzU8GFSNyD4UbehWG4OjU4i0BrfWytXUj6LlfIrTi+E7u+y0nh+E6cK+RWEgUAHowxa5MSc3wn3jja5O2THd493eOr5jV/uWnw7ukeb5/s8MbRJju+E48IAJwHQbCY9ueu73Lh7ICL1RIXqyVudzrc7nT6z4WzA3Z9lwcFv5RSHjO/ylJa13f7sCRBsVr6JwDwrVKpvMsCHhQ0bq/64OG4bn59Emity/l8/vU08J6gflnnVquVGLW49iR47hmemh54+P7/FQzvQC2ucf2yPrILzxZkXbS/+/RgWajdg8QAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/popup.css: -------------------------------------------------------------------------------- 1 | .olturf-popup { 2 | background-color: #fff; 3 | background-color: rgba(255 255 255 / 100%); 4 | border-radius: 4px; 5 | display: inline-block; 6 | left: 2.5em; 7 | padding: 2px; 8 | position: absolute; 9 | text-align: center; 10 | top: 2.5em; 11 | z-index: 9999; 12 | } 13 | 14 | .olturf-popup-message { 15 | background-color: #00a088; 16 | background-color: rgba(0 60 136 / 50%); 17 | border-radius: 2px; 18 | padding: 10px; 19 | } 20 | 21 | .olturf-popup-button-container { 22 | display: inline-block; 23 | padding: 10px; 24 | } 25 | -------------------------------------------------------------------------------- /src/css/random.css: -------------------------------------------------------------------------------- 1 | .olturf-random { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAQdEVYdFRpdGxlAHN0YXRpc3RpY3OXvVBuAAAAGHRFWHRBdXRob3IAUm9iZXJ0IFN6Y3plcGFuZWtfVrEIAAAAGHRFWHRDcmVhdGlvbiBUaW1lADIwMTEtMTAtMjKAOOW6AAAAUnRFWHRDb3B5cmlnaHQAQ0MgQXR0cmlidXRpb24tU2hhcmVBbGlrZSBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8zLjAvXoNavAAAAclJREFUSIntlT9oFEEUxn9vNhwRTSGIpSApUoggiIhWXmEtMdnJ3RmVI1j5h9jYn4WNxMrCRg4Rzd3scluKiqAIYmEhKrHSQmxFD1OcpzfPwj8E3fH2iiCIDxZmd77vfe9j570RVWU9w6xr9n9CYCzvY1yND4jqlcJZvImdc8/ztnIdpK30ASorwBSwzaBHN26Y2LX2wZu9KnISMESDqZEcqKpaa48h+hjY4ZF2t9vd0+l03q2B9YB7cTVewOu+kEDwHzjnVg2DQ8B7YPtYySTlcvm3gpLl5KEY3obyyLA+sLXDB/HmFhABl10rPf1Hwi8x9BS5m527wLnvr6dsdWZhFIGhDn5EXJ29Lso80FeRcrKcPCrCK9wHm8YnTgBPgJJRf6Qor7BAs9nsIXoBuK8+OluUl3tM86JSmZ6E6MznT4PpLEv7RXmFHNRqtS1ezFW8OZ5l2YeiyQsJ1Ov18S++f4NBtOicexPCWWtLIws0Gg2z2vt4TZRLzrmnIdzc3Ow8sHtkgZWXL5YEvdNup7dDGGvtThXOA7nDLtgHcWVmUZCLwKtgBcpmhK3Aa9dKJ/MgoXG9X5AlvjkMTkrk5+pZEPL/Tv7rAl8B/v6YOTBe3esAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/sample.css: -------------------------------------------------------------------------------- 1 | .olturf-sample { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAadEVYdFRpdGxlAHNwYXRpYWwgcXVlcnkgdmVjdG9yZBbLugAAABh0RVh0QXV0aG9yAFJvYmVydCBTemN6ZXBhbmVrX1axCAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDExLTAyLTE5q66OygAAAFJ0RVh0Q29weXJpZ2h0AENDIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMy4wL16DWrwAAAQ2SURBVEiJrVZdTFtlGH6+r6e0FBgKzcjM1DhGZNmikUQu/AsSOn5uDA3DzZBIGly2LC5RFjI6l124lYXpbtwcM0IWkVJLV2aMcWUGgheKOBgZWQwimLkM4kab0Za2h55+rxdA7SmHhQu/5L047/N+z/M973nzncOICJtZ9fvrnmeM7TWZTJUMbJsgkSeEyFqFiTEmAAjO+d+RSMRFRNfcLs9dZjnmtRGRnTHmGDhX26VBXGg0Gr/PyMh4as/uPbri4mJT7pZcZGVnIdOYucJOlIz7c/cxPj4euTVxC4qi7JSIyH7iSFXhmYvXTwBYJ2DKNDktFktRTXUN34zTgoIClLxUYuru6Y6OjIwc5Ywxx8ef/RBREuJbzR0MW3cV79Ikj3i9mLfsRcTrXZcri8iZkiS9ywfO1XYthqMnwxGZaZEoceWy2+Ne0npXjy58jkJHGxZajmM2z4zZPDMWWo6j0NEG7nJBCJHFAYBD5wOhUktgOb7cPjc3Nz3807BIxwwvvoA/mppgbj+LHYEF7AgswNx+FjP2Vpjea4IQIoMDwOgXB+4AyCm1uZ5OJ3G7PCIWizV4+72xYDCowmK3J5F//hOYrNZkzmS1YtuNAeTU1UEIIaX2dkDoFU0XbpfnjhDiQk9vz9JaLj41BWV+HsayMq0t4JyDiHhSgIF8jJimAADE4/FTk5OTelmWAQBBZy9y3q4H0+k068PhMPR6fTgpIAnDjyC8WV/fp7nD7fLEDAbDA3/AD0okEHb3IeedA0k8faKCwSD0kt6fFPj5y30BxjB9N08p3cgF59wfCoUQHRyCtH079EVFSWzxUgcKHW1YvNSx8hxcBNfxB6r5JkY+QYnHtekZc74ZIWev6vQAkHv4EGbsrcg9fAgAMDY2tpxQErdVApzpfCBWtZGALMtPPsE5okNDyLbWqrC16TFZrRj5dYRujt30R6KRFpXAswFpFISdrzT15WkJSJIU+avjMjLLy8Fzc9fhsVgMg0ODiR5nz5Isy9Vul+eRlFrgdu9LvHywZ0hhcgUAdzqBoig1Dzs7B4dffy2Krs6ELMu0GvAH/FI4HDYajcZflpeXG90uzywASOkkxMiHlXFdJ9D6zdWHCeCfryXeqPw2uhVAFEBsNeYATF/p+kpRuU4n4XHJR1LilFaLEkAjB7qdnmsD6Zilud9GjL6zNPc7bnz637W/7pYc7dp/D0Co9GDv7tR8H2M6BjQAuKIlTozsHx2pKiRGdtWBtYrB4BNQj+tzQCWAeyVEv2tuIeY4ffH6DCPmUCunfI3W4o2jfefLP/AsVXzotRERJgsKbBP5+aGJLVu6teofF5oO9Hr+1sn3q01rdoUQ9mKnM5sZDK+m1lma+20Vx7x/Wpr7bZqd2KhFjNiZVLucc8dUQ8MM5/y0yv0GfVdzbfKvQmutTo6dEVNNzv8msJn1LyNcJmUnpr21AAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/simplify.css: -------------------------------------------------------------------------------- 1 | .olturf-simplify { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAPLSURBVEiJrVRfTFtVHP7uPefc9rYUCqVuAcSXVUY2hfHXtCOsJTH64IMPwAJbJPpAWHzyxee9EDMTF59m2RbMYmbU6B6MPhAjGU6MkgpkWWArAgoz1rW0wij9c+/9+TBaihS4Rr/k3OR+3+98X87v3PsDEcHMOvve2ZbuT7uZ2frckmECfZf7XpINeUr5Tblgpr4Qhwb4L/q5wpWg1+sF42y453JPxf8aUOWouuCudFe0tLTgeP1xbmO2S/8mQCKifcX+d/rLucp/7e3tdbhcLqRSKYx+OLpFWfK9PW8hHWiViFSJKJRibLo5GEz+04MflC5sYtjzrEe4XC4AgNVqxWmvz7rw7Q8hWVU37E4nA2MslUikLZub6r2hoXHStNdOXr0aOfQE5y+dr2NWNj0wMKCqqprniQiffHQT3bZ6tDpqd3jDwKO5uUxiaSlFuj5wcmTkFnDAHXCVf9De1q4UmgOAJEk47e/Ex7EZZEjf4WUZT504oTzt85XKnN+4Ozj43L4B594996JQRGtDYwMrptfU1MBddRRfx+f2aGp5OY42Ntplxr4IDQ6KPQE9n/UwYRXBM51n7IwV9QcAeDs7MBa/j1h2c4/mqK6WVKezSiEaYLbaJsc3s79U3J4Jl9yeCZdsPlp+01XpfLmjo0Ps6w7AYrFANwzMriygraR2j05EIhmNZuSMEL8rQl5UhLzImL4kyfqw3++3HWSew6nmJoQzMcwn/9yjWZ1OgKhdBpEaCHSpgUCXqrri1mOeY3C73Wb8wTmHt7MDN6IhGNj9NSp2O0jXj+TvILERwb3FCXi9L5gyz8Hj8UCU2jCeWNjFp9fXIXO+nA+4M30TTc2nYLOZ6s4u+AKduLV2F4/1dJ5LxeOQgEkOAJqWwWrkPlYiBkJTIQAA5Y5MBDIMSJIEg4xtKq+i8EddSSdQbzsCECGxvPw4q2lfcgDgXMEbr74PIgMSJEACth+QIEEZ/wply/OoaWqE9KTiiSbl3qiABWIPHmja1tbPz4+MfJ5vkeAWKEKFEFYIboXgFghuAecKjMAryKQyiM+HwQhgkgwmyZC3bQvN/1pdpVg4nMwCfYCJcQ0AYBzJ199CDAKLE98hGY2CDGNHJ0J6fR0rk5PJyMzMgp7N+hquXHkIHDJNC0F2B7b6h5Cd/Qkrd8ZAaz9ClJZB1w3QeiIjMxY1dH00DVxsvnYtm9tnOiAHraENWkMboGuQ/3iIqcnv0TU7UVkXDG4UqzfXomJgHEb1M4iVVaLu+vWi5v8twCS4LMlrY2Nj5mZDEchMjhyk/w3QjaRIs68UFAAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/square-grid.css: -------------------------------------------------------------------------------- 1 | .olturf-square-grid { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAALdEVYdFRpdGxlAHRpbGVzJgvN9gAAABh0RVh0QXV0aG9yAFJvYmVydCBTemN6ZXBhbmVrX1axCAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDEyLTA0LTI1nbbUYwAAAFJ0RVh0Q29weXJpZ2h0AENDIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMy4wL16DWrwAAABgSURBVEiJY6ycuuI/AwHQlhXO2LxwK0F1tfHejP3rj6KoYyKkiVIwasGoBUPAAsb//wnmH4oAC7k5FBsoDLRmnLr97GhOHrVg1AI0QPucTG4OxQayPY0Z0cWGfhzQ3AIAh9skQy/0zaIAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/square.css: -------------------------------------------------------------------------------- 1 | .olturf-square { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAwOC0xMi0xMlguO78AAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAABVklEQVRIie2WQUsCQRTHf6M7IkRkkJkX9dwl8LB4SAJPfobdmx+gBL3ZMW8uRB/AW34Ib9ElPBTkORA7LAZpBYGQOV20Vl2jXRA6+E7DvJn/b9483psRSilWaYGVqgPadJA1j09BVICwD50hqOr15cXZUgCIyocSqZvGec+resYoxqSgAywAnFcU9iMOMNnnGvnKc7AGrAFrwEyr8GaGZRwKhAXoAIk0mJbpbM0thSr5BgiEFd+O61sbEbSgRv4gz1iNad43GX2OeH1/0e2BbfkGAHo0skswEAQguZMEQGoSqUlCMoQ9sHVnDoYZoxjzQpiK/+ZzRKCqUtDJmid/eg8Sacjt50hFUzPzhaMCAN3nLncPtz+AyWOx0M+XmWmZavDWJ7655+p/6vfmI/Bu9av697hm1AAoN8oza/5vHQAtJjUA0H5suyW9Jfx+W+YLze0AClX6AsqfXp6VLHAFAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/tag.css: -------------------------------------------------------------------------------- 1 | .olturf-tag { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAkdEVYdFRpdGxlAGludGVycG9sYXRlIHJhc3RlciBmcm9tIHZlY3RvcmrJ/SEAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAxMi0wNC0yNZ221GMAAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAABEElEQVRIic1VSw6CMBB9NR6AO2hi9BL+YIGwE1EOY+JtNMYlygL8rdljSPQUbtzVlYbgVKlplLdqpn3z0tfpDBuNhzPIwRXEm1Swmg90uv2abpg2AERh4B/220tR5VajAW9gAwDmGx9JmqKSP6Qbpr2Ir9oivmoPoaLwBjZujoub4z6FXgRU48WiKAz8ScYimWTzjQ9vtXyuAYD94pFJAmNsKUhExjnnZJ7fv8E7tDu9um6YFgBEYbA+HnbnTxypG+iGaWVK2CrCKZdFURisJxmLinDYaDzkgr0TSRBU1/+qiGpQKlGhGpRSAeUZc6hSDUqpQJKmp6mE75yLio5GuT7aAzJj9asbyIzVclokM1bvtPx83Qun1+QAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/tesselate.css: -------------------------------------------------------------------------------- 1 | .olturf-tesselate { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAASdEVYdFRpdGxlAHBsYXkgZm9yd2FyZKkytTEAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAxMi0xMC0xNHOeCdEAAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAACsklEQVRIie3VsU8TYRzG8e8dvd615QptvVZpogYSB0hMXE2Mo3EzDkR5iRvREAZDdwh/wLkQjYuDiQcsin8Ai0hYnayJCUhMKqFQCq0tba+9cxCqtlfqoE7+5s/7PPe73JuTXNflb478V9P/RYEPYHR+1FBs5SYya9ZDa9MLClMYwE1gzUp5G6+RAZSashLvSzynQXrMHJsZnRv1e9iVeH/iOZAWppgRpvAy3gXA5ZHzIwCqrulzqq6+u/vo7tUW2zShQO+cLMnvhClaTceC5qiKykAsORxUgmvj5vjj8fnxcKvRfCoDsYFhza+tCVM8FqZoMx0LcsUcucIeRtiQonp0Epv0mDl2q93kOBM2pJgem5QkKS1Mcas1y7MA4Kh2RCaXQZIkkrFkMqAElr3Ml2MzEEsmNUVbFqZ4KUxxrmsBgOM67BX2yBX3MfqMU03+2ET06G3ggzDFfWEK6dSC5pNWy2T2M6eacrVMJpeh0agD9AFPgTfCFJd+66I5jtPduA6FcgEA13Gp2/VrwLM/fpMrxQo7GztUChUA2fc7hxr1Bj2+nq7mcPsQu2YTTUbxB/1vgXtdNyjlS2Q3st3NZhZFU4gPxg/9Qf8D4LqVsrY6blCv1slv5wEwLnp/RXbV5mD74Lu5YOBTfa+AKStlbZ+YtgLXdSnuFSntlwjHwwQjwQwwBSy3mXyJsBEmFAlljoNft+Y1X9H7z++plqtkN7LUK3XiQ3G3N9L7RPbLwwuphdcnplau/TCDcTcUCT0Bhr3Cf9lga+sThd0C/Wf70XQt7UjOxIvpF+s/409bmxR3i00DTFgpa70t1WODVU3XSAwlqqquztpf7SuL04utB1cDeoDEUKKq6doscKVbeHMDuUe+g8SNBo31pemljx3sHblHvgGsWymrk2kb6f9Pv9t8AwDfIczBYm+bAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/tin.css: -------------------------------------------------------------------------------- 1 | .olturf-tin { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAYdEVYdEF1dGhvcgBSb2JlcnQgU3pjemVwYW5la19WsQgAAAAndEVYdERlc2NyaXB0aW9uAGh0dHA6Ly9yb2JlcnQuc3pjemVwYW5lay5wbJBZSGAAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAwOC0xMi0xMlguO78AAABSdEVYdENvcHlyaWdodABDQyBBdHRyaWJ1dGlvbi1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzMuMC9eg1q8AAAB9ElEQVRIie3VPW/TQBgH8L/fYsdxnVpt2iQIBGWoGBEDfAAkPgGR0uvI28BAUyEBArGjOoFPgCrFHcIXAAEbDCAhBkBsCBCQQAjORa6d2I6PoQoDctRQXFj6X056dPf87oZHxzHGsJvhd7X7vwDEuCJZIxfBoQLgseiLV9avrnd2CsS/gEP1+OKJQwDOhFL4lpiEJAsAkiqrAIDizL7clKrXiUnul2+XDyYF/EqbfkNGyaBgFE6luNSbpepSpXSvJCQGBMMArR9NbA5cFIyiqiu6KX2UnpWr5aOJAKP0XIqW3YSWnkLeyB9L8anny+byrVKtlE4EAIAg3HqN5/cxb+RFBnZZiqTXZI2cTAQAAAYGutnF5++fRqUFcHhITHI9EeA3DU7HgdNxAOBc3JbYQZskQT+A/cUGL/CYLk4DQC0RgEUMvXYPHvWgz+tQs+o7MJy3Vq1Hfw0MnAHspg1ZlTF3eC4UBKHm8/7NxkrDG3dmIiAaRqAtCt/zYRQMyJr8IuKis/VK/eV2Z8cC7sDdWqkL+pUik80gt5BzOYG7EewP7jRON4aTXG4s8PTVE3SbXUTDCLMHZiEp0oNIiC5sXNp4P0nj7QAa9IOsoinQDK0NHivWqmX9SeNRYueAgV1L6+kP2ox2VwzFIzttDgDc3p/834GfOq+zkx441RAAAAAASUVORK5CYII="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/triangle-grid.css: -------------------------------------------------------------------------------- 1 | .olturf-triangle-grid { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAgdEVYdFRpdGxlAHBsYXllciByZXBlYXQgYmFjayBmb3J3YXJkX/t6ugAAABh0RVh0QXV0aG9yAFJvYmVydCBTemN6ZXBhbmVrX1axCAAAABh0RVh0Q3JlYXRpb24gVGltZQAyMDEyLTEwLTE0c54J0QAAAFJ0RVh0Q29weXJpZ2h0AENDIEF0dHJpYnV0aW9uLVNoYXJlQWxpa2UgaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMy4wL16DWrwAAALkSURBVEiJ1ZXNaxRnHMc/z4yZ2beZfZtNE5OYeFFvnvQUsNdCqSdJ4aHQgv4BZQ8thJ6KUA+Df4CCoswhCB5U7DkQKKhNKcST2Bdks+nuOplsZ19mZ3enl4ka1iRajeD3Njy/3+fzPPPMPI+IooiDjHKg9A8hOLRfgbTlPHAVqANfAGlgKR7+zik7K3v1i732QNryK+CK7/q6QJAupL8F9Clr+ieiiMrzSgBccMrOzbdagbSlAH4smtZiSk/xuL62PZQD0NQxALKprB4OwhvSlseBH5yyMzLbkT2QtkwCS4cLhxdPTJ9gq+XtusJu2MUyLYyksQgsxb27C6QtJ4DluU/mzs2Oz7H6dJVmu7mrIAgDqptVsukcuXTuHLAcM0YF0pYnhRAPjk0fP1Uyx/n16SM6QXtX+HbCfkjVXSeVSFM0i6eEEA+kLU/uEEhbfg6s6GP6jKZq/PbHKr2wty98O4PhgA23ypiqkUlkZoCVmIn6xHjyGXAX0PuDPrWtGsNouPNVtAMA9LS+DJDP5D8F8F7Zn4gIv+vT6/cANODL27/cfqQA3xRNS8ll8m884/3SrDfxqp4CfK0A1z1/c5jUEpSyJYQQ/xscRRFuxSVoBZjj5hC4pjhl5/5gODi74W74ABP5SVRFfWv4sD+k8VcDAGvW8hVVOeuUnZ8VAKfs3IuI5utb9WedoM1kYZKxQ9obw8MgpPZnjUQmQWGq8EwIMe+UnXvwymfqlJ3fgdNey3u46XtM5CdIaiP/zUi6fpfG3w3McROjZDwETscsdghiyQZwptX1b9W8f7CyJcykiaqqKOrL0l6/R28Q0nJbeOsexZkiqWzqFnAmZvBaQSzpAAtBGFysuusYKYMjs0cwCsaLmkqjwuO1NfxNH+uohZbULgILce+O7HuaKkK5YmVL+r/tJp1e53sgCFrBZd/1KUwVAqGIPU/TPQWxZB64FD8uAC3gDlACzr/TffA+8vHfyQcu+A9VBynBFm+eOAAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/union.css: -------------------------------------------------------------------------------- 1 | .olturf-union { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAfklEQVRIie3WwQnAIAwFUGcXZ/jiQQi4gu7QSYpHz72kA1TQtBVaiPCveRfziTGTz6VSLWWWxKVSZ+cbS5m3/RDFUmYFPgqE4CsAliYSzQEAuDUSB4ACY2Bqk58A3YFLgV6JvQr0FkiBIRCJxDUBgEPw12/5r5ZU4Baw+hw5AY7bJM35PKnCAAAAAElFTkSuQmCC"); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/css/within.css: -------------------------------------------------------------------------------- 1 | .olturf-within { 2 | background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAQdEVYdFRpdGxlAHpvb20gdG91Y2ggx6j1AAAAGHRFWHRBdXRob3IAUm9iZXJ0IFN6Y3plcGFuZWtfVrEIAAAAGHRFWHRDcmVhdGlvbiBUaW1lADIwMTItMDQtMjYEv4XZAAAAUnRFWHRDb3B5cmlnaHQAQ0MgQXR0cmlidXRpb24tU2hhcmVBbGlrZSBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8zLjAvXoNavAAABHFJREFUSImtlV1sFFUYht+zO53pdMuutbjThHaFdUvLwlYvFsICxsaqpJG/JmTRENkbTCSikZh4AVFL0Bs1mBglJnJhSRBomlRqsUTSRFFYEkrDT5mW/ix0K9KRQDu7W2bPzJk93kBTm+3CRd/L833f88w5MzlDOOeYDiHk0ptYJBTBeL6F38M8hPxPAOBKjJTbHCs5R47ncDV8lI8DQDQaFRljGyRJChNCVlBKFUmSNM55H6W0RxCEztbWVvOxAgC49BZ5zQlUc6AMHLdarTWJm6RqXyAQcL9UX7+wpqZmgcvlwtjYmK5ev26oqmoMDw+nGGMftbW1XX+soGc7qXA6sBME5XdznpUmxGDZsjXZ2jeaiasqKM/sTU1Ojtq2bV27dg0tLS2Gbds/HD9+/MijuiPfuYWP8nFw3JrKSf4SYoYXiVNubwlx3/7qFeXOj7vkHOd2llI9retjtm1bABAKhdDc3Cw7nc63t27durygAABG+TNndJRGSgQuVO09O1K56mVH9f4LmXTvz8L9GxfHjUzmLmOMzpwpLS1FLBaTBUH4IhqNigUFR4x1ax+4l2Tlmnpd/vt3Lz/1vpzr7+BFi1dNGpdPLphrLhQKIRAIuBljGwoKJEkKkxeiupm44HYENzvJ698Y2cr6f81E3F1ct1Gfaw4AgsGgLElSGACEuZoIISsqghEqG+szQ5+u9pQub2Dpq58slmobJgSlms41BwA+nw+EkBUFBZRSRVEULIx9f8+ZueNM93YUFb347ojgrc4WggOAoiiglCpA4SPSNE1DzrYt0ftc7un1Hxj54EwbkjJnDnqZNiQ9WtM0DZIkaQUFnPO+ZDIJ07IMZllTlmmmZ/fox3b77h/aVMv+6XPdP7SpVj+22wcAyWQSnPO+ggJKaY+qqgY4z6VTqTtTmczd2U9OB7rLlD1d/UpoZVrZ09VPB7rLmDYkqapqUEp7CgoEQegcHBzk3d3dcr569uovHtEfSYmJLnfxuQPPiokut+iPpJKnDpYPDw+nBEHoLCiwLGunYRhrT5w4UdPb21s6u15ct1E3E3G36W9MZdd+PGr6G1PZwbOeif7zxUv42OePLr68X1FTU9MOxti38XicPFwKbNu27UZDQ4MxvUOlmkq1DRPa143LRH8kZbR9WfmAESbCVKNF5/0AzgN5LrumpqZ1ZR75N11PyX/8eQEAEIlEcrIsn1u6dCkJBoOyz+eDoijQNA3jalzil1s9JambxR5k4i4HTYDjnp3D4fBRPi7MhlcuWnh63zt1sj7agb1YDZMRLgjCewAOq6q6YWRkJM//oKpnhzx6zkXoq+BYTIAJ4kAdgPHpHcyAuxT+KwZGJrH/J+8Dajl2tbe3H8ETpmc7qSAO1BECh5PgIuGc54UfOObNGKajsb29/a8nhc/MlRgpZxZksmXLlnXlT8mnP/swMm/w6RBCBFnMtWxeddtVwVrRf4vNHxwAOOfOQPWy3oExKSoKVPyus3z+4A8z/Q5kMddimI7YfMIB4D9940EruB9YXAAAAABJRU5ErkJggg=="); 3 | background-repeat: no-repeat; 4 | background-size: cover; 5 | } 6 | -------------------------------------------------------------------------------- /src/js/along.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'along'; 5 | 6 | /* 7 | * Find point along line at given distance 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idDistance = utils.getName([name, 'distance'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idUnits = utils.getName([name, 'units'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather line seleted 20 | const collection = utils.getCollection(control, 1, 1); 21 | const lines = utils.getLines(collection, 1, 1); 22 | const line = lines[0]; 23 | 24 | // Gather form inputs 25 | const distance = utils.getFormNumber(idDistance, 'distance'); 26 | const units = utils.getFormString(idUnits, 'units'); 27 | 28 | // Collect polygons 29 | const output = turf.along(line, distance, {units}); 30 | 31 | // Remove form and display results 32 | control.showForm(); 33 | const inputs = { 34 | line: line, 35 | distance: distance, 36 | units: units, 37 | }; 38 | control.toolbar.olturf.handler.callback(name, output, inputs); 39 | } catch (e) { 40 | control.showMessage(e); 41 | } 42 | }; 43 | 44 | const onCancel = function() { 45 | control.showForm(); 46 | }; 47 | 48 | const controls = [ 49 | utils.getControlNumber(idDistance, 50 | 'Distance', 'Distance along the line', '0', 'any', '0'), 51 | utils.getControlSelect(idUnits, 52 | 'Units', utils.getOptionsUnits()), 53 | utils.getControlInput(idOk, onOK, '', 'OK'), 54 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 55 | ]; 56 | 57 | control.showForm(controls, idForm); 58 | }; 59 | 60 | export default { 61 | create: function(toolbar, prefix) { 62 | const title = 'Find point along line at given distance'; 63 | return Control.create(toolbar, prefix, name, title, action); 64 | }, 65 | }; 66 | -------------------------------------------------------------------------------- /src/js/area.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'area'; 5 | 6 | /* 7 | * Compute area 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | const output = turf.area(collection); 12 | const inputs = { 13 | input: collection, 14 | }; 15 | control.toolbar.olturf.handler.callback(name, output, inputs); 16 | }; 17 | 18 | export default { 19 | create: function(toolbar, prefix) { 20 | const title = 'Measure Area'; 21 | return Control.create(toolbar, prefix, name, title, action); 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/bearing.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'bearing'; 5 | 6 | /* 7 | * Compute bearing between two points 8 | */ 9 | const action = function(control) { 10 | // Gather points seleted 11 | const collection = utils.getCollection(control, 2, 2); 12 | const points = utils.getPoints(collection, 2, 2); 13 | const start = points[0]; 14 | const end = points[1]; 15 | const output = turf.bearing(start, end); 16 | const inputs = { 17 | start: start, 18 | end: end, 19 | }; 20 | control.toolbar.olturf.handler.callback(name, output, inputs); 21 | }; 22 | 23 | export default { 24 | create: function(toolbar, prefix) { 25 | const title = 'Measure Bearing'; 26 | return Control.create(toolbar, prefix, name, title, action); 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /src/js/bezier.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'bezier'; 5 | 6 | /* 7 | * Create bezier curve of line 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idResolution = utils.getName([name, 'resolution'], 15 | control.prefix); 16 | const idSharpness = utils.getName([name, 'sharpness'], 17 | control.prefix); 18 | 19 | const onOK = function() { 20 | try { 21 | // Gather line seleted 22 | const collection = utils.getCollection(control, 1, 1); 23 | const lines = utils.getLines(collection, 1, 1); 24 | const line = lines[0]; 25 | 26 | // Gather form inputs 27 | const resolution = utils.getFormNumber(idResolution, 28 | 'resolution'); 29 | const sharpness = utils.getFormNumber(idSharpness, 'sharpness'); 30 | 31 | // Create bezier curve 32 | const output = turf.bezierSpline(line, {resolution, sharpness}); 33 | 34 | // Remove form and display results 35 | control.showForm(); 36 | const inputs = { 37 | line: line, 38 | resolution: resolution, 39 | sharpness: sharpness, 40 | }; 41 | control.toolbar.olturf.handler.callback(name, output, inputs); 42 | } catch (e) { 43 | control.showMessage(e); 44 | } 45 | }; 46 | 47 | const onCancel = function() { 48 | control.showForm(); 49 | }; 50 | 51 | const controls = [ 52 | utils.getControlNumber(idResolution, 'Resolution', 53 | 'Time between points (milliseconds)', '10000', 'any', '0'), 54 | utils.getControlNumber(idSharpness, 'Sharpness', 55 | 'Measure of how curvy the path should be between splines', '0.85', 56 | '0.01', '0', '1'), 57 | utils.getControlInput(idOk, onOK, '', 'OK'), 58 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 59 | ]; 60 | 61 | control.showForm(controls, idForm); 62 | }; 63 | 64 | export default { 65 | create: function(toolbar, prefix) { 66 | const title = 'Create bezier curve of line'; 67 | return Control.create(toolbar, prefix, name, title, action); 68 | }, 69 | }; 70 | -------------------------------------------------------------------------------- /src/js/buffer.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'buffer'; 5 | 6 | /* 7 | * Buffer feature by given radius 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idDistance = utils.getName([name, 'distance'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idUnits = utils.getName([name, 'units'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 1, Infinity); 21 | 22 | // Gather form inputs 23 | const distance = utils.getFormNumber(idDistance, 'distance'); 24 | const units = utils.getFormString(idUnits, 'units'); 25 | 26 | // Collect polygons 27 | const output = turf.buffer(collection, distance, {units}); 28 | 29 | // Remove form and display results 30 | control.showForm(); 31 | const inputs = { 32 | feature: collection, 33 | distance: distance, 34 | unit: units, 35 | }; 36 | control.toolbar.olturf.handler.callback(name, output, inputs); 37 | } catch (e) { 38 | control.showMessage(e); 39 | } 40 | }; 41 | 42 | const onCancel = function() { 43 | control.showForm(); 44 | }; 45 | 46 | const controls = [ 47 | utils.getControlNumber(idDistance, 'Distance', 48 | 'Distance to draw the buffer', '0', 'any', '0'), 49 | utils.getControlSelect(idUnits, 'Units', 50 | utils.getOptionsUnits()), 51 | utils.getControlInput(idOk, onOK, '', 'OK'), 52 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 53 | ]; 54 | 55 | control.showForm(controls, idForm); 56 | }; 57 | 58 | export default { 59 | create: function(toolbar, prefix) { 60 | const title = 'Buffer feature by given radius'; 61 | return Control.create(toolbar, prefix, name, title, action); 62 | }, 63 | }; 64 | -------------------------------------------------------------------------------- /src/js/center-of-mass.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'center-of-mass'; 5 | 6 | /* 7 | * Compute center-of-mass 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | const output = turf.centerOfMass(collection); 12 | const inputs = { 13 | features: collection, 14 | }; 15 | control.toolbar.olturf.handler.callback(name, output, inputs); 16 | }; 17 | 18 | export default { 19 | create: function(toolbar, prefix) { 20 | const title = 'Measure center of mass'; 21 | return Control.create(toolbar, prefix, name, title, action); 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/center.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'center'; 5 | 6 | /* 7 | * Compute center 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | const output = turf.center(collection); 12 | const inputs = { 13 | features: collection, 14 | }; 15 | control.toolbar.olturf.handler.callback(name, output, inputs); 16 | }; 17 | 18 | export default { 19 | create: function(toolbar, prefix) { 20 | const title = 'Measure Center'; 21 | return Control.create(toolbar, prefix, name, title, action); 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/centroid.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'centroid'; 5 | 6 | /* 7 | * Compute centroid 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | const output = turf.centroid(collection); 12 | const inputs = { 13 | features: collection, 14 | }; 15 | control.toolbar.olturf.handler.callback(name, output, inputs); 16 | }; 17 | 18 | export default { 19 | create: function(toolbar, prefix) { 20 | const title = 'Measure Centroid'; 21 | return Control.create(toolbar, prefix, name, title, action); 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/circle.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'circle'; 5 | 6 | /* 7 | * Create circle 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idRadius = utils.getName([name, 'radius'], control.prefix); 15 | const idSteps = utils.getName([name, 'steps'], control.prefix); 16 | const idUnits = utils.getName([name, 'units'], control.prefix); 17 | 18 | const onOK = function() { 19 | try { 20 | // Gather center point 21 | const collection = utils.getCollection(control, 1, 1); 22 | const points = utils.getPoints(collection, 1, 1); 23 | const center = points[0]; 24 | 25 | // Gather form inputs 26 | const radius = utils.getFormNumber(idRadius, 'radius'); 27 | const steps = utils.getFormNumber(idSteps, 'steps'); 28 | const units = utils.getFormString(idUnits, 'units'); 29 | 30 | // Collect polygons 31 | const output = turf.circle(center, radius, {steps, units}); 32 | 33 | // Remove form and display results 34 | control.showForm(); 35 | const inputs = { 36 | center: center, 37 | radius: radius, 38 | steps: steps, 39 | units: units, 40 | }; 41 | control.toolbar.olturf.handler.callback(name, output, inputs); 42 | } catch (e) { 43 | control.showMessage(e); 44 | } 45 | }; 46 | 47 | const onCancel = function() { 48 | control.showForm(); 49 | }; 50 | 51 | const controls = [ 52 | utils.getControlNumber(idRadius, 'Radius', 'Radius of the circle', 53 | '0', 'any', '0'), 54 | utils.getControlNumber(idSteps, 'Steps', 55 | 'Number of steps around circle', '3', '1', '3'), 56 | utils.getControlSelect(idUnits, 'Units', 57 | utils.getOptionsUnits()), 58 | utils.getControlInput(idOk, onOK, '', 'OK'), 59 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 60 | ]; 61 | 62 | control.showForm(controls, idForm); 63 | }; 64 | 65 | export default { 66 | create: function(toolbar, prefix) { 67 | const title = 'Create circle'; 68 | return Control.create(toolbar, prefix, name, title, action); 69 | }, 70 | }; 71 | -------------------------------------------------------------------------------- /src/js/collect.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'collect'; 5 | 6 | /* 7 | * Collect point attributes within polygon 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idIn = utils.getName([name, 'in', 'property'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idOut = utils.getName([name, 'out', 'property'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected points and polygons 20 | const collection = utils.getCollection(control, 2, Infinity); 21 | const points = utils.getPoints(collection, 1, 22 | collection.features.length - 1); 23 | const numPolygons = collection.features.length - points.length; 24 | const polygons = utils.getPolygons(collection, numPolygons, numPolygons); 25 | 26 | // Gather form inputs 27 | const inProperty = utils.getFormString(idIn, 'In-Property'); 28 | const outProperty = utils.getFormString(idOut, 'Out-Property'); 29 | 30 | // Collect polygons 31 | const inPolygons = turf.featureCollection(polygons); 32 | const inPoints = turf.featureCollection(points); 33 | const output = turf.collect(inPolygons, 34 | inPoints, 35 | inProperty, 36 | outProperty); 37 | 38 | // Remove form and display results 39 | control.showForm(); 40 | const inputs = { 41 | polygons: inPolygons, 42 | points: inPoints, 43 | inProperty: inProperty, 44 | outProperty: outProperty, 45 | }; 46 | control.toolbar.olturf.handler.callback(name, output, inputs); 47 | } catch (e) { 48 | control.showMessage(e); 49 | } 50 | }; 51 | 52 | const onCancel = function() { 53 | control.showForm(); 54 | }; 55 | 56 | const controls = [ 57 | utils.getControlText(idIn, 'In Property', 'Property to be nested from'), 58 | utils.getControlText(idOut, 'Out Property', 'Property to be nested into'), 59 | utils.getControlInput(idOk, onOK, '', 'OK'), 60 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 61 | ]; 62 | 63 | control.showForm(controls, idForm); 64 | }; 65 | 66 | export default { 67 | create: function(toolbar, prefix) { 68 | const title = 'Collect points within polygons'; 69 | return Control.create(toolbar, prefix, name, title, action); 70 | }, 71 | }; 72 | 73 | -------------------------------------------------------------------------------- /src/js/combine.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'combine'; 5 | 6 | /* 7 | * Compute combine of feature collection 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | 12 | const output = turf.combine(collection); 13 | const inputs = { 14 | fc: collection, 15 | }; 16 | control.toolbar.olturf.handler.callback(name, output, inputs); 17 | }; 18 | 19 | export default { 20 | create: function(toolbar, prefix) { 21 | const title = 'Combine feature collection'; 22 | return Control.create(toolbar, prefix, name, title, action); 23 | }, 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/js/concave.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'concave'; 5 | 6 | /* 7 | * Buffer feature by given radius 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idMaxEdge = utils.getName([name, 'max', 'edge'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idUnits = utils.getName([name, 'units'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 3, Infinity); 21 | const numPoints = collection.features.length; 22 | const pts = utils.getPoints(collection, numPoints, numPoints); 23 | 24 | // Gather form inputs 25 | const maxEdge = utils.getFormNumber(idMaxEdge, 'Max Edge'); 26 | const units = utils.getFormString(idUnits, 'units'); 27 | 28 | // Collect polygons 29 | const points = turf.featureCollection(pts); 30 | const output = turf.concave(points, {maxEdge, units}); 31 | 32 | // Remove form and display results 33 | control.showForm(); 34 | const inputs = { 35 | points: points, 36 | maxEdge: maxEdge, 37 | units: units, 38 | }; 39 | control.toolbar.olturf.handler.callback(name, output, inputs); 40 | } catch (e) { 41 | control.showMessage(e); 42 | } 43 | }; 44 | 45 | const onCancel = function() { 46 | control.showForm(); 47 | }; 48 | 49 | const controls = [ 50 | utils.getControlNumber(idMaxEdge, 'Max Edge Size', 51 | 'Maximum size of an edge necessary for part of the hull to become ' + 52 | 'concave', '0', 'any', '0'), 53 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 54 | utils.getControlInput(idOk, onOK, '', 'OK'), 55 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 56 | ]; 57 | 58 | control.showForm(controls, idForm); 59 | }; 60 | 61 | export default { 62 | create: function(toolbar, prefix) { 63 | const title = 'Create Concave Hull'; 64 | return Control.create(toolbar, prefix, name, title, action); 65 | }, 66 | }; 67 | 68 | -------------------------------------------------------------------------------- /src/js/controls.js: -------------------------------------------------------------------------------- 1 | import along from './along'; 2 | import area from './area'; 3 | import bearing from './bearing'; 4 | import bezier from './bezier'; 5 | import buffer from './buffer'; 6 | import center from './center'; 7 | import centerOfMass from './center-of-mass'; 8 | import centroid from './centroid'; 9 | import circle from './circle'; 10 | import collect from './collect'; 11 | import combine from './combine'; 12 | import concave from './concave'; 13 | import convex from './convex'; 14 | import destination from './destination'; 15 | import difference from './difference'; 16 | import distance from './distance'; 17 | import envelope from './envelope'; 18 | import explode from './explode'; 19 | import flip from './flip'; 20 | import hexGrid from './hex-grid'; 21 | import inside from './inside'; 22 | import intersect from './intersect'; 23 | import isolines from './isolines'; 24 | import kinks from './kinks'; 25 | import lineDistance from './line-distance'; 26 | import lineSliceAlong from './line-slice-along'; 27 | import midpoint from './midpoint'; 28 | import nearest from './nearest'; 29 | import planepoint from './planepoint'; 30 | import pointGrid from './point-grid'; 31 | import pointOnLine from './point-on-line'; 32 | import pointOnSurface from './point-on-surface'; 33 | import popup from './popup'; 34 | import random from './random'; 35 | import sample from './sample'; 36 | import simplify from './simplify'; 37 | import squareGrid from './square-grid'; 38 | import square from './square'; 39 | import tag from './tag'; 40 | import tesselate from './tesselate'; 41 | import tin from './tin'; 42 | import toolbars from './toolbars'; 43 | import triangleGrid from './triangle-grid'; 44 | import union from './union'; 45 | import utils from './utils'; 46 | import within from './within'; 47 | 48 | export default { 49 | along, 50 | area, 51 | bearing, 52 | bezier, 53 | buffer, 54 | center, 55 | 'center-of-mass': centerOfMass, 56 | centroid, 57 | circle, 58 | collect, 59 | combine, 60 | concave, 61 | convex, 62 | destination, 63 | difference, 64 | distance, 65 | envelope, 66 | explode, 67 | flip, 68 | 'hex-grid': hexGrid, 69 | inside, 70 | intersect, 71 | isolines, 72 | kinks, 73 | 'line-distance': lineDistance, 74 | 'line-slice-along': lineSliceAlong, 75 | midpoint, 76 | nearest, 77 | planepoint, 78 | 'point-grid': pointGrid, 79 | 'point-on-line': pointOnLine, 80 | 'point-on-surface': pointOnSurface, 81 | popup, 82 | random, 83 | sample, 84 | simplify, 85 | 'square-grid': squareGrid, 86 | square, 87 | tag, 88 | tesselate, 89 | tin, 90 | toolbars, 91 | 'triangle-grid': triangleGrid, 92 | union, 93 | utils, 94 | within, 95 | }; 96 | -------------------------------------------------------------------------------- /src/js/convex.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'convex'; 5 | 6 | /* 7 | * Compute convex hull 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | 12 | const output = turf.convex(collection); 13 | const inputs = { 14 | featurecollection: collection, 15 | }; 16 | control.toolbar.olturf.handler.callback(name, output, inputs); 17 | }; 18 | 19 | export default { 20 | create: function(toolbar, prefix) { 21 | const title = 'Create Convex Hull'; 22 | return Control.create(toolbar, prefix, name, title, action); 23 | }, 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/js/destination.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'destination'; 5 | 6 | /* 7 | * Find destination point from given point 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idBearing = utils.getName([name, 'bearing'], control.prefix); 12 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 13 | const idDistance = utils.getName([name, 'distance'], control.prefix); 14 | const idForm = utils.getName([name, 'form'], control.prefix); 15 | const idOk = utils.getName([name, 'ok'], control.prefix); 16 | const idUnits = utils.getName([name, 'units'], control.prefix); 17 | 18 | const onOK = function() { 19 | try { 20 | // Gather point seleted 21 | const collection = utils.getCollection(control, 1, 1); 22 | const points = utils.getPoints(collection, 1, 1); 23 | const point = points[0]; 24 | 25 | // Gather form inputs 26 | const distance = utils.getFormNumber(idDistance, 'distance'); 27 | const bearing = utils.getFormNumber(idBearing, 'bearing'); 28 | const units = utils.getFormString(idUnits, 'units'); 29 | 30 | // Collect polygons 31 | const output = turf.destination(point, 32 | distance, 33 | bearing, 34 | {units}); 35 | 36 | // Remove form and display results 37 | control.showForm(); 38 | const inputs = { 39 | from: point, 40 | distance: distance, 41 | bearing: bearing, 42 | units: units, 43 | }; 44 | control.toolbar.olturf.handler.callback(name, output, inputs); 45 | } catch (e) { 46 | control.showMessage(e); 47 | } 48 | }; 49 | 50 | const onCancel = function() { 51 | control.showForm(); 52 | }; 53 | 54 | const controls = [ 55 | utils.getControlNumber(idBearing, 'Bearing', 'Bearing angle (degrees)', 56 | '0', 'any', '-180', '180'), 57 | utils.getControlNumber(idDistance, 'Distance', 58 | 'Distance from the starting point', '0', 'any', '0'), 59 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 60 | utils.getControlInput(idOk, onOK, '', 'OK'), 61 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 62 | ]; 63 | 64 | control.showForm(controls, idForm); 65 | }; 66 | 67 | export default { 68 | create: function(toolbar, prefix) { 69 | const title = 'Find destination point from given point'; 70 | return Control.create(toolbar, prefix, name, title, action); 71 | }, 72 | }; 73 | 74 | -------------------------------------------------------------------------------- /src/js/difference.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'difference'; 5 | 6 | /* 7 | * Compute difference between two polygons 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, 2); 11 | const polygons = utils.getPolygons(collection, 2, 2); 12 | const poly1 = polygons[0]; 13 | const poly2 = polygons[1]; 14 | const output = turf.difference(poly1, poly2); 15 | const inputs = { 16 | poly1: poly1, 17 | poly2: poly2, 18 | }; 19 | control.toolbar.olturf.handler.callback(name, output, inputs); 20 | }; 21 | 22 | export default { 23 | create: function(toolbar, prefix) { 24 | const title = 'Create Difference Polygon'; 25 | return Control.create(toolbar, prefix, name, title, action); 26 | }, 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /src/js/distance.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'distance'; 5 | 6 | /* 7 | * Find distance between points 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idUnits = utils.getName([name, 'units'], control.prefix); 15 | 16 | const onOK = function() { 17 | try { 18 | // Gather points seleted 19 | const collection = utils.getCollection(control, 2, 2); 20 | const points = utils.getPoints(collection, 2, 2); 21 | const from = points[0]; 22 | const to = points[1]; 23 | 24 | // Gather form inputs 25 | const units = utils.getFormString(idUnits, 'units'); 26 | 27 | // Collect polygons 28 | const output = turf.distance(from, to, {units}); 29 | 30 | // Remove form and display results 31 | control.showForm(); 32 | const inputs = { 33 | from: from, 34 | to: to, 35 | units: units, 36 | }; 37 | control.toolbar.olturf.handler.callback(name, output, inputs); 38 | } catch (e) { 39 | control.showMessage(e); 40 | } 41 | }; 42 | 43 | const onCancel = function() { 44 | control.showForm(); 45 | }; 46 | 47 | const controls = [ 48 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 49 | utils.getControlInput(idOk, onOK, '', 'OK'), 50 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 51 | ]; 52 | 53 | control.showForm(controls, idForm); 54 | }; 55 | 56 | export default { 57 | create: function(toolbar, prefix) { 58 | const title = 'Find distance between points'; 59 | return Control.create(toolbar, prefix, name, title, action); 60 | }, 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /src/js/envelope.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'envelope'; 5 | 6 | /* 7 | * Compute envelope 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | 12 | const output = turf.envelope(collection); 13 | const inputs = { 14 | fc: collection, 15 | }; 16 | control.toolbar.olturf.handler.callback(name, output, inputs); 17 | }; 18 | 19 | export default { 20 | create: function(toolbar, prefix) { 21 | const title = 'Measure Envelope'; 22 | return Control.create(toolbar, prefix, name, title, action); 23 | }, 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/js/explode.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'explode'; 5 | 6 | /* 7 | * Compute explode of feature collection 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | 12 | const output = turf.explode(collection); 13 | const inputs = { 14 | geojson: collection, 15 | }; 16 | control.toolbar.olturf.handler.callback(name, output, inputs); 17 | }; 18 | 19 | export default { 20 | create: function(toolbar, prefix) { 21 | const title = 'Explode feature collection'; 22 | return Control.create(toolbar, prefix, name, title, action); 23 | }, 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/js/flip.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'flip'; 5 | 6 | /* 7 | * Compute feature coordinate flip 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | 12 | const output = turf.flip(collection); 13 | const inputs = { 14 | input: collection, 15 | }; 16 | control.toolbar.olturf.handler.callback(name, output, inputs); 17 | }; 18 | 19 | export default { 20 | create: function(toolbar, prefix) { 21 | const title = 'Flip features coordinates'; 22 | return Control.create(toolbar, prefix, name, title, action); 23 | }, 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/js/form.js: -------------------------------------------------------------------------------- 1 | import utils from './utils'; 2 | 3 | /** 4 | * @description Properties of control form 5 | * @typedef {object} FormProperties 6 | * @memberOf olturf 7 | * @property {object} [properties] Form properties. 8 | * @property {string} [properties.title] Control display title. 9 | * @property {string} [properties.type] "input" or "select". 10 | * @property {object} [properties.attributes] Attributes. 11 | * @private 12 | */ 13 | 14 | /** 15 | * Creates a form as a table with one control per row, the control's title 16 | * in the first column and the control in the second column. 17 | * @param {string} parent Element or ID string of parent element. 18 | * @param {string} formId ID of new form element. 19 | * @param {olturf.FormProperties[]} controls Array defining form controls. 20 | * @param {object} attributes Form attributes. 21 | * @private 22 | * @return {Element} Form DOM element. 23 | */ 24 | export default function(parent, formId, controls, attributes) { 25 | let container = null; 26 | if (typeof parent === 'string') { 27 | container = document.getElementById(parent); 28 | } else { 29 | container = parent; 30 | } 31 | if (container === null) { 32 | throw new Error('olturf.form: Parent element not found.'); 33 | } 34 | if (formId === undefined) { 35 | throw new Error('olturf.form: Form ID not provided.'); 36 | } 37 | if (controls === undefined) { 38 | throw new Error('olturf.form: Form controls not provided.'); 39 | } 40 | 41 | // Create a form to add to parent 42 | const form = document.createElement('form'); 43 | form.id = formId; 44 | form.className = 'olturf-form ol-unselectable ol-control'; 45 | form.setAttribute('onsubmit', 'return false;'); 46 | utils.extend(attributes, form); 47 | 48 | // Create a table to add to form 49 | const table = document.createElement('table'); 50 | table.className = 'olturf-form-table'; 51 | 52 | // Each form control is a table row with a title in the 53 | // header column and the control in the data column. 54 | controls.forEach(function(element) { 55 | const row = document.createElement('tr'); 56 | row.className = 'olturf-form-row'; 57 | 58 | const th = document.createElement('th'); 59 | th.innerHTML = element.title; 60 | th.className = 'olturf-form-header'; 61 | row.appendChild(th); 62 | 63 | const td = document.createElement('td'); 64 | td.className = 'olturf-form-data'; 65 | 66 | const control = document.createElement(element.type); 67 | control.className = 'olturf-form-input'; 68 | utils.extend(element.attributes, control); 69 | 70 | // Check if this is a selection and add pulldown options 71 | if (element.type === 'select') { 72 | control.className = 'olturf-form-select'; 73 | if (element.options !== undefined) { 74 | element.options.forEach(function(opt) { 75 | const option = document.createElement('option'); 76 | option.innerHTML = opt.text; 77 | option.className = 'olturf-form-option'; 78 | utils.extend(opt.attributes, option); 79 | control.appendChild(option); 80 | }); 81 | } 82 | } 83 | 84 | // Add control to table 85 | td.appendChild(control); 86 | row.appendChild(td); 87 | table.appendChild(row); 88 | }); 89 | 90 | // Add table to form and form to container 91 | form.appendChild(table); 92 | container.appendChild(form); 93 | return form; 94 | }; 95 | -------------------------------------------------------------------------------- /src/js/handler.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Callback handler 3 | * @constructor 4 | * @param {olturf.Toolbar} toolbar olturf toolbar 5 | * @private 6 | */ 7 | const Handler = function(toolbar) { 8 | this.toolbar = toolbar; 9 | }; 10 | 11 | /** 12 | * Default function called by each control when turf function is completed. 13 | * @param {string} name Name of olturf control being handled 14 | * @param {object} output Output of turf function 15 | * @param {object} inputs Inputs provided to turf function as properties 16 | * @private 17 | */ 18 | Handler.prototype.callback = function(name, output, inputs) { 19 | const control = this.toolbar.olturf.controls[name]; 20 | 21 | // First handle controls with custom messages 22 | // then handle controls that add output features to map 23 | if (output === null) { 24 | control.showMessage(name + ' returned null'); 25 | } else if (name === 'area') { 26 | control.showMessage('area = ' + output + ' msq'); 27 | } else if (name === 'bearing') { 28 | control.showMessage('bearing = ' + output + ' degrees'); 29 | } else if (name === 'distance') { 30 | control.showMessage('distance = ' + output + ' ' + inputs.units); 31 | } else if (name === 'inside') { 32 | let message = 'Point is'; 33 | if (output === false) { 34 | message += ' not'; 35 | } 36 | message += ' inside polygon.'; 37 | control.showMessage(message); 38 | } else if (name === 'line-distance') { 39 | control.showMessage('length = ' + output + ' ' + inputs.units); 40 | } else if (name === 'planepoint') { 41 | control.showMessage('z = ' + output); 42 | } else { 43 | control.addFeatures(output); 44 | } 45 | }; 46 | 47 | export default Handler; 48 | -------------------------------------------------------------------------------- /src/js/hex-grid.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'hex-grid'; 5 | 6 | /* 7 | * Generate Hex Grid 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idCellSize = utils.getName([name, 'cell-size'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idType = utils.getName([name, 'type'], control.prefix); 15 | const idOk = utils.getName([name, 'ok'], control.prefix); 16 | const idUnits = utils.getName([name, 'units'], control.prefix); 17 | 18 | const onOK = function() { 19 | try { 20 | // Gather selected features 21 | const collection = utils.getCollection(control, 1, Infinity); 22 | 23 | // Gather form inputs 24 | const cellSize = utils.getFormNumber(idCellSize, 'cell size'); 25 | const type = utils.getFormString(idType, 'grid type'); 26 | const units = utils.getFormString(idUnits, 'units'); 27 | const triangles = (type === 'triangles'); 28 | 29 | // Collect polygons 30 | const bbox = turf.bbox(collection); 31 | const output = turf.hexGrid(bbox, cellSize, {units, triangles}); 32 | 33 | // Remove form and display results 34 | control.showForm(); 35 | const inputs = { 36 | bbox: bbox, 37 | cellSize: cellSize, 38 | units: units, 39 | triangles: triangles, 40 | }; 41 | control.toolbar.olturf.handler.callback(name, output, inputs); 42 | } catch (e) { 43 | control.showMessage(e); 44 | } 45 | }; 46 | 47 | const onCancel = function() { 48 | control.showForm(); 49 | }; 50 | 51 | const controls = [ 52 | utils.getControlNumber(idCellSize, 'Cell Size', 'Dimension of cell', '1', 53 | 'any', '0'), 54 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 55 | utils.getControlSelect(idType, 'Type', utils.getOptionsGrids()), 56 | utils.getControlInput(idOk, onOK, '', 'OK'), 57 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 58 | ]; 59 | 60 | control.showForm(controls, idForm); 61 | }; 62 | 63 | export default { 64 | create: function(toolbar, prefix) { 65 | const title = 'Generate Hex Grid'; 66 | return Control.create(toolbar, prefix, name, title, action); 67 | }, 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /src/js/inside.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'inside'; 5 | 6 | /* 7 | * Compute if point is inside polygon 8 | */ 9 | const action = function(control) { 10 | // Gather point and polygon selected 11 | const collection = utils.getCollection(control, 2, 2); 12 | const points = utils.getPoints(collection, 1, 1); 13 | const polygons = utils.getPolygonsAll(collection, 1, 1); 14 | const point = points[0]; 15 | const polygon = polygons[0]; 16 | 17 | const output = turf.booleanPointInPolygon(point, polygon); 18 | const inputs = { 19 | point: point, 20 | polygon: polygon, 21 | }; 22 | control.toolbar.olturf.handler.callback(name, output, inputs); 23 | }; 24 | 25 | export default { 26 | create: function(toolbar, prefix) { 27 | const title = 'Point inside polygon?'; 28 | return Control.create(toolbar, prefix, name, title, action); 29 | }, 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /src/js/intersect.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'intersect'; 5 | 6 | /* 7 | * Compute intersection of two polygons 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, 2); 11 | const polygons = utils.getPolygonsAll(collection, 2, 2); 12 | 13 | const poly1 = polygons[0]; 14 | const poly2 = polygons[1]; 15 | const output = turf.intersect(poly1, poly2); 16 | const inputs = { 17 | poly1: poly1, 18 | poly2: poly2, 19 | }; 20 | control.toolbar.olturf.handler.callback(name, output, inputs); 21 | }; 22 | 23 | export default { 24 | create: function(toolbar, prefix) { 25 | const title = 'Create Intersection Polygon'; 26 | return Control.create(toolbar, prefix, name, title, action); 27 | }, 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /src/js/isolines.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'isolines'; 5 | 6 | /* 7 | * Create isolines 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idBreaks = utils.getName([name, 'breaks'], control.prefix); 12 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idZ = utils.getName([name, 'zProperty'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 1, Infinity); 21 | 22 | // Gather form inputs 23 | const breaks = utils.getFormArray(idBreaks, 'breaks'); 24 | const zProperty = utils.getFormString(idZ, 'zProperty'); 25 | 26 | // Generate isolines features 27 | const output = turf.isolines(collection, breaks, {zProperty}); 28 | 29 | // Remove form and display results 30 | control.showForm(); 31 | const inputs = { 32 | points: collection, 33 | zProperty: zProperty, 34 | breaks: breaks, 35 | }; 36 | control.toolbar.olturf.handler.callback(name, output, inputs); 37 | } catch (e) { 38 | control.showMessage(e); 39 | } 40 | }; 41 | 42 | const onCancel = function() { 43 | control.showForm(); 44 | }; 45 | 46 | const controls = [ 47 | utils.getControlText(idZ, 'Z Property', 48 | 'Property name in points from which z-values will be pulled'), 49 | utils.getControlText(idBreaks, 'Breaks', 50 | 'Comma separated list of where to draw contours'), 51 | utils.getControlInput(idOk, onOK, '', 'OK'), 52 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 53 | ]; 54 | 55 | control.showForm(controls, idForm); 56 | }; 57 | 58 | export default { 59 | create: function(toolbar, prefix) { 60 | const title = 'Create isolines'; 61 | return Control.create(toolbar, prefix, name, title, action); 62 | }, 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /src/js/kinks.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'kinks'; 5 | 6 | /* 7 | * Compute polygon kinks 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, 1); 11 | const polygons = utils.getPolygons(collection, 1, 1); 12 | const polygon = polygons[0]; 13 | const output = turf.kinks(polygon); 14 | if (output.features.length === 0) { 15 | throw new Error('No kinks found.'); 16 | } 17 | const inputs = { 18 | polygon: polygon, 19 | }; 20 | control.toolbar.olturf.handler.callback(name, output, inputs); 21 | }; 22 | 23 | export default { 24 | create: function(toolbar, prefix) { 25 | const title = 'Create polygon self-intersections'; 26 | return Control.create(toolbar, prefix, name, title, action); 27 | }, 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /src/js/line-distance.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'line-distance'; 5 | 6 | /* 7 | * Compute length of feature 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idUnits = utils.getName([name, 'units'], control.prefix); 15 | 16 | const onOK = function() { 17 | try { 18 | // Gather selected features 19 | const collection = utils.getCollection(control, 1, Infinity); 20 | 21 | // Gather form inputs 22 | const units = utils.getFormString(idUnits, 'units'); 23 | 24 | // Compute length 25 | const output = turf.lineDistance(collection, {units}); 26 | 27 | // Remove form and display results 28 | control.showForm(); 29 | const inputs = { 30 | line: collection, 31 | units: units, 32 | }; 33 | control.toolbar.olturf.handler.callback(name, output, inputs); 34 | } catch (e) { 35 | control.showMessage(e); 36 | } 37 | }; 38 | 39 | const onCancel = function() { 40 | control.showForm(); 41 | }; 42 | 43 | const controls = [ 44 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 45 | utils.getControlInput(idOk, onOK, '', 'OK'), 46 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 47 | ]; 48 | 49 | control.showForm(controls, idForm); 50 | }; 51 | 52 | export default { 53 | create: function(toolbar, prefix) { 54 | const title = 'Measure Length'; 55 | return Control.create(toolbar, prefix, name, title, action); 56 | }, 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /src/js/line-slice-along.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'line-slice-along'; 5 | 6 | /* 7 | * Compute line slice 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idStart = utils.getName([name, 'start'], control.prefix); 15 | const idStop = utils.getName([name, 'stop'], control.prefix); 16 | const idUnits = utils.getName([name, 'units'], control.prefix); 17 | 18 | const onOK = function() { 19 | try { 20 | // Gather line seleted 21 | const collection = utils.getCollection(control, 1, 1); 22 | const lines = utils.getLines(collection, 1, 1); 23 | const line = lines[0]; 24 | 25 | // Gather form inputs 26 | const start = utils.getFormNumber(idStart, 'start'); 27 | const stop = utils.getFormNumber(idStop, 'stop'); 28 | 29 | const isOrdered = (start < stop); 30 | if (isOrdered !== true) { 31 | throw new Error('Start must be less than stop'); 32 | } 33 | 34 | // Truncate at line length otherwise lineSliceAlong fails 35 | const units = utils.getFormString(idUnits, 'units'); 36 | const length = turf.lineDistance(line, {units}); 37 | if (start > length) { 38 | throw new Error('Start must be less than line length'); 39 | } 40 | if (stop > length) { 41 | throw new Error('Stop must be less than line length'); 42 | } 43 | 44 | // Collect polygons 45 | const output = turf.lineSliceAlong(line, start, stop, {units}); 46 | 47 | // Remove form and display results 48 | control.showForm(); 49 | const inputs = { 50 | line: line, 51 | start: start, 52 | stop: stop, 53 | units: units, 54 | }; 55 | control.toolbar.olturf.handler.callback(name, output, inputs); 56 | } catch (e) { 57 | control.showMessage(e); 58 | } 59 | }; 60 | 61 | const onCancel = function() { 62 | control.showForm(); 63 | }; 64 | 65 | const controls = [ 66 | utils.getControlNumber(idStart, 'Start', 67 | 'Starting distance along the line', '0', 'any', '0'), 68 | utils.getControlNumber(idStop, 'Stop', 'Stoping distance along the line', 69 | '0', 'any', '0'), 70 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 71 | utils.getControlInput(idOk, onOK, '', 'OK'), 72 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 73 | ]; 74 | 75 | control.showForm(controls, idForm); 76 | }; 77 | 78 | export default { 79 | create: function(toolbar, prefix) { 80 | const title = 'Create line slice'; 81 | return Control.create(toolbar, prefix, name, title, action); 82 | }, 83 | }; 84 | 85 | -------------------------------------------------------------------------------- /src/js/main.js: -------------------------------------------------------------------------------- 1 | import controls from './controls'; 2 | import Handler from './handler'; 3 | import toolbars from './toolbars'; 4 | 5 | /** 6 | * @namespace olturf 7 | */ 8 | const olturf = { 9 | controls, 10 | Handler, 11 | toolbars, 12 | }; 13 | 14 | /** 15 | * ol main namespace 16 | * @external ol 17 | * @see {@link http://openlayers.org/en/latest/apidoc/ol.html} 18 | */ 19 | 20 | /** 21 | * ol control namespace 22 | * @memberof external:ol 23 | * @namespace control 24 | * @see {@link http://openlayers.org/en/latest/apidoc/ol.control.html} 25 | */ 26 | 27 | /** 28 | * ol control base class 29 | * @class Control 30 | * @memberof external:ol.control 31 | * @see {@link http://openlayers.org/en/latest/apidoc/ol.control.Control.html} 32 | */ 33 | 34 | /** 35 | * Function that handles processing the output of the olturf controls. 36 | * @callback Callback 37 | * @memberOf olturf 38 | * @param {string} name Name of control to process 39 | * @param {object} inputs Inputs passed to the control's corresponding turf 40 | * function 41 | * @param {*} output Output returned by the turf function 42 | */ 43 | 44 | /** 45 | * @description olturf custom callback handler. 46 | * @typedef {object} Handler 47 | * @memberOf olturf 48 | * @property {olturf.Callback} callback Function to handle processing 49 | * turf commands. 50 | */ 51 | 52 | /** 53 | * @description olturf constructor options. 54 | * @typedef {object} Options 55 | * @memberOf olturf 56 | * @property {string[]} [controls={@link olturf.toolbars.all}] List of names of 57 | * control to enable. 58 | * @property {olturf.Handler} [handler='undefined'] Optional function that 59 | * handles processing the output of the olturf controls. This is 60 | * useful to bypass the default handler and provide custom processing 61 | * of the results. The default handler adds features to the map or 62 | * displays a message with any values returned by the turf function. 63 | * @property {string} [prefix='olturf'] Prefix to apply to control element 64 | * IDs. Only needed to make IDs unique if multiple instances of an 65 | * olturf toolbar are used on the same page. 66 | * @property {string} [style='olturf-toolbar'] The name of the class to apply 67 | * to the toolbar. 68 | */ 69 | 70 | /** 71 | * OpenLayers Turf Control 72 | * @constructor 73 | * @extends {external:ol.control.Control} 74 | * @param {object} [options] Control options extends ol.control.Control options 75 | * @param {olturf.Options} [options.olturf] olturf specific options 76 | * @memberof olturf 77 | */ 78 | const Toolbar = function(options) { 79 | const self = this; 80 | 81 | // Process options 82 | const opts = options || {}; 83 | opts.olturf = opts.olturf || {}; 84 | if (opts.olturf.controls === undefined) { 85 | // Default is to enable all controls and display them in this order. 86 | opts.olturf.controls = olturf.toolbars.all(); 87 | } 88 | 89 | // Set control handler 90 | if (opts.olturf.handler === undefined) { 91 | opts.olturf.handler = new olturf.Handler(self); 92 | } 93 | 94 | // Define default style 95 | if (opts.olturf.style === undefined) { 96 | opts.olturf.style = 'olturf-toolbar'; 97 | } 98 | 99 | // Define default prefix 100 | if (opts.olturf.prefix === undefined) { 101 | opts.olturf.prefix = 'olturf'; 102 | } 103 | 104 | // Create turf toolbar DOM if not provided by user 105 | if (opts.element === undefined) { 106 | opts.element = document.createElement('div'); 107 | } 108 | if (opts.element.className === '') { 109 | opts.element.className = opts.olturf.style + ' ol-unselectable ol-control'; 110 | } 111 | 112 | // Add controls to toolbar 113 | const olturfcontrols = {}; 114 | opts.olturf.controls.forEach(function(name) { 115 | if (olturf.controls[name] !== undefined) { 116 | // Store control in olturf member and add button to div 117 | const control = olturf.controls[name].create(self, opts.olturf.prefix); 118 | olturfcontrols[name] = control; 119 | opts.element.appendChild(control.element); 120 | } 121 | }); 122 | 123 | // Object to internally store olturf specific attributes 124 | this.olturf = { 125 | controls: olturfcontrols, 126 | element: opts.element, 127 | handler: opts.olturf.handler, 128 | }; 129 | 130 | ol.control.Control.call(this, opts); 131 | }; 132 | ol.inherits(Toolbar, ol.control.Control); 133 | 134 | export default { 135 | toolbars, 136 | Toolbar, 137 | }; 138 | -------------------------------------------------------------------------------- /src/js/midpoint.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'midpoint'; 5 | 6 | /* 7 | * Compute midpoint 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, 2); 11 | const points = utils.getPoints(collection, 2, 2); 12 | const from = points[0]; 13 | const to = points[1]; 14 | const output = turf.midpoint(from, to); 15 | const inputs = { 16 | from: from, 17 | to: to, 18 | }; 19 | control.toolbar.olturf.handler.callback(name, output, inputs); 20 | }; 21 | 22 | export default { 23 | create: function(toolbar, prefix) { 24 | const title = 'Measure Midpoint'; 25 | return Control.create(toolbar, prefix, name, title, action); 26 | }, 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /src/js/nearest.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'nearest'; 5 | 6 | /* 7 | * Compute nearest point 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, Infinity); 11 | const numPoints = collection.features.length; 12 | const pts = utils.getPoints(collection, numPoints, numPoints); 13 | const targetPoint = pts[0]; 14 | const points = turf.featureCollection(pts.slice(1)); 15 | 16 | const output = turf.nearest(targetPoint, points); 17 | const inputs = { 18 | targetPoint: targetPoint, 19 | points: points, 20 | }; 21 | control.toolbar.olturf.handler.callback(name, output, inputs); 22 | }; 23 | 24 | export default { 25 | create: function(toolbar, prefix) { 26 | const title = 'Find set point nearest to first point'; 27 | return Control.create(toolbar, prefix, name, title, action); 28 | }, 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /src/js/planepoint.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'planepoint'; 5 | 6 | /* 7 | * Triangulate a point in a plane 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, 2); 11 | const pt = utils.getPoints(collection, 1, 1); 12 | const tr = utils.getPolygons(collection, 1, 1); 13 | const point = pt[0]; 14 | const triangle = tr[0]; 15 | 16 | const output = turf.planepoint(point, triangle); 17 | const inputs = { 18 | point: point, 19 | triangle: triangle, 20 | }; 21 | control.toolbar.olturf.handler.callback(name, output, inputs); 22 | }; 23 | 24 | export default { 25 | create: function(toolbar, prefix) { 26 | const title = 'Triangulate a point in a plane'; 27 | return Control.create(toolbar, prefix, name, title, action); 28 | }, 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /src/js/point-grid.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'point-grid'; 5 | 6 | /* 7 | * Generate Point Grid 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idCellSize = utils.getName([name, 'cell-size'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idUnits = utils.getName([name, 'units'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 1, Infinity); 21 | 22 | // Gather form inputs 23 | const cellSize = utils.getFormNumber(idCellSize, 'cell size'); 24 | const units = utils.getFormString(idUnits, 'units'); 25 | 26 | // Collect polygons 27 | const bbox = turf.bbox(collection); 28 | const output = turf.pointGrid(bbox, cellSize, {units}); 29 | 30 | // Remove form and display results 31 | control.showForm(); 32 | const inputs = { 33 | bbox: bbox, 34 | cellSize: cellSize, 35 | units: units, 36 | }; 37 | control.toolbar.olturf.handler.callback(name, output, inputs); 38 | } catch (e) { 39 | control.showMessage(e); 40 | } 41 | }; 42 | 43 | const onCancel = function() { 44 | control.showForm(); 45 | }; 46 | 47 | const controls = [ 48 | utils.getControlNumber(idCellSize, 'Cell Size', 'Dimension of cell', '1', 49 | 'any', '0'), 50 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 51 | utils.getControlInput(idOk, onOK, '', 'OK'), 52 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 53 | ]; 54 | 55 | control.showForm(controls, idForm); 56 | }; 57 | 58 | export default { 59 | create: function(toolbar, prefix) { 60 | const title = 'Generate Point Grid'; 61 | return Control.create(toolbar, prefix, name, title, action); 62 | }, 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /src/js/point-on-line.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'point-on-line'; 5 | 6 | /* 7 | * Compute point on line 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, 2); 11 | const points = utils.getPoints(collection, 1, 1); 12 | const lines = utils.getLines(collection, 1, 1); 13 | const line = lines[0]; 14 | const point = points[0]; 15 | 16 | const output = turf.pointOnLine(line, point); 17 | const inputs = { 18 | line: line, 19 | point: point, 20 | }; 21 | control.toolbar.olturf.handler.callback(name, output, inputs); 22 | }; 23 | 24 | export default { 25 | create: function(toolbar, prefix) { 26 | const title = 'Project point on line'; 27 | return Control.create(toolbar, prefix, name, title, action); 28 | }, 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /src/js/point-on-surface.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'point-on-surface'; 5 | 6 | /* 7 | * Compute pointOnSurface 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, Infinity); 11 | 12 | const output = turf.pointOnFeature(collection); 13 | const inputs = { 14 | fc: collection, 15 | }; 16 | control.toolbar.olturf.handler.callback(name, output, inputs); 17 | }; 18 | 19 | export default { 20 | create: function(toolbar, prefix) { 21 | const title = 'Measure Point on Surface'; 22 | return Control.create(toolbar, prefix, name, title, action); 23 | }, 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /src/js/popup.js: -------------------------------------------------------------------------------- 1 | import utils from './utils'; 2 | 3 | /** 4 | * Displays a message in a popup window. 5 | * @param {string} message Message to display 6 | * @param {function} callback Callback function when user closes popup. 7 | * @param {object} parent Popup parent element 8 | * @param {object} attributes Popup div attributes 9 | * @return {Element} Popup DOM element 10 | * @private 11 | */ 12 | export default function display(message, callback, parent, attributes) { 13 | // Popup id 14 | const id = 'olturf-popup'; 15 | 16 | // Remove existing popup 17 | const currentPopup = document.getElementById(id); 18 | let currentParent = null; 19 | if (currentPopup !== null) { 20 | currentParent = currentPopup.parentNode; 21 | if (currentParent !== null) { 22 | currentParent.removeChild(currentPopup); 23 | } 24 | } 25 | 26 | // If no message then we are just closing the popup 27 | if (message === undefined || message === null) { 28 | return; 29 | } 30 | 31 | // onclose callback wrapper 32 | const onClick = function() { 33 | if (callback !== undefined && callback !== null) { 34 | callback(); 35 | } 36 | display(); 37 | }; 38 | 39 | // If no parent then add to body 40 | let container = document.body; 41 | if (parent !== undefined && parent !== null) { 42 | container = parent; 43 | } 44 | 45 | // Create a div to contain popup 46 | const popup = document.createElement('div'); 47 | popup.className = id; 48 | popup.id = id; 49 | utils.extend(attributes, popup); 50 | 51 | // Create a div to contain message 52 | const divMessage = document.createElement('div'); 53 | divMessage.className = 'olturf-popup-message'; 54 | divMessage.innerHTML = message; 55 | 56 | // Create a button 57 | const button = document.createElement('button'); 58 | button.className = 'olturf-popup-button'; 59 | button.innerHTML = 'OK'; 60 | button.onclick = onClick; 61 | button.type = 'button'; 62 | 63 | const divButton = document.createElement('div'); 64 | divButton.className = 'olturf-popup-button-container'; 65 | divButton.appendChild(button); 66 | 67 | // Create popup 68 | popup.appendChild(divMessage); 69 | popup.appendChild(divButton); 70 | container.appendChild(popup); 71 | 72 | return popup; 73 | }; 74 | -------------------------------------------------------------------------------- /src/js/random.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'random'; 5 | 6 | /* 7 | * Create random data 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idCount = utils.getName([name, 'count'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idMaxRadialLength = utils.getName([name, 'max-radial-length'], 15 | control.prefix); 16 | const idNumVertices = utils.getName([name, 'num-vertices'], control.prefix); 17 | const idOk = utils.getName([name, 'ok'], control.prefix); 18 | const idType = utils.getName([name, 'type'], control.prefix); 19 | 20 | const onOK = function() { 21 | try { 22 | // Gather selected features 23 | let bbox = null; 24 | const collection = utils.getCollection(control, 0, Infinity); 25 | if (collection.features.length !== 0) { 26 | bbox = turf.bbox(collection); 27 | } 28 | 29 | // Get form inputs 30 | const count = utils.getFormInteger(idCount, 'count'); 31 | const maxRadialLength = utils.getFormInteger(idMaxRadialLength, 32 | 'maximum radial length'); 33 | const numVertices = utils.getFormInteger(idNumVertices, 34 | 'number of vertices'); 35 | const type = utils.getFormString(idType, 'type'); 36 | 37 | // Generate random polygons 38 | const options = { 39 | max_radial_length: maxRadialLength, 40 | num_vertices: numVertices, 41 | }; 42 | if (bbox !== null) { 43 | options.bbox = bbox; 44 | } 45 | let output = null; 46 | if (type === 'points') { 47 | output = turf.randomPoint(count, options); 48 | } else if (type === 'polygons') { 49 | output = turf.randomPolygon(count, options); 50 | } 51 | 52 | // Remove form and display results 53 | control.showForm(); 54 | const inputs = { 55 | type: type, 56 | count: count, 57 | options: options, 58 | }; 59 | control.toolbar.olturf.handler.callback(name, output, inputs); 60 | } catch (e) { 61 | control.showMessage(e); 62 | } 63 | }; 64 | 65 | const onCancel = function() { 66 | control.showForm(); 67 | }; 68 | 69 | const controls = [ 70 | utils.getControlSelect(idType, 'Type', utils.getOptionsGeometry()), 71 | utils.getControlNumber(idCount, 'Count', 72 | 'How many geometries should be generated', '1', '1', '1'), 73 | utils.getControlNumber(idNumVertices, '# Vertices', 74 | 'Used only for polygon type', '10', '1', '3'), 75 | utils.getControlNumber(idMaxRadialLength, 'Max Length', 76 | 'Maximum degrees a polygon can extent outwards from its center ' + 77 | '(degrees)', '10', '0.01', '0', '180'), 78 | utils.getControlInput(idOk, onOK, '', 'OK'), 79 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 80 | ]; 81 | 82 | control.showForm(controls, idForm); 83 | }; 84 | 85 | export default { 86 | create: function(toolbar, prefix) { 87 | const title = 'Create random data'; 88 | return Control.create(toolbar, prefix, name, title, action); 89 | }, 90 | }; 91 | 92 | -------------------------------------------------------------------------------- /src/js/sample.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'sample'; 5 | 6 | /* 7 | * Randomly sample features 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idCount = utils.getName([name, 'count'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | 16 | const onOK = function() { 17 | try { 18 | // Gather selected features 19 | const collection = utils.getCollection(control, 1, Infinity); 20 | 21 | // Get form inputs 22 | const count = utils.getFormInteger(idCount, 'count'); 23 | if (count > collection.features.length) { 24 | throw new Error('Feature count must be greater than sampling count.'); 25 | } 26 | 27 | // Generate sample features 28 | const output = turf.sample(collection, count); 29 | 30 | // Remove form and display results 31 | control.showForm(); 32 | const inputs = { 33 | featurecollection: collection, 34 | num: count, 35 | }; 36 | control.toolbar.olturf.handler.callback(name, output, inputs); 37 | } catch (e) { 38 | control.showMessage(e); 39 | } 40 | }; 41 | 42 | const onCancel = function() { 43 | control.showForm(); 44 | }; 45 | 46 | const controls = [ 47 | utils.getControlNumber(idCount, 'Count', 48 | 'Number of random features to sample', '1', '1', '1'), 49 | utils.getControlInput(idOk, onOK, '', 'OK'), 50 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 51 | ]; 52 | 53 | control.showForm(controls, idForm); 54 | }; 55 | 56 | export default { 57 | create: function(toolbar, prefix) { 58 | const title = 'Randomly sample features'; 59 | return Control.create(toolbar, prefix, name, title, action); 60 | }, 61 | }; 62 | 63 | -------------------------------------------------------------------------------- /src/js/simplify.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'simplify'; 5 | 6 | /* 7 | * Simplify shape 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idQuality = utils.getName([name, 'quality'], control.prefix); 15 | const idTolerance = utils.getName([name, 'tolerance'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 1, Infinity); 21 | 22 | // Get form inputs 23 | const tolerance = utils.getFormNumber(idTolerance, 'tolerance'); 24 | const quality = utils.getFormString(idQuality, 'quality'); 25 | const highQuality = (quality === 'high'); 26 | 27 | // Collect polygons 28 | const output = turf.simplify(collection, {tolerance, highQuality}); 29 | 30 | // Remove form and display results 31 | control.showForm(); 32 | const inputs = { 33 | feature: collection, 34 | tolerance: tolerance, 35 | highQuality: highQuality, 36 | }; 37 | control.toolbar.olturf.handler.callback(name, output, inputs); 38 | } catch (e) { 39 | control.showMessage(e); 40 | } 41 | }; 42 | 43 | const onCancel = function() { 44 | control.showForm(); 45 | }; 46 | 47 | const controls = [ 48 | utils.getControlNumber(idTolerance, 'Tolerance', 49 | 'Simplification tolerance', '1', '0.01', '0'), 50 | utils.getControlSelect(idQuality, 'Quality', utils.getOptionsQuality()), 51 | utils.getControlInput(idOk, onOK, '', 'OK'), 52 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 53 | ]; 54 | 55 | control.showForm(controls, idForm); 56 | }; 57 | 58 | export default { 59 | create: function(toolbar, prefix) { 60 | const title = 'Simplify shape'; 61 | return Control.create(toolbar, prefix, name, title, action); 62 | }, 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /src/js/square-grid.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'square-grid'; 5 | 6 | /* 7 | * Generate Square Grid 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idCellSize = utils.getName([name, 'cell-size'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idUnits = utils.getName([name, 'units'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 1, Infinity); 21 | 22 | // Get form inputs 23 | const cellSize = utils.getFormNumber(idCellSize, 'cell size'); 24 | const units = utils.getFormString(idUnits, 'units'); 25 | 26 | // Collect polygons 27 | const bbox = turf.bbox(collection); 28 | const output = turf.squareGrid(bbox, cellSize, {units}); 29 | 30 | // Remove form and display results 31 | control.showForm(); 32 | const inputs = { 33 | bbox: bbox, 34 | cellSize: cellSize, 35 | units: units, 36 | }; 37 | control.toolbar.olturf.handler.callback(name, output, inputs); 38 | } catch (e) { 39 | control.showMessage(e); 40 | } 41 | }; 42 | 43 | const onCancel = function() { 44 | control.showForm(); 45 | }; 46 | 47 | const controls = [ 48 | utils.getControlNumber(idCellSize, 'Cell Size', 'Dimension of cell', '1', 49 | 'any', '0'), 50 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 51 | utils.getControlInput(idOk, onOK, '', 'OK'), 52 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 53 | ]; 54 | 55 | control.showForm(controls, idForm); 56 | }; 57 | 58 | export default { 59 | create: function(toolbar, prefix) { 60 | const title = 'Generate Square Grid'; 61 | return Control.create(toolbar, prefix, name, title, action); 62 | }, 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /src/js/square.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'square'; 5 | 6 | /* 7 | * Compute square 8 | */ 9 | const action = function(control) { 10 | // Gather selected features 11 | const collection = utils.getCollection(control, 1, Infinity); 12 | const bbox = turf.bbox(collection); 13 | const square = turf.square(bbox); 14 | 15 | const output = turf.bboxPolygon(square); 16 | const inputs = { 17 | bbox: bbox, 18 | }; 19 | control.toolbar.olturf.handler.callback(name, output, inputs); 20 | }; 21 | 22 | export default { 23 | create: function(toolbar, prefix) { 24 | const title = 'Create Square'; 25 | return Control.create(toolbar, prefix, name, title, action); 26 | }, 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /src/js/tag.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'tag'; 5 | 6 | /* 7 | * Collect point attributes within polygon 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idField = utils.getName([name, 'field-property'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idOutField = utils.getName([name, 'out-field-property'], 16 | control.prefix); 17 | 18 | const onOK = function() { 19 | try { 20 | // Gather selected features 21 | const collection = utils.getCollection(control, 2, Infinity); 22 | const points = utils.getPoints(collection, 1, 23 | collection.features.length - 1); 24 | const numPolygons = collection.features.length - points.length; 25 | const polygons = utils.getPolygons(collection, numPolygons, numPolygons); 26 | 27 | // Get form inputs 28 | const field = utils.getFormString(idField, 'field'); 29 | const outField = utils.getFormString(idOutField, 'out field'); 30 | 31 | // Collect polygons 32 | const inPolygons = turf.featureCollection(polygons); 33 | const inPoints = turf.featureCollection(points); 34 | const output = turf.tag(inPoints, inPolygons, field, outField); 35 | 36 | // Remove form and display results 37 | control.showForm(); 38 | const inputs = { 39 | points: inPoints, 40 | polygons: inPolygons, 41 | field: field, 42 | outField: outField, 43 | }; 44 | control.toolbar.olturf.handler.callback(name, output, inputs); 45 | } catch (e) { 46 | control.showMessage(e); 47 | } 48 | }; 49 | 50 | const onCancel = function() { 51 | control.showForm(); 52 | }; 53 | 54 | const controls = [ 55 | utils.getControlText(idField, 'Field', 56 | 'Property in polygons to add to joined point features'), 57 | utils.getControlText(idOutField, 'Out Field', 58 | 'Property in points in which to store joined property from polygons'), 59 | utils.getControlInput(idOk, onOK, '', 'OK'), 60 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 61 | ]; 62 | 63 | control.showForm(controls, idForm); 64 | }; 65 | 66 | export default { 67 | create: function(toolbar, prefix) { 68 | const title = 'Perform spatial join of points and polygons'; 69 | return Control.create(toolbar, prefix, name, title, action); 70 | }, 71 | }; 72 | 73 | -------------------------------------------------------------------------------- /src/js/tesselate.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'tesselate'; 5 | 6 | /* 7 | * Compute tesselation 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 1, 1); 11 | const polygons = utils.getPolygons(collection, 1, 1); 12 | const polygon = polygons[0]; 13 | 14 | const output = turf.tesselate(polygon); 15 | const inputs = { 16 | polygon: polygon, 17 | }; 18 | control.toolbar.olturf.handler.callback(name, output, inputs); 19 | }; 20 | 21 | export default { 22 | create: function(toolbar, prefix) { 23 | const title = 'Create tesselation'; 24 | return Control.create(toolbar, prefix, name, title, action); 25 | }, 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /src/js/tin.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'tin'; 5 | 6 | /* 7 | * Compute tin mesh 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idForm = utils.getName([name, 'form'], control.prefix); 13 | const idOk = utils.getName([name, 'ok'], control.prefix); 14 | const idZ = utils.getName([name, 'z'], control.prefix); 15 | 16 | const onOK = function() { 17 | try { 18 | let collection = utils.getCollection(control, 3, Infinity); 19 | const numPoints = collection.features.length; 20 | const points = utils.getPoints(collection, numPoints, numPoints); 21 | collection = turf.featureCollection(points); 22 | 23 | // Get form inputs 24 | const z = utils.getFormString(idZ, 'z'); 25 | 26 | const output = turf.tin(collection, z); 27 | const inputs = { 28 | points: collection, 29 | z: z, 30 | }; 31 | control.toolbar.olturf.handler.callback(name, output, inputs); 32 | } catch (e) { 33 | control.showMessage(e); 34 | } 35 | }; 36 | 37 | const onCancel = function() { 38 | control.showForm(); 39 | }; 40 | 41 | const controls = [ 42 | utils.getControlText(idZ, 'Z', 43 | '(Optional) Property from which to pull z values'), 44 | utils.getControlInput(idOk, onOK, '', 'OK'), 45 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 46 | ]; 47 | 48 | control.showForm(controls, idForm); 49 | }; 50 | 51 | export default { 52 | create: function(toolbar, prefix) { 53 | const title = 'Create TIN'; 54 | return Control.create(toolbar, prefix, name, title, action); 55 | }, 56 | }; 57 | 58 | -------------------------------------------------------------------------------- /src/js/toolbars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @namespace toolbars 3 | * @memberof olturf 4 | */ 5 | 6 | /** 7 | * Aggregation toolbar: 'collect' 8 | * @memberof olturf.toolbars 9 | * @return {string[]} Control names for the aggregation toolbar 10 | */ 11 | function aggregation() { 12 | return ['collect']; 13 | }; 14 | 15 | /** 16 | * Classification toolbar: 'nearest' 17 | * @memberof olturf.toolbars 18 | * @return {string[]} Control names for the classification toolbar 19 | */ 20 | function classification() { 21 | return ['nearest']; 22 | }; 23 | 24 | /** 25 | * Data toolbar: 'random', 'sample' 26 | * @memberof olturf.toolbars 27 | * @return {string[]} Control names for the data toolbar 28 | */ 29 | function data() { 30 | return [ 31 | 'random', 32 | 'sample', 33 | ]; 34 | }; 35 | 36 | /** 37 | * Grids toolbar: 'hex-grid', 'point-grid', 'square-grid', 'triangle-grid', 38 | * 'tesselate' 39 | * @memberof olturf.toolbars 40 | * @return {string[]} Control names for the grids toolbar 41 | */ 42 | function grids() { 43 | return [ 44 | 'hex-grid', 45 | 'point-grid', 46 | 'square-grid', 47 | 'triangle-grid', 48 | 'tesselate', 49 | ]; 50 | }; 51 | 52 | /** 53 | * Interpolation toolbar: 'isolines', 'planepoint', 'tin' 54 | * @memberof olturf.toolbars 55 | * @return {string[]} Control names for the interpolation toolbar 56 | */ 57 | function interpolation() { 58 | return [ 59 | 'isolines', 60 | 'planepoint', 61 | 'tin', 62 | ]; 63 | }; 64 | 65 | /** 66 | * Joins toolbar: 'inside', 'tag', 'within' 67 | * @memberof olturf.toolbars 68 | * @return {string[]} Control names for the joins toolbar 69 | */ 70 | function joins() { 71 | return [ 72 | 'inside', 73 | 'tag', 74 | 'within', 75 | ]; 76 | }; 77 | 78 | /** 79 | * Measurement toolbar: 'distance', 'line-distance', 'area', 'bearing', 80 | * 'center-of-mass', 'center', 'centroid', 'midpoint', 81 | * 'point-on-surface', 'envelope', 'square', 'circle', 82 | * 'along', 'destination' 83 | * @memberof olturf.toolbars 84 | * @return {string[]} Control names for the measurement toolbar 85 | */ 86 | function measurement() { 87 | return [ 88 | 'distance', 89 | 'line-distance', 90 | 'area', 91 | 'bearing', 92 | 'center-of-mass', 93 | 'center', 94 | 'centroid', 95 | 'midpoint', 96 | 'point-on-surface', 97 | 'envelope', 98 | 'square', 99 | 'circle', 100 | 'along', 101 | 'destination', 102 | ]; 103 | }; 104 | 105 | /** 106 | * Miscellaneous toolbar: 'combine', 'explode', 'flip', 'kinks', 107 | * 'line-slice-along', 'point-on-line' 108 | * @memberof olturf.toolbars 109 | * @return {string[]} Control names for the miscellaneous toolbar 110 | */ 111 | function misc() { 112 | return [ 113 | 'combine', 114 | 'explode', 115 | 'flip', 116 | 'kinks', 117 | 'line-slice-along', 118 | 'point-on-line', 119 | ]; 120 | }; 121 | 122 | /** 123 | * Transformation toolbar: 'bezier', 'buffer', 'concave', 'convex', 124 | * 'difference', 'intersect', 'simplify', 'union' 125 | * @memberof olturf.toolbars 126 | * @return {string[]} Control names for the transformation toolbar 127 | */ 128 | function transformation() { 129 | return [ 130 | 'bezier', 131 | 'buffer', 132 | 'concave', 133 | 'convex', 134 | 'difference', 135 | 'intersect', 136 | 'simplify', 137 | 'union', 138 | ]; 139 | }; 140 | 141 | /** 142 | * Toolbar with all controls: 'distance', 'line-distance', 'area', 'bearing', 143 | * 'center-of-mass', 'center', 'centroid', 'midpoint', 'point-on-surface', 144 | * 'envelope', 'square', 'circle', 'along', 'destination', 'bezier', 'buffer', 145 | * 'concave', 'convex', 'difference', 'intersect', 'simplify', 'union', 146 | * 'combine', 'explode', 'flip', 'kinks', 'line-slice-along', 'point-on-line', 147 | * 'inside', 'tag', 'within', 'nearest', 'collect', 'random', 'sample', 148 | * 'isolines', 'planepoint', 'tin', 'hex-grid', 'point-grid', 'square-grid', 149 | * 'triangle-grid', 'tesselate' 150 | * @memberof olturf.toolbars 151 | * @return {string[]} Control names for all the controls 152 | */ 153 | function all() { 154 | const all = []; 155 | all.push(...measurement()); 156 | all.push(...transformation()); 157 | all.push(...misc()); 158 | all.push(...joins()); 159 | all.push(...classification()); 160 | all.push(...aggregation()); 161 | all.push(...data()); 162 | all.push(...interpolation()); 163 | all.push(...grids()); 164 | return all; 165 | }; 166 | 167 | export default { 168 | aggregation, 169 | all, 170 | classification, 171 | data, 172 | grids, 173 | interpolation, 174 | joins, 175 | measurement, 176 | misc, 177 | transformation, 178 | }; 179 | -------------------------------------------------------------------------------- /src/js/triangle-grid.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'triangle-grid'; 5 | 6 | /* 7 | * Generate Triangle Grid 8 | */ 9 | const action = function(control) { 10 | // Define control ids 11 | const idCancel = utils.getName([name, 'cancel'], control.prefix); 12 | const idCellSize = utils.getName([name, 'cell-size'], control.prefix); 13 | const idForm = utils.getName([name, 'form'], control.prefix); 14 | const idOk = utils.getName([name, 'ok'], control.prefix); 15 | const idUnits = utils.getName([name, 'units'], control.prefix); 16 | 17 | const onOK = function() { 18 | try { 19 | // Gather selected features 20 | const collection = utils.getCollection(control, 1, Infinity); 21 | 22 | // Get form inputs 23 | const cellSize = utils.getFormNumber(idCellSize, 'cell size'); 24 | const units = utils.getFormString(idUnits, 'units'); 25 | 26 | // Collect polygons 27 | const bbox = turf.bbox(collection); 28 | const output = turf.triangleGrid(bbox, cellSize, {units}); 29 | 30 | // Remove form and display results 31 | control.showForm(); 32 | const inputs = { 33 | bbox: bbox, 34 | cellSize: cellSize, 35 | units: units, 36 | }; 37 | control.toolbar.olturf.handler.callback(name, output, inputs); 38 | } catch (e) { 39 | control.showMessage(e); 40 | } 41 | }; 42 | 43 | const onCancel = function() { 44 | control.showForm(); 45 | }; 46 | 47 | const controls = [ 48 | utils.getControlNumber(idCellSize, 'Cell Size', 'Dimension of cell', '1', 49 | 'any', '0'), 50 | utils.getControlSelect(idUnits, 'Units', utils.getOptionsUnits()), 51 | utils.getControlInput(idOk, onOK, '', 'OK'), 52 | utils.getControlInput(idCancel, onCancel, '', 'Cancel'), 53 | ]; 54 | 55 | control.showForm(controls, idForm); 56 | }; 57 | 58 | export default { 59 | create: function(toolbar, prefix) { 60 | const title = 'Generate Triangle Grid'; 61 | return Control.create(toolbar, prefix, name, title, action); 62 | }, 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /src/js/union.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'union'; 5 | 6 | /* 7 | * Compute union of two polygons 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, 2); 11 | const polygons = utils.getPolygons(collection, 2, 2); 12 | const poly1 = polygons[0]; 13 | const poly2 = polygons[1]; 14 | 15 | const output = turf.union(poly1, poly2); 16 | const inputs = { 17 | poly1: poly1, 18 | poly2: poly2, 19 | }; 20 | control.toolbar.olturf.handler.callback(name, output, inputs); 21 | }; 22 | 23 | export default { 24 | create: function(toolbar, prefix) { 25 | const title = 'Create Union Polygon'; 26 | return Control.create(toolbar, prefix, name, title, action); 27 | }, 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /src/js/within.js: -------------------------------------------------------------------------------- 1 | import Control from './control'; 2 | import utils from './utils'; 3 | 4 | const name = 'within'; 5 | 6 | /* 7 | * Compute points within polygons 8 | */ 9 | const action = function(control) { 10 | const collection = utils.getCollection(control, 2, Infinity); 11 | const pts = utils.getPoints(collection, 1, collection.features.length - 1); 12 | const numPolygons = collection.features.length - pts.length; 13 | const polys = utils.getPolygons(collection, numPolygons, numPolygons); 14 | 15 | const points = turf.featureCollection(pts); 16 | const polygons = turf.featureCollection(polys); 17 | 18 | const output = turf.pointsWithinPolygon(points, polygons); 19 | if (output.features.length === 0) { 20 | throw new Error('No points found within.'); 21 | } 22 | const inputs = { 23 | points: points, 24 | polygons: polygons, 25 | }; 26 | control.toolbar.olturf.handler.callback(name, output, inputs); 27 | }; 28 | 29 | export default { 30 | create: function(toolbar, prefix) { 31 | const title = 'Find points within polygons'; 32 | return Control.create(toolbar, prefix, name, title, action); 33 | }, 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /test/index.css: -------------------------------------------------------------------------------- 1 | #map { 2 | height: 750px; 3 | width: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OpenLayers Turf test 5 | 6 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | const pti = require('puppeteer-to-istanbul'); 3 | 4 | const url = 'file://' + __dirname + '/index.html'; 5 | 6 | const isFormValid = async (name) => { 7 | const control = `#olturf-${name}`; 8 | const form = `${control}-form`; 9 | const cancel = `${form} input[value="Cancel"]`; 10 | expect((await page.$$(form)).length).toEqual(0); 11 | await expect(page).toClick(control); 12 | expect((await page.$$(form)).length).not.toEqual(0); 13 | await expect(page).toClick(cancel); 14 | expect((await page.$$(form)).length).toEqual(0); 15 | }; 16 | 17 | describe('olturf', () => { 18 | beforeAll(async () => { 19 | await page.coverage.startJSCoverage(); 20 | await page.goto(url); 21 | }); 22 | 23 | afterAll(async () => { 24 | const jsCoverage = await page.coverage.stopJSCoverage(); 25 | pti.write(jsCoverage); 26 | }); 27 | 28 | describe('API', () => { 29 | it('creates a valid olturf object', async () => { 30 | const olturf = await page.evaluate(() => olturf); 31 | expect(olturf).not.toBeNull(); 32 | }); 33 | }); 34 | 35 | describe('along', () => { 36 | it('creates a valid form', async () => { 37 | await isFormValid('along'); 38 | }); 39 | }); 40 | 41 | describe('bezier', () => { 42 | it('creates a valid form', async () => { 43 | await isFormValid('bezier'); 44 | }); 45 | }); 46 | 47 | describe('buffer', () => { 48 | it('creates a valid form', async () => { 49 | await isFormValid('buffer'); 50 | }); 51 | }); 52 | 53 | describe('circle', () => { 54 | it('creates a valid form', async () => { 55 | await isFormValid('circle'); 56 | }); 57 | }); 58 | 59 | describe('collect', () => { 60 | it('creates a valid form', async () => { 61 | await isFormValid('collect'); 62 | }); 63 | }); 64 | 65 | describe('concave', () => { 66 | it('creates a valid form', async () => { 67 | await isFormValid('concave'); 68 | }); 69 | }); 70 | 71 | describe('destination', () => { 72 | it('creates a valid form', async () => { 73 | await isFormValid('destination'); 74 | }); 75 | }); 76 | 77 | describe('distance', () => { 78 | it('creates a valid form', async () => { 79 | await isFormValid('distance'); 80 | }); 81 | }); 82 | 83 | describe('hex-grid', () => { 84 | it('creates a valid form', async () => { 85 | await isFormValid('hex-grid'); 86 | }); 87 | }); 88 | 89 | describe('isolines', () => { 90 | it('creates a valid form', async () => { 91 | await isFormValid('isolines'); 92 | }); 93 | }); 94 | 95 | describe('line-distance', () => { 96 | it('creates a valid form', async () => { 97 | await isFormValid('line-distance'); 98 | }); 99 | }); 100 | 101 | describe('line-slice-along', () => { 102 | it('creates a valid form', async () => { 103 | await isFormValid('line-slice-along'); 104 | }); 105 | }); 106 | 107 | describe('point-grid', () => { 108 | it('creates a valid form', async () => { 109 | await isFormValid('point-grid'); 110 | }); 111 | }); 112 | 113 | describe('random', () => { 114 | it('creates a valid form', async () => { 115 | await isFormValid('random'); 116 | }); 117 | }); 118 | 119 | describe('sample', () => { 120 | it('creates a valid form', async () => { 121 | await isFormValid('sample'); 122 | }); 123 | }); 124 | 125 | describe('simplify', () => { 126 | it('creates a valid form', async () => { 127 | await isFormValid('simplify'); 128 | }); 129 | }); 130 | 131 | describe('square-grid', () => { 132 | it('creates a valid form', async () => { 133 | await isFormValid('square-grid'); 134 | }); 135 | }); 136 | 137 | describe('tag', () => { 138 | it('creates a valid form', async () => { 139 | await isFormValid('tag'); 140 | }); 141 | }); 142 | 143 | describe('tin', () => { 144 | it('creates a valid form', async () => { 145 | await isFormValid('tin'); 146 | }); 147 | }); 148 | 149 | describe('triangle-grid', () => { 150 | it('creates a valid form', async () => { 151 | await isFormValid('triangle-grid'); 152 | }); 153 | }); 154 | }); 155 | --------------------------------------------------------------------------------