├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.js ├── circle.yml ├── cleanup.js ├── coverage ├── base.css ├── circle │ ├── circle.ts.html │ └── index.html ├── coverage.json ├── geojson │ ├── geojson.ts.html │ └── index.html ├── group │ ├── group.ts.html │ └── index.html ├── helpers │ ├── coodinateHandler.ts.html │ ├── geoJsonReader.ts.html │ └── index.html ├── index.html ├── map │ ├── index.html │ └── map.ts.html ├── models │ ├── index.html │ └── path.ts.html ├── prettify.css ├── services │ ├── globalId.service.ts.html │ ├── group.service.ts.html │ ├── helper.service.ts.html │ ├── index.html │ ├── map.service.ts.html │ └── popup.service.ts.html ├── sort-arrow-sprite.png └── test │ ├── index.html │ ├── main.test.ts.html │ ├── mock.component.ts.html │ └── tsloader.ts.html ├── karma.conf.js ├── ngx.leaflet.components.ts ├── package-lock.json ├── package.json ├── public_api.ts ├── rollup.config.esm.js ├── rollup.config.umd.js ├── src ├── circle │ ├── circle.spec.ts │ ├── circle.ts │ └── index.ts ├── circlemarker │ ├── circlemarker.ts │ └── index.ts ├── geojson │ ├── geojson.spec.ts │ ├── geojson.ts │ └── index.ts ├── group │ ├── group.ts │ └── index.ts ├── helpers │ ├── coordinateHandler.ts │ └── geoJsonReader.ts ├── imageoverlay │ ├── image-overlay.ts │ └── index.ts ├── index.ts ├── interfaces │ └── path.ts ├── layer │ ├── index.ts │ └── layer.ts ├── map │ ├── attribution │ │ ├── attribution.ts │ │ └── index.ts │ ├── index.ts │ ├── map.spec.ts │ ├── map.ts │ ├── scale │ │ ├── index.ts │ │ └── scale.ts │ ├── watermark │ │ ├── index.ts │ │ └── watermark.ts │ └── zoom │ │ ├── index.ts │ │ └── zoom.ts ├── marker │ ├── index.ts │ └── marker.ts ├── models │ ├── attributionModel.ts │ ├── path.ts │ ├── scaleModel.ts │ └── zoomModel.ts ├── ngx.leaflet.components.ts ├── ngx.leaflet.module.ts ├── polygon │ ├── index.ts │ └── polygon.ts ├── polyline │ ├── index.ts │ └── polyline.ts ├── popup │ ├── index.ts │ └── popup.ts ├── services │ ├── globalId.service.ts │ ├── group.service.ts │ ├── helper.service.ts │ ├── map.service.ts │ └── popup.service.ts └── test │ ├── main.test.ts │ ├── mock.component.ts │ ├── tsloader.js │ └── tsloader.ts ├── tsconfig-build.json ├── tsconfig.json ├── tslint.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | typings/ 3 | dist/ 4 | test/mock/ 5 | .vscode/ 6 | documentation/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Change Log 2 | 3 | ## 1.4.1 4 | * Angular updated to 5.0 5 | * Fixed empty popups on all elements 6 | * Changlelog was moved here 7 | * Changes on package.json to avoid certain webpack error 8 | * Change structure to be more compatible with a stricter tsconfig 9 | * Live website with some examples [here](https://elasticrash.github.io/Angular.io.MapViewer/app/) 10 | 11 | ## 1.4.0 12 | * Changes for depended type geojson 13 | * Css bug fixes 14 | * updates on tests 15 | 16 | ## 1.3.2 17 | * Angular updated to version 4.0.0 18 | * Project was renamed to ngx.leaflet.components (for obvious reasons) and previous one got deprecated 19 | * Coordinates now are automatically get re-projected, except for (wgs84 and 3857) so when using a custom crs, you need to pass, on the components, the coordinates associated with that particular crs. Automatic reprojection to wgs84 works on all components except ImageOverlay. 20 | * Bug Fixes 21 | * Components now accept x,y as inputs as well as lat lngs 22 | 23 | ## 1.3.1 24 | * Angular updated to 2.4.7 25 | * Circle Marker Element Added 26 | * Bug fixes 27 | 28 | ## 1.3.0 29 | * Polyline, Polygon, Circle and Marker now implement an ng-content pop up strategy 30 | * Increased Webpack compatibility (seems to work fine now) 31 | * Marker layer is no longer slow (it should work fine even with nearly 1000 markers) 32 | * Bug fixes 33 | 34 | ## 1.2.6 35 | * Bug fixes 36 | * Layers have attributions 37 | * Map has optional maxBounds 38 | 39 | ## 1.2.5 40 | * Scale, Zoom and Attribution are different components 41 | * Coverage reports for tests 42 | * Improved Webpack support 43 | 44 | ## 1.2.4 45 | * ImageOverlay support 46 | * GeoJson Layer support 47 | * CRS support for different coordinate systems (Proj4Leaflet is not working for leaflet 1.0.x though you need to write your own custom projection, I am working on an example) 48 | * Fixed a bug that didn't display a wms layer when set as basemap 49 | * Stopped using typings, switched to @types 50 | * Unit testing for more stable releases 51 | * Upgraded to typescript 2.14 and Angular 2.41 52 | 53 | ## 1.2.3 54 | * Fixed a bug that didn't allow the usage of polygons in a multiple map per page set up 55 | 56 | ## 1.2.2 57 | * Angular updated to 2.3.0 58 | * Bug fixes 59 | * Polygon element now supports holes 60 | * Polygon element can now be dynamically updated 61 | 62 | ## 1.2.1 63 | * Code was optimised, now everything is much faster 64 | * Layer Control can now be dynamically updated 65 | * polyline element now can be dynamically updated (able to create animated elements). Soon more elements will follow. 66 | 67 | ## 1.2.0 68 | * Added popup element 69 | 70 | ## 1.1.4 71 | * Choose whether a layer should be basemap or overlay on layerControl 72 | * Add names for the layers or groups on the layerControl 73 | 74 | ## 1.1.3 75 | * Custom marker icon 76 | 77 | ## 1.1.2 78 | * Multiple maps support 79 | * mouseover and onclick popup's for marker and all vector elements 80 | 81 | ## 1.1.1 82 | * css had top:64px now it has 0px so the map can take the whole available space 83 | * Added polygon element 84 | * Added polyline element 85 | 86 | ## 1.1.0 87 | * Error handling for circle-element 88 | * Error handling for marker-element 89 | * Added layer groups -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 stefanos kouroupis 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ngx.leaflet.component 2 | 3 | ## Native Angular Components designed to be used directly on the templates without much customization 4 | 5 | [website with examples](https://elasticrash.github.io/Angular.io.MapViewer/app/) 6 | 7 | Old Examples 8 | * [base example](https://elasticrash.github.io/Angular.io.MapViewer/example/) 9 | * [multi-map example ](https://elasticrash.github.io/Angular.io.MapViewer/example/#/mm-map) 10 | * [star map using L.CRS.Simple ](https://elasticrash.github.io/Angular.io.MapViewer/example/#/simple) 11 | * [custom CRS using leaflet ](https://elasticrash.github.io/Angular.io.MapViewer/example/#/prj) 12 | * [a genetic like algorithm trying to solve the Travelling salesman problem ](https://elasticrash.github.io/Angular.io.MapViewer/example/#/random) 13 | 14 | Examples sources can be found in the following github repository [here](https://github.com/elasticrash/Angular.io.MapViewer) 15 | 16 | 17 | Install 18 | ```terminal 19 | npm install ngx.leaflet.components 20 | npm install leaflet 21 | ``` 22 | 23 | USE 24 | 25 | ```javascript 26 | import { ngxLeafletModule } from 'ngx.leaflet.components'; 27 | 28 | @NgModule({ 29 | imports: [ngxLeafletModule], 30 | }) 31 | ``` 32 | 33 | Leaflet stylesheets are not included automatically for the time, so you need to add it yourself 34 | 35 | for usage and basic examples check the wiki 36 | 37 | https://github.com/elasticrash/ngx.leaflet.component/wiki 38 | 39 | 40 | If anyone wants to help in any way feel free to do a fork and a pull request 41 | 42 | ## NOTE 43 | 44 | * angular 4/5 use for versions 1.4.2 45 | * angular 6 use versions 2.0.0+ 46 | 47 | version 2.0.0 at the moment is not yet on npm due to not being tested properly but it can be easily be build by running 48 | * npm run build 49 | -------------------------------------------------------------------------------- /build.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const shell = require('shelljs'); 4 | const chalk = require('chalk'); 5 | 6 | const PACKAGE = `src/ngx.leaflet.components`; 7 | const NPM_DIR = `dist`; 8 | const ESM2015_DIR = `${NPM_DIR}/esm2015`; 9 | const ESM5_DIR = `${NPM_DIR}/esm5`; 10 | const BUNDLES_DIR = `${NPM_DIR}/bundles`; 11 | const OUT_DIR_ESM5 = `${NPM_DIR}/package/esm5`; 12 | 13 | shell.echo(`Start building...`); 14 | 15 | shell.rm(`-Rf`, `${NPM_DIR}/*`); 16 | shell.mkdir(`-p`, `./${ESM2015_DIR}`); 17 | shell.mkdir(`-p`, `./${ESM5_DIR}`); 18 | shell.mkdir(`-p`, `./${BUNDLES_DIR}`); 19 | 20 | /* TSLint with Codelyzer */ 21 | // https://github.com/palantir/tslint/blob/master/src/configs/recommended.ts 22 | // https://github.com/mgechev/codelyzer 23 | shell.echo(`Start TSLint`); 24 | shell.exec(`tslint -c tslint.json -t stylish src/**/*.ts`); 25 | shell.echo(chalk.green(`TSLint completed`)); 26 | 27 | /* AoT compilation */ 28 | shell.echo(`Start AoT compilation`); 29 | if (shell.exec(`ngc -p tsconfig-build.json`).code !== 0) { 30 | shell.echo(chalk.red(`Error: AoT compilation failed`)); 31 | shell.exit(1); 32 | } 33 | shell.echo(chalk.green(`AoT compilation completed`)); 34 | 35 | /* BUNDLING PACKAGE */ 36 | shell.echo(`Start bundling`); 37 | shell.echo(`Rollup package`); 38 | if (shell.exec(`rollup -c rollup.config.esm.js -i ${NPM_DIR}/${PACKAGE}.js -o ${ESM2015_DIR}/${PACKAGE}.js`).code !== 0) { 39 | shell.echo(chalk.red(`Error: Rollup package failed`)); 40 | shell.exit(1); 41 | } 42 | 43 | shell.echo(`Produce ESM5 version`); 44 | shell.exec(`ngc -p tsconfig-build.json --target es5 -d false --outDir ${OUT_DIR_ESM5} --importHelpers true --sourceMap`); 45 | if (shell.exec(`rollup -c rollup.config.esm.js -i ${OUT_DIR_ESM5}/${PACKAGE}.js -o ${ESM5_DIR}/${PACKAGE}.js`).code !== 0) { 46 | shell.echo(chalk.red(`Error: ESM5 version failed`)); 47 | shell.exit(1); 48 | } 49 | 50 | shell.echo(`Run Rollup conversion on package`); 51 | if (shell.exec(`rollup -c rollup.config.umd.js -i ${ESM5_DIR}/${PACKAGE}.js -o ${BUNDLES_DIR}/${PACKAGE}.umd.js`).code !== 0) { 52 | shell.echo(chalk.red(`Error: Rollup conversion failed`)); 53 | shell.exit(1); 54 | } 55 | 56 | shell.echo(`Minifying`); 57 | shell.cd(`${BUNDLES_DIR}`); 58 | shell.exec(`uglifyjs ${PACKAGE}.umd.js -c --comments -o ${PACKAGE}.umd.min.js --source-map "filename='${PACKAGE}.umd.min.js.map', includeSources"`); 59 | shell.cd(`..`); 60 | shell.cd(`..`); 61 | 62 | shell.echo(chalk.green(`Bundling completed`)); 63 | 64 | shell.rm(`-Rf`, `${NPM_DIR}/package`); 65 | shell.rm(`-Rf`, `${NPM_DIR}/node_modules`); 66 | shell.rm(`-Rf`, `${NPM_DIR}/*.js`); 67 | shell.rm(`-Rf`, `${NPM_DIR}/*.js.map`); 68 | shell.rm(`-Rf`, `${NPM_DIR}/src/**/*.js`); 69 | shell.rm(`-Rf`, `${NPM_DIR}/src/**/*.js.map`); 70 | 71 | shell.cp(`-Rf`, [`package.json`, `LICENSE`, `README.md`], `${NPM_DIR}`); 72 | 73 | shell.echo(chalk.green(`End building`)); -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 8.4.0 4 | npm: 5 | version: 5.2.0 -------------------------------------------------------------------------------- /cleanup.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | console.log(__dirname); 4 | var appPath = __dirname.split('node_modules')[0]; 5 | rmDir(appPath +"//"); 6 | 7 | function rmDir(dirPath) { 8 | var findWorkingDir = dirPath; 9 | console.log("findWorkingDir", findWorkingDir); 10 | 11 | if (findWorkingDir.indexOf('node_modules') === -1) { 12 | var files = fs.readdirSync(findWorkingDir); 13 | 14 | if (files.length > 0) { 15 | for (var i = 0; i < files.length; i++) { 16 | 17 | var filePath = findWorkingDir + files[i]; 18 | 19 | if (filePath.indexOf('test') === -1 && filePath.indexOf('dist') === -1) { 20 | if (files[i].charAt(0) !== ".") { 21 | if (fs.statSync(filePath).isFile()) { 22 | if (files[i].indexOf('.js') !== -1) { 23 | if (files[i] !== "karma.conf.js" && 24 | files[i] !== "webpack.config.js" && 25 | files[i] !== "tsloader.js" && 26 | files[i] !== "build.js" && 27 | files[i] !== "cleanup.js" && 28 | files[i] !== "rollup.config.esm.js" && 29 | files[i] !== "rollup.config.umd.js" && 30 | files[i].indexOf('.json') === -1 && 31 | files[i].indexOf('.js.map') === -1) { 32 | fs.unlinkSync(filePath); 33 | //fs.rename(filePath, filePath.replace(appPath, appPath + "/test/mock/")); 34 | console.log("delete", files[i]); 35 | } 36 | } 37 | } 38 | else { 39 | rmDir(filePath + "/"); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | console.log('all js files are deleted'); -------------------------------------------------------------------------------- /coverage/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* dark red */ 156 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 157 | .low .chart { border:1px solid #C21F39 } 158 | /* medium red */ 159 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 160 | /* light red */ 161 | .low, .cline-no { background:#FCE1E5 } 162 | /* light green */ 163 | .high, .cline-yes { background:rgb(230,245,208) } 164 | /* medium green */ 165 | .cstat-yes { background:rgb(161,215,106) } 166 | /* dark green */ 167 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 168 | .high .chart { border:1px solid rgb(77,146,33) } 169 | /* dark yellow (gold) */ 170 | .medium .chart { border:1px solid #f9cd0b; } 171 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 172 | /* light yellow */ 173 | .medium { background: #fff4c2; } 174 | /* light gray */ 175 | span.cline-neutral { background: #eaeaea; } 176 | 177 | .cbranch-no { background: yellow !important; color: #111; } 178 | 179 | .cstat-skip { background: #ddd; color: #111; } 180 | .fstat-skip { background: #ddd; color: #111 !important; } 181 | .cbranch-skip { background: #ddd !important; color: #111; } 182 | 183 | 184 | .cover-fill, .cover-empty { 185 | display:inline-block; 186 | height: 12px; 187 | } 188 | .chart { 189 | line-height: 0; 190 | } 191 | .cover-empty { 192 | background: white; 193 | } 194 | .cover-full { 195 | border-right: none !important; 196 | } 197 | pre.prettyprint { 198 | border: none !important; 199 | padding: 0 !important; 200 | margin: 0 !important; 201 | } 202 | .com { color: #999 !important; } 203 | .ignore-none { color: #999; font-weight: normal; } 204 | 205 | .wrapper { 206 | min-height: 100%; 207 | height: auto !important; 208 | height: 100%; 209 | margin: 0 auto -48px; 210 | } 211 | .footer, .push { 212 | height: 48px; 213 | } 214 | -------------------------------------------------------------------------------- /coverage/circle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for circle\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files circle/ 20 |

