适用于 Filament PHP 的 Google Maps 包,具有字段、列和小部件
Requires
- php: ^8.0
- geocoder-php/google-maps-provider: ^4.7
- guzzlehttp/guzzle: ^7.5
- laravel/prompts: ^0.1.4
- mastani/laravel-google-static-map: ^2.2
- php-http/guzzle7-adapter: ^1.0
- php-http/message: ^1.13
- ryangjchandler/blade-capture-directive: ^0.3
- spatie/guzzle-rate-limiter-middleware: ^2.0
- spatie/laravel-package-tools: ^1.9
Requires (Dev)
- filament/filament: ^3.0
- laravel/pint: ^1.6
- nonsapiens/realaddressfactory: ^2.0
- orchestra/testbench: ^7.11|^8.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- pestphp/pest-plugin-livewire: ^2.0
- timacdonald/log-fake: ^2.0
README
微点 Google Maps
本包为 Filament PHP 生态系统(Laravel 的应用构建器)提供了一套使用 Google Maps 的完整工具,可用于管理面板或独立的前端表单、表格和仪表板。
关于项目
微点 v3 版本发布
这是 v3 分支,兼容最新的微点 v3 版本。不久的将来,我们将用这个 v3 分支替换主分支(目前是兼容微点 v2 的分支),并将微点 v2 支持移动到 v2 分支。
请在 GitHub 问题页面 报告任何发现的问题,或在我的 Discord 服务器上找到我 (@cheesegrits)。
API 使用
重要提示 - 本包的一些功能可能会增加您的 API 账单。如果您有大型表格,并在其上显示静态地图,并且频繁清除缓存。或者,如果您允许公共访问使用地理编码的表单,并且受到机器人的攻击。
我们强烈建议您在 Google 控制台 中设置使用配额。如果您收到意外账单,我们不承担责任!
TL/DR
如果您无法忍受阅读文档,想直接上手...
composer require cheesegrits/filament-google-maps "^3.0"
...那么请按照以下说明,为任何使用这些组件的模型(它们应该已经有独立的经纬度字段,即使为空,请参阅批量命令部分)添加计算属性...
php artisan filament-google-maps:model-code
...然后开始使用组件,例如...
use Cheesegrits\FilamentGoogleMaps\Fields\Map ... ->schema[ ... // must use the computed attribute name you used on your model // which must NOT exist on the table itself Map::make('location'), ... ]
组件
地图字段
地图字段显示(不出所料)一个 Google 地图,具有全面的配置选项。它支持地图和表单之间的双向坐标更新,正向和反向地理补全,反向地理编码和 KML 层。
地理补全字段
地理补全字段将您的表单上的文本字段转换为 Google 地理补全字段,并可选择反向地理编码地址组件。
地图小部件
地图小部件显示来自模型的过滤位置集,具有可选的聚类、可模板化的标签、可定制的图标等。
地图表格小部件
地图表格小部件显示地图小部件和 Filament 表格,并响应表格上的所有过滤和搜索。
地图列
地图列显示可定制的静态地图图像,并将图像本地缓存以减少 API 开销。
静态地图操作
静态地图操作是一个批量操作,允许您选择任意数量的表格行,并生成一个显示这些位置的可下载静态地图。
半径过滤器
半径过滤器提供针对地理补全地址的半径过滤,单位为公里或英里。
批量命令
Artisan 命令允许您对位置表进行批量处理,无论是将地址字段组合成经纬度,还是将经纬度反向地理编码为地址字段。
(返回顶部)
入门
先决条件
此包基于 Filament V2 和 Laravel 9 构建。它可能在更早版本的 Laravel 上运行,但尚未经过测试。
安装
您可以通过 composer 安装此项目
composer install cheesegrits/filament-google-maps
资源
此包处理JS和CSS资源的异步加载,适用于Filament管理面板和独立页面,无需发布任何内容或修改项目。
准备模型
为了简化处理坐标数据,我们要求在用于地图数据的任何模型上有一个计算属性,它将您的表中的单独的经度和纬度字段转换为带有'lat'和'lng'键的Google点风格数组。
要准备您的模型,请使用Artisan命令
php artisan filament-google-maps:model-code
...它将提示您输入
- 模型:您的模型类,例如地点,或经销商/经销商
- 纬度:您的纬度属性(现有表字段)
- 经度:您的经度属性(现有表字段)
- 位置:计算属性名称,该名称不应存在于您的表中
当您创建地图字段和列时,将使用'位置'计算属性。如果您没有宗教偏好并且它尚未存在于您的表中,只需使用'位置'即可。
然后它会输出代码供您复制并粘贴到模型类中。
注意 - 如果需要,此脚本还会为您提供修改后的$fillable和$appends数组,这些数组将合并这些数组中任何现有的内容,请确保您替换了现有的数组。
设置您的Google Maps API密钥
所有使用Google Maps API都需要API密钥。如果您没有,请参阅Google的文档。
一旦您有了密钥,您可以将其添加到.env文件中,如下所示
GOOGLE_MAPS_API_KEY=your_map_key_here
...或者发布并编辑filament-google-maps.php配置文件。我们建议使用环境变量。请注意,我们故意使用大多数Google相关Laravel包使用的相同密钥名称,以便生活更加简单。但是,如果您需要为此包使用不同的密钥,您也可以这样做 - 参考下一节的配置文件。
发布配置
您可以可选地发布包配置。配置包含一组合理的默认值,因此我们建议除非您确实需要更改某些内容,否则不要发布...并且即使在那时,也最好使用.env变量来更改。
php artisan vendor:publish --tag="filament-google-maps-config"
...然后可以在./config/filament-google-maps.php中找到
特别需要注意的是API密钥和缓存存储的配置设置。默认情况下,我们将使用您的默认缓存驱动程序缓存所有API响应30天。对于大多数常规使用,这已经足够,但如果您预计会有大量使用,我们建议在您的cache.php配置中设置一个专门的Redis存储,并使用FILAMENT_GOOGLE_MAPS_CACHE_STORE环境变量指定此存储。
(点击展开)
<?php return [ /* | Your Google Maps API key, usually set in .env (but see 'keys' section below). */ 'key' => env('GOOGLE_MAPS_API_KEY'), /* | If you need to use both a browser key (restricted by HTTP Referrer) for use in the Javascript API on the | front end, and a server key (restricted by IP address) for server side API calls, you will need to set those | keys here (or preferably set the appropriate .env variables) */ 'keys' => [ 'web_key' => env('FILAMENT_GOOGLE_MAPS_WEB_API_KEY', env('GOOGLE_MAPS_API_KEY')), 'server_key' => env('FILAMENT_GOOGLE_MAPS_SERVER_API_KEY', env('GOOGLE_MAPS_API_KEY')), 'signing_key' => env('FILAMENT_GOOGLE_MAPS_SIGNING_KEY', null), ], /* | By default the browser side Google Maps API will be loaded with just the 'places' library. If you need | additional libraries for your own custom code, just add them as a comma separated list here (or in the | appropriate env key) */ 'libraries' => env('FILAMENT_GOOGLE_MAPS_ADDITIONAL_LIBRARIES', null), /* | Region and country codes. | | Google STRONGLY ENCOURAGED you to set a region code (US, GB, etc) which they use to bias the results | | https://developers.google.com/maps/coverage | | Google discourage you from setting a language, as this should be controlled by the user's browser setting, | and only controls localization of the UI. So we do not apply a language code to the Javascript API. However, | we will apply any language code set here to server side API calls like static maps (as used in the Column). | | https://developers.google.com/maps/faq#languagesupport */ 'locale' => [ 'region' => env('FILAMENT_GOOGLE_MAPS_REGION_CODE', null), 'language' => env('FILAMENT_GOOGLE_MAPS_LANGUAGE_CODE', null), ], /* | Rate limit for API calls, although you REALLY should also set usage quota limits in your Google Console */ 'rate-limit' => env('FILAMENT_GOOGLE_MAPS_RATE_LIMIT', 150), /* | Log channel to use, default is 'null' (no logging), set to your desired channel from logging.php if you want | logs. Typically only useful for debugging, or if you want to keep track of a scheduled geocoding task. */ 'log' => [ 'channel' => env('FILAMENT_GOOGLE_MAPS_LOG_CHANNEL', 'null'), ], /* | Cache store and duration (in seconds) to use for API results. Specify store as null to use the default from | your cache.php config, false will disable caching (STRONGLY discouraged, unless you want a big Google | API bill!). For heavy usage, we suggest using a dedicated Redis store. Max cache duration permitted by | Google is 30 days. */ 'cache' => [ 'duration' => env('FILAMENT_GOOGLE_MAPS_CACHE_DURATION_SECONDS', 60 * 60 * 24 * 30), 'store' => env('FILAMENT_GOOGLE_MAPS_CACHE_STORE', null), ] /* | Force https for Google API calls, rather than matching the schema of the current request, | may be needed if your app is behind a reverse proxy. */ 'force-https' => env('FILAMENT_GOOGLE_MAPS_FORCE_HTTPS', false), ];
(返回顶部)
用法
表单字段
表单字段可以不添加任何选项,只需将其添加到您的Filament表单模式中
use Cheesegrits\FilamentGoogleMaps\Fields\Map ... ->schema[ ... Map::make('location'), ... ]
用于make()的名称必须是与您为模型设置的计算位置属性相同的名称。请注意,您可以在表单上添加多个地图,方法是通过添加第二个计算属性来引用第二对经纬度字段。
完整选项
完整选项集如下。所有选项方法都支持闭包以及直接值。
use Cheesegrits\FilamentGoogleMaps\Fields\Map ... Map::make('location') ->mapControls([ 'mapTypeControl' => true, 'scaleControl' => true, 'streetViewControl' => true, 'rotateControl' => true, 'fullscreenControl' => true, 'searchBoxControl' => false, // creates geocomplete field inside map 'zoomControl' => false, ]) ->height(fn () => '400px') // map height (width is controlled by Filament options) ->defaultZoom(5) // default zoom level when opening form ->autocomplete('full_address') // field on form to use as Places geocompletion field ->autocompleteReverse(true) // reverse geocode marker location to autocomplete field ->reverseGeocode([ 'street' => '%n %S', 'city' => '%L', 'state' => '%A1', 'zip' => '%z', ]) // reverse geocode marker location to form fields, see notes below ->debug() // prints reverse geocode format strings to the debug console ->defaultLocation([39.526610, -107.727261]) // default for new forms ->draggable() // allow dragging to move marker ->clickable(false) // allow clicking to move marker ->geolocate() // adds a button to request device location and set map marker accordingly ->geolocateLabel('Get Location') // overrides the default label for geolocate button ->geolocateOnLoad(true, false) // geolocate on load, second arg 'always' (default false, only for new form)) ->layers([ 'https://googlearchive.github.io/js-v2-samples/ggeoxml/cta.kml', ]) // array of KML layer URLs to add to the map ->geoJson('https://fgm.test/storage/AGEBS01.geojson') // GeoJSON file, URL or JSON ->geoJsonContainsField('geojson') // field to capture GeoJSON polygon(s) which contain the map marker
不带注释的mapControls是标准的Google Maps控件,请参阅API文档。
地理补全
autocomplete('field_name')选项将您提供的字段名称转换为Google Places地理补全字段,在您键入时会建议位置。选择建议将移动地图上的标记。
如果您指定autocompleteReverse(),移动地图标记将更新autocomplete()中指定的字段,使用Google的formatted_address组件以反向地理编码的地址。
您可以为 autocomplete() 方法指定三个附加选项(通常作为命名参数),有关详细信息,请参阅 Geocomplete 字段部分。
Map::make('location') ->autocomplete( fieldName: 'airport_name', types: ['airport'], placeField: 'name', countries: ['US', 'CA', 'MX'], )
反向地理编码
reverseGeocode() 选项允许您指定表单中的字段名称列表,以及从 Google 解码地址组件响应的对应格式字符串。我们使用由 Geocoder PHP 定义的 printf() 风格格式,如下所示
- 街道编号:%n
- 街道名称:%S
- 城市(或瑞典和英国的邮政城镇):%L
- 城市区域(次区域):%D
- 邮编(邮政编码):%z
- 行政级别名称:%A1, %A2, %A3, %A4, %A5
- 行政级别代码:%a1, %a2, %a3, %a4, %a5
- 国家:%C
- 国家代码:%c
- 地址点:%p
请注意,%p 未在 Geocoder PHP 文档中列出,如果存在,代表地址的 "地址点",通常是一个地点名称,如 "老农场"。
为了帮助您确定所需的格式字符串,您可以在地图字段上设置 debug(),这将 console.log() 每个 reverse geocode 事件的响应(例如,每次移动标记时)。
图层 / GeoJSON
向地图添加图层有两种方法。layers() 方法接受 KML 或 GeoRSS 文件 URL 的数组,这些 URL 将使用 Maps API 的 KmlLayer() 方法添加到地图中。请注意,这些 URL 必须是公开可访问的,因为 KmlLayer() 方法需要 Google 服务器读取和处理文件,有关详细信息和使用限制,请参阅 KML & GeoRSS Layers 文档。
第二种方法允许使用 geoJson() 方法指定单个 GeoJSON 文件,该方法接受一个闭包或字符串,可以是本地文件路径、原始 GeoJSON 或指向 GeoJSON 文件的 URL。如果指定本地路径,可选的第二个参数可以是要使用的 Storage 磁盘的名称。GeoJSON 将使用 Maps API 的 数据层 在地图上渲染。
Map::make('location') // ->geoJson('jsons/MyGeoJson.geojson', 'json-disk') // ... or ... ->geoJson('https://my.site/jsons/MyGeoJson.geojson') // ... or ... ->geoJson(function () { // code that builds and returns raw GeoJSON return $json; })
当使用 GeoJSON 时,我们提供了一个便利方法来存储包含地图标记坐标的任何多边形特征的引用,使用 geoJsonContainsField() 方法。此方法的第一个参数是您的表单上的字段名称(可以是隐藏字段类型),其中要存储数据。第二个参数是可选的,指定从您的 GeoJSON 特征中存储的属性名称。如果没有指定,将存储整个 GeoJSON 特征。
Map::make('location') ->geoJson(function () { return <<<EOT { "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ] }, "properties": { "prop0": "value0", "prop1": 0.0 } }, ] } EOT; }) ->geoJsonContainsField('geojson_contains', 'prop0') ->geoJsonVisible(false)
在上面的示例中,如果用户将地图标记投掷到矩形内部,则 'geojson_contains' 字段将更新为 ["value0"]。如果省略第二个参数,则字段将更新为包含矩形 JSON 的 GeoJSON FeatureCollection。如果您有重叠的特征,并且多个多边形包含标记,则将包括包含标记的所有特征数组 / FeatureCollection。
请注意,还可以使用 geoJsonVisible(false) 方法的可选使用,这会隐藏层(创建一个单独的数据层并将其附加到地图),这样您可以在不显示多边形的情况下跟踪哪些多边形包含标记。
响应式表单字段
如果您希望地图标记对您表单上 lat 或 lng 字段的变化做出反应
Forms\Components\TextInput::make('latitude') ->reactive() ->afterStateUpdated(function ($state, callable $get, callable $set) { $set('location', [ 'lat' => floatVal($state), 'lng' => floatVal($get('longitude')), ]); }) ->lazy(), // important to use lazy, to avoid updates as you type Forms\Components\TextInput::make('longitude') ->reactive() ->afterStateUpdated(function ($state, callable $get, callable $set) { $set('location', [ 'lat' => floatval($get('latitude')), 'lng' => floatVal($state), ]); }) ->lazy(), // important to use lazy, to avoid updates as you type
如果您希望在移动地图标记时更新表单上的 lat 和 lng 字段
Map::make('location') ->reactive() ->afterStateUpdated(function ($state, callable $get, callable $set) { $set('latitude', $state['lat']); $set('longitude', $state['lng']); }),
反向地理编码 & 地点更改回调
要使用本节中的功能,您必须将 InteractsWithMaps 特性添加到您的 Livewire 组件中。如果您在 Filament 面板中使用它,这通常是在您资源的 EditFoo 页面(对于简单资源为 ManageFoo)上
// use Cheesegrits\FilamentGoogleMaps\Concerns\InteractsWithMaps; class EditLocation extends EditRecord { use InteractsWithMaps; // }
在独立表单上下文中,这将是您自己的组件。
如果内置的反向地理编码符号映射不能满足您的需求,您可以为 Livewire 在地图上发生反向地理编码时调用的闭包提供。您将传入一个包含地理编码结果的数组,然后可以按自己的方式处理这些结果,并使用 $set 可调用函数相应地设置表单字段。
注意:reverseGeocodeUsing() 可以与 reverseGeocode() 结合使用,因此您可以使用较简单的 reverseGeocode() 方法填写一些字段,而使用 reverseGeocodeUsing() 填写其他字段。例如,如果您有县和/或州表,并使用这些表与具有关系的选择字段,则需要以不同的方式处理县/州(通过查找表中相应的地址组件并设置表单字段到适当的键)。
Map::make('location') ->reverseGeocodeUsing(function (callable $set, array $results) { // get whatever you need from $results, and $set your field(s) $set('street', $results['address_components'][1]['long_name']) })
同样,如果您想在地图上解析出地点时进行自定义处理,通常是从 Geocomplete 或通过点击地图上的地点标记,可以使用以下方法:
Map::make('location') ->placeUpdatedUsing(function (callable $set, array $place) { // do whatever you need with the $place results, and $set your field(s) $set('city', 'foo wibble'); }),
注意:当您提供 placeUpdatedUsing() 回调函数时,我们会自动将 'photos' 添加到从 API 获取的地点字段列表中,这些字段随后将可用于 $place 数组。
另外注意:placeUpdatedUsing() 在地图点击时可能会添加额外的 API 调用,所以如果您试图将 API 使用量保持在最低,请务必注意。
地理补全字段
Geocomplete 字段将表单上的字段转换为 Google Geocomplete 字段。您通常会使用此功能 代替 地图字段(如果您想同时使用 Geocomplete 字段和地图,您通常会在地图字段上使用 autocomplete() 功能)。
Geocomplete 字段可以以两种模式之一运行。一种是独立模式,您只需在表单上使用一个普通文本字段,例如 'full_address',此组件将简单地使用用户从下拉列表中选择时返回的格式化地址填写该字段。
use Cheesegrits\FilamentGoogleMaps\Fields\Geocomplete ... Geocomplete::make('full_address'),
第二种模式是 isLocation() 模式,您使用它与模型中的 'location' 计算属性字段。在这种用法中,当表单保存时,当前选定的地址将被地理编码到您的 lat 和 lng 字段。当表单加载时,如果指定了 geocodeOnLoad(),当前 lat 和 lng 将被反向地理编码为一个完整地址(使用 Google 的 formatted_address 字段)。
注意 - geocodeOnLoad() 功能需要从您的服务器获取 API 访问权限。如果您使用的是仅限于 HTTP Referrers 的 API 密钥,则此功能将无法正常工作。您需要添加另一个使用 FILAMENT_GOOGLE_MAPS_SERVER_API_KEY 的密钥(请参阅配置部分),该密钥受 IP 地址限制。
use Cheesegrits\FilamentGoogleMaps\Fields\Geocomplete ... Geocomplete::make('location') // field name must be the computed attribute name on your model ->isLocation() ->geocodeOnLoad(), // server side geocode of lat/lng to address when form is loaded
在 isLocation 模式下,表单上的字段在加载时将为空(因为它不是可以存储地址的文本字段)。如果您想将其填写,可以使用 geocodeOnLoad(),这将执行服务器端 API 调用来解析 lat/lng 到地址。请参阅配置部分中的有关服务器端 API 密钥的说明。
在这两种模式下,您都可以指定要显示的地点类型以及用于填充字段的地点响应字段。请参阅 Google 地点 API 文档中的 地点类型 和 地点数据字段。请注意类型数量和组合的限制 - 表 3 中的 1 个(如 'address' 或 'establishment'),或来自表 1 或 2 的 5 个(如 'airport'、'subway_station' 等)。
Geocomplete::make('location') ->types(['car_dealer', 'car_rental', 'car_repair']) ->placesField('name')
在这两种模式下,您还可以选择性地指定字段,使用与上述地图组件相同的方法反向地理编码所选地址组件数据。
以下示例中没有显示,但您也可以使用 reverseGeocodeUsing() 方法提供自己的闭包来处理反向地理编码数据,如上所述的地图组件。
Geocomplete::make('location') ->isLocation() ->reverseGeocode([ 'city' => '%L', 'zip' => '%z', 'state' => '%A1', 'street' => '%n %S', ]) ->countries(['us']) // restrict autocomplete results to these countries ->debug() // output the results of reverse geocoding in the browser console, useful for figuring out symbol formats ->updateLatLng() // update the lat/lng fields on your form when a Place is selected ->maxLength(1024) ->prefix('Choose:') ->placeholder('Start typing an address ...') ->geolocate() // add a suffix button which requests and reverse geocodes the device location ->geolocateIcon('heroicon-o-map'), // override the default icon for the geolocate button
Geocomplete 字段还提供了与 Filament 的 TextInput 相同的许多功能,如前缀、后缀、占位符等。
表单小部件地图字段
如果您需要在表单上的地图中显示多个标记,可以使用WidgetMap字段。这是主MapWidget的一个简化版本(见下文),提供了多个标记的只读显示。您不能移动或更新标记,只能显示它们。
WidgetMap::make('widget_map') ->mapControls([ 'zoomControl' => true, ]) ->markers(function () { // retrieve and display all records from the Geocode model $markers = []; Geocode::all()->each(function (Geocode $record) use (&$markers) { $markers[] = [ 'location' => [ 'lat' => $record->lat ? round(floatval($record->lat), 8) : 0, 'lng' => $record->lng ? round(floatval($record->lat), 8) : 0, ], 'label' => $record->name, ]; }); return $markers; }) ->columnSpan(2)
markers()方法必须返回一个包含位置数组的数组(与主Map Widget相同)的形式
[ [ 'location' = > [ 'lat' => 12.34, 'lng' => -12.34 ], 'label' => 'Foo bar', // optional 'icon' => [ 'url' => 'path/to/foo.svg', 'type' => 'svg', 'scale' = [35,35] ] // optional ], // ]
您还可以使用center()和zoom()方法来自定义地图的初始显示。
表列
表列显示一个静态的Google地图图像。这些图像通过调用地图API在服务器端创建,并在服务器本地缓存(使用Laravel的默认缓存驱动程序)30天,以防止过度使用API。请参阅本页顶部关于API使用的警告。
use Cheesegrits\FilamentGoogleMaps\Columns\MapColumn; ... MapColumn::make('location') ->extraAttributes([ 'class' => 'my-funky-class' ]) // Optionally set any additional attributes, merged into the wrapper div around the image tag ->extraImgAttributes( fn ($record): array => ['title' => $record->latitude . ',' . $record->longitude] ) // Optionally set any additional attributes you want on the img tag ->height('150') // API setting for map height in PX ->width('250') // API setting got map width in PX ->type('hybrid') // API setting for map type (hybrid, satellite, roadmap, tarrain) ->zoom(15) // API setting for zoom (1 through 20) ->ttl(60 * 60 * 24 * 30), // number of seconds to cache image before refetching from API
注意标记为“API设置”的选项用作缓存键的一部分,因此更改其中任何一项都将强制刷新表中的所有图像(因为它们被显示)。
半径过滤
半径过滤器允许您指定一个地址(使用geocomplete下拉菜单)、一个数字距离和可选的单位选择,然后表将被过滤到指定地址的距离内的记录。
use Cheesegrits\FilamentGoogleMaps\Filters\RadiusFilter; ... RadiusFilter::make('radius') ->latitude('lat') // optional lat and lng fields on your table, default to the getLatLngAttributes() method ->longitude('lng') // you should have one your model from the fgm:model-code command when you installed ->selectUnit() // add a Kilometer / Miles select ->kilometers() // use (or default the select to) kilometers (defaults to miles) ->section('Radius Search') // optionally wrap the filter in a section with heading
如果您的位置在相关表中,例如,如果您想在“events”表上放置一个RadiusFilter,而您的位置在“places”表中,并且您在Event模型上有一个“place”BelongsTo关系。
您还可以重写颜色和图标。
RadiusFilter::make('radius') ->attribute('place.location') // the relationship, with the computed location attribute ->color('primary') ->icon('heroicon-m-map'),
在半径过滤时,您还可以使用RadiusAction,允许您在表的行上点击按钮来设置当前半径过滤使用的地址。
注意 - 您必须将RadiusAction命名为与您的RadiusFilter相同的名称。默认为'radius'。
use Cheesegrits\FilamentGoogleMaps\Actions\RadiusAction; // protected function getTableActions(): array { return [ // RadiusAction::make(), ]; }
如果您的位置在相关数据中,您可以在RadiusAction中添加一个relationship()方法。您还可以重写颜色和图标
use Cheesegrits\FilamentGoogleMaps\Actions\RadiusAction; // protected function getTableActions(): array { return [ // RadiusAction::make() ->relationship('location') ->color('primary') ->icon('heroicon-m-map'), ]; }
地图过滤器
有关如何将地图用作表格过滤器的详细信息,请参阅下方的地图表小部件部分。
静态地图批量操作
静态地图批量操作允许您选择表中的任意行数,然后生成包含那些位置的下载able静态地图,并有一个对话框来指定地图大小、类型和比例。
use Cheesegrits\FilamentGoogleMaps\Actions\StaticMapAction; // ->bulkActions([ // StaticMapAction::make(), // ]); //
地图小部件
地图小部件可以在Filament管理面板中使用(见Filament文档),也可以作为独立的正常Livewire组件。
要生成小部件的代码,请运行此Artisan命令
php artisan fgm:make-widget Widget type (just a map, or map with integrated table [Map]: [0] Map [1] Map & Table > 1 Name (e.g. `DealershipMap`): > LocationMapTableWidget Model (e.g. `Location` or `Maps/Dealership`): > Location (Optional) Resource (e.g. `LocationResource`): > LocationResource Successfully created the LocationMapTableWidget in your LocationResource resource class. Make sure to register the widget both in `LocationResource::getWidgets()`, and in either `getHeaderWidgets()` or `getFooterWidgets()` of any `LocationResource` page.
如果您省略了Resource,则小部件将在主小部件文件夹/Filament/Widgets中创建,并且命令将告诉您如何在前端使用它
Your widget has been created as: App/Filament/Resources/LocationMapTableWidget.php If you want to use it on the front end, copy/move it to somewhere in your Livewire folder, say ... /Http/Livewire/Widgets/LocationMapTableWidget.php ... and then invoke it from a front end Blade template like ... @livewire('widgets.location_map_table_widget')
生成的代码看起来像这样
<?php namespace App\Http\Livewire\Widgets; use App\Models\Dealerships; use Cheesegrits\FilamentGoogleMaps\Widgets\MapWidget; class DealershipMap extends MapWidget { protected static ?string $heading = 'Dealership Locations'; protected static ?bool $clustering = true; protected function getData(): array { $dealerships = Dealerships::all(); $data = []; foreach ($dealerships as $dealership) { if ($dealership->latitude && $dealership->longitude) { /** * Each element in the returned data must be an array * containing a 'location' array of 'lat' and 'lng', * and a 'label' string. * * You should also aan 'id' attribute for internal use by this plugin. */ $data[] = [ 'location' => [ 'lat' => $dealership->latitude, 'lng' => $dealership->longitude, ], 'label' => $dealership->name, 'id' => $dealership->getKey(), /** * Optionally you can provide custom icons for the map markers, * either as scalable SVG's, or PNG, which doesn't support scaling. * If you don't provide icons, the map will use the standard Google marker pin. */ 'icon' => [ 'url' => url('images/dealership.svg'), 'type' => 'svg', 'scale' => [35,35], ], ]; } } return $data; } }
可选地,您可以使用Blade模板(见Google API文档中关于您可以使用哪些HTML标记和样式的限制)渲染您的标签,并提供一个图标(svg或png)...
$data[] = [ // ... 'label' => view( 'widgets.dealership-label', [ 'dealershipId' => $dealership->id, 'dealershipName' => $dealership->name, 'dealershipIcon' => $dealership->icon, ] )->render(), // ... ];
要为您的标记添加可点击的弹出动作,例如显示记录的Infolist,您可以添加一个markerAction()方法,该方法可以使用actions的record()方法中的'model_id'从$arguments中定位被点击标记的记录,例如
use Filament\Actions\Action; use Filament\Infolists\Components\Card; use Filament\Infolists\Components\TextEntry; class DealershipMap extends MapWidget { // must be the name of both the Action and your method that returns the Action protected static ?string $markerAction = 'markerAction'; // public function markerAction(): Action { return Action::make('markerAction') ->label('Details') ->infolist([ Card::make([ TextEntry::make('name'), TextEntry::make('street'), TextEntry::make('city'), TextEntry::make('state'), TextEntry::make('zip'), TextEntry::make('formatted_address'), ]) ->columns(3) ]) ->record(function (array $arguments) { return array_key_exists('model_id', $arguments) ? Location::find($arguments['model_id']) : null; }) ->modalSubmitAction(false); } // }
您可以通过重写getConfig()方法并向配置中的地图创建传递['mapConfig']条目来向地图配置中添加选项(传递给JavaScript中Google地图创建的'opts'对象)。您添加到其中的任何内容都将逐字传递到地图创建中。例如,要隐藏POI(兴趣点)标记
public function getConfig(): array { $config = parent::getConfig(); // Disable points of interest $config['mapConfig']['styles'] = [ [ 'featureType' => 'poi', 'elementType' => 'labels', 'stylers' => [ ['visibility' => 'off'], ], ], ]; return $config; }
请参阅父组件代码,以了解您可以重写的其他方法和变量,例如更改或删除图标或使地图部分可折叠。
地图表格小部件
地图表格小部件具有普通小部件的所有功能,但增加了下方的丝网表格。地图可以响应对表格上的所有过滤和搜索操作,这些操作使用标准的丝网表格方法和模式执行。
要生成经销商表格地图,您将运行相同的Artisan命令,但选择“地图 & 表格”选项。生成的代码将与地图选项类似,但增加了定义表格列、过滤器、操作等熟悉的丝网方法。
protected function getTableFilters(): array { return [ MapIsFilter::make('map'), ]; } protected function getTableActions(): array { return [ GoToAction::make() ->zoom(14), ]; }
use Cheesegrits\FilamentGoogleMaps\Widgets\MapTableWidget; // ... class DealershipMap extends MapTableWidget { // ... protected function getTableQuery(): Builder { return Dealer::all(); } protected function getTableColumns(): array { return [ Tables\Columns\TextColumn::make('name'), Tables\Columns\TextColumn::make('state.name'), Tables\Columns\TextColumn::make('phone') ->searchable(), Tables\Columns\TextColumn::make('email') ->searchable(), ]; } protected function getTableFilters(): array { return [ Tables\Filters\SelectFilter::make('state') ->label('State') ->relationship('state','state_name'), MapIsFilter::make('map'), ]; } // ... }
您可以在普通丝网表格中执行的所有操作,都可以在这个表格中执行。
请注意MapIsFilter表格过滤器的作用。通过将此过滤器作为可选内容包含在表格过滤器中,地图充当附加表格的过滤器,因此缩放和平移以更改可见地图图钉将相应地过滤表格。
此小部件还提供了一个额外的操作,即GoToAction,单击时将放大并平移地图到所选位置。
(返回顶部)
Artisan命令
以下命令也可以作为fgm引用,而不是filament-google-maps:,因为我们也不喜欢连续输入。
辅助命令
通常很有用能够测试单个地理编码查找。我们提供了两个命令...
php artisan filament-google-maps:geocode --address="1600 Pennsylvania Avenue NW, Washington, DC 20500" -A -C -G lat: 38.8976633 lng: -77.0365739 [ 'lat' => 38.8976633 'lng' => -77.0365739 [ --lat=38.8976633 --lng=-77.0365739 php artisan filament-google-maps:reverse-geocode --lat=38.8976633 --lng=-77.0365739
...其中开关是可选的,控制纬度/经度的格式,对于(例如)获取用于设置地图字段的默认位置的数组非常有用。或者,正如我们在这里所做的那样,找到用于反向查找命令的地址坐标,以便我们可以检查地址组件格式...
php artisan filament-google-maps:reverse-geocode --lat=38.8976633 --lng=-77.0365739 +--------+-------------------------------+ | Symbol | Result | +--------+-------------------------------+ | %n | 1600 | | %S | Pennsylvania Avenue Northwest | | %L | Washington | | %D | | | %z | 20502 | | %A1 | District of Columbia | | %A2 | | | %A3 | | | %A4 | | | %A5 | | | %a1 | DC | | %a2 | | | %a3 | | | %a4 | | | %a5 | | | %C | United States | | %c | US | | %T | | +--------+-------------------------------+
批量命令
处理位置数据时,通常会有包含纬度和经度数据但无地址数据或相反的表格。本软件包提供了一个方便的方式来处理表格,以便对其进行地理编码或反向地理编码以填充空白。
批量地理编码
要将地址数据中的纬度和经度坐标添加到表格中,请运行此命令
php artisan filament-google-maps:geocode-table
...它将提示您以下内容
- model - 您的模型名称,如Location或Dealerships/Location
- fields - 组成地址的字段顺序,逗号分隔列表,如'street,city,state,zip'
- lat - 您的纬度字段
- lng - 您的经度字段
- processed - 可选字段名称,在地理编码时将其设置为1,如果设置为1则排除
- rate-limit - 每分钟查找的最大次数(最大为300,这是谷歌的硬限制,建议最大值为150)
或者,您可以跳过手动操作,并按以下方式发出...
php artisan filament-google-maps:geocode-table Location --fields=street,city,state,zip --lat=lat --lng=lng --rate-limit=100
如果您的地址数据中有任何是连接关系,例如,您有一个“states”表格,其中的“state”字段是外键,您可以使用点表示法指定它,例如'states.state_full_name',其中第一部分(states)是您模型上的关系名称。
该命令将从您的表中选择所有记录,其中纬度或经度字段为空(0、null或空字符串)。
批量反向地理编码
从命令行进行反向地理编码稍微复杂一些,因为我们必须分解和映射谷歌返回的相当复杂的地址格式。为此,我们使用来自Gecocoder PHP的标准printf样式格式化。
这里不一一解释,以下是一个示例终端会话...
(点击展开)
fgm> php artisan filament-google-maps:reverse-geocode Location Name of latitude element on table (e.g. `latitude`): > lat Name of longitude element on table (e.g. `longitude`): > lng Optional name of field to set to 1 when record is processed (e.g. `processed`) > processed +------------------------------+-------------------------+ | Component | Format | +------------------------------+-------------------------+ | Street Number | %n | | Street Name | %S | | City (Locality) | %L | | City District (Sub-Locality) | %D | | Zipcode (Postal Code) | %z | | Admin Level Name | %A1, %A2, %A3, %A4, %A5 | | Admin Level Code | %a1, %a2, %a3, %a4, %a5 | | Country | %C | | Country Code | %c | | Timezone | %T | +------------------------------+-------------------------+ Use the table above to enter your address component mapping. Google returns a complex set of address components. You need to tell us how you want those components mapped on to your database fields. We use a standard symbolic format as summarixed in the table above to extract the address components. Each mapping should be of the form <field name>=<format symbol(s)>, for example to map (say) a street address to your `street_name` field, you would need ... street_name=%n %S ... and you might also add ... city=%L state=%A2 zip=%z ... or just ... formatted_address=%s %S, %L, %A2, %z You may enter as many mappings as you need, enter a blank line to continue. Test your field mapping. Yes. This is complicated. If you would like us to look up an example record from your table and show you what all those formats translate to, enter an ID here. If not, just press enter. ID (primary key on table): > 1 +--------+-------------------+ | Symbol | Result | +--------+-------------------+ | %n | 19225 | | %S | North 44th Avenue | | %L | Glendale | | %D | | | %z | 85308 | | %A1 | Arizona | | %A2 | Maricopa County | | %A3 | | | %A4 | | | %A5 | | | %a1 | AZ | | %a2 | Maricopa County | | %a3 | | | %a4 | | | %a5 | | | %C | United States | | %c | US | | %T | | +--------+-------------------+ Field mapping (e.g. city=%L), blank line to continue: > street=%n %S Field mapping (e.g. city=%L), blank line to continue: > city=%L Field mapping (e.g. city=%L), blank line to continue: > state=%A1 Field mapping (e.g. city=%L), blank line to continue: > zip=%z Field mapping (e.g. city=%L), blank line to continue: > formatted_address=%n %S, %L, %z %a1 Field mapping (e.g. city=%L), blank line to continue: > Rate limit as API calls per minute (max 300): > 100 Results API Lookups: 2 Records Updated: 2 Command summary - you may wish to copy and save this somewhere! php artisan filament-google-maps:reverse-geocode Location --fields="street=%n %S" --fields="city=%L" --fields="state=%A1" --fields="zip=%z" --fields="formatted_address=%n %S, %L, %z %a1" --lat=lat --lng=lng --processed=processed --rate-limit=100
(返回顶部)
示例 / 测试仓库
您可以使用一个示例应用程序进行测试,它提供了本软件包提供的几乎所有功能的示例。
(返回顶部)
路线图
- 为所有API使用添加缓存
- 为静态地图添加使用哪个缓存存储的选项
- 添加Geocomplete字段
- 改进Geocomplete字段位置数据字段处理(允许组合多个字段)
- 为地理编码/反向地理编码表添加工匠命令,当源表有地址但没有坐标,或者反过来时非常有用。
- 添加API调用可选请求签名。
- 将区域添加到所有API调用中。
- 添加制作小部件的工匠命令。
- 将KML图层添加到字段和小部件中。
- 为表单字段添加更多地理编码选项,针对单个地址组件(街道、城市、邮编等)。
- 改进反向地理编码的格式语法,例如,交替...%A3|%A2(%A3是否为空,尝试%A2),等等。
- 编写测试套件。
(返回顶部)
问题
如果您发现错误,请在本页问题页面上报告它们,我们将尽快修复。
(返回顶部)
贡献
如果您有改进这个项目的建议,请fork仓库并创建一个pull请求。您也可以简单地创建一个带有“增强”标签的问题。
- Fork项目
- 创建您的功能分支(
git checkout -b feature/AmazingFeature
) - 提交您的更改(
git commit -m '添加一些AmazingFeature'
) - 推送到分支(
git push origin feature/AmazingFeature
) - 打开Pull Request
(返回顶部)
许可证
在MIT许可证下分发。有关更多信息,请参阅LICENSE.txt
。
(返回顶部)
联系
Hugh Messenger - @cheesegrits - hugh.messenger@gmail.com
项目链接: https://github.com/cheesegrits/filament-google-maps
(返回顶部)
致谢
(返回顶部)