本文共 20171 字,大约阅读时间需要 67 分钟。
gatsby
Get ready for the summer by building your own road trip mapping app with this step-by-step guide!
通过此逐步指南,构建自己的公路旅行地图应用,为夏天做好准备!
Author’s Note: Even though we’re going through some challenging times, we can still be optimistic that we’ll get through this together and be able to enjoy our summer. Stay safe and wash your hands. ❤️
作者的注释:即使我们正在经历一些艰难的时期,我们仍然很乐观,因为我们会一起度过难关并能够享受我们的夏天。 保持安全并洗手。 ❤️
We’ll be walking through building a new mapping app that shows a route representing the trip. Each location will have a little card where we can add a picture and some things we did.
我们将逐步构建一个新的地图应用程序,该应用程序显示代表行程的路线。 每个位置都会有一张小卡片,我们可以在其中添加图片和所做的一些事情。
To get started, we’re going to use this I created to make the initial setup a little smoother. With our app bootstrapped, we’ll create our list of locations and use Leaflet’s API to draw our route on the map.
首先,我们将使用我创建的来初始设置。 引导我们的应用程序后,我们将创建位置列表并使用Leaflet的API在地图上绘制路线。
Yup. If you haven’t played with maps before, don’t be discouraged! It's not as bad as you probably think. If you’d rather start with mapping basics, you can first.
对。 如果您以前从未玩过地图,请不要气!! 它并不像您想象的那么糟糕。 如果您想开始使用映射基础知识,则可以首先 。
If you followed along with my last tutorial for , you can follow the same steps to get started. If not, we’ll want to make sure we have the following set up:
如果您遵循了我的上一本有关教程,则可以按照相同的步骤开始。 如果没有,我们将确保我们进行以下设置:
or - I'll be using yarn, but you can substitute with npm where appropriate
或 -我将使用毛线,但是您可以在适当的地方用npm代替
- yarn global add gatsby-cli
- yarn global add gatsby-cli
If you’re not sure about one of the above items, you can try checking out the beginning of .
如果您不确定上述项目之一,可以尝试查看的开头。
We’ll also want to set up a foundation for our map. We can do this by utilizing the Leaflet Gatsby Starter I put together that provides us a basic setup with and .
我们还想为我们的地图建立基础。 我们可以利用我组合在一起的Leaflet Gatsby Starter来做到这一点,它为我们提供了和的基本设置。
gatsby new my-road-trip https://github.com/colbyfayock/gatsby-starter-leaflet
After that’s finished running, you can navigate to the newly created project directory and start your local development server:
完成运行后,您可以导航到新创建的项目目录并启动本地开发服务器:
cd my-road-tripyarn develop
If all goes as planned, your server should start and you should now be able to see your basic mapping app in your browser!
如果一切按计划进行,则服务器将启动,您现在应该可以在浏览器中看到基本的地图应用程序!
The Gatsby Starter we're using to spin up this app comes with some demo code that we don’t need here. We’ll want to make all of the changes below in the file src/pages/index.js
, which is the homepage of our app.
我们用来启动该应用程序的Gatsby Starter附带了一些此处不需要的演示代码。 我们要在文件src/pages/index.js
以下所有更改,这是我们应用程序的主页。
First, let’s remove everything from the mapEffect
function. This function is used to run code that fires when the map renders.
首先,让我们从mapEffect
函数中删除所有内容。 此函数用于运行在地图渲染时触发的代码。
// In src/pages/index.jsasync function mapEffect({ leafletElement } = {}) { // Get rid of everything in here}
Next, we don’t want a marker this time, so let’s remove the <Marker
component from our <Map
component:
接下来,我们这次不想要标记,因此让我们从<Map
组件中删除<Marker
组件:
Now that we have those pieces cleared out, we can remove all of the following imports and variables from the top of our file:
现在,我们已经清除了这些部分,可以从文件顶部删除以下所有导入和变量:
After, our map should still work, but not do anything.
之后,我们的地图应该仍然有效,但是什么也没做。
This step will involve preparing our location data that will populate our road trip app. Our locations will include properties like a name, date, things we did, and a picture if we want.
此步骤将涉及准备将填充我们的公路旅行应用程序的位置数据。 我们的位置将包括属性,例如名称,日期,我们做的事情,以及如果需要的图片。
First, create a new file in the src/data
directory called locations.js
. Inside of that file, we want to create and export a new array.
首先,在src/data
目录中创建一个名为locations.js
的新文件。 在该文件内部,我们要创建和导出一个新数组。
export const locations = [ { placename: ‘Herndon, VA’, date: ‘August 1, 2015’, location: { lat: 38.958988, lng: -77.417320 }, todo: [ ‘Where we start! 🚀’ ] }, { placename: ‘Middlesboro, KY', date: ‘August 1, 2015’, location: { lat: 36.627517, lng: -83.621635 }, todo: [ ‘Cumberland Gap 🌳’ ] }];
You can use the above to get started, but you’ll eventually want to change the details to something of your choosing.
您可以使用以上内容开始使用,但最终您需要将详细信息更改为您选择的内容。
If you want to add an image to your location, you can do so by including an image
property to the object. You can use either a URL string or you can import a local file if you have one available, like I’m doing in this example:
如果要将图像添加到您的位置,可以通过在对象中包含image
属性来实现。 您可以使用URL字符串,也可以导入本地文件(如果有可用的话),例如我在本示例中所做的:
import imgHerndonStart from 'assets/images/herndon-start.jpg’;export const locations = [ { placename: ‘Herndon, VA’, date: ‘August 1, 2015’, image: imgHerndonStart, location: { lat: 38.958988, lng: -77.417320 }, todo: [ ‘Where we start! 🚀’ ] }]
Once we have that file created, we can now import our locations into our src/pages/index.js
file so we can use it in our next step:
创建完该文件后,我们现在可以将位置导入到src/pages/index.js
文件中,以便在下一步中使用它:
import { locations } from 'data/locations’;
If you add a console.log(locations)
inside of your page, you should now see all of your location data in an array!
如果在页面内添加console.log(locations)
,现在应该在数组中看到所有位置数据!
To try to keep things simple and focused, I grouped together 3 important components of creating our map into functions. Though it’s available to copy and paste, we’ll walk through what’s happening in each function.
为了使事情简单而集中,我将创建地图的3个重要组件归为一组。 尽管可以复制和粘贴,但我们将逐步介绍每个函数中发生的情况。
You can place each of these functions at the bottom of the src/pages/index.js
file so they’re ready to use in our next step.
您可以将每个函数放在src/pages/index.js
文件的底部,以便在下一步中使用它们。
Our first function is going to take the array of our locations and return a , with our locations mapped into an individual Feature. We’ll use this function to create the individual points on our map.
我们的第一个函数将获取我们的位置数组,并返回一个 ,并将我们的位置映射到一个单独的Feature中。 我们将使用此功能在地图上创建各个点。
What is a GeoJSON document? It's essentially a JavaScript object or JSON document with a specific structure that creates consistency with geographical data.
什么是GeoJSON文档? 本质上,它是具有特定结构JavaScript对象或JSON文档,可与地理数据保持一致。
function createTripPointsGeoJson({ locations } = {}) { return { “type”: “FeatureCollection”, “features”: locations.map(({ placename, location = {}, image, date, todo = [] } = {}) => { const { lat, lng } = location; return { “type”: “Feature”, “properties”: { placename, todo, date, image }, “geometry”: { “type”: “Point”, “coordinates”: [ lng, lat ] } } }) }}
So what’s happening in the above?
那么上面发生了什么?
Within the object, we map our locations to individual Feature
objects
在对象内,我们将位置映射到各个Feature
对象
Each object includes a Point
shape using our coordinates
使用我们的坐标,每个对象都包含一个Point
形状
When this function is invoked, we will have a newly created JavaScript object that includes an array of Points representing the locations we are stopping at on our road trip.
调用此函数后,我们将创建一个新创建JavaScript对象,该对象包括一个Points数组,这些Points表示我们在旅途中要停靠的位置。
We’re going to create another function that’s similar to the previous one. This time however, instead of points, we want to create lines that represent going from one point to the next.
我们将创建另一个与上一个功能相似的功能。 但是,这次,我们要创建代表从一个点到下一个点的线,而不是点。
function createTripLinesGeoJson({ locations } = {}) { return { “type”: “FeatureCollection”, “features”: locations.map((stop = {}, index) => { const prevStop = locations[index - 1]; if ( !prevStop ) return []; const { placename, location = {}, date, todo = [] } = stop; const { lat, lng } = location; const properties = { placename, todo, date }; const { location: prevLocation = {} } = prevStop; const { lat: prevLat, lng: prevLng } = prevLocation; return { type: ‘Feature’, properties, geometry: { type: ‘LineString’, coordinates: [ [ prevLng, prevLat ], [ lng, lat ] ] } } }) }}
So you’ll immediately notice that this is very similar to our last function. We’re returning an object and setting our metadata properties on a list of Features.
因此,您会立即注意到,这与我们的上一个功能非常相似。 我们将返回一个对象,并在功能列表上设置元数据属性。
The big difference, however, is that we're creating a Line. To do this, we're looking up and referring to prevStop
which will be the previous stop. We’ll use both the previous stop and our current stop in order to have 2 points which we can use to draw the line.
但是,最大的不同是我们正在创建一条线。 为此,我们要查找并引用prevStop
,这将是上一站。 我们将使用上一个停靠点和当前停靠点,以便有2个点可以用来画线。
If we don’t have a previous stop, we return an empty array, which basically means we’re at the beginning of our journey with no line before it.
如果我们没有上一个停靠点,那么我们将返回一个空数组,这基本上意味着我们正处在旅途的开始,之前没有任何一行。
With the previous stop and current stop, we create a LineString
type of Feature with our 2 points.
使用上一个停靠点和当前停靠点,我们用2个点创建LineString
类型的Feature。
Our last function is going to allow us to create custom content for each of the points that we will be adding to our map. We’ll actually be utilizing this function within a Leaflet property, so we’ll be conforming our arguments to that specification.
我们的最后一个功能是允许我们为要添加到地图中的每个点创建自定义内容。 实际上,我们将在Leaflet属性中利用此函数,因此我们将使参数符合该规范。
function tripStopPointToLayer( feature = {}, latlng ) { const { properties = {} } = feature; const { placename, todo = [], image, date } = properties; const list = todo.map(what => `
Things we will or have done…
${date}
${ listString }One thing you’ll notice as we work through this function is that we create strings of HTML text. Given that the Leaflet API we’re utilizing for this doesn’t interface directly with React, we have to build out HTML manually to pass it in to our functions.
在使用此功能时,您会注意到的一件事是,我们创建了HTML文本字符串。 鉴于我们为此目的使用的Leaflet API不能直接与React交互,我们必须手动构建HTML才能将其传递给我们的函数。
Starting from the top:
从顶部开始:
We take in 2 arguments, feature
and latlng
. Leaflet passes these 2 values in for us to use in our function.
我们接受两个参数, feature
和latlng
。 Leaflet将这两个值传递给我们以在我们的函数中使用。
If we include a todo
property as an array, we add a new list with each item inside.
如果我们包含一个todo
属性作为数组,我们将在其中添加每个项目的新列表。
With our popup HTML, we create a Leaflet popup
instance
使用我们的弹出HTML,我们创建一个Leaflet popup
实例
With the latlng argument and our popup, we create a new Leaflet marker
instance. This will represent the point on the map.
使用latlng参数和我们的弹出窗口,我们创建一个新的Leaflet marker
实例。 这将代表地图上的点。
Remember to make sure you put all of the functions above at the bottom of your src/pages/index.js
page.
请记住要确保将上面的所有功能放在src/pages/index.js
页面的底部。
Once all of those functions are added, our map should still be the same thing, basically nothing happening.
一旦添加了所有这些功能,我们的地图就应该是同一件事,基本上什么也没有发生。
This is where things get interesting. We’ll now utilize the functions we created to build our road trip path. All of our work here will be within the mapEffect
function inside of the src/pages/index.js
file.
这就是事情变得有趣的地方。 现在,我们将利用我们创建的功能来构建公路旅行路径。 我们在这里的所有工作都将在src/pages/index.js
文件内的mapEffect
函数内。
For context, our mapEffect
function includes an argument called leafletElement
. This value refers to the Map instance that Leaflet recognizes. This Map instance includes our map state as well as many utility functions to work with our map.
对于背景下,我们mapEffect
功能包括一个名为参数leafletElement
。 此值是指Leaflet识别的Map实例。 这个Map实例包含我们的地图状态以及许多可与我们的地图一起使用的实用程序功能。
First, at the top of the function, we want to make sure we have a map. If not, we can return to bail out of the function.
首先,在函数顶部,我们要确保有一张地图。 如果没有,我们可以退出该功能的保释。
if ( !leafletElement ) return;
Next, we want to use the eachLayer
utility function and remove each layer
from our map element. We do this to make sure we always have the correct map layer state.
接下来,我们要使用eachLayer
实用程序功能并从我们的map元素中删除每个layer
。 我们这样做是为了确保我们始终具有正确的地图图层状态。
leafletElement.eachLayer((layer) => leafletElement.removeLayer(layer));
With our cleaned up map, we can utilize 2 of the functions we created to create new GeoJSON objects.
通过清理后的地图,我们可以利用创建的两个功能来创建新的GeoJSON对象。
const tripPoints = createTripPointsGeoJson({ locations });const tripLines = createTripLinesGeoJson({ locations });
With our GeoJSON objects, we need to convert those to Leaflet GeoJSON instances, which we’ll use to add to the map.
使用我们的GeoJSON对象,我们需要将其转换为Leaflet GeoJSON实例,并将其用于添加到地图中。
const tripPointsGeoJsonLayers = new L.geoJson(tripPoints, { pointToLayer: tripStopPointToLayer});const tripLinesGeoJsonLayers = new L.geoJson(tripLines);
If you notice in the above, we're using our tripStopPointToLayer
function. As I alluded to before, the geoJson
instance we’re creating includes a property that allows us to pass in a function, giving us the ability to manipulate the layer creation. This is how we create our point and popup content.
如果您在以上内容中注意到,我们正在使用tripStopPointToLayer
函数。 正如我之前提到的,我们正在创建的geoJson
实例包含一个属性,该属性允许我们传递一个函数,从而使我们能够操纵图层的创建。 这就是我们创建指向和弹出内容的方式。
We can proceed to adding both of those new layers to our map using the addTo
.
我们可以使用addTo
两个新图层都添加到地图中。
tripPointsGeoJsonLayers.addTo(leafletElement);tripLinesGeoJsonLayers.addTo(leafletElement);
Next, to make sure we zoom and center on the right location, we want to grab the bounds of the map using the getBounds
function on our GeoJSON layer instance.
接下来,要确保缩放并在正确的位置居中,我们想在我们的GeoJSON图层实例上使用getBounds
函数来获取地图的边界。
const bounds = tripPointsGeoJsonLayers.getBounds();
Finally, we fit our map's view to those bounds using the fitBounds
function on our Map instance.
最后,我们使用Map实例上的fitBounds
函数使地图视图适合这些边界。
leafletElement.fitBounds(bounds);
Once you save and reload the page, you should now see a blue path representing the jump from each of our locations on the map!
保存并重新加载页面后,您现在应该会看到一条蓝色路径,表示从地图上每个位置的跳转!
One issue though. If you notice, we only see the path. This is because we need to add some CSS which we’ll get to in the next step.
不过有一个问题。 如果您注意到,我们只会看到路径。 这是因为我们需要添加一些CSS,我们将在下一步中进行介绍。
Our last step will be adding some styles that will allow our markers to show and our popups to look just right.
我们的最后一步是添加一些样式,这些样式将允许我们的标记显示并且我们的弹出窗口看起来恰到好处。
In this step, we’ll be working inside of the _home.scss
file, which you can find in src/assets/stylesheets/pages
.
在这一步中,我们将在_home.scss
文件中工作,您可以在src/assets/stylesheets/pages
找到该文件。
We can get started by copy and pasting this block of styles into the bottom of that file. With that done, we can walk through what’s happening.
我们可以通过复制此样式块并将其粘贴到该文件的底部开始。 完成此操作后,我们可以逐步了解正在发生的事情。
.trip-stop { width: 400px; overflow: hidden; h2 { font-size: 1.4em; margin-top: 0; margin-bottom: .2em; } p, ul, h3 { font-size: 1.2em; font-weight: normal; } p { margin: .2em 0; } .trip-stop-date { color: $grey-600; font-size: 1em; } ul { padding: 0 0 0 1.4em; margin: 0; }}.trip-stop-image { display: block; float: left; overflow: hidden; width: 150px; height: 150px; text-indent: 100%; color: transparent; background-position: center; background-size: cover;}.trip-stop-content { float: left; width: 250px; padding-left: 1em;}.icon-trip-stop { display: block; width: 1.5em; height: 1.5em; background-color: $orange-500; border-radius: 100%; box-shadow: 0 2px 5px rgba(0,0,0,.5); &:hover { background-color: $deep-orange-400; }}
There’s three components to our styles above:
上面的样式包含三个组成部分:
.trip-stop-images
: Inside of the marker popup, we optionally can include an image. These styles set the size, make the text transparent, (it’s there for accessibility), and float it to the left so that our popup content can align correctly side by side.
.trip-stop-images
:在标记弹出窗口内,我们可以选择包含图像。 这些样式设置大小,使文本透明(在此处可访问),然后将其浮动到左侧,以便我们的弹出内容可以正确并排对齐。
.trip-stop-content
: This refers to the other half of our popup content. All we need to do here is make sure our size is appropriate and that it floats next to our image.
.trip-stop-content
:这是我们弹出窗口内容的另一半。 我们在这里需要做的就是确保我们的尺寸合适并且浮在图像旁边。
.icon-trip-stop
: The HTML tag that we’re using as our icon designation gets styled here. We size it up, set a color using a predetermined Scss variable, and we’re good to go.
.icon-trip-stop
:在此处设置我们用作图标名称HTML标签的样式。 我们将其调整大小,使用预定的Scss变量设置颜色,我们一切顺利。
Once those styles are saved, you should now see the points on the map representing each location. Additionally, you should be able to click each of these points to open up a popup containing information about the stop.
保存这些样式后,您现在应该在地图上看到代表每个位置的点。 此外,您应该能够单击这些点中的每一个,以打开一个包含有关停靠点信息的弹出窗口。
The last thing that's completely optional is to make a few style tweaks to give your site a little personality. I’m not going to go over this in details, but if you’d like to follow along and dress things up a little bit, you can follow along with which shows each code change I made.
完全可选的最后一件事是进行一些样式调整,使您的网站更具个性。 我将不做详细介绍,但是如果您想继续并进行一些修饰,则可以执行 ,其中显示了我所做的每个代码更改。
If you followed along with me, or skipped right to the starter, you should now have a mapping app that you can use for your next road trip.
如果您跟着我,或者直接跳到入门者那里,那么您现在应该拥有一个地图应用程序,可用于下一次旅行。
The good news is this project can apply to anything! Want to map out your favorite restaurants in Washington, DC? Add your locations and remove the lines. Want to create line drawings over the map? That's certainly an option.
好消息是该项目可以应用于任何事物! 想要绘制出您在华盛顿特区最喜欢的餐厅吗? 添加您的位置并删除行。 是否要在地图上创建线条图? 那当然是一个选择。
Whatever it is, if you enjoyed getting this map spun up, get creative and apply it to your next project!
无论是什么,如果您喜欢旋转地图,就可以发挥创意并将其应用于下一个项目!
You can check out a few of my other resources to get started:
您可以查看其他一些资源以开始使用:
翻译自:
gatsby
转载地址:http://fbuzd.baihongyu.com/