21 |
22 |
23 | 65.22% 24 | Statements 25 | 30/46 26 |
27 |
28 | 14.29% 29 | Branches 30 | 2/14 31 |
32 |
33 | 50% 34 | Functions 35 | 2/4 36 |
37 |
38 | 62.79% 39 | Lines 40 | 27/43 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
circle.ts
65.22%30/4614.29%2/1450%2/462.79%27/43
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/geojson/geojson.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for geojson\geojson.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / geojson/ geojson.ts 20 |

21 |
22 |
23 | 92.11% 24 | Statements 25 | 35/38 26 |
27 |
28 | 60% 29 | Branches 30 | 6/10 31 |
32 |
33 | 100% 34 | Functions 35 | 4/4 36 |
37 |
38 | 91.43% 39 | Lines 40 | 32/35 41 |
42 |
43 |
44 |
45 |

 46 | 
236 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 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 | 140 | 141 |   142 |   143 | 144 |   145 | 146 |   147 | 148 |   149 | 150 | 151 |   152 | 153 |   154 | 155 |   156 |   157 | 158 |   159 |   160 |   161 |   162 |   163 |   164 |   165 |   166 |   167 |   168 | 169 | 170 |   171 | 172 |  
import { Component, Input, Injector, Optional } from '@angular/core';
173 | import { LeafletElement } from '../map/map';
174 | import { LeafletGroup } from '../group/group';
175 | import { MapService } from '../services/map.service';
176 | import { GroupService } from '../services/group.service';
177 | import { PopupService } from '../services/popup.service';
178 | import { GuidService } from '../services/globalId.service';
179 | import { HelperService } from '../services/helper.service';
180 | import { GeoJSONCoordinateHandler } from '../helpers/geoJsonReader';
181 |  
182 | import * as L from 'leaflet';
183 |  
184 | @Component({
185 |   moduleId: module.id.toString(),
186 |   selector: 'geojson-element',
187 |   templateUrl: 'geojson.html',
188 |   styleUrls: ['geojson.css']
189 | })
190 |  
191 | export class GeoJsonElement extends GeoJSONCoordinateHandler {
192 |   originalObject: any = Object.assign({}, this.geojson);
193 |   globalId: string = this.guidService.newGuid();
194 |  
195 |   constructor(
196 |     private mapService: MapService,
197 |     private groupService: GroupService,
198 |     private popupService: PopupService,
199 |     private guidService: GuidService,
200 |     private helperService: HelperService,
201 |     @Optional() private LeafletElement?: LeafletElement,
202 |     @Optional() private LeafletGroup?: LeafletGroup) {
203 |     super();
204 |   }
205 |  
206 |   ngOnInit() {
207 |     //check if any of the two optional injections exist
208 |     Eif (this.LeafletElement || this.LeafletGroup) {
209 |       //polyline shouldn't have a fill
210 |       let map = this.mapService.getMap();
211 |  
212 |       Eif (this.geojson) {
213 |         super.transformJSONCoordinates(this.geojson, this.LeafletElement.crs);
214 |  
215 |         let gjson = L.geoJSON(this.geojson);
216 |  
217 |         Iif (this.LeafletGroup) {
218 |           this.groupService.addOLayersToGroup(gjson, map, this.mapService, this.LeafletGroup, false, this.globalId);
219 |         } else {
220 |           gjson.addTo(map);
221 |         }
222 |       } else {
223 |         console.warn("geojson object seems to be undefined");
224 |       }
225 |     } else {
226 |       console.warn("This polyline-element will not be rendered \n the expected parent node of polyline-element should be either leaf-element or leaflet-group");
227 |     }
228 |  
229 |   }
230 |  
231 |   ngDoCheck() {
232 |     let map = this.mapService.getMap();
233 |   }
234 | }
235 |  
237 |
238 |
239 | 243 | 244 | 245 | 252 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /coverage/geojson/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for geojson\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files geojson/ 20 |

21 |
22 |
23 | 92.11% 24 | Statements 25 | 35/38 26 |
27 |
28 | 60% 29 | Branches 30 | 6/10 31 |
32 |
33 | 100% 34 | Functions 35 | 4/4 36 |
37 |
38 | 91.43% 39 | Lines 40 | 32/35 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
geojson.ts
92.11%35/3860%6/10100%4/491.43%32/35
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/group/group.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for group\group.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / group/ group.ts 20 |

21 |
22 |
23 | 73.33% 24 | Statements 25 | 11/15 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 25% 34 | Functions 35 | 1/4 36 |
37 |
38 | 69.23% 39 | Lines 40 | 9/13 41 |
42 |
43 |
44 |
45 |

 46 | 
146 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 81 | 82 | 83 |   84 |   85 |   86 |   87 |   88 |   89 |   90 |   91 |   92 |   93 |   94 | 95 | 96 |   97 |   98 |   99 |   100 |   101 |   102 |   103 |   104 | 105 |   106 |   107 | 108 |   109 |   110 |   111 | 112 |  
import { Component, Input } from '@angular/core';
113 | import { MapService } from '../services/map.service';
114 | import { GroupService } from '../services/group.service';
115 | import { GuidService } from '../services/globalId.service';
116 | import * as L from 'leaflet';
117 |  
118 |  
119 | @Component({
120 |     moduleId: module.id.toString(),
121 |     selector: 'leaflet-group',
122 |     templateUrl: 'group.html',
123 |     styleUrls: ['group.css'],
124 |     providers: [GroupService]
125 | })
126 |  
127 | export class LeafletGroup {
128 |     @Input() name: string = '';
129 |     globalId: string = this.guidService.newGuid();
130 |  
131 |     constructor(
132 |         private mapService: MapService,
133 |         private groupService: GroupService,
134 |         private guidService: GuidService) {
135 |     }
136 |  
137 |     ngOnInit() {
138 |     }
139 |  
140 |     ngAfterViewInit() {
141 |     }
142 |  
143 |  
144 | }
145 |  
147 |
148 |
149 | 153 | 154 | 155 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /coverage/group/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for group\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files group/ 20 |

21 |
22 |
23 | 73.33% 24 | Statements 25 | 11/15 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 25% 34 | Functions 35 | 1/4 36 |
37 |
38 | 69.23% 39 | Lines 40 | 9/13 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
group.ts
73.33%11/15100%0/025%1/469.23%9/13
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/helpers/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for helpers\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files helpers/ 20 |

21 |
22 |
23 | 58.33% 24 | Statements 25 | 56/96 26 |
27 |
28 | 50% 29 | Branches 30 | 22/44 31 |
32 |
33 | 50% 34 | Functions 35 | 11/22 36 |
37 |
38 | 56.99% 39 | Lines 40 | 53/93 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
FileStatementsBranchesFunctionsLines
coodinateHandler.ts
54.55%24/4427.27%6/2271.43%5/753.49%23/43
geoJsonReader.ts
61.54%32/5272.73%16/2240%6/1560%30/50
89 |
90 |
91 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /coverage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for All files 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | / 20 |

21 |
22 |
23 | 59.23% 24 | Statements 25 | 276/466 26 |
27 |
28 | 23.9% 29 | Branches 30 | 38/159 31 |
32 |
33 | 51.61% 34 | Functions 35 | 48/93 36 |
37 |
38 | 57.24% 39 | Lines 40 | 249/435 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 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 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 |
FileStatementsBranchesFunctionsLines
circle/
65.22%30/4614.29%2/1450%2/462.79%27/43
geojson/
92.11%35/3860%6/10100%4/491.43%32/35
group/
73.33%11/15100%0/025%1/469.23%9/13
helpers/
58.33%56/9650%22/4450%11/2256.99%53/93
map/
83.33%35/4250%5/1080%4/582.05%32/39
models/
85%17/2025%1/4100%2/284.21%16/19
services/
38.1%72/1892.6%2/7734.88%15/4335.06%61/174
test/
100%20/20100%0/0100%9/9100%19/19
167 |
168 |
169 | 173 | 174 | 175 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /coverage/map/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for map\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files map/ 20 |

21 |
22 |
23 | 83.33% 24 | Statements 25 | 35/42 26 |
27 |
28 | 50% 29 | Branches 30 | 5/10 31 |
32 |
33 | 80% 34 | Functions 35 | 4/5 36 |
37 |
38 | 82.05% 39 | Lines 40 | 32/39 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
map.ts
83.33%35/4250%5/1080%4/582.05%32/39
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/map/map.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for map\map.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / map/ map.ts 20 |

21 |
22 |
23 | 83.33% 24 | Statements 25 | 35/42 26 |
27 |
28 | 50% 29 | Branches 30 | 5/10 31 |
32 |
33 | 80% 34 | Functions 35 | 4/5 36 |
37 |
38 | 82.05% 39 | Lines 40 | 32/39 41 |
42 |
43 |
44 |
45 |

 46 | 
281 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 112 | 67 113 | 68 114 | 69 115 | 70 116 | 71 117 | 72 118 | 73 119 | 74 120 | 75 121 | 76 122 | 77 123 | 78 124 | 79 125 | 126 | 127 | 128 |   129 |   130 |   131 |   132 |   133 |   134 |   135 |   136 |   137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 |   149 | 150 |   151 | 152 | 153 |   154 |   155 | 156 | 157 |   158 | 159 | 160 | 161 | 162 |   163 |   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 | 202 |  
import { Component, Input, ViewChild, ElementRef, EventEmitter } from '@angular/core';
203 | import { MapService } from '../services/map.service';
204 | import { CoordinateHandler } from '../helpers/coodinateHandler';
205 | import * as L from 'leaflet';
206 |  
207 | @Component({
208 |   moduleId: module.id.toString(),
209 |   selector: 'leaf-element',
210 |   templateUrl: 'map.html',
211 |   styleUrls: ['map.css'],
212 |   providers: [MapService]
213 | })
214 |  
215 | export class LeafletElement extends CoordinateHandler {
216 |   @Input() lat: number = 52.6;
217 |   @Input() lon: number = -1.1;
218 |   @Input() zoom: number = 12;
219 |   @Input() minZoom: number = 4;
220 |   @Input() maxZoom: number = 19;
221 |   @Input() layerControl: boolean = false;
222 |   @Input() crs: any = L.CRS.EPSG3857;
223 |   @Input() zoomControl: boolean;
224 |   @Input() maxBounds: L.LatLngBounds = null;
225 |   @ViewChild('map') mapElement: ElementRef;
226 |  
227 |   layerControlObject = null;
228 |  
229 |   constructor(private mapService: MapService) {
230 |     super();
231 |   }
232 |  
233 |   ngOnInit() {
234 |     super.assignCartesianPointToLeafletsLatLngSchema();
235 |  
236 |     if (typeof (this.crs) === "string") {
237 |       var splitCrs = this.crs.split(".");
238 |       Eif (splitCrs[0] === "L") {
239 |         this.crs = L[splitCrs[1]][splitCrs[2]];
240 |       } else {
241 |         console.warn("something is not right, reverting to default EPSG3857");
242 |         this.crs = L.CRS.EPSG3857;
243 |       }
244 |     }
245 |  
246 |     super.transformPointCoordinates(this.crs);
247 |  
248 |     let map = L.map(this.mapElement.nativeElement, {
249 |       crs: this.crs,
250 |       zoomControl: this.zoomControl,
251 |       center: L.latLng(this.lat, this.lon),
252 |       zoom: this.zoom,
253 |       minZoom: this.minZoom,
254 |       maxZoom: this.maxZoom,
255 |       maxBounds: this.maxBounds,
256 |       layers: [],
257 |       closePopupOnClick: false,
258 |       attributionControl: false
259 |     });
260 |     this.mapElement.nativeElement.myMapProperty = map;
261 |  
262 |     //set variables for childrent components
263 |     this.mapService.setMap(map);
264 |     this.mapService.setLayerControl(this.layerControl);
265 |   }
266 |  
267 |   ngAfterViewInit() {
268 |   }
269 |  
270 |   setLayerControl() {
271 |     if (this.layerControl) {
272 |       let map = this.mapService.getMap();
273 |       if (this.layerControlObject !== null) {
274 |         this.layerControlObject.getContainer().innerHTML = '';
275 |       }
276 |       this.layerControlObject = L.control.layers(this.mapService.getBasemaps(), this.mapService.getOverlays()).addTo(map);
277 |     }
278 |   }
279 | }
280 |  
282 |
283 |
284 | 288 | 289 | 290 | 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /coverage/models/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for models\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files models/ 20 |

21 |
22 |
23 | 85% 24 | Statements 25 | 17/20 26 |
27 |
28 | 25% 29 | Branches 30 | 1/4 31 |
32 |
33 | 100% 34 | Functions 35 | 2/2 36 |
37 |
38 | 84.21% 39 | Lines 40 | 16/19 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
FileStatementsBranchesFunctionsLines
path.ts
85%17/2025%1/4100%2/284.21%16/19
76 |
77 |
78 | 82 | 83 | 84 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /coverage/models/path.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for models\path.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / models/ path.ts 20 |

21 |
22 |
23 | 85% 24 | Statements 25 | 17/20 26 |
27 |
28 | 25% 29 | Branches 30 | 1/4 31 |
32 |
33 | 100% 34 | Functions 35 | 2/2 36 |
37 |
38 | 84.21% 39 | Lines 40 | 16/19 41 |
42 |
43 |
44 |
45 |

 46 | 
122 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 |   73 | 74 |   75 |   76 |   77 |   78 |   79 |   80 |   81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |   94 | 95 | 96 |  
export class path {
 97 |     constructor(pathInfo: any) {
 98 |         Iif (pathInfo !== null) {
 99 |             for (var key in pathInfo) {
100 |                 if (pathInfo[key] !== undefined) {
101 |                     this[key] = pathInfo[key];
102 |                 }
103 |             }
104 |         }
105 |     }
106 |     stroke: boolean = true;	//Whether to draw stroke along the path. Set it to false to disable borders on polygons or circles.
107 |     color: string = '#3388ff';	//Stroke color
108 |     weight: number = 3;	//Stroke width in pixels
109 |     opacity: number = 1;	//Stroke opacity
110 |     lineCap: string = 'round'; //	A string that defines shape to be used at the end of the stroke.
111 |     lineJoin: string = 'round'; //A string that defines shape to be used at the corners of the stroke.
112 |     dashArray: string = null;	//A string that defines the stroke dash pattern. Doesn't work on Canvas-powered layers in some old browsers.
113 |     dashOffset: string = null;	//A string that defines the distance into the dash pattern to start the dash. Doesn't work on Canvas-powered layers in some old browsers.
114 |     fill: boolean = true; //Whether to fill the path with color. Set it to false to disable filling on polygons or circles.
115 |     fillColor: string = '#3388ff';	//Fill color. Defaults to the value of the color option
116 |     fillOpacity: number = 0.2;	//	Fill opacity.
117 |     fillRule: string = 'evenodd';	//	A string that defines how the inside of a shape is determined.
118 |     //TODO renderer: Renderer; 		Use this specific instance of Renderer for this path. Takes precedence over the map's default renderer.
119 |     className: string = null;	//null	Custom class name set on an element. Only for SVG renderer.
120 | }
121 |  
123 |
124 |
125 | 129 | 130 | 131 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /coverage/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/services/globalId.service.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for services\globalId.service.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / services/ globalId.service.ts 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 10/10 26 |
27 |
28 | 100% 29 | Branches 30 | 2/2 31 |
32 |
33 | 100% 34 | Functions 35 | 4/4 36 |
37 |
38 | 100% 39 | Lines 40 | 7/7 41 |
42 |
43 |
44 |
45 |

 46 | 
 89 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 |   62 |   63 |   64 | 65 |   66 |   67 |   68 | 69 | 70 | 31× 71 | 31× 72 |   73 |   74 |
