shootkiran / filament-google-maps
Filament PHP 的 Google Maps 包,包含字段、列和部件
Requires
- php: ^8.1
- 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: 1.0.0
- 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
- v3.x-dev
- v3.0.14
- v3.0.13
- v3.0.12
- v3.0.11
- v3.0.10
- v3.0.9
- v3.0.8
- v3.0.7
- v3.0.6
- v3.0.5
- v3.0.4
- v3.0.3
- v3.0.2
- v3.0.1
- v3.0.0
- v2.0.0-alpha17
- v2.0.0-alpha16
- v2.0.0-alpha15
- v2.0.0-alpha14
- v2.0.0-alpha13
- v2.0.0-alpha12
- v2.0.0-alpha11
- v2.0.0-alpha10
- v2.0.0-alpha9
- v2.0.0-alpha8
- v2.0.0-alpha7
- v2.0.0-alpha6
- v2.0.0-alpha5
- v2.0.0-alpha4
- v2.0.0-alpha3
- v2.0.0-alpha2
- v2.0.0-alpha1
- v1.0.25
- v1.0.24
- v1.0.23
- v1.0.22
- v1.0.21
- v1.0.20
- v1.0.19
- v1.0.18
- v1.0.17
- v1.0.16
- v1.0.15
- v1.0.14
- v1.0.13
- v1.0.12
- v1.0.11
- v1.0.10
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- dev-cheesegrits-v3
- dev-v3-alpha
- dev-main
- dev-dev
This package is auto-updated.
Last update: 2024-09-27 16:03:57 UTC
README
Filament Google Maps
本包为 Filament PHP 生态系统(一个 Laravel 应用程序构建器)提供了使用 Google Maps 的完整工具集(无论是作为管理面板的一部分,还是在独立的前端表单、表格和仪表板中),包括字段、列和部件。
关于本项目
Filament v3 版本发布
这是 v3 分支,与最近的 Filament v3 版本兼容。在不久的将来,我们将用这个 v3 分支替换主分支(目前是 Filament v2 兼容分支),并将 Filament v2 支持转移到 v2 分支。
请在 GitHub 问题页面 上报告您发现的问题,或在 Filament 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 地理补全字段,可选地反向地理编码地址组件。
信息列表字段
MapEntry 信息列表字段显示一个(只读)地图,显示单个标记。目前正在进行中,即将添加功能和功能(如 KML 层、GeoJSON 绘图等)。
地图小部件
MapWidget 显示模型中可筛选的位置集,可选地具有聚类、可模板化标签、自定义图标等。
地图表格小部件
MapTableWidget 显示地图小部件和 Filament 表格,并响应表格上的所有筛选和搜索。
地图列
MapColumn 显示可定制的静态地图图像,并将图像缓存在本地以减少 API 开销。
静态地图操作
StaticMapAction 是一个批量操作,允许您选择任意数量的表格行,并生成显示这些位置的下载静态地图。
半径筛选
RadiusFilter 提供针对地理补全地址的半径筛选,单位为公里或英里。
批量命令
《工匠命令》允许您对位置表进行批量处理,无论是将地址字段组合成经纬度,还是将经纬度反向地理编码到地址字段。
(返回顶部)
入门指南
先决条件
此包基于 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
... 它会提示您输入
- 模型:您的模型类,例如 Places 或 Dealerships/Dealership
- 纬度:您的纬度属性(现有表字段)
- 经度:您的经度属性(现有表字段)
- 位置:计算属性名称,不应在您的表上存在
当您创建地图字段和列时,将使用 'location' 计算属性。如果您没有宗教信仰且它尚未存在于您的表上,只需使用 'location' 即可。
然后它会自动生成代码供您复制和粘贴到模型类中。
注意 - 如果需要,此脚本还提供了修改后的 $fillable 和 $appends 数组,这些数组将合并这些数组中现有的任何内容,请确保您已经替换了现有的数组。
设置您的 Google 地图 API 密钥
所有使用 Google 地图 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 地图控件,请参阅 API 文档。
地理补全
autocomplete('field_name') 选项将您提供的字段名称转换为 Google 地点自动补全字段,在您键入时建议位置。选择建议将移动地图上的标记。
如果您指定 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() 每个反向地理编码事件的响应(例如,每次移动标记时)。
图层 / GeoJSON
有两种方法可以向地图添加图层。layers() 方法接受一个 KML 或 GeoRSS 文件 URL 数组,这些 URL 将使用 Maps API KmlLayer() 方法添加到地图上。请注意,这些 URL 必须是公开可访问的,因为 KmlLayer() 方法需要 Google 服务器读取和处理文件,有关详细信息和使用限制,请参阅 KML & GeoRSS 图层 文档。
第二种方法允许使用 geoJson() 方法指定单个 GeoJSON 文件,该方法接受一个闭包或字符串,可以是本地文件路径、原始 GeoJSON 或 GeoJSON 文件的 URL。如果指定本地路径,可选的第二个参数可以是使用的存储磁盘名称。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()。例如,如果您有县和/或州表,并使用它们与具有关系的 Select 字段,则需要不同地处理县/州(通过在您的表中查找相应的地址组件并设置您的表单字段到适当的键)。
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(如 'address' 或 'establishment')的一个,要么是来自表 1 或 2 的最多 5 个(如 'airport'、'subway_station' 等)。
Geocomplete::make('location') ->types(['car_dealer', 'car_rental', 'car_repair']) ->placesField('name')
在两种模式中,您都可以选择性地指定用于将选定的地址组件数据反向地理编码的字段,使用的方法与上述地图组件中记录的方法相同。
以下示例中没有显示,但你也可以使用reverseGeocodeUsing()方法提供自己的闭包来处理反向地理编码数据,如上文中Map组件所述。
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相同的许多功能,如前缀、后缀、占位符等。
信息列表字段
Infolist字段显示一个只读地图,其中只有一个字段显示字段的位置。
use Cheesegrits\FilamentGoogleMaps\Infolists\MapEntry; // public function infolist(Infolist $infolist): Infolist { return $infolist->schema([ TextEntry::make('street'), TextEntry::make('city'), TextEntry::make('state'), TextEntry::make('zip'), MapEntry::make('location') ->columnSpan(2), ]); }
表单WidgetMap字段
如果你需要在表单上的地图中显示多个标记,可以使用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地图图像。图像在服务器端通过调用Maps 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'表上放置半径过滤器,并且你的位置在'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'), ]; }
地图是过滤
有关如何将地图用作表格的过滤器的详细信息,请参阅下文Map Table Widget部分。
静态地图批量操作
静态地图批量操作允许你选择表中的任意数量的行,然后生成这些位置的下载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.
如果你省略了资源,小部件将被创建在主小部件文件夹/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()方法中的'arguments'中的'model_id'来定位被点击标记的记录,例如
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()方法,并在$config中添加一个['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; }
请参阅父组件代码以获取更多可重写的函数和变量,如更改或删除图标或使地图部分可折叠。
地图表格小部件
地图表格小部件具有原表格的所有功能,但增加了其下方的Filament表格。地图响应表格上的所有过滤和搜索,这是通过标准的Filament表格方法和模式完成的。
要生成经销商表格地图,您将运行相同的Artisan命令,但选择地图和表格选项。生成的代码将类似于地图选项,但增加了定义表格列、过滤器、操作等熟悉的Filament方法。
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'), ]; } // ... }
您可以在正常Filament表格中做任何事情,也可以在这个表格中做。
此外,请注意使用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
...这将提示您以下内容
- 模型 - 您的模型名称,例如位置或Dealerships/位置
- 字段 - 由地址组成的字段列表,按顺序,以逗号分隔,例如'street,city,state,zip'
- 纬度 - 您的纬度字段
- 经度 - 您的经度字段
- 处理 - 可选字段名称,当地理编码时将设置为1,当设置为1时将被排除
- rate-limit - 每分钟的查找最大次数(最大为300,这是Google的硬限制,建议的最大值为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字段位置数据字段处理(允许组合多个字段)
- 添加地理编码/反向地理编码表的Artisan命令,当源表有地址但没有坐标,或反之亦然时很有用
- 添加API调用的可选请求签名
- 向所有API调用添加区域设置
- 添加make-widget artisan命令
- 向字段和小部件添加KML图层
- 为表单字段添加更多地理编码选项,针对单个地址组件(街道、城市、邮编等)
- 改进反向地理编码格式语法,例如交替... %A3|%A2(%A3是否为空,尝试%A2),等等
- 编写测试套件
(返回顶部)
问题
如果您(当)发现错误,请在本问题页面上报告它们,我们将尽快修复它们。
(返回顶部)
贡献
如果您有改进此应用的建议,请将其仓库fork并创建一个pull请求。您也可以简单地打开一个带有“增强”标签的问题。
- Fork项目
- 创建您的功能分支(
git checkout -b feature/AmazingFeature
) - 提交您的更改(
git commit -m 'Add some 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
(返回顶部)
致谢
(返回顶部)