├── .gitattributes ├── .gitignore ├── README.md ├── composer.json ├── dist ├── css │ └── field.css └── js │ └── field.js ├── images └── vendor │ └── leaflet │ └── dist │ ├── layers-2x.png │ ├── layers.png │ └── marker-icon.png ├── mix-manifest.json ├── package.json ├── resources ├── img │ ├── layers-2x.png │ ├── layers.png │ ├── marker-icon-2x.png │ ├── marker-icon.png │ ├── marker-shadow.png │ └── marker.svg ├── js │ ├── components │ │ ├── DetailField.vue │ │ ├── FormField.vue │ │ ├── IndexField.vue │ │ └── MapDetail.vue │ └── field.js └── sass │ └── field.scss ├── src ├── FieldServiceProvider.php └── Map.php └── webpack.mix.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /vendor 3 | /node_modules 4 | package-lock.json 5 | composer.phar 6 | composer.lock 7 | phpunit.xml 8 | .phpunit.result.cache 9 | .DS_Store 10 | Thumbs.db 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Total Downloads](https://poser.pugx.org/davidpiesse/nova-map/downloads)](https://packagist.org/packages/davidpiesse/nova-map) 2 | [![Latest Stable Version](https://poser.pugx.org/davidpiesse/nova-map/v/stable)](https://packagist.org/packages/davidpiesse/nova-map) 3 | # Map Field 4 | 5 | This map field currently ONLY shows in details view 6 | 7 | ![Gif!](https://res.cloudinary.com/davidpiesse/image/upload/v1535397821/ezgif.com-resize_fbxddc.gif) 8 | 9 | You can use this Map Field with three different sort of spatial data: 10 | * GeoJSON String property 11 | * Latitude and Longitude properties 12 | * Latitude and Longitude both in a single text field 13 | * Core Laravel Spatial Types 14 | * Point 15 | * LineString 16 | * Polygon 17 | * Geometry 18 | * GeometryCollection 19 | * MultiPoint 20 | * MultiLineString 21 | * MultiPolygon 22 | To use these core types you need to install grimzy/laravel-mysql-spatial 23 | See the section below on setting this up. 24 | This can work with other databases, but YMMV. 25 | 26 | * You can set the height of the map in px 27 | * The field is disabled in Index and Form views by default 28 | * This is very much a WIP - please submit issues to GitHub 29 | 30 | # Spatial Types 31 | To specify what sort of spatial data you are passing to this field you MUST set the spatialType() for example 32 | ```php 33 | ->spatialType('Point') 34 | ``` 35 | These are the valid Spatial Types 36 | * LatLon 37 | * LatLonField (single field) 38 | * GeoJSON 39 | * Point 40 | * LineString 41 | * Polygon 42 | * Geometry 43 | * GeometryCollection 44 | * MultiPoint 45 | * MultiLineString 46 | * MultiPolygon 47 | 48 | 49 | # Examples 50 | 51 | ## Point 52 | ```php 53 | Map::make('Some Point Field', 'point_field_name') 54 | ->spatialType('Point'), 55 | ``` 56 | 57 | ## Polygon 58 | ```php 59 | Map::make('Some Polygon Field', 'polygon_field_name') 60 | ->spatialType('Polygon'), 61 | ``` 62 | 63 | ## GeoJSON 64 | ```php 65 | Map::make('Some GeoJSON Field') 66 | ->spatialType('GeoJSON') 67 | ->geojson('geojson_field_name'), 68 | ``` 69 | 70 | ## Latitude & Longitude (in seperate fields) 71 | ```php 72 | Map::make('Some Point Location') 73 | ->spatialType('LatLon') 74 | ->latitude('latitude_field_name') 75 | ->longitude('longitude_field_name'), 76 | ``` 77 | 78 | ## Latitude & Longitude (in single fields) 79 | ```php 80 | Map::make('Some Point Location', 'coordinate_field_name') 81 | ->spatialType('LatLonField'), 82 | ``` 83 | 84 | ## Set the Height 85 | ```php 86 | Map::make('Some Point Field', 'point_field_name') 87 | ->spatialType('Point') 88 | ->height('300px'), 89 | ``` 90 | 91 | # Setting up the Laravel Spatial Types 92 | You need to install [grimzy/laravel-mysql-spatial](https://github.com/grimzy/laravel-mysql-spatial) into your main application 93 | ``` 94 | composer require grimzy/laravel-mysql-spatial 95 | ``` 96 | Add the SpatialTrait to your Model 97 | ```php 98 | use SpatialTrait; 99 | ``` 100 | You then also need to set any spatial fields you have set in the Model 101 | ```php 102 | protected $spatialFields = [ 103 | 'geo_point', 104 | 'geo_linestring', 105 | ... 106 | ]; 107 | ``` 108 | Your Model is now ready to process spatial data to Nova 109 | 110 | # Future Development 111 | * Editing capabilities for all Spatial Types 112 | * View Place Field address on a Map 113 | * Remove reliance on grimzy package from accessing core Spatial Types 114 | * Allow all DB spatial fields to be used 115 | * Customize the map futher 116 | * Tailwind Height classes 117 | * Customise Geometry Styling 118 | * Marker Icon 119 | * Colors, Thicknesses, Opacity 120 | * Basemap 121 | * Streets 122 | * Topo 123 | * Satellite 124 | * Navigation Tools (Compass, Zoom In/Out) 125 | * Alternative Map Providers 126 | * Google Maps 127 | * Mapbox 128 | * OpenLayers 129 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "davidpiesse/nova-map", 3 | "description": "Map field for Laravel Nova", 4 | "keywords": [ 5 | "laravel", 6 | "nova" 7 | ], 8 | "license": "MIT", 9 | "require": { 10 | "php": ">=7.1.0" 11 | }, 12 | "autoload": { 13 | "psr-4": { 14 | "Davidpiesse\\Map\\": "src/" 15 | } 16 | }, 17 | "extra": { 18 | "laravel": { 19 | "providers": [ 20 | "Davidpiesse\\Map\\FieldServiceProvider" 21 | ] 22 | } 23 | }, 24 | "config": { 25 | "sort-packages": true 26 | }, 27 | "minimum-stability": "dev", 28 | "prefer-stable": true 29 | } 30 | -------------------------------------------------------------------------------- /dist/css/field.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/dist/css/field.css -------------------------------------------------------------------------------- /images/vendor/leaflet/dist/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/images/vendor/leaflet/dist/layers-2x.png -------------------------------------------------------------------------------- /images/vendor/leaflet/dist/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/images/vendor/leaflet/dist/layers.png -------------------------------------------------------------------------------- /images/vendor/leaflet/dist/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/images/vendor/leaflet/dist/marker-icon.png -------------------------------------------------------------------------------- /mix-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "/dist/js/field.js": "/dist/js/field.js", 3 | "/dist/css/field.css": "/dist/css/field.css" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "npm run development", 5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "watch-poll": "npm run watch -- --watch-poll", 8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 9 | "prod": "npm run production", 10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 11 | }, 12 | "devDependencies": { 13 | "cross-env": "^5.2.1", 14 | "laravel-mix": "^1.0", 15 | "laravel-nova": "^3.0" 16 | }, 17 | "dependencies": { 18 | "@types/leaflet": "^1.5.12", 19 | "leaflet": "^1.3.4", 20 | "vue": "^2.6.12", 21 | "vue2-leaflet": "^2.4.3" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /resources/img/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/resources/img/layers-2x.png -------------------------------------------------------------------------------- /resources/img/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/resources/img/layers.png -------------------------------------------------------------------------------- /resources/img/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/resources/img/marker-icon-2x.png -------------------------------------------------------------------------------- /resources/img/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/resources/img/marker-icon.png -------------------------------------------------------------------------------- /resources/img/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidpiesse/nova-map/49ece0aff2d22ea84483884212f07699ac656b77/resources/img/marker-shadow.png -------------------------------------------------------------------------------- /resources/img/marker.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/js/components/DetailField.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 36 | -------------------------------------------------------------------------------- /resources/js/components/FormField.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 59 | -------------------------------------------------------------------------------- /resources/js/components/IndexField.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /resources/js/components/MapDetail.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 124 | 125 | 128 | -------------------------------------------------------------------------------- /resources/js/field.js: -------------------------------------------------------------------------------- 1 | Nova.booting((Vue, router) => { 2 | Vue.component('map-detail', require('./components/MapDetail')); 3 | Vue.component('index-map-field', require('./components/IndexField')); 4 | Vue.component('detail-map-field', require('./components/DetailField')); 5 | Vue.component('form-map-field', require('./components/FormField')); 6 | }) 7 | -------------------------------------------------------------------------------- /resources/sass/field.scss: -------------------------------------------------------------------------------- 1 | // Nova Tool CSS 2 | -------------------------------------------------------------------------------- /src/FieldServiceProvider.php: -------------------------------------------------------------------------------- 1 | withMeta([ 19 | 'height' => $height 20 | ]); 21 | } 22 | 23 | public function spatialType($type){ 24 | return $this->withMeta([ 25 | 'spatialType' => $type 26 | ]); 27 | } 28 | 29 | public function zoom($zoom = 13){ 30 | return $this->withMeta([ 31 | 'zoom' => $zoom 32 | ]); 33 | } 34 | 35 | public function latitude($latitude_field){ 36 | $this->attribute = null; 37 | 38 | return $this->withMeta([ 39 | 'latitude_field' => $latitude_field 40 | ]); 41 | } 42 | 43 | public function longitude($longitude_field){ 44 | $this->attribute = null; 45 | 46 | return $this->withMeta([ 47 | 'longitude_field' => $longitude_field 48 | ]); 49 | } 50 | 51 | public function geojson($geojson_field){ 52 | $this->attribute = $geojson_field; 53 | 54 | return $this->withMeta([ 55 | 'geojson_field' => $geojson_field 56 | ]); 57 | } 58 | 59 | public function rawGeojson($geojson_data){ 60 | $this->attribute = null; 61 | 62 | return $this->withMeta([ 63 | 'geojson_data' => $geojson_data //pass in string 64 | ]); 65 | } 66 | 67 | public function resolveAttribute($resource, $attribute = null){ 68 | switch($this->meta['spatialType']){ 69 | case 'LatLon': 70 | return [ 71 | 'lat' => $resource->{$this->meta['latitude_field']}, 72 | 'lon' => $resource->{$this->meta['longitude_field']}, 73 | ]; 74 | break; 75 | case 'LatLonField': 76 | $parts = collect(explode(',',$resource->{$attribute}))->map(function($item){ 77 | return trim($item); 78 | }); 79 | 80 | return [ 81 | 'lat' => $parts[0], 82 | 'lon' => $parts[1], 83 | ]; 84 | break; 85 | case 'GeoJSON': 86 | return $resource->{$attribute}; 87 | break; 88 | case 'RawGeoJSON': 89 | return json_decode($this->meta['geojson_data']); 90 | break; 91 | default: 92 | return $resource->{$attribute}; 93 | break; 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /webpack.mix.js: -------------------------------------------------------------------------------- 1 | let mix = require('laravel-mix') 2 | 3 | mix.js('resources/js/field.js', 'dist/js') 4 | .sass('resources/sass/field.scss', 'dist/css') 5 | .webpackConfig({ 6 | resolve: { 7 | symlinks: false 8 | } 9 | }) 10 | --------------------------------------------------------------------------------