import { Injectable } from '@angular/core';
 75 |  
 76 |  
 77 | @Injectable()
 78 | export class GuidService {
 79 |  
 80 |     constructor() { }
 81 |  
 82 |      newGuid() {
 83 |         return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
 84 |             var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
 85 |             return v.toString(16);
 86 |         });
 87 |     }
 88 | }
90 |
91 |
92 | 96 | 97 | 98 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /coverage/services/group.service.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for services\group.service.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / services/ group.service.ts 20 |

21 |
22 |
23 | 39.13% 24 | Statements 25 | 18/46 26 |
27 |
28 | 0% 29 | Branches 30 | 0/14 31 |
32 |
33 | 25% 34 | Functions 35 | 2/8 36 |
37 |
38 | 38.1% 39 | Lines 40 | 16/42 41 |
42 |
43 |
44 |
45 |

 46 | 
242 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 | 48 94 | 49 95 | 50 96 | 51 97 | 52 98 | 53 99 | 54 100 | 55 101 | 56 102 | 57 103 | 58 104 | 59 105 | 60 106 | 61 107 | 62 108 | 63 109 | 64 110 | 65 111 | 66 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 |   140 |   141 |   142 |   143 |   144 |   145 |   146 |   147 |   148 |   149 |   150 |   151 |   152 |   153 |   154 |   155 |   156 |   157 | 158 |   159 |   160 |   161 |   162 |   163 |   164 |   165 | 166 |   167 |   168 |   169 | 170 |   171 |   172 |   173 | 174 |   175 |   176 |
import { Injectable } from '@angular/core';
177 | import { Observable } from 'rxjs/Rx';
178 | import { GuidService } from '../services/globalId.service';
179 | import * as L from 'leaflet';
180 |  
181 |  
182 | @Injectable()
183 | export class GroupService {
184 |     private layerGroup: Array<any> = [];
185 |     private layerId: Array<any> = [];
186 |     private layerGroupNumber: number = 0;
187 |     private group: any = {};
188 |  
189 |     constructor(private guidService: GuidService) { }
190 |  
191 |     public addOLayersToGroup(overlay, map, mapService, group, replace = false, gId?: String) {
192 |         if (!gId) {
193 |             gId = this.guidService.newGuid();
194 |         }
195 |         if (this.layerId.indexOf(gId) === -1) {
196 |             this.layerId.push(gId);
197 |         }
198 |         if (Object.keys(this.group).length !== 0) {
199 |             if (replace) {
200 |                 map.removeLayer(this.group);
201 |                 if (this.layerId.indexOf(gId) !== -1) {
202 |                     this.layerGroup[this.layerId.indexOf(gId)] = overlay;
203 |                 } else {
204 |                     this.layerGroup.push(overlay);
205 |                 }
206 |                 this.group = L.layerGroup(this.getLayerGroup());
207 |                 this.group.addTo(map);
208 |             } else {
209 |                 this.layerGroup.push(overlay);
210 |                 this.group.addLayer(overlay);
211 |             }
212 |         }
213 |         if (!replace) {
214 |             this.layerGroup.push(overlay);
215 |             this.group = L.layerGroup(this.getLayerGroup());
216 |             this.group.addTo(map);
217 |         }
218 |  
219 |         mapService.addOverlay(this.getGroup(), group.name, group.globalId);
220 |     }
221 |  
222 |     public getObservableGroup() {
223 |         return Observable.create(observer => {
224 |             var group = this.getGroup();
225 |             observer.next(group);
226 |             observer.complete();
227 |         });
228 |     }
229 |  
230 |     public getGroup() {
231 |         return this.group;
232 |     }
233 |  
234 |     public getLayerGroup() {
235 |         return this.layerGroup;
236 |     }
237 |  
238 |     public getLayerNumber() {
239 |         return this.layerGroupNumber;
240 |     }
241 | }
243 |
244 |
245 | 249 | 250 | 251 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /coverage/services/helper.service.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for services\helper.service.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / services/ helper.service.ts 20 |

21 |
22 |
23 | 40% 24 | Statements 25 | 6/15 26 |
27 |
28 | 0% 29 | Branches 30 | 0/10 31 |
32 |
33 | 66.67% 34 | Functions 35 | 2/3 36 |
37 |
38 | 30.77% 39 | Lines 40 | 4/13 41 |
42 |
43 |
44 |
45 |

 46 | 
122 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 |   73 |   74 |   75 | 76 |   77 |   78 |   79 | 80 |   81 |   82 |   83 |   84 |   85 |   86 |   87 |   88 |   89 |   90 |   91 |   92 |   93 |   94 |   95 |   96 |
import { Injectable } from '@angular/core';
 97 |  
 98 |  
 99 | @Injectable()
100 | export class HelperService {
101 |  
102 |     constructor() { }
103 |  
104 |     arrayCompare(a, b) {
105 |         if (a.length != b.length) {
106 |             return false;
107 |         }
108 |         for (var i in a) {
109 |             // Don't forget to check for arrays in our arrays.
110 |             if (a[i] instanceof Array && b[i] instanceof Array) {
111 |                 if (!this.arrayCompare(a[i], b[i])) {
112 |                     return false;
113 |                 }
114 |             }
115 |             else if (a[i] != b[i]) {
116 |                 return false;
117 |             }
118 |         }
119 |         return true;
120 |     }
121 | }
123 |
124 |
125 | 129 | 130 | 131 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /coverage/services/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for services\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files services/ 20 |

21 |
22 |
23 | 38.1% 24 | Statements 25 | 72/189 26 |
27 |
28 | 2.6% 29 | Branches 30 | 2/77 31 |
32 |
33 | 34.88% 34 | Functions 35 | 15/43 36 |
37 |
38 | 35.06% 39 | Lines 40 | 61/174 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 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 |
FileStatementsBranchesFunctionsLines
globalId.service.ts
100%10/10100%2/2100%4/4100%7/7
group.service.ts
39.13%18/460%0/1425%2/838.1%16/42
helper.service.ts
40%6/150%0/1066.67%2/330.77%4/13
map.service.ts
36.78%32/870%0/2225%5/2036.14%30/83
popup.service.ts
19.35%6/310%0/2925%2/813.79%4/29
128 |
129 |
130 | 134 | 135 | 136 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /coverage/services/popup.service.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for services\popup.service.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / services/ popup.service.ts 20 |

21 |
22 |
23 | 19.35% 24 | Statements 25 | 6/31 26 |
27 |
28 | 0% 29 | Branches 30 | 0/29 31 |
32 |
33 | 25% 34 | Functions 35 | 2/8 36 |
37 |
38 | 13.79% 39 | Lines 40 | 4/29 41 |
42 |
43 |
44 |
45 |

 46 | 
185 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 | 39 85 | 40 86 | 41 87 | 42 88 | 43 89 | 44 90 | 45 91 | 46 92 | 47 93 |   94 |   95 |   96 | 97 |   98 |   99 |   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 |   138 |
import { Injectable } from '@angular/core';
139 |  
140 |  
141 | @Injectable()
142 | export class PopupService {
143 |  
144 |     constructor() { }
145 |  
146 |     public enablePopup(mouseover, onclick, element, text) {
147 |         if (mouseover && onclick) {
148 |             mouseover = undefined;
149 |             console.warn('you can not use mouseover and onclick at the same time, mouseover is going to be depressed');
150 |         }
151 |         if (mouseover) {
152 |             if (mouseover === 'true' && text) {
153 |                 mouseover = text;
154 |             } else if (mouseover === true && !text) {
155 |                 mouseover = "true";
156 |             }
157 |             element.bindPopup(mouseover);
158 |             element.on('mouseover', function () {
159 |                 this.openPopup();
160 |             }).on('mouseout', function () {
161 |                 this.closePopup();
162 |             });
163 |         }
164 |         if (onclick) {
165 |             if (onclick === 'true' && text) {
166 |                 onclick = text;
167 |             } else if (onclick === true && !text) {
168 |                 onclick = "true";
169 |             }
170 |             element.bindPopup(onclick);
171 |             element.on('click', function () {
172 |                 this.openPopup();
173 |             })
174 |         }
175 |         if (!mouseover && !onclick && text) {
176 |             element.bindPopup(text);
177 |             element.on('mouseover', function () {
178 |                 this.openPopup();
179 |             }).on('mouseout', function () {
180 |                 this.closePopup();
181 |             });
182 |         }
183 |     }
184 | }
186 |
187 |
188 | 192 | 193 | 194 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /coverage/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elasticrash/ngx.leaflet.component/83c75124fc71209990268876b2914ba921113b61/coverage/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for test\ 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files test/ 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 20/20 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 9/9 36 |
37 |
38 | 100% 39 | Lines 40 | 19/19 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 |
FileStatementsBranchesFunctionsLines
main.test.ts
100%20/20100%0/0100%8/8100%19/19
tsloader.ts
100%0/0100%0/0100%1/1100%0/0
89 |
90 |
91 | 95 | 96 | 97 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /coverage/test/main.test.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for test\main.test.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / test/ main.test.ts 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 20/20 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 8/8 36 |
37 |
38 | 100% 39 | Lines 40 | 19/19 41 |
42 |
43 |
44 |
45 |

 46 | 
158 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 26 72 | 27 73 | 28 74 | 29 75 | 30 76 | 31 77 | 32 78 | 33 79 | 34 80 | 35 81 | 36 82 | 37 83 | 38 84 |   85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |   94 |   95 |   96 |   97 |   98 |   99 | 100 |   101 |   102 | 103 |   104 |   105 |   106 |   107 | 108 | 109 |   110 |   111 |   112 |   113 | 114 | 115 | 116 | 117 | 118 | 119 |   120 |  
import 'core-js'; // ES6 + reflect-metadata
121 | // zone.js
122 | import 'zone.js/dist/zone';
123 | import 'zone.js/dist/long-stack-trace-zone';
124 | import 'zone.js/dist/proxy.js';
125 | import 'zone.js/dist/sync-test';
126 | import 'zone.js/dist/jasmine-patch';
127 | import 'zone.js/dist/async-test';
128 | import 'zone.js/dist/fake-async-test';
129 | import 'leaflet/dist/leaflet';
130 |  
131 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
132 | declare var __karma__: any;
133 | declare var require: any;
134 |  
135 | // Prevent Karma from running prematurely.
136 | __karma__.loaded = function () { };
137 | declare var System: any;
138 |  
139 | Promise.all([
140 |     System.import('@angular/core/testing'),
141 |     System.import('@angular/platform-browser-dynamic/testing')
142 | ])
143 |     // First, initialize the Angular testing environment.
144 |     .then(([testing, testingBrowser]) => {
145 |         testing.getTestBed().initTestEnvironment(
146 |             testingBrowser.BrowserDynamicTestingModule,
147 |             testingBrowser.platformBrowserDynamicTesting()
148 |         );
149 |     })
150 |     .then(() => require.context('../map', true, /\.spec\.ts/))
151 |     .then(context => context.keys().map(context))
152 |     .then(() => require.context('../geojson', true, /\.spec\.ts/))
153 |     .then(context => context.keys().map(context))
154 |     .then(() => require.context('../circle', true, /\.spec\.ts/))
155 |     .then(context => context.keys().map(context))
156 |     // Finally, start Karma to run the tests.
157 |     .then(__karma__.start, __karma__.error);
159 |
160 |
161 | 165 | 166 | 167 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /coverage/test/mock.component.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for test/mock.component.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / test/ mock.component.ts 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 6/6 26 |
27 |
28 | 50% 29 | Branches 30 | 1/2 31 |
32 |
33 | 100% 34 | Functions 35 | 3/3 36 |
37 |
38 | 100% 39 | Lines 40 | 5/5 41 |
42 |
43 |
44 |
45 |

 46 | 
 86 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 |   61 | 62 | 63 |   64 |   65 |   66 |   67 |   68 |   69 | 70 |   71 | 72 |  
import { Component } from '@angular/core';
 73 |  
 74 | export function MockComponent(options: Component): Component {
 75 |   let metadata: Component = {
 76 |     selector: options.selector,
 77 |     template: options.template || '',
 78 |     inputs: options.inputs,
 79 |     outputs: options.outputs
 80 |   };
 81 |  
 82 |   class Mock {}
 83 |  
 84 |   return Component(metadata)(Mock);
 85 | }
87 |
88 |
89 | 93 | 94 | 95 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /coverage/test/tsloader.ts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for test\tsloader.ts 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | all files / test/ tsloader.ts 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 0/0 26 |
27 |
28 | 100% 29 | Branches 30 | 0/0 31 |
32 |
33 | 100% 34 | Functions 35 | 1/1 36 |
37 |
38 | 100% 39 | Lines 40 | 0/0 41 |
42 |
43 |
44 |
45 |

46 | 
47 | 
1 
require('./main.test.ts');
48 |
49 |
50 | 54 | 55 | 56 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | config.set({ 3 | basePath: '', 4 | frameworks: ['jasmine'], 5 | files: [ 6 | { pattern: 'src/test/tsloader.js', watched: false }, 7 | ], 8 | exclude: [ 9 | ], 10 | preprocessors: { 11 | 'src/test/tsloader.js': ['webpack', 'sourcemap','coverage'], 12 | }, 13 | webpack: require('./webpack.config')({ env: 'test' }), 14 | reporters: ['spec', 'coverage', 'remap-coverage'], 15 | port: 9876, 16 | colors: true, 17 | logLevel: config.LOG_DEBUG, 18 | autoWatch: true, 19 | browsers: ['ChromeHeadless'], 20 | coverageReporter: { 21 | reporters: [ 22 | { type: 'json', subdir: '.', file: 'coverage.json' }, 23 | { type : 'text-summary'}, 24 | ] 25 | }, 26 | singleRun: true, 27 | concurrency: Infinity 28 | }); 29 | }; -------------------------------------------------------------------------------- /ngx.leaflet.components.ts: -------------------------------------------------------------------------------- 1 | export * from './public_api'; 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngx.leaflet.components", 3 | "version": "2.0.0", 4 | "description": "an angular.io component collection for leaflet", 5 | "main": "./bundles/src/ngx.leaflet.components.umd.js", 6 | "jsnext:main": "./esm5/src/ngx.leaflet.components.js", 7 | "module": "./esm5/src/ngx.leaflet.components.js", 8 | "es2015": "./esm2015/src/ngx.leaflet.components.js", 9 | "types": "./src/ngx.leaflet.components.d.ts", 10 | "scripts": { 11 | "start": "npm run clean && tsc", 12 | "tsc": "tsc", 13 | "tsc:w": "tsc -w", 14 | "ngc": "ngc", 15 | "build": "node build.js", 16 | "pretest": "node cleanup.js", 17 | "test": "karma start karma.conf.js", 18 | "coverage": "http-server -c-1 -o -p 9875 ./coverage", 19 | "remap": "node_modules/.bin/remap-istanbul -i coverage/coverage.json -o coverage -t html", 20 | "documentation": "./node_modules/.bin/compodoc -p tsconfig.json" 21 | }, 22 | "keywords": [ 23 | "angular", 24 | "javascript", 25 | "typescript", 26 | "leaflet", 27 | "spatial" 28 | ], 29 | "repository": { 30 | "type": "git", 31 | "url": "http://github.com/elasticrash/ngx.leaflet.component.git" 32 | }, 33 | "author": "Stefanos Kouroupis", 34 | "contributors": [ 35 | { 36 | "name": "Giorgos Papapdakis", 37 | "url": "https://github.com/xalikoutis" 38 | } 39 | ], 40 | "license": "ISC", 41 | "bugs": { 42 | "url": "https://github.com/elasticrash/ngx.leaflet.component/issues" 43 | }, 44 | "peerDependencies": { 45 | "tslib": "1.9.2", 46 | "@angular/core": ">=6.0.0", 47 | "@angular/http": ">=6.0.0", 48 | "@angular/common": ">=6.0.0", 49 | "rxjs": ">=6.0.0", 50 | "leaflet": ">=1.0.0", 51 | "typescript": ">=2.7.2" 52 | }, 53 | "homepage": "https://github.com/elasticrash/ngx.leaflet.component#readme", 54 | "devDependencies": { 55 | "@angular/common": "6.0.5", 56 | "@angular/compiler": "6.0.5", 57 | "@angular/compiler-cli": "6.0.5", 58 | "@angular/core": "6.0.5", 59 | "@angular/http": "6.0.5", 60 | "@angular/platform-browser": "6.0.5", 61 | "@angular/platform-browser-dynamic": "6.0.5", 62 | "@compodoc/compodoc": "1.1.3", 63 | "@types/geojson": "7946.0.3", 64 | "@types/jasmine": "2.8.8", 65 | "@types/leaflet": "1.2.7", 66 | "angular2-template-loader": "https://github.com/elasticrash/angular2-template-loader.git", 67 | "awesome-typescript-loader": "5.0.0", 68 | "chalk": "2.3.0", 69 | "codelyzer": "4.0.0", 70 | "core-js": "^2.5.0", 71 | "css-loader": "^0.26.4", 72 | "es-module-loader": "^1.3.5", 73 | "es6-shim": "^0.35.3", 74 | "html-loader": "^0.4.5", 75 | "http-server": "0.11.1", 76 | "istanbul-instrumenter-loader": "^1.2.0", 77 | "jasmine": "^2.7.0", 78 | "jasmine-core": "^2.7.0", 79 | "jasmine-spec-reporter": "2.5.0", 80 | "karma": "1.2.0", 81 | "karma-chrome-launcher": "^2.2.0", 82 | "karma-cli": "^1.0.1", 83 | "karma-coverage": "^1.1.1", 84 | "karma-jasmine": "^1.1.0", 85 | "karma-phantomjs-launcher": "^1.0.4", 86 | "karma-remap-coverage": "^0.1.4", 87 | "karma-sourcemap-loader": "^0.3.7", 88 | "karma-spec-reporter": "0.0.26", 89 | "karma-webpack": "2.0.6", 90 | "leaflet": ">=1.0.0", 91 | "node-sass": "^4.6.0", 92 | "node-static": "^0.7.9", 93 | "phantomjs-prebuilt": "2.1.16", 94 | "plugin-typescript": "^5.3.3", 95 | "protractor": "~4.0.13", 96 | "reflect-metadata": "0.1.10", 97 | "remap-istanbul": "^0.8.4", 98 | "rollup": "^0.51.7", 99 | "rollup-plugin-commonjs": "^8.2.6", 100 | "rollup-plugin-license": "0.5.0", 101 | "rollup-plugin-node-resolve": "3.0.0", 102 | "rollup-plugin-sourcemaps": "0.4.2", 103 | "rxjs": "6.2.1", 104 | "shelljs": "0.7.8", 105 | "source-map-loader": "0.2.3", 106 | "source-map-support": "^0.4.15", 107 | "ts-loader": "3.1.1", 108 | "ts-node": "1.2.1", 109 | "tslint": "^5.10.0", 110 | "typedoc": "^0.8.0", 111 | "typescript": "2.7.2", 112 | "uglify-js": "3.1.6", 113 | "webpack": "^3.8.1", 114 | "zone.js": "^0.8.26" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /public_api.ts: -------------------------------------------------------------------------------- 1 | export * from './src/ngx.leaflet.components'; -------------------------------------------------------------------------------- /rollup.config.esm.js: -------------------------------------------------------------------------------- 1 | import sourcemaps from 'rollup-plugin-sourcemaps'; 2 | import commonjs from 'rollup-plugin-commonjs'; 3 | 4 | const path = require('path'); 5 | 6 | export default { 7 | output: { 8 | format: 'es', 9 | sourcemap: false 10 | }, 11 | plugins: [ 12 | sourcemaps() 13 | , commonjs({ 14 | include: ['node_modules/rxjs/**'] 15 | })], 16 | onwarn: () => { return } 17 | } -------------------------------------------------------------------------------- /rollup.config.umd.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | import sourcemaps from 'rollup-plugin-sourcemaps'; 3 | import commonjs from 'rollup-plugin-commonjs'; 4 | 5 | const globals = { 6 | '@angular/core': 'ng.core', 7 | '@angular/http': 'ng.http', 8 | '@angular/common': 'ng.common', 9 | 'rxjs/Observable': 'Rx', 10 | 'rxjs/add/operator/map': 'Rx.Observable.prototype', 11 | 'rxjs/add/operator/catch': 'Rx.Observable.prototype', 12 | 'leaflet': 'L' 13 | }; 14 | 15 | export default { 16 | external: Object.keys(globals), 17 | plugins: [resolve(), sourcemaps(), commonjs({ 18 | include: ['node_modules/rxjs/**'] 19 | })], 20 | onwarn: () => { return }, 21 | output: { 22 | format: 'umd', 23 | name: 'ng.ngxLeafletComponents', 24 | globals: globals, 25 | external: [ 26 | '@angular/core', 27 | '@angular/http', 28 | 'rxjs/Observable', 29 | 'rxjs/add/operator/map', 30 | 'rxjs/add/operator/catch', 31 | 'leaflet' 32 | ], 33 | sourcemap: false, 34 | exports: 'named' 35 | } 36 | } -------------------------------------------------------------------------------- /src/circle/circle.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, async } from '@angular/core/testing'; 2 | import { By } from '@angular/platform-browser'; 3 | import { DebugElement } from '@angular/core'; 4 | import { CircleElement } from '../circle/circle'; 5 | import { MapService } from '../services/map.service'; 6 | import { GroupService } from '../services/group.service'; 7 | import { PopupService } from '../services/popup.service'; 8 | import { MockComponent } from '../test/mock.component'; 9 | import { LeafletElement } from '../map/map'; 10 | import { GuidService } from '../services/globalId.service'; 11 | 12 | describe('CircleElement', () => { 13 | 14 | const mock: any = MockComponent( 15 | { 16 | selector: "app-element", outputs: [], 17 | template: "" 18 | }); 19 | 20 | beforeEach(() => { 21 | TestBed.configureTestingModule({ 22 | declarations: [mock, 23 | LeafletElement, CircleElement], 24 | providers: [ 25 | MapService, 26 | GroupService, 27 | PopupService, 28 | GuidService 29 | ] 30 | }).compileComponents(); 31 | }); 32 | 33 | it('circle-element works well', async(() => { 34 | const fixture = TestBed.createComponent(mock); 35 | // const el = fixture.debugElement.nativeElement as HTMLElement; 36 | // fixture.detectChanges(); 37 | expect(1).toEqual(1); 38 | })); 39 | }); 40 | -------------------------------------------------------------------------------- /src/circle/circle.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, ElementRef, ViewChild, OnInit, AfterViewInit } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { LeafletGroup } from '../group/group'; 4 | import { MapService } from '../services/map.service'; 5 | import { GroupService } from '../services/group.service'; 6 | import { PopupService } from '../services/popup.service'; 7 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 8 | import { Path } from '../models/path'; 9 | import { Ipath } from '../interfaces/path'; 10 | import * as L from 'leaflet'; 11 | 12 | @Component({ 13 | selector: 'circle-element', 14 | template: `
`, 15 | styles: [''] 16 | }) 17 | 18 | export class CircleElement extends CoordinateHandler implements OnInit, AfterViewInit { 19 | @Input() public lat: number = 52.6; 20 | @Input() public lon: number = -1.1; 21 | @Input() public radius: number = 20; 22 | @Input() public mouseover: string | undefined = undefined; 23 | @Input() public onclick: string | undefined = undefined; 24 | @Input() public Options: any = new Path(null); 25 | @ViewChild('ngel') public ngEl: ElementRef; 26 | 27 | public circle: any = null; 28 | 29 | constructor( 30 | private mapService: MapService, 31 | private popupService: PopupService, 32 | @Optional() private groupService?: GroupService, 33 | @Optional() private leafletElement?: LeafletElement, 34 | @Optional() private leafletGroup?: LeafletGroup) { 35 | super(); 36 | } 37 | 38 | public ngOnInit() { 39 | super.assignCartesianPointToLeafletsLatLngSchema(); 40 | 41 | // check if any of the two optional injections exist 42 | if (this.leafletElement || this.leafletGroup) { 43 | const inheritedOptions: any = new Path(this.Options); 44 | const map = this.mapService.getMap(); 45 | 46 | super.transformPointCoordinates(this.leafletElement.crs); 47 | 48 | this.circle = L.circle([this.lat, this.lon], this.radius, inheritedOptions); 49 | 50 | if (this.leafletGroup) { 51 | this.groupService.addOLayersToGroup(this.circle, map, this.mapService, this.leafletGroup); 52 | } else { 53 | this.circle.addTo(map); 54 | } 55 | } else { 56 | // tslint:disable-next-line:no-console 57 | console.warn(`This circle-element will not be rendered 58 | the expected parent node of circle-element should be either leaf-element or leaflet-group`); 59 | } 60 | } 61 | 62 | public ngAfterViewInit() { 63 | if (this.leafletElement || this.leafletGroup) { 64 | let textInput; 65 | if (this.ngEl.nativeElement.childNodes.length > 0) { 66 | const textNode = this.ngEl.nativeElement.childNodes[0]; 67 | textInput = textNode.nodeValue; 68 | } 69 | 70 | // add popup methods on element only if any of the tests are not undefined 71 | if (this.mouseover !== undefined || this.onclick !== undefined || textInput !== undefined) { 72 | this.popupService.enablePopup(this.mouseover, this.onclick, this.circle, textInput); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/circle/index.ts: -------------------------------------------------------------------------------- 1 | export * from './circle'; 2 | -------------------------------------------------------------------------------- /src/circlemarker/circlemarker.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, ElementRef, ViewChild, AfterViewInit, OnInit } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { LeafletGroup } from '../group/group'; 4 | import { MapService } from '../services/map.service'; 5 | import { GroupService } from '../services/group.service'; 6 | import { PopupService } from '../services/popup.service'; 7 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 8 | import { Path } from '../models/path'; 9 | import { Ipath } from '../interfaces/path'; 10 | import * as L from 'leaflet'; 11 | 12 | @Component({ 13 | selector: 'circle-marker-element', 14 | template: `
`, 15 | styles: [''] 16 | }) 17 | 18 | export class CircleMarkerElement extends CoordinateHandler implements OnInit, AfterViewInit { 19 | @Input() public lat: number = 52.6; 20 | @Input() public lon: number = -1.1; 21 | @Input() public mouseover: string | undefined = undefined; 22 | @Input() public onclick: string | undefined = undefined; 23 | @Input() public Options: any = new Path(null); 24 | @ViewChild('ngel') public ngEl: ElementRef; 25 | public circle: any = null; 26 | 27 | constructor( 28 | private mapService: MapService, 29 | private popupService: PopupService, 30 | @Optional() private groupService?: GroupService, 31 | @Optional() private leafletElement?: LeafletElement, 32 | @Optional() private leafletGroup?: LeafletGroup) { 33 | super(); 34 | } 35 | 36 | public ngOnInit() { 37 | super.assignCartesianPointToLeafletsLatLngSchema(); 38 | // check if any of the two optional injections exist 39 | if (this.leafletElement || this.leafletGroup) { 40 | const inheritedOptions: any = new Path(this.Options); 41 | const map = this.mapService.getMap(); 42 | 43 | const elementPosition: any = super.transformPointCoordinates(this.leafletElement.crs); 44 | 45 | this.circle = L.circleMarker([this.lat, this.lon], inheritedOptions); 46 | 47 | if (this.leafletGroup) { 48 | this.groupService.addOLayersToGroup(this.circle, map, this.mapService, this.leafletGroup); 49 | } else { 50 | this.circle.addTo(map); 51 | } 52 | } else { 53 | // tslint:disable-next-line:no-console 54 | console.warn(`This circle-element will not be rendered 55 | the expected parent node of circle-element should be either leaf-element or leaflet-group`); 56 | } 57 | } 58 | 59 | public ngAfterViewInit() { 60 | let textInput; 61 | if (this.ngEl.nativeElement.childNodes.length > 0) { 62 | const textNode = this.ngEl.nativeElement.childNodes[0]; 63 | textInput = textNode.nodeValue; 64 | } 65 | 66 | // add popup methods on element only if any of the tests are not undefined 67 | if (this.mouseover !== undefined || this.onclick !== undefined || textInput !== undefined) { 68 | this.popupService.enablePopup(this.mouseover, this.onclick, this.circle, textInput); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/circlemarker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './circlemarker'; 2 | -------------------------------------------------------------------------------- /src/geojson/geojson.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, async } from '@angular/core/testing'; 2 | import { By } from '@angular/platform-browser'; 3 | import { DebugElement } from '@angular/core'; 4 | import { GeoJsonElement } from './geojson'; 5 | import { MapService } from '../services/map.service'; 6 | import { GroupService } from '../services/group.service'; 7 | import { PopupService } from '../services/popup.service'; 8 | import { GuidService } from '../services/globalId.service'; 9 | import { HelperService } from '../services/helper.service'; 10 | import { LeafletElement } from '../map/map'; 11 | import { LeafletGroup } from '../group/group'; 12 | import { MockComponent } from '../test/mock.component'; 13 | 14 | describe('GeoJsonElement', () => { 15 | 16 | const g = { 17 | type: "FeatureCollection", 18 | features: [{ 19 | type: "Feature", 20 | geometry: { 21 | type: "Point", 22 | coordinates: [375000, 4202000] 23 | }, 24 | properties: { 25 | prop0: "value0" 26 | } 27 | }, { 28 | type: "Feature", 29 | geometry: { 30 | type: "LineString", 31 | coordinates: [[376000, 4202500], [377000, 4203500]] 32 | }, 33 | properties: { 34 | prop0: "value1" 35 | } 36 | }] 37 | }; 38 | const mock: any = MockComponent( 39 | { 40 | selector: "app-element", outputs: [], 41 | template: "" 43 | }); 44 | 45 | beforeEach(() => { 46 | TestBed.configureTestingModule({ 47 | declarations: [mock, LeafletElement, GeoJsonElement], 48 | providers: [ 49 | MapService, 50 | GroupService, 51 | PopupService, 52 | GuidService, 53 | HelperService 54 | ] 55 | }).compileComponents(); 56 | }); 57 | 58 | it('geojson component test', async(() => { 59 | const appMock = TestBed.createComponent(mock); 60 | appMock.detectChanges(); 61 | const el = appMock.debugElement.nativeElement as HTMLElement; 62 | expect(el.tagName).toEqual("DIV"); 63 | })); 64 | }); -------------------------------------------------------------------------------- /src/geojson/geojson.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, DoCheck, Optional } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { LeafletGroup } from '../group/group'; 4 | import { MapService } from '../services/map.service'; 5 | import { GroupService } from '../services/group.service'; 6 | import { PopupService } from '../services/popup.service'; 7 | import { GuidService } from '../services/globalId.service'; 8 | import { HelperService } from '../services/helper.service'; 9 | import { GeoJSONCoordinateHandler } from '../helpers/geoJsonReader'; 10 | 11 | import * as L from 'leaflet'; 12 | 13 | @Component({ 14 | selector: 'geojson-element', 15 | template: ``, 16 | styles: [''] 17 | }) 18 | 19 | export class GeoJsonElement extends GeoJSONCoordinateHandler implements OnInit, DoCheck { 20 | public originalObject: any = Object.assign({}, this.geojson); 21 | public globalId: string = this.guidService.newGuid(); 22 | 23 | constructor( 24 | private mapService: MapService, 25 | private popupService: PopupService, 26 | private guidService: GuidService, 27 | private helperService: HelperService, 28 | @Optional() private groupService?: GroupService, 29 | @Optional() private leafletElement?: LeafletElement, 30 | @Optional() private leafletGroup?: LeafletGroup) { 31 | super(); 32 | } 33 | 34 | public ngOnInit() { 35 | // check if any of the two optional injections exist 36 | if (this.leafletElement || this.leafletGroup) { 37 | // polyline shouldn't have a fill 38 | const map = this.mapService.getMap(); 39 | 40 | if (this.geojson) { 41 | super.transformJSONCoordinates(this.geojson, this.leafletElement.crs); 42 | 43 | const gjson = L.geoJSON(this.geojson); 44 | 45 | if (this.leafletGroup) { 46 | this.groupService.addOLayersToGroup(gjson, map, this.mapService, this.leafletGroup, false, this.globalId); 47 | } else { 48 | gjson.addTo(map); 49 | } 50 | } else { 51 | // tslint:disable-next-line:no-console 52 | console.warn("geojson object seems to be undefined"); 53 | } 54 | } else { 55 | // tslint:disable-next-line:no-console 56 | console.warn(`This polyline-element will not be rendered 57 | the expected parent node of polyline-element should be either leaf-element or leaflet-group`); 58 | } 59 | 60 | } 61 | 62 | public ngDoCheck() { 63 | const map = this.mapService.getMap(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/geojson/index.ts: -------------------------------------------------------------------------------- 1 | export * from './geojson'; 2 | -------------------------------------------------------------------------------- /src/group/group.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { MapService } from '../services/map.service'; 3 | import { GroupService } from '../services/group.service'; 4 | import { GuidService } from '../services/globalId.service'; 5 | 6 | @Component({ 7 | selector: 'leaflet-group', 8 | template: ``, 9 | styles: [''], 10 | providers: [GroupService] 11 | }) 12 | 13 | export class LeafletGroup { 14 | @Input() public name: string = ''; 15 | public globalId: string = this.guidService.newGuid(); 16 | 17 | constructor( 18 | private mapService: MapService, 19 | private groupService: GroupService, 20 | private guidService: GuidService) { 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/group/index.ts: -------------------------------------------------------------------------------- 1 | export * from './group'; 2 | -------------------------------------------------------------------------------- /src/helpers/coordinateHandler.ts: -------------------------------------------------------------------------------- 1 | import { Input } from '@angular/core'; 2 | 3 | export class CoordinateHandler { 4 | @Input() public lat: number; 5 | @Input() public lon: number; 6 | @Input() public x: number; 7 | @Input() public y: number; 8 | @Input() public latlngs: any; 9 | @Input() public xys: number; 10 | 11 | public assignCartesianPointToLeafletsLatLngSchema() { 12 | if (this.x !== undefined) { 13 | this.lon = this.x; 14 | } 15 | 16 | if (this.y !== undefined) { 17 | this.lat = this.y; 18 | } 19 | } 20 | 21 | public assignCartesianArrayToLeafletsLatLngSchema(arr?) { 22 | if (this.xys !== undefined) { 23 | if (!arr) { 24 | arr = this.xys; 25 | } 26 | 27 | for (const v of arr) { 28 | if (typeof (arr[0]) !== "number") { 29 | this.assignCartesianArrayToLeafletsLatLngSchema(v); 30 | } else { 31 | arr.reverse(); 32 | } 33 | } 34 | this.latlngs = this.xys; 35 | } 36 | } 37 | 38 | public transformPointCoordinates(crs) { 39 | /** 40 | * this is because leaflet default CRS is 3857 (so it can render wms properly) 41 | * but uses 4326 everywhere else so if CRS is 3857 don't reproject coordinates 42 | * also proj4 by default unprojects (inverse) to wgs84 (4326) which is handy but 43 | * doesnt match leaflet's default projection. Generally I don't really agree on 44 | * how leaflet doesn't handle projections on a global state 45 | */ 46 | if (crs.code && crs.code !== "EPSG:3857") { 47 | const newlatlng = crs.unproject({ y: this.lat, x: this.lon }); 48 | this.setNewLatLng(newlatlng); 49 | } else { 50 | const newlatlng = { lat: this.lat, lng: this.lon }; 51 | this.setNewLatLng(newlatlng); 52 | } 53 | } 54 | 55 | public setNewLatLng(newlatlng) { 56 | this.lat = newlatlng.lat; 57 | this.lon = newlatlng.lng; 58 | } 59 | 60 | public transformArrayCoordinates(crs, arr?) { 61 | if (!arr) { 62 | arr = this.latlngs; 63 | } 64 | for (let i = 0; i < arr.length; i++) { 65 | if (typeof (arr[0]) !== "number") { 66 | arr[i] = this.transformArrayCoordinates(crs, arr[i]); 67 | } else { 68 | if (crs.code && crs.code !== "EPSG:3857") { 69 | const trasformed = crs.unproject({ x: arr[0], y: arr[1] }); 70 | arr = { lat: trasformed.lat, lng: trasformed.lng }; 71 | } else { 72 | arr = { lat: arr[0], lng: arr[1] }; 73 | } 74 | } 75 | } 76 | return arr; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/helpers/geoJsonReader.ts: -------------------------------------------------------------------------------- 1 | import { Input } from '@angular/core'; 2 | 3 | export class GeoJSONCoordinateHandler { 4 | @Input() public geojson: any = {}; 5 | 6 | public transformJSONCoordinates(geoJSON: any, crs: any) { 7 | /** 8 | * 7. GeoJSON Types Are Not Extensible 9 | * Implementations MUST NOT extend the fixed set of GeoJSON types: 10 | * FeatureCollection, Feature, Point, LineString, MultiPoint, Polygon, 11 | * MultiLineString, MultiPolygon, and GeometryCollection. 12 | */ 13 | if (geoJSON.type === "FeatureCollection") { 14 | const featureCollection = geoJSON; 15 | featureCollection.features.forEach((feature) => { 16 | this.transformJSONCoordinates(feature, crs); 17 | }); 18 | } 19 | if (geoJSON.type === "Feature") { 20 | const feature = geoJSON; 21 | this.transformJSONCoordinates(feature.geometry, crs); 22 | } 23 | if (geoJSON.type === "Point") { 24 | const point = geoJSON; 25 | this.transformPointCoordinates(point.coordinates, crs); 26 | } 27 | if (geoJSON.type === "LineString") { 28 | const lineString = geoJSON; 29 | lineString.coordinates.forEach((point) => { 30 | this.transformPointCoordinates(point, crs); 31 | }); 32 | } 33 | if (geoJSON.type === "MultiPoint") { 34 | const multiPoint = geoJSON; 35 | multiPoint.coordinates.forEach((point) => { 36 | this.transformPointCoordinates(point, crs); 37 | }); 38 | } 39 | if (geoJSON.type === "Polygon") { 40 | const polygon = geoJSON; 41 | polygon.coordinates.forEach((polygonElement) => { 42 | polygonElement.forEach((point) => { 43 | this.transformPointCoordinates(point, crs); 44 | }); 45 | }); 46 | } 47 | if (geoJSON.type === "MultiLineString") { 48 | const multiLineString = geoJSON; 49 | multiLineString.coordinates.forEach((lineString) => { 50 | lineString.forEach((point) => { 51 | this.transformPointCoordinates(point, crs); 52 | }); 53 | }); 54 | } 55 | if (geoJSON.type === "MultiPolygon") { 56 | const multiPolygon = geoJSON; 57 | multiPolygon.coordinates.forEach((polygon) => { 58 | polygon.forEach((polygonElement) => { 59 | polygonElement.forEach((point) => { 60 | this.transformPointCoordinates(point, crs); 61 | }); 62 | }); 63 | }); 64 | } 65 | if (geoJSON.type === "GeometryCollection") { 66 | const geometryCollection = geoJSON; 67 | geometryCollection.geometries.forEach((geometry) => { 68 | this.transformJSONCoordinates(geometry, crs); 69 | }); 70 | } 71 | } 72 | 73 | public transformPointCoordinates(point, crs) { 74 | /** 75 | * this is because leaflet default CRS is 3857 (so it can render wms properly) 76 | * but uses 4326 everywhere else so if CRS is 3857 don't reproject coordinates 77 | * also proj4 by default unprojects (inverse) to wgs84 (4326) which is handy but 78 | * doesnt match leaflet's default projection. Generally I don't really agree on 79 | * how leaflet doesn't handle projections on a global state 80 | */ 81 | if (crs.code && crs.code !== "EPSG:3857") { 82 | const newlatlng = crs.unproject({ x: point[0], y: point[1] }); 83 | point[1] = newlatlng.lat; 84 | point[0] = newlatlng.lng; 85 | return point; 86 | } else { 87 | return point; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/imageoverlay/image-overlay.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, OnInit } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { MapService } from '../services/map.service'; 4 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 5 | import * as L from 'leaflet'; 6 | 7 | @Component({ 8 | selector: 'image-overlay-element', 9 | template: ``, 10 | styles: [''] 11 | }) 12 | 13 | export class ImageOverlayElement extends CoordinateHandler implements OnInit { 14 | @Input() public bounds: any = [[-26.5, -25], [1021.5, 1023]]; 15 | @Input() public imagepath: string = ''; 16 | @Input() public name: string = ''; 17 | @Input() public opacity: number = 1; 18 | @Input() public type: string = 'overlay'; 19 | public latlngs: any; 20 | 21 | constructor( 22 | private mapService: MapService, 23 | @Optional() private leafletElement?: LeafletElement) { 24 | super(); 25 | } 26 | 27 | public ngOnInit() { 28 | this.latlngs = this.bounds; 29 | 30 | if (this.leafletElement) { 31 | const map = this.mapService.getMap(); 32 | super.transformArrayCoordinates(this.leafletElement.crs); 33 | 34 | let layer = null; 35 | 36 | layer = L.imageOverlay(this.imagepath, this.bounds).setOpacity(this.opacity); 37 | 38 | if (layer !== {}) { 39 | if (this.type === "overlay") { 40 | this.mapService.addOverlay(layer, this.name); 41 | layer.addTo(map); 42 | } else if (this.type === "basemap") { 43 | this.mapService.addBasemap(layer, this.name); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/imageoverlay/index.ts: -------------------------------------------------------------------------------- 1 | export * from './image-overlay'; 2 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { LeafletElement } from './map/map'; 2 | import { AttributionControl } from './map/attribution/attribution'; 3 | import { ScaleControl } from './map/scale/scale'; 4 | import { ZoomControl } from './map/zoom/zoom'; 5 | import { WatermarkControl } from './map/watermark/watermark'; 6 | 7 | import { LayerElement } from './layer/layer'; 8 | import { ImageOverlayElement } from './imageoverlay/image-overlay'; 9 | import { MarkerElement } from './marker/marker'; 10 | import { CircleElement } from './circle/circle'; 11 | import { CircleMarkerElement } from './circlemarker/circlemarker'; 12 | import { PolygonElement } from './polygon/polygon'; 13 | import { PolylineElement } from './polyline/polyline'; 14 | import { GeoJsonElement } from './geojson/geojson'; 15 | 16 | import { PopupElement } from './popup/popup'; 17 | import { LeafletGroup } from './group/group'; 18 | 19 | import { MapService } from './services/map.service'; 20 | import { GroupService } from './services/group.service'; 21 | import { PopupService } from './services/popup.service'; 22 | import { GuidService } from './services/globalId.service'; 23 | import { HelperService } from './services/helper.service'; 24 | 25 | export const CandTLeafletComponent = [ 26 | // map and controls 27 | LeafletElement, 28 | AttributionControl, 29 | ScaleControl, 30 | ZoomControl, 31 | WatermarkControl, 32 | // layers and vectors 33 | LayerElement, 34 | ImageOverlayElement, 35 | MarkerElement, 36 | CircleElement, 37 | CircleMarkerElement, 38 | PolygonElement, 39 | PolylineElement, 40 | GeoJsonElement, 41 | PopupElement, 42 | // rest 43 | LeafletGroup 44 | ]; 45 | 46 | export const CandTLeafletService = [MapService, 47 | GroupService, 48 | PopupService, 49 | GuidService, 50 | HelperService]; 51 | -------------------------------------------------------------------------------- /src/interfaces/path.ts: -------------------------------------------------------------------------------- 1 | export interface Ipath { 2 | stroke: boolean; 3 | color: string; 4 | weight: number; 5 | opacity: number; 6 | lineJoin: string; 7 | dashArray: string; 8 | dashOffset: string; 9 | fill: boolean; 10 | fillColor: string; 11 | fillOpacity: number; 12 | fillRule: string; 13 | className: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/layer/index.ts: -------------------------------------------------------------------------------- 1 | export * from './layer'; 2 | -------------------------------------------------------------------------------- /src/layer/layer.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { MapService } from '../services/map.service'; 3 | import * as L from 'leaflet'; 4 | 5 | @Component({ 6 | selector: 'layer-element', 7 | template: ``, 8 | styles: [''] 9 | }) 10 | 11 | export class LayerElement implements OnInit { 12 | @Input() public slippyLayer: string = ''; 13 | @Input() public wmsLayer: string = ''; 14 | @Input() public name: string = ''; 15 | @Input() public opacity: number = 1; 16 | @Input() public type: string = 'overlay'; 17 | @Input() public attribution: string = null; 18 | 19 | constructor(private mapService: MapService) { 20 | } 21 | 22 | public ngOnInit() { 23 | this.mapService.increaseNumber(); 24 | const map = this.mapService.getMap(); 25 | let layer = null; 26 | if (this.slippyLayer !== "") { 27 | layer = L.tileLayer(this.slippyLayer, { 28 | attribution: this.attribution, 29 | }); 30 | } 31 | if (this.wmsLayer !== "" && this.name !== "") { 32 | layer = L.tileLayer.wms(this.wmsLayer, { 33 | layers: this.name, 34 | attribution: this.attribution 35 | }).setOpacity(this.opacity); 36 | } 37 | 38 | if (layer !== {}) { 39 | if (this.type === "overlay") { 40 | this.mapService.addOverlay(layer, this.name); 41 | layer.addTo(map); 42 | } else if (this.type === "basemap") { 43 | this.mapService.addBasemap(layer, this.name); 44 | layer.addTo(map); 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/map/attribution/attribution.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, OnInit } from '@angular/core'; 2 | import { LeafletElement } from '../map'; 3 | import { MapService } from '../../services/map.service'; 4 | import { AttributionModel } from '../../models/AttributionModel'; 5 | import * as L from 'leaflet'; 6 | 7 | @Component({ 8 | selector: 'attribution-control', 9 | template: ``, 10 | styles: [''] 11 | }) 12 | export class AttributionControl implements OnInit { 13 | @Input() public Options: any = new AttributionModel(null); 14 | constructor( 15 | private mapService: MapService, 16 | @Optional() private leafletElement?: LeafletElement) { } 17 | 18 | public ngOnInit() { 19 | if (this.leafletElement) { 20 | const map = this.mapService.getMap(); 21 | L.control.attribution(this.Options).addTo(map); 22 | } else { 23 | // tslint:disable-next-line:no-console 24 | console.warn(`This attribution-control will not be rendered 25 | the expected parent node of attribution-control should be either leaf-element or layer-element`); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/map/attribution/index.ts: -------------------------------------------------------------------------------- 1 | export * from './attribution'; 2 | -------------------------------------------------------------------------------- /src/map/index.ts: -------------------------------------------------------------------------------- 1 | export * from './map'; 2 | export * from './attribution/attribution'; 3 | export * from './scale/scale'; 4 | export * from './zoom/zoom'; 5 | export * from './watermark/watermark'; 6 | -------------------------------------------------------------------------------- /src/map/map.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, async } from '@angular/core/testing'; 2 | import { By } from '@angular/platform-browser'; 3 | import { DebugElement } from '@angular/core'; 4 | import { LeafletElement } from './map'; 5 | import { MapService } from '../services/map.service'; 6 | 7 | 8 | describe('LeafletElement', () => { 9 | 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [LeafletElement], // declare the test component 13 | providers: [{ provide: MapService }] 14 | }).compileComponents(); 15 | }); 16 | 17 | it('works well', async(() => { 18 | const fixture = TestBed.createComponent(LeafletElement); 19 | fixture.componentInstance.lat = 52.6; 20 | fixture.detectChanges(); 21 | const el = fixture.debugElement.nativeElement as HTMLElement; 22 | expect(fixture.componentInstance.lat).toBe(52.6); 23 | })) 24 | }); 25 | 26 | describe('sub map test', () => { 27 | it('never fails', () => { 28 | expect(1).toBe(1); 29 | }); 30 | }); -------------------------------------------------------------------------------- /src/map/map.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, ViewChild, ElementRef, OnInit } from '@angular/core'; 2 | import { MapService } from '../services/map.service'; 3 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 4 | import * as L from 'leaflet'; 5 | 6 | @Component({ 7 | selector: 'leaf-element', 8 | template: ` 9 |
10 |
11 |
`, 12 | styles: [ 13 | ':host {width: 100%;height:100%;}' + 14 | ':host .map-container {position: absolute;display: block;top: 0px;left: 0px;right: 0px;bottom: 0px;}' + 15 | 'leaf-element{width:100%;}' + 16 | '.leaflet-pane {z-index: 0 !important;}' + 17 | '.leaflet-bottom.leaflet-left {z-index: 1 !important;}'], 18 | providers: [MapService] 19 | }) 20 | 21 | export class LeafletElement extends CoordinateHandler implements OnInit { 22 | @Input() public lat: number = 52.6; 23 | @Input() public lon: number = -1.1; 24 | @Input() public zoom: number = 12; 25 | @Input() public minZoom: number = 4; 26 | @Input() public maxZoom: number = 19; 27 | @Input() public layerControl: boolean = false; 28 | @Input() public crs: any = L.CRS.EPSG3857; 29 | @Input() public zoomControl: boolean; 30 | @Input() public maxBounds: L.LatLngBounds = null; 31 | @ViewChild('map') public mapElement: ElementRef; 32 | 33 | public layerControlObject = null; 34 | 35 | constructor(private mapService: MapService) { 36 | super(); 37 | } 38 | 39 | public ngOnInit() { 40 | super.assignCartesianPointToLeafletsLatLngSchema(); 41 | 42 | if (typeof (this.crs) === "string") { 43 | const splitCrs = this.crs.split("."); 44 | if (splitCrs[0] === "L") { 45 | this.crs = L[splitCrs[1]][splitCrs[2]]; 46 | } else { 47 | // tslint:disable-next-line:no-console 48 | console.warn("something is not right, reverting to default EPSG3857"); 49 | this.crs = L.CRS.EPSG3857; 50 | } 51 | } 52 | 53 | super.transformPointCoordinates(this.crs); 54 | 55 | const map = L.map(this.mapElement.nativeElement, { 56 | crs: this.crs, 57 | zoomControl: this.zoomControl, 58 | center: L.latLng(this.lat, this.lon), 59 | zoom: this.zoom, 60 | minZoom: this.minZoom, 61 | maxZoom: this.maxZoom, 62 | maxBounds: this.maxBounds, 63 | layers: [], 64 | closePopupOnClick: false, 65 | attributionControl: false 66 | }); 67 | this.mapElement.nativeElement.myMapProperty = map; 68 | 69 | // set variables for childrent components 70 | this.mapService.setMap(map); 71 | this.mapService.setLayerControl(this.layerControl); 72 | } 73 | 74 | public setLayerControl() { 75 | if (this.layerControl) { 76 | const map = this.mapService.getMap(); 77 | if (this.layerControlObject !== null) { 78 | this.layerControlObject.getContainer().innerHTML = ''; 79 | } 80 | this.layerControlObject = L.control.layers(this.mapService.getBasemaps(), 81 | this.mapService.getOverlays()).addTo(map); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/map/scale/index.ts: -------------------------------------------------------------------------------- 1 | export * from './scale'; 2 | -------------------------------------------------------------------------------- /src/map/scale/scale.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, OnInit } from '@angular/core'; 2 | import { LeafletElement } from '../map'; 3 | import { MapService } from '../../services/map.service'; 4 | import { ScaleModel } from '../../models/scaleModel'; 5 | import * as L from 'leaflet'; 6 | 7 | 8 | @Component({ 9 | selector: 'scale-control', 10 | template: ``, 11 | styles: [''] 12 | }) 13 | export class ScaleControl implements OnInit { 14 | @Input() public Options: any = new ScaleModel(null); 15 | constructor( 16 | private mapService: MapService, 17 | @Optional() private leafletElement?: LeafletElement) { 18 | } 19 | 20 | public ngOnInit() { 21 | if (this.leafletElement) { 22 | const map = this.mapService.getMap(); 23 | L.control.scale(this.Options).addTo(map); 24 | } else { 25 | // tslint:disable-next-line:no-console 26 | console.warn(`This scale-control will not be rendered 27 | the expected parent node of scale-control should be leaf-element`); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/map/watermark/index.ts: -------------------------------------------------------------------------------- 1 | export * from './watermark'; 2 | -------------------------------------------------------------------------------- /src/map/watermark/watermark.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, OnInit } from '@angular/core'; 2 | import { MapService } from '../../services/map.service'; 3 | import { LeafletElement } from '../map'; 4 | import * as L from 'leaflet'; 5 | 6 | @Component({ 7 | selector: 'watermark-element', 8 | template: ``, 9 | styles: [''] 10 | }) 11 | 12 | export class WatermarkControl implements OnInit { 13 | @Input() public url: string; 14 | @Input() public imagewidth: number; 15 | @Input() public imageheight: number; 16 | 17 | constructor( 18 | private mapService: MapService, 19 | @Optional() private leafletElement?: LeafletElement) { } 20 | 21 | public ngOnInit() { 22 | const self = this; 23 | if (this.leafletElement) { 24 | const map = this.mapService.getMap(); 25 | if (this.url) { 26 | L.Control['Watermark'] = {} as any; 27 | 28 | L.Control['Watermark'] = L.Control.extend({ 29 | onAdd: (fmap) => { 30 | const basediv: any = L.DomUtil.create('div', 'watermark'); 31 | 32 | const howManyInX = Math.ceil(fmap.getSize().x / self.imagewidth); 33 | const howManyInY = Math.ceil(fmap.getSize().y / self.imageheight); 34 | 35 | const numberOfLogo = howManyInX * howManyInY; 36 | 37 | let i = 0; 38 | for (i; i < numberOfLogo; i++) { 39 | const img: any = L.DomUtil.create('img', 'watermark-elements', basediv); 40 | img.src = self.url; 41 | img.style.width = self.imagewidth + 'px'; 42 | } 43 | return basediv; 44 | }, 45 | 46 | onRemove: (fmap) => { 47 | // TODO 48 | } 49 | }); 50 | 51 | L.control['watermark'] = (opts) => { 52 | return new L.Control['Watermark'](opts); 53 | }; 54 | } 55 | 56 | L.control['watermark']({ position: "bottomleft" }).addTo(map); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/map/zoom/index.ts: -------------------------------------------------------------------------------- 1 | export * from './zoom'; 2 | -------------------------------------------------------------------------------- /src/map/zoom/zoom.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, OnInit } from '@angular/core'; 2 | import { LeafletElement } from '../map'; 3 | import { MapService } from '../../services/map.service'; 4 | import { ΖoomModel } from '../../models/zoomModel'; 5 | import * as L from 'leaflet'; 6 | 7 | @Component({ 8 | selector: 'zoom-control', 9 | template: ``, 10 | styles: [''] 11 | }) 12 | export class ZoomControl implements OnInit { 13 | @Input() public Options: any = new ΖoomModel(null); 14 | constructor( 15 | private mapService: MapService, 16 | @Optional() private leafletElement?: LeafletElement) { 17 | } 18 | 19 | public ngOnInit() { 20 | if (this.leafletElement) { 21 | const map = this.mapService.getMap(); 22 | L.control.zoom(this.Options).addTo(map); 23 | } else { 24 | // tslint:disable-next-line:no-console 25 | console.warn(`This zoom-control will not be rendered 26 | the expected parent node of zoom-control should be leaf-element`); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/marker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './marker'; 2 | -------------------------------------------------------------------------------- /src/marker/marker.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, ElementRef, ViewChild, OnInit } from '@angular/core'; 2 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import { MapService } from '../services/map.service'; 4 | import { GroupService } from '../services/group.service'; 5 | import { PopupService } from '../services/popup.service'; 6 | import { LeafletElement } from '../map/map'; 7 | import { LeafletGroup } from '../group/group'; 8 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 9 | import { Observable } from 'rxjs'; 10 | import { map } from 'rxjs/operators'; 11 | import * as L from 'leaflet'; 12 | 13 | @Component({ 14 | selector: 'marker-element', 15 | template: `
`, 16 | styles: [''], 17 | providers: [PopupService] 18 | }) 19 | 20 | export class MarkerElement extends CoordinateHandler implements OnInit { 21 | @Input() public lat: number = 52.6; 22 | @Input() public lon: number = -1.1; 23 | @Input() public mouseover: string | undefined = undefined; 24 | @Input() public onclick: string | undefined = undefined; 25 | @Input() public iconUrl: string = ""; 26 | @ViewChild('ngel') public ngEl: ElementRef; 27 | public marker: any = null; 28 | 29 | constructor( 30 | private mapService: MapService, 31 | private popupService: PopupService, 32 | private http: HttpClient, 33 | @Optional() private groupService?: GroupService, 34 | @Optional() private leafletElement?: LeafletElement, 35 | @Optional() private leafletGroup?: LeafletGroup) { 36 | super(); 37 | } 38 | 39 | public ngOnInit() { 40 | super.assignCartesianPointToLeafletsLatLngSchema(); 41 | const model = this; 42 | if (this.leafletElement || this.leafletGroup) { 43 | 44 | const mapObject = this.mapService.getMap(); 45 | 46 | super.transformPointCoordinates(this.leafletElement.crs); 47 | 48 | if (this.iconUrl === "") { 49 | this.marker = L.marker([this.lat, this.lon]); 50 | this.createMarkerlayer(this.marker, mapObject); 51 | } else { 52 | this.imageExists(this.iconUrl, (exists) => { 53 | 54 | model.getImage().subscribe( 55 | (image) => { 56 | const img = document.createElement("img"); 57 | window.URL.createObjectURL(image.blob()); 58 | const reader = new FileReader(); 59 | reader.onload = () => { 60 | img.src = reader.result; 61 | const myIcon = L.icon({ 62 | iconUrl: model.iconUrl, 63 | iconSize: [img.width, img.height], 64 | iconAnchor: [img.width / 2, img.height - 1], 65 | popupAnchor: [0, -img.height] 66 | }); 67 | 68 | const obj = { icon: myIcon, options: null }; 69 | model.marker = L.marker([model.lat, model.lon], obj); 70 | model.createMarkerlayer(model.marker, mapObject); 71 | }; 72 | reader.readAsDataURL(image.blob()); 73 | }, (err) => { 74 | // tslint:disable-next-line:no-console 75 | console.log(err); 76 | }); 77 | }); 78 | } 79 | } else { 80 | // tslint:disable-next-line:no-console 81 | console.warn(`This marker-element will not be rendered 82 | the expected parent node of marker-element should be either leaf-element or leaflet-group`); 83 | } 84 | } 85 | 86 | public createMarkerlayer(marker, mapObject) { 87 | let textInput; 88 | if (this.ngEl.nativeElement.childNodes.length > 0) { 89 | const textNode = this.ngEl.nativeElement.childNodes[0]; 90 | textInput = textNode.nodeValue; 91 | } 92 | 93 | // add popup methods on element only if any of the tests are not undefined 94 | if (this.mouseover !== undefined || this.onclick !== undefined || textInput !== undefined) { 95 | this.popupService.enablePopup(this.mouseover, this.onclick, this.marker, textInput); 96 | } 97 | 98 | // only if the parent is map should the marker-element should be directly added to the map 99 | if (this.leafletGroup) { 100 | this.groupService.addOLayersToGroup(marker, mapObject, this.mapService, this.leafletGroup); 101 | } else { 102 | marker.addTo(mapObject); 103 | } 104 | } 105 | 106 | public imageExists(url, callback) { 107 | const img = new Image(); 108 | img.onload = () => { callback(true); }; 109 | img.onerror = () => { callback(false); }; 110 | img.src = url; 111 | } 112 | 113 | public getImage(): any { 114 | const headers = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'); 115 | return this.http.get(this.iconUrl, { 116 | headers, 117 | responseType: "blob" 118 | }).pipe(map((res: Response) => res)).toPromise() 119 | .catch((error: any) => Observable.throw('Server error')); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/models/attributionModel.ts: -------------------------------------------------------------------------------- 1 | export class AttributionModel { 2 | // The HTML text shown before the attributions. Pass false to disable. 3 | public prefix: string = "Leaflet"; 4 | // The position of the control (one of the map corners). 5 | // Possible values are 'topleft', 'topright', 'bottomleft' or 'bottomright' 6 | public position: string = "bottomright"; 7 | 8 | constructor(options: any) { 9 | if (options !== null) { 10 | for (const key in options) { 11 | if (options[key] !== undefined) { 12 | this[key] = options[key]; 13 | } 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/models/path.ts: -------------------------------------------------------------------------------- 1 | export class Path { 2 | // Whether to draw stroke along the path. Set it to false to disable borders on polygons or circles. 3 | public stroke: boolean = true; 4 | // Stroke color 5 | public color: string = '#3388ff'; 6 | // Stroke width in pixels 7 | public weight: number = 3; 8 | // Stroke opacity 9 | public opacity: number = 1; 10 | // A string that defines shape to be used at the end of the stroke. 11 | public lineCap: string = 'round'; 12 | // A string that defines shape to be used at the corners of the stroke. 13 | public lineJoin: string = 'round'; 14 | // A string that defines the stroke dash pattern. Doesn't work on Canvas-powered layers in some old browsers. 15 | public dashArray: string = null; 16 | // A string that defines the distance into the dash pattern to start the dash. 17 | // Doesn't work on Canvas-powered layers in some old browsers. 18 | public dashOffset: string = null; 19 | // Whether to fill the path with color.Set it to false to disable filling on polygons or circles. 20 | public fill: boolean = true; 21 | // Fill color. Defaults to the value of the color option 22 | public fillColor: string = '#3388ff'; 23 | // Fill opacity. 24 | public fillOpacity: number = 0.2; 25 | // A string that defines how the inside of a shape is determined. 26 | public fillRule: string = 'evenodd'; 27 | // TODO renderer: Renderer; 28 | // Use this specific instance of Renderer for this path. Takes precedence over the map's default renderer. 29 | // null Custom class name set on an element. Only for SVG renderer. 30 | public className: string = null; 31 | constructor(pathInfo: any) { 32 | const source: any = pathInfo; 33 | const copy: any = this; 34 | if (source !== null) { 35 | for (const key in source) { 36 | if (source[key] !== undefined) { 37 | copy[key] = source[key]; 38 | } 39 | } 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/models/scaleModel.ts: -------------------------------------------------------------------------------- 1 | export class ScaleModel { 2 | // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500). 3 | public maxWidth: number = 100; 4 | // Whether to show the metric scale line (m/km). 5 | public metric: boolean = true; 6 | // Whether to show the imperial scale line (mi/ft). 7 | public imperial: boolean = true; 8 | // If true, the control is updated on moveend, otherwise it's always up-to-date (updated on move). 9 | public updateWhenIdle: boolean = true; 10 | // The position of the control (one of the map corners). 11 | // Possible values are 'topleft', 'topright', 'bottomleft' or 'bottomright' 12 | public position: string = "bottomleft"; 13 | 14 | constructor(options: any) { 15 | const source: any = options; 16 | const copy: any = this; 17 | 18 | if (source !== null) { 19 | for (const key in source) { 20 | if (source[key] !== undefined) { 21 | copy[key] = source[key]; 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/models/zoomModel.ts: -------------------------------------------------------------------------------- 1 | export class ΖoomModel { 2 | // The text set on the 'zoom in' button. 3 | public zoomInText: string = "+"; 4 | // The title set on the 'zoom in' button. 5 | public zoomInTitle: string = "Zoom in"; 6 | // The text set on the 'zoom out' button. 7 | public zoomOutText: string = "-"; 8 | // The title set on the 'zoom out' button. 9 | public zoomOutTitle: string = "Zoom out"; 10 | // The position of the control (one of the map corners). 11 | // Possible values are 'topleft', 'topright', 'bottomleft' or 'bottomright' 12 | public position: string = "topright"; 13 | constructor(options: any) { 14 | const source: any = options; 15 | const copy: any = this; 16 | 17 | if (source !== null) { 18 | for (const key in source) { 19 | if (source[key] !== undefined) { 20 | copy[key] = source[key]; 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/ngx.leaflet.components.ts: -------------------------------------------------------------------------------- 1 | export { LeafletElement } from './map/map'; 2 | export { CoordinateHandler } from './helpers/coordinateHandler'; 3 | export { GeoJSONCoordinateHandler } from './helpers/geoJsonReader'; 4 | export { AttributionControl } from './map/attribution/attribution'; 5 | export { ScaleControl } from './map/scale/scale'; 6 | export { ZoomControl } from './map/zoom/zoom'; 7 | export { WatermarkControl } from './map/watermark/watermark'; 8 | export { LayerElement } from './layer/layer'; 9 | export { ImageOverlayElement } from './imageoverlay/image-overlay'; 10 | export { MarkerElement } from './marker/marker'; 11 | export { CircleElement } from './circle/circle'; 12 | export { CircleMarkerElement } from './circlemarker/circlemarker'; 13 | export { PolygonElement } from './polygon/polygon'; 14 | export { PolylineElement } from './polyline/polyline'; 15 | export { GeoJsonElement } from './geojson/geojson'; 16 | export { PopupElement } from './popup/popup'; 17 | export { LeafletGroup } from './group/group'; 18 | export { MapService } from './services/map.service'; 19 | export { GroupService } from './services/group.service'; 20 | export { PopupService } from './services/popup.service'; 21 | export { GuidService } from './services/globalId.service'; 22 | export { HelperService } from './services/helper.service'; 23 | export { AttributionModel } from './models/AttributionModel'; 24 | export { Path } from './models/path'; 25 | export { ScaleModel } from './models/scaleModel'; 26 | export { ΖoomModel } from './models/zoomModel'; 27 | export { ngxLeafletModule } from './ngx.leaflet.module'; 28 | -------------------------------------------------------------------------------- /src/ngx.leaflet.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from "@angular/core"; 2 | import { LeafletElement } from './map/map'; 3 | import { AttributionControl } from './map/attribution/attribution'; 4 | import { ScaleControl } from './map/scale/scale'; 5 | import { ZoomControl } from './map/zoom/zoom'; 6 | import { WatermarkControl } from './map/watermark/watermark'; 7 | 8 | import { LayerElement } from './layer/layer'; 9 | import { ImageOverlayElement } from './imageoverlay/image-overlay'; 10 | import { MarkerElement } from './marker/marker'; 11 | import { CircleElement } from './circle/circle'; 12 | import { CircleMarkerElement } from './circlemarker/circlemarker'; 13 | import { PolygonElement } from './polygon/polygon'; 14 | import { PolylineElement } from './polyline/polyline'; 15 | import { GeoJsonElement } from './geojson/geojson'; 16 | 17 | import { PopupElement } from './popup/popup'; 18 | import { LeafletGroup } from './group/group'; 19 | 20 | import { MapService } from './services/map.service'; 21 | import { GroupService } from './services/group.service'; 22 | import { PopupService } from './services/popup.service'; 23 | import { GuidService } from './services/globalId.service'; 24 | import { HelperService } from './services/helper.service'; 25 | import { HttpModule } from '@angular/http'; 26 | import { ElementRef } from "@angular/core"; 27 | import { CommonModule } from "@angular/common"; 28 | 29 | @NgModule({ 30 | imports: [ 31 | CommonModule, 32 | HttpModule 33 | ], 34 | declarations: [ 35 | LeafletElement, 36 | AttributionControl, 37 | ScaleControl, 38 | ZoomControl, 39 | WatermarkControl, 40 | LayerElement, 41 | ImageOverlayElement, 42 | MarkerElement, 43 | CircleElement, 44 | CircleMarkerElement, 45 | PolygonElement, 46 | PolylineElement, 47 | GeoJsonElement, 48 | PopupElement, 49 | LeafletGroup 50 | ], 51 | providers: [ 52 | PopupService, 53 | GuidService, 54 | HelperService 55 | ], 56 | exports: [ 57 | LeafletElement, 58 | AttributionControl, 59 | ScaleControl, 60 | ZoomControl, 61 | WatermarkControl, 62 | LayerElement, 63 | ImageOverlayElement, 64 | MarkerElement, 65 | CircleElement, 66 | CircleMarkerElement, 67 | PolygonElement, 68 | PolylineElement, 69 | GeoJsonElement, 70 | PopupElement, 71 | LeafletGroup 72 | ] 73 | }) 74 | 75 | export class ngxLeafletModule { } 76 | -------------------------------------------------------------------------------- /src/polygon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './polygon'; 2 | -------------------------------------------------------------------------------- /src/polygon/polygon.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, ElementRef, ViewChild, OnInit, AfterViewInit, DoCheck } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { LeafletGroup } from '../group/group'; 4 | import { MapService } from '../services/map.service'; 5 | import { GroupService } from '../services/group.service'; 6 | import { PopupService } from '../services/popup.service'; 7 | import { GuidService } from '../services/globalId.service'; 8 | import { HelperService } from '../services/helper.service'; 9 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 10 | import { Path } from '../models/path'; 11 | import * as L from 'leaflet'; 12 | 13 | @Component({ 14 | selector: 'polygon-element', 15 | template: `
`, 16 | styles: [''] 17 | }) 18 | 19 | export class PolygonElement extends CoordinateHandler implements OnInit, AfterViewInit, DoCheck { 20 | @Input() public latlngs: any = [[[52.65, -1.2], [52.645, -1.15], [52.696, -1.155], [52.697, -1.189]], 21 | [[52.66, -1.19], [52.665, -1.16], [52.686, -1.161], [52.687, -1.179]]]; 22 | @Input() public Options: Path = new Path(null); 23 | @Input() public mouseover: string | undefined = undefined; 24 | @Input() public onclick: string | undefined = undefined; 25 | @ViewChild('ngel') public ngEl: ElementRef; 26 | public polygon: any = null; 27 | public originalObject: any = [...this.latlngs]; 28 | public globalId: string = this.guidService.newGuid(); 29 | 30 | constructor( 31 | private mapService: MapService, 32 | private popupService: PopupService, 33 | private guidService: GuidService, 34 | private helperService: HelperService, 35 | @Optional() private groupService?: GroupService, 36 | @Optional() private leafletElement?: LeafletElement, 37 | @Optional() private leafletGroup?: LeafletGroup) { 38 | super(); 39 | } 40 | 41 | public ngOnInit() { 42 | super.assignCartesianArrayToLeafletsLatLngSchema(); 43 | // check if any of the two optional injections exist 44 | if (this.leafletElement || this.leafletGroup) { 45 | const inheritedOptions: any = new Path(this.Options); 46 | const map = this.mapService.getMap(); 47 | 48 | super.transformArrayCoordinates(this.leafletElement.crs); 49 | 50 | this.polygon = L.polygon([this.latlngs], inheritedOptions); 51 | 52 | if (this.leafletGroup) { 53 | this.groupService.addOLayersToGroup( 54 | this.polygon, map, this.mapService, this.leafletGroup, false, this.globalId); 55 | } else { 56 | this.polygon.addTo(map); 57 | } 58 | } else { 59 | // tslint:disable-next-line:no-console 60 | console.warn(`This polygon-element will not be rendered 61 | the expected parent node of polygon-element should be either leaf-element or leaflet-group`); 62 | } 63 | } 64 | 65 | public ngAfterViewInit() { 66 | let textInput; 67 | if (this.ngEl.nativeElement.childNodes.length > 0) { 68 | const textNode = this.ngEl.nativeElement.childNodes[0]; 69 | textInput = textNode.nodeValue; 70 | } 71 | 72 | // add popup methods on element only if any of the tests are not undefined 73 | if (this.mouseover !== undefined || this.onclick !== undefined || textInput !== undefined) { 74 | this.popupService.enablePopup(this.mouseover, this.onclick, this.polygon, textInput); 75 | } 76 | } 77 | 78 | public ngDoCheck() { 79 | const map = this.mapService.getMap(); 80 | 81 | const same: boolean = this.helperService.arrayCompare(this.originalObject, this.latlngs); 82 | 83 | if (!same) { 84 | this.originalObject = [...this.latlngs]; 85 | // if the layer is part of a group 86 | const inheritedOptions: any = new Path(this.Options); 87 | 88 | if (this.leafletGroup) { 89 | this.polygon = L.polygon([this.latlngs], inheritedOptions); 90 | this.groupService.addOLayersToGroup(this.polygon, map, this.mapService, this.leafletGroup, true, this.globalId); 91 | } else { 92 | map.removeLayer(this.polygon); 93 | this.polygon = L.polygon([this.latlngs], inheritedOptions); 94 | this.polygon.addTo(map); 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/polyline/index.ts: -------------------------------------------------------------------------------- 1 | export * from './polyline'; 2 | -------------------------------------------------------------------------------- /src/polyline/polyline.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, ElementRef, ViewChild, OnInit, AfterViewInit, DoCheck } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { LeafletGroup } from '../group/group'; 4 | import { MapService } from '../services/map.service'; 5 | import { GroupService } from '../services/group.service'; 6 | import { PopupService } from '../services/popup.service'; 7 | import { GuidService } from '../services/globalId.service'; 8 | import { HelperService } from '../services/helper.service'; 9 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 10 | import { Path } from '../models/path'; 11 | import { Ipath } from '../interfaces/path'; 12 | import * as L from 'leaflet'; 13 | 14 | @Component({ 15 | selector: 'polyline-element', 16 | template: `
`, 17 | styles: [''] 18 | }) 19 | 20 | export class PolylineElement extends CoordinateHandler implements OnInit, AfterViewInit, DoCheck { 21 | @Input() public latlngs: any = [[52.6, -1.1], [52.605, -1.1], [52.606, -1.105], [52.697, -1.109]]; 22 | @Input() public Options: any = new Path(null); 23 | @Input() public mouseover: string | undefined = undefined; 24 | @Input() public onclick: string | undefined = undefined; 25 | @ViewChild('ngel') public ngEl: ElementRef; 26 | public polyline: any = null; 27 | public originalObject: any = [...this.latlngs]; 28 | public globalId: string = this.guidService.newGuid(); 29 | 30 | constructor( 31 | private mapService: MapService, 32 | private popupService: PopupService, 33 | private guidService: GuidService, 34 | private helperService: HelperService, 35 | @Optional() private groupService?: GroupService, 36 | @Optional() private leafletElement?: LeafletElement, 37 | @Optional() private leafletGroup?: LeafletGroup) { 38 | super(); 39 | } 40 | 41 | public ngOnInit() { 42 | super.assignCartesianArrayToLeafletsLatLngSchema(); 43 | // check if any of the two optional injections exist 44 | if (this.leafletElement || this.leafletGroup) { 45 | // polyline shouldn't have a fill 46 | this.Options.fill = false; 47 | const inheritedOptions: any = new Path(this.Options); 48 | const map = this.mapService.getMap(); 49 | 50 | super.transformArrayCoordinates(this.leafletElement.crs); 51 | 52 | this.polyline = L.polyline(this.latlngs, inheritedOptions); 53 | 54 | if (this.leafletGroup) { 55 | this.groupService.addOLayersToGroup( 56 | this.polyline, map, this.mapService, this.leafletGroup, false, this.globalId); 57 | } else { 58 | this.polyline.addTo(map); 59 | } 60 | } else { 61 | // tslint:disable-next-line:no-console 62 | console.warn(`This polyline-element will not be rendered 63 | the expected parent node of polyline-element should be either leaf-element or leaflet-group`); 64 | } 65 | } 66 | 67 | public ngAfterViewInit() { 68 | let textInput; 69 | if (this.ngEl.nativeElement.childNodes.length > 0) { 70 | const textNode = this.ngEl.nativeElement.childNodes[0]; 71 | textInput = textNode.nodeValue; 72 | } 73 | 74 | // add popup methods on element only if any of the tests are not undefined 75 | if (this.mouseover !== undefined || this.onclick !== undefined || textInput !== undefined) { 76 | this.popupService.enablePopup(this.mouseover, this.onclick, this.polyline, textInput); 77 | } 78 | } 79 | 80 | public ngDoCheck() { 81 | const map = this.mapService.getMap(); 82 | 83 | const same: boolean = this.helperService.arrayCompare(this.originalObject, this.latlngs); 84 | 85 | if (!same) { 86 | this.originalObject = [...this.latlngs]; 87 | // if the layer is part of a group 88 | this.Options.fill = false; 89 | const inheritedOptions: any = new Path(this.Options); 90 | 91 | if (this.leafletGroup) { 92 | this.polyline = L.polyline(this.latlngs, inheritedOptions); 93 | this.groupService.addOLayersToGroup( 94 | this.polyline, map, this.mapService, this.leafletGroup, true, this.globalId); 95 | } else { 96 | map.removeLayer(this.polyline); 97 | this.polyline = L.polyline(this.latlngs, inheritedOptions); 98 | this.polyline.addTo(map); 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/popup/index.ts: -------------------------------------------------------------------------------- 1 | export * from './popup'; 2 | -------------------------------------------------------------------------------- /src/popup/popup.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Optional, OnInit } from '@angular/core'; 2 | import { LeafletElement } from '../map/map'; 3 | import { LeafletGroup } from '../group/group'; 4 | import { MapService } from '../services/map.service'; 5 | import { GroupService } from '../services/group.service'; 6 | import { CoordinateHandler } from '../helpers/coordinateHandler'; 7 | import * as L from 'leaflet'; 8 | 9 | @Component({ 10 | selector: 'popup-element', 11 | template: ``, 12 | styles: [''] 13 | }) 14 | 15 | export class PopupElement extends CoordinateHandler implements OnInit { 16 | @Input() public lat: number = 52.6; 17 | @Input() public lon: number = -1.9; 18 | @Input() public content: string = "nice popup"; 19 | 20 | constructor( 21 | private mapService: MapService, 22 | @Optional() private groupService?: GroupService, 23 | @Optional() private leafletElement?: LeafletElement, 24 | @Optional() private leafletGroup?: LeafletGroup) { 25 | super(); 26 | } 27 | 28 | public ngOnInit() { 29 | super.assignCartesianPointToLeafletsLatLngSchema(); 30 | // check if any of the two optional injections exist 31 | if (this.leafletElement || this.leafletGroup) { 32 | 33 | const map = this.mapService.getMap(); 34 | 35 | this.transformPointCoordinates(this.leafletElement.crs); 36 | 37 | const popup = L.popup({ autoClose: false, keepInView: true }) 38 | .setLatLng([this.lat, this.lon]).setContent(this.content); 39 | 40 | if (this.leafletGroup) { 41 | this.groupService.addOLayersToGroup(popup, map, this.mapService, this.leafletGroup); 42 | } else { 43 | popup.addTo(map); 44 | } 45 | } else { 46 | // tslint:disable-next-line:no-console 47 | console.warn(`This popup-element will not be rendered 48 | the expected parent node of popup-element should be either leaf-element or leaflet-group`); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/services/globalId.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class GuidService { 5 | 6 | public newGuid() { 7 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { 8 | const r = Math.random() * 16 | 0; 9 | const v = c === 'x' ? r : (r & 0x3 | 0x8); 10 | return v.toString(16); 11 | }); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/services/group.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import { GuidService } from '../services/globalId.service'; 4 | import * as L from 'leaflet'; 5 | 6 | @Injectable() 7 | export class GroupService { 8 | private layerGroup: any[] = []; 9 | private layerId: any[] = []; 10 | private layerGroupNumber: number = 0; 11 | private group: any = {}; 12 | 13 | constructor(private guidService: GuidService) { } 14 | 15 | public addOLayersToGroup(overlay, map, mapService, group, replace = false, gId?: string) { 16 | if (!gId) { 17 | gId = this.guidService.newGuid(); 18 | } 19 | if (this.layerId.indexOf(gId) === -1) { 20 | this.layerId.push(gId); 21 | } 22 | if (Object.keys(this.group).length !== 0) { 23 | if (replace) { 24 | map.removeLayer(this.group); 25 | if (this.layerId.indexOf(gId) !== -1) { 26 | this.layerGroup[this.layerId.indexOf(gId)] = overlay; 27 | } else { 28 | this.layerGroup.push(overlay); 29 | } 30 | this.group = L.layerGroup(this.getLayerGroup()); 31 | this.group.addTo(map); 32 | } else { 33 | this.layerGroup.push(overlay); 34 | this.group.addLayer(overlay); 35 | } 36 | } 37 | if (!replace) { 38 | this.layerGroup.push(overlay); 39 | this.group = L.layerGroup(this.getLayerGroup()); 40 | this.group.addTo(map); 41 | } 42 | 43 | mapService.addOverlay(this.getGroup(), group.name, group.globalId); 44 | } 45 | 46 | public getObservableGroup() { 47 | return Observable.create((observer) => { 48 | const group = this.getGroup(); 49 | observer.next(group); 50 | observer.complete(); 51 | }); 52 | } 53 | 54 | public getGroup() { 55 | return this.group; 56 | } 57 | 58 | public getLayerGroup() { 59 | return this.layerGroup; 60 | } 61 | 62 | public getLayerNumber() { 63 | return this.layerGroupNumber; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/services/helper.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class HelperService { 5 | 6 | public arrayCompare(a, b) { 7 | if (a.length !== b.length) { 8 | return false; 9 | } 10 | for (const i in a) { 11 | // Don't forget to check for arrays in our arrays. 12 | if (a[i] instanceof Array && b[i] instanceof Array) { 13 | if (!this.arrayCompare(a[i], b[i])) { 14 | return false; 15 | } 16 | } else if (a[i] !== b[i]) { 17 | return false; 18 | } 19 | } 20 | return true; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/services/map.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Observable } from 'rxjs'; 3 | import * as L from 'leaflet'; 4 | 5 | @Injectable() 6 | export class MapService { 7 | private map; 8 | private basemaps: any = {}; 9 | private overlays: any = {}; 10 | private layerControlflag: boolean = false; 11 | private layersInControlNumber: number = 0; 12 | private layerControlObject: any = {}; 13 | private groupIdentifiers: string[] = []; 14 | private groupNames: string[] = []; 15 | 16 | public setMap(map) { 17 | this.map = map; 18 | } 19 | public getMap() { 20 | return this.map; 21 | } 22 | 23 | public setLayerControl(state) { 24 | this.layerControlflag = state; 25 | } 26 | public getLayerControl() { 27 | return this.layerControlflag; 28 | } 29 | 30 | public addBasemap(basemap, name) { 31 | if (name === '') { 32 | name = 'unknown layer'; 33 | } 34 | if (this.basemaps[name] === undefined) { 35 | this.basemaps[name] = basemap; 36 | } else { 37 | name = this.getUniqueName(name); 38 | this.addBasemap(basemap, name); 39 | } 40 | } 41 | 42 | public getUniqueName(name) { 43 | let nameindex: number = 0; 44 | let newName: string = name; 45 | if (name.indexOf('(') !== -1) { 46 | nameindex = +(name.split('(')[1].split(')')[0]); 47 | nameindex += 1; 48 | newName = name.split('(')[0]; 49 | } else { 50 | nameindex = 1; 51 | } 52 | return name = newName + '(' + nameindex + ')'; 53 | } 54 | 55 | public addOverlay(overlay, name: string, gId?: string) { 56 | if (this.groupIdentifiers.indexOf(gId) !== -1) { 57 | const index = this.groupIdentifiers.indexOf(gId); 58 | const existingName: string = this.groupNames[index]; 59 | this.overlays[existingName] = overlay; 60 | } else { 61 | if (name === '') { 62 | name = 'unknown group'; 63 | } 64 | if (this.overlays[name] === undefined) { 65 | this.groupNames.push(name); 66 | this.groupIdentifiers.push(gId); 67 | this.overlays[name] = overlay; 68 | } else { 69 | name = this.getUniqueName(name); 70 | if (this.groupNames.indexOf(name) === -1) { 71 | this.groupNames.push(name); 72 | this.groupIdentifiers.push(gId); 73 | } else { 74 | this.addOverlay(overlay, name); 75 | } 76 | } 77 | } 78 | 79 | this.addControl(); 80 | } 81 | 82 | public getBasemaps() { 83 | return this.basemaps; 84 | } 85 | 86 | public getOverlays() { 87 | return this.overlays; 88 | } 89 | 90 | public getObservableOverlays() { 91 | return Observable.create((observer) => { 92 | observer.next(this.overlays); 93 | observer.complete(); 94 | }); 95 | } 96 | 97 | public getObservableBasemaps() { 98 | return Observable.create((observer) => { 99 | observer.next(this.basemaps); 100 | observer.complete(); 101 | }); 102 | } 103 | 104 | public refreshOverlays(remove, add) { 105 | const overlays = this.getOverlays(); 106 | for (const key in overlays) { 107 | if (overlays[key] instanceof Array) { 108 | overlays[key].forEach((element, index, arr) => { 109 | if (element._leaflet_id === remove._leaflet_id) { 110 | arr[index] = add; 111 | } 112 | }); 113 | } 114 | } 115 | } 116 | 117 | public increaseNumber() { 118 | this.layersInControlNumber += 1; 119 | } 120 | 121 | public getLayerNumber() { 122 | return this.layersInControlNumber; 123 | } 124 | 125 | public addControl() { 126 | if (this.layerControlflag) { 127 | const map = this.getMap(); 128 | if (Object.keys(this.layerControlObject).length !== 0) { 129 | this.layerControlObject.getContainer().innerHTML = ''; 130 | map.removeControl(this.layerControlObject); 131 | } 132 | this.layerControlObject = L.control.layers(this.getBasemaps(), this.getOverlays()).addTo(map); 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/services/popup.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class PopupService { 5 | 6 | public enablePopup(mouseover, onclick, element, text) { 7 | if (mouseover && onclick) { 8 | mouseover = undefined; 9 | // tslint:disable-next-line:no-console 10 | console.warn('you can not use mouseover and onclick at the same time, mouseover is going to be depressed'); 11 | } 12 | if (mouseover) { 13 | if (mouseover === 'true' && text) { 14 | mouseover = text; 15 | } else if (mouseover === true && !text) { 16 | mouseover = "true"; 17 | } 18 | element.bindPopup(mouseover); 19 | element.on('mouseover', function(this: { openPopup: any, closePopup: any }) { 20 | this.openPopup(); 21 | }).on('mouseout', function(this: { openPopup: any, closePopup: any }) { 22 | this.closePopup(); 23 | }); 24 | } 25 | if (onclick) { 26 | if (onclick === 'true' && text) { 27 | onclick = text; 28 | } else if (onclick === true && !text) { 29 | onclick = "true"; 30 | } 31 | element.bindPopup(onclick); 32 | element.on('click', function(this: { openPopup: any, closePopup: any }) { 33 | this.openPopup(); 34 | }); 35 | } 36 | if (!mouseover && !onclick && text) { 37 | element.bindPopup(text); 38 | element.on('mouseover', function(this: { openPopup: any, closePopup: any }) { 39 | this.openPopup(); 40 | }).on('mouseout', function(this: { openPopup: any, closePopup: any }) { 41 | this.closePopup(); 42 | }); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/test/main.test.ts: -------------------------------------------------------------------------------- 1 | import 'core-js'; // ES6 + reflect-metadata 2 | // zone.js 3 | import 'zone.js/dist/zone'; 4 | import 'zone.js/dist/long-stack-trace-zone'; 5 | import 'zone.js/dist/proxy.js'; 6 | import 'zone.js/dist/sync-test'; 7 | import 'zone.js/dist/jasmine-patch'; 8 | import 'zone.js/dist/async-test'; 9 | import 'zone.js/dist/fake-async-test'; 10 | import 'leaflet/dist/leaflet'; 11 | 12 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 13 | declare var __karma__: any; 14 | declare var require: any; 15 | 16 | // Prevent Karma from running prematurely. 17 | __karma__.loaded = () => { 18 | // TODO 19 | }; 20 | declare var System: any; 21 | 22 | Promise.all([ 23 | System.import('@angular/core/testing'), 24 | System.import('@angular/platform-browser-dynamic/testing') 25 | ]) 26 | // First, initialize the Angular testing environment. 27 | .then(([testing, testingBrowser]) => { 28 | testing.getTestBed().initTestEnvironment( 29 | testingBrowser.BrowserDynamicTestingModule, 30 | testingBrowser.platformBrowserDynamicTesting() 31 | ); 32 | }) 33 | .then(() => require.context('../map', true, /\.spec\.ts/)) 34 | .then((context) => context.keys().map(context)) 35 | .then(() => require.context('../geojson', true, /\.spec\.ts/)) 36 | .then((context) => context.keys().map(context)) 37 | .then(() => require.context('../circle', true, /\.spec\.ts/)) 38 | .then((context) => context.keys().map(context)) 39 | // Finally, start Karma to run the tests. 40 | .then(__karma__.start, __karma__.error); 41 | -------------------------------------------------------------------------------- /src/test/mock.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter } from '@angular/core'; 2 | 3 | export function MockComponent(options: Component): Component { 4 | const metadata: Component = { 5 | selector: options.selector, 6 | template: options.template || '', 7 | inputs: options.inputs, 8 | outputs: options.outputs || [] 9 | }; 10 | 11 | class Mock { } 12 | metadata.outputs.forEach((method) => { 13 | Mock.prototype[method] = new EventEmitter(); 14 | }); 15 | 16 | return Component(metadata)(Mock as any); 17 | } 18 | -------------------------------------------------------------------------------- /src/test/tsloader.js: -------------------------------------------------------------------------------- 1 | require('./main.test.ts'); 2 | //# sourceMappingURL=tsloader.js.map -------------------------------------------------------------------------------- /src/test/tsloader.ts: -------------------------------------------------------------------------------- 1 | require('./main.test.ts'); 2 | -------------------------------------------------------------------------------- /tsconfig-build.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "baseUrl": ".", 5 | "paths": { 6 | "@angular/*": [ 7 | "node_modules/@angular/*" 8 | ], 9 | "leaflet/*": [ 10 | "node_modules/leaflet/*" 11 | ], 12 | "rxjs/*": [ 13 | "node_modules/rxjs/*" 14 | ] 15 | }, 16 | "outDir": "dist", 17 | "declaration": true, 18 | "strict": true, 19 | "strictNullChecks": false, 20 | "noImplicitAny": false, 21 | "moduleResolution": "node", 22 | "module": "es2015", 23 | "target": "es2015", 24 | "typeRoots": [ 25 | "node_modules/@types" 26 | ], 27 | "lib": [ 28 | "es2015", 29 | "dom" 30 | ], 31 | "types": [ 32 | "node", 33 | "jasmine", 34 | "leaflet", 35 | "geojson" 36 | ], 37 | "skipLibCheck": true, 38 | "experimentalDecorators": true, 39 | "emitDecoratorMetadata": true, 40 | "sourceMap": true, 41 | "inlineSources": true 42 | }, 43 | "files": [ 44 | "public_api.ts", 45 | "node_modules/zone.js/dist/zone.js.d.ts" 46 | ], 47 | "angularCompilerOptions": { 48 | "skipTemplateCodegen": false, 49 | "annotateForClosureCompiler": true, 50 | "strictMetadataEmit": true, 51 | "skipMetadataEmit": true, 52 | "flatModuleOutFile": "ngx.leaflet.components.js", 53 | "flatModuleId": "ngx.leaflet.components" 54 | } 55 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "noImplicitAny": false, 6 | "target": "es5", 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "removeComments": true, 10 | "sourceMap": true, 11 | "declaration": true, 12 | "outDir": "./dist", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2015", 18 | "dom" 19 | ], 20 | "types": [ 21 | "node", 22 | "jasmine", 23 | "leaflet", 24 | "geojson" 25 | ] 26 | }, 27 | "awesomeTypeScriptLoaderOptions": { 28 | "useWebpackText": true 29 | }, 30 | "exclude": [ 31 | "node_modules" 32 | ] 33 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "node_modules/codelyzer" 5 | ], 6 | "rules": { 7 | "angular-whitespace": [ 8 | true, 9 | "check-interpolation", 10 | "check-pipe" 11 | ], 12 | "banana-in-box": true, 13 | "templates-no-negated-async": true, 14 | "directive-selector": [ 15 | true, 16 | "attribute", 17 | [ 18 | "dir-prefix1", 19 | "dir-prefix2" 20 | ], 21 | "camelCase" 22 | ], 23 | "component-selector": [ 24 | false, 25 | "element", 26 | "kebab-case" 27 | ], 28 | "object-literal-sort-keys": false, 29 | "use-input-property-decorator": true, 30 | "use-output-property-decorator": true, 31 | "use-host-property-decorator": true, 32 | "no-attribute-parameter-decorator": true, 33 | "no-input-rename": true, 34 | "no-output-rename": true, 35 | "no-forward-ref": true, 36 | "no-bitwise": false, 37 | "use-view-encapsulation": false, 38 | "use-life-cycle-interface": true, 39 | "use-pipe-transform-interface": true, 40 | "pipe-naming": [ 41 | true, 42 | "camelCase", 43 | "Pipe" 44 | ], 45 | "component-class-suffix": [ 46 | false 47 | ], 48 | "directive-class-suffix": [ 49 | false 50 | ], 51 | "ordered-imports": [ 52 | false 53 | ], 54 | "quotemark": [ 55 | false 56 | ], 57 | "trailing-comma": [ 58 | false 59 | ] 60 | } 61 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | 4 | module.exports = () => { 5 | return { 6 | entry: { 7 | main: './src/index.ts' 8 | }, 9 | output: { 10 | path: './dist', 11 | filename: '[name].bundle.js' 12 | }, 13 | plugins: [ 14 | // Workaround for https://github.com/angular/angular/issues/11580 15 | new webpack.ContextReplacementPlugin( 16 | /angular(\\|\/)core(\\|\/)(@angular|esm5)/, 17 | path.resolve(__dirname, './src') 18 | ) 19 | ], 20 | resolve: { 21 | extensions: ['.js', '.ts', '.html'] 22 | }, 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.ts$/, 27 | loaders: 28 | [ 29 | 'awesome-typescript-loader?' + JSON.stringify({ 30 | sourceMap: false, 31 | inlineSourceMap: true 32 | }), 33 | 'angular2-template-loader' 34 | ] 35 | }, 36 | { 37 | test: /\.html$/, 38 | loader: 'html-loader' 39 | }, 40 | { 41 | test: /\.css$/, 42 | loader: 'css-loader' 43 | }, 44 | { 45 | test: /\.ts$/, 46 | loader: 'istanbul-instrumenter-loader', 47 | exclude: [ 48 | 'node_modules', 49 | 'test', 50 | /\.(e2e|spec)\.ts$/ 51 | ], 52 | enforce: 'post' 53 | } 54 | ] 55 | }, 56 | devtool: 'inline-source-map' 57 | } 58 | }; --------------------------------------------------------------------------------