博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
gatsby_如何使用Gatsby和React Leaflet创建自己的圣诞老人追踪器
阅读量:2523 次
发布时间:2019-05-11

本文共 17366 字,大约阅读时间需要 57 分钟。

gatsby

The Christmas season is a magical time of year. We have Santa flying around spreading cheer and Elf roaming around New York during our yearly rewatch with family and friends.

圣诞节是一年中不可思议的时期。 在与家人和朋友的年度重看期间,我们在圣诞老人的欢呼声中四处飞扬,在纽约四处漫游的精灵。

To get in the spirit, we’re going to spin up a web app that includes a map that tracks Santa on it!

为了振作精神,我们将启动一个网络应用程序,其中包括一个在其上跟踪圣诞老人的地图!

Edit 12/23: Updated the app to request directly to Santa's route, just in case the original API doesn't work as originally expected.

编辑12/23:更新了应用程序,以直接请求圣诞老人的路线,以防万一原始API不能按预期运行的情况。

我们要建造什么? (What are we going to build?)

We’re going to work through building a mapping app that tracks Santa’s route and his current location.

我们将通过构建一个映射应用程序来工作,该应用程序可跟踪圣诞老人的路线及其当前位置。

To achieve this, we’re going to spin up a premade Gatsby starter that will give us a basic foundation for a map, utilize Google’s unofficial API to grab Santa’s route, and overlay his position and route on top of the map with Leaflet.

为了实现这一目标,我们将准备一个预制的盖茨比启动器,该启动器将为我们提供地图的基本基础,利用Google的非官方API来获取圣诞老人的路线,并使用Leaflet将其位置和路线叠加在地图上。

哇,地图应用? (Woah, a mapping app?)

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.

对。 如果您以前从未玩过地图,请不要气!! 它并不像您想象的那么糟糕。 如果您想开始使用映射基础知识,则可以首先 。

开始之前需要什么? (What do we need before we get started?)

For this exercise, I’m going to assume you have or installed. For each example, I'll use yarn, but use the tool of your choice.

对于本练习,我将假设您已安装或 。 对于每个示例,我将使用yarn,但是使用您选择的工具。

You’ll also want to install globally which will allow us to use their .

您还需要在全球范围内安装 ,这将使我们能够使用其 。

To set up Gatsby’s CLI, run the following command:

要设置盖茨比的CLI,请运行以下命令:

yarn global add gatsby-cli

After, you should be able to run gatsby -h to see the available commands, which means it’s successfully installed.

之后,您应该能够运行gatsby -h来查看可用的命令,这意味着它已成功安装。

For more info about the Gatsby CLI, you can .

有关Gatsby CLI的更多信息,您可以 。

我们的地图基础入门 (Getting started with our map foundation)

Once our command line tools are set up, the first thing we’ll want to do is create a new Gatsby project using I put together. It provides us with a basic setup with and .

设置完命令行工具后,我们要做的第一件事就是使用我放在一起程序创建一个新的Gatsby项目。 它为我们提供了和的基本设置。

Starting in your project directory, let’s install the project:

从项目目录开始,让我们安装项目:

gatsby new [directory] https://github.com/colbyfayock/gatsby-starter-leaflet

Make sure to replace [directory] with the location you want to set up your project.

确保将[directory]替换为您要设置项目的位置。

Once you run that command, Gatsby will clone that project without any of the git references and install the packages required to start.

一旦您运行了该命令,Gatsby将在没有任何git引用的情况下克隆该项目,并安装启动所需的软件包。

To make sure it works, you can now navigate to that directory, spin up your server, and test it in the browser:

为了确保其正常工作,您现在可以导航到该目录,启动服务器,然后在浏览器中对其进行测试:

cd [directory]yarn develop

Where you see [directory] above, make sure to use the same path as you did before when setting up the new Gatsby project.

在上方的[directory] ,请确保使用与设置新Gatsby项目时相同的路径。

If all goes as planned, your server should start and you should now be able to see your basic mapping app in your browser!

如果一切按计划进行,则服务器将启动,您现在应该可以在浏览器中看到基本的地图应用程序!

清理东西 (Cleaning things up)

This starter comes with a quick example of how we can interact with the map. We're not going to need this at all for our purposes so we can go ahead and clean things up.

此入门指南提供了一个有关如何与地图进行交互的快速示例。 为了我们的目的,我们根本不需要它,因此我们可以继续进行清理。

To start, we’re going to open up our index.js file, the homepage file, and get rid of everything inside of the mapEffect function, which leaves us with:

首先,我们将打开index.js文件(即主页文件),并摆脱mapEffect函数内部的所有内容,从而使我们拥有:

// In src/pages/index.jsasync function mapEffect({ leafletElement } = {}) {  // Get rid of everything in here}

Now, let’s remove the Marker component nested inside of our Map, so we end up with:

现在,让我们删除嵌套在Map内的Marker组件,最后得到:

Now that we’re no longer using that functionality, we can get rid of the variables and references at the top of the file, so you can go ahead and remove:

现在我们不再使用该功能,我们可以摆脱文件顶部的变量和引用,因此可以继续删除:

  • useRef

    useRef
  • promiseToFlyTo

    promiseToFlyTo
  • getCurrentLocation

    getCurrentLocation
  • Marker

    记号笔
  • gatsby_astronaut

    gatsby_astronaut
  • ZOOM

    放大
  • timeToZoom

    timeToZoom
  • timeToOpenPopupAfterZoom

    timeToOpenPopupAfterZoom
  • timeToUpdatePopupAfterZoom

    timeToUpdatePopupAfterZoom
  • popupContentHello

    popupContentHello
  • popupContentGatsby

    popupContentGatsby
  • markerRef

    markerRef

寻找圣诞老人 (Finding Santa)

Now that we’re in a good place, let’s get our hands dirty and find Santa. To do this, we’re going to use Google’s unofficial, undocumented API. This means that it’s possible this API won’t be available the day after this get’s published, but let’s be optimistic.

现在我们处于一个好的地方,让我们动起来,找到圣诞老人。 为此,我们将使用Google的非官方,未记录的API。 这意味着该API发布后的第二天可能将不可用,但是让我们保持乐观。

Additionally, at the time of writing, it’s still showing last year’s destinations, so what we’re really going to be visualizing here is Santa’s previous year’s route, though the hope is this would reset on the 24th and we’ll all be merry!

此外,在撰写本文时,它仍在显示去年的目的地,因此我们真正要在这里看到的是圣诞老人的前一年路线,尽管希望这会在24日重置,并且我们都会很高兴!

Before we get Santa, let’s first add a line back to our mapEffect function:

在获得圣诞老人之前,让我们先在mapEffect函数中添加一行:

async function mapEffect({ leafletElement } = {}) {  if ( !leafletElement ) return;}

What this will do is prevent the rest of our code from running in the event our map isn't ready yet. The mapEffect function itself, as you can see in the Map component, runs inside of an instance of useEffect passing an argument of a ref to the map, allowing us to run some code after our component renders.

这样做是为了防止我们的其余代码在地图尚未准备好时运行。 如您在Map组件中所见, mapEffect函数本身在useEffect实例内部运行,该实例将ref的参数传递给map,从而使我们能够在组件渲染后运行一些代码。

So once we have that line, let’s now fetch Santa’s route inside of our mapEffect function:

因此,一旦有了这一行,现在就可以在mapEffect函数中获取圣诞老人的路线:

async function mapEffect({ leafletElement } = {}) {  if ( !leafletElement ) return;  let route, routeJson;  try {    route = await fetch('https://firebasestorage.googleapis.com/v0/b/santa-tracker-firebase.appspot.com/o/route%2Fsanta_en.json?alt=media&2018b');    routeJson = await route.json();  } catch(e) {    console.log(`Failed to find Santa!: ${e}`);  }  console.log(‘routeJson’, routeJson);}

Let’s break this down:

让我们分解一下:

  • We grab Santa’s route via the API endpoint

    我们通过API端点获取圣诞老人的路线
  • Once we have his route, we grab the response in a JSON format to make it easier to work with

    确定路线后,我们将以JSON格式获取响应,从而更轻松地使用
  • This is all wrapped in a try/catch so we can safely handle any response errors

    这些都包装在try / catch中,因此我们可以安全地处理任何响应错误
  • Finally, we just log out our response for now

    最后,我们暂时log响应

Now we have Santa and his route, which means we can see all the destinations in his route. If you dig in the response a little bit, you can see some fun things like how many presents were delivered to each location and the weather at the time!

现在我们有了圣诞老人和他的路线,这意味着我们可以看到他的路线中的所有目的地。 如果您仔细研究一下响应,您会发现一些有趣的事情,例如,每个地点已送出多少礼物以及当时的天气!

将图钉放在他的位置 (Put a pin in his location)

We found Santa! 🎉 Now let’s put him on the map.

我们找到了圣诞老人! 🎉现在让我们把他放在地图上。

For our purposes, we’ll need to find the latitude and longitude of Santa. The problem is, we don’t get this exact value defined anywhere, we just get his destinations.

为了我们的目的,我们需要找到圣诞老人的经度和纬度。 问题是,我们没有在任何地方定义这个确切的值,我们只是得到他的目的地。

Since we don’t have his location specified anywhere, we can utilize his last known location where presents were delivered. Add the following after our last snippet inside the mapEffect function:

由于我们没有在任何地方指定他的位置,因此我们可以利用他最后一次知道礼物递送的位置。 在mapEffect函数内的最后一个片段之后添加以下内容:

const { destinations = [] } = routeJson || {};    const destinationsVisited = destinations.filter(({arrival}) => arrival < Date.now());    const destinationsWithPresents = destinationsVisited.filter(({presentsDelivered}) => presentsDelivered > 0);const lastKnownDestination = destinationsWithPresents[destinationsWithPresents.length - 1]

Below our request code, we:

在我们的请求代码下方,我们:

  • Destructure routeJson to grab destinations into a constant, adding a fallback to an empty object

    routeJson以将destinations捕获为常量,从而向空对象添加后备

  • Filter the results to only find the destinations that he's visited, using the arrival time from the route object

    使用路线对象的到达时间,过滤结果以仅找到他访问过的目的地
  • Filter the results to find only the locations with presents

    过滤结果以仅找到带有礼物的位置
  • And finally grab the last item from the array, which shows his last known location

    最后从数组中获取最后一个项目,这显示了他的最后一个已知位置

At this point in time, 12/23, we don't actually have any destinations, as Santa is still at the North Pole. At any time, we can test this out to simulate a future date by replaceing Date.now() in destinationsVisited with a future date, such as 1577188980000 which would be around 7pm Eastern on 12/24. With that change, we can see what Santa's route actually looks like!

目前时间12/23,我们实际上没有任何目的地,因为圣诞老人仍在北极。 在任何时候,我们都可以通过使用将来的日期(例如1577188980000 ,将在12/24东部时间晚上7点左右Date.now() destinationsVisited Date.now()来测试该日期,以模拟将来的日期。 有了这一更改,我们可以看到圣诞老人的路线实际上是什么样子!

处理失踪的圣诞老人 (Handle a missing Santa)

Now that it's close to Christmas, Santa will still be at the North Pole, so let's handle the case where we don't have a location.

现在临近圣诞节,圣诞老人仍将在北极,所以让我们来处理一下我们没有地点的情况。

Above the line where we set lastKnownDestination, let's add:

在我们设置lastKnownDestination的行lastKnownDestination ,让我们添加:

if ( destinationsWithPresents.length === 0 ) {  // Create a Leaflet Market instance using Santa's LatLng location  const center = new L.LatLng( 0, 0 );  const noSanta = L.marker( center, {    icon: L.divIcon({      className: 'icon',      html: `
🎅
`, iconSize: 50 }) }); noSanta.addTo( leafletElement ); noSanta.bindPopup( `Santa's still at the North Pole!` ); noSanta.openPopup(); return;}

Okay so what are we doing here?

好吧,我们在这里做什么?

  • First, we’re checking if we have any destinations with presents, which here we don't

    首先,我们要检查是否有带礼物的目的地,在这里我们没有
  • We first create a LatLng of the center of the map

    我们首先创建地图中心的LatLng
  • We create a Leaflet marker, using that center, with a custom Icon of Santa

    我们使用该中心和自定义的圣诞老人图标创建一个小叶标记
  • Next we add that Santa marker to the leafletElement, which is our map

    接下来,我们将该圣诞老人标记添加到leafletElement(这是我们的地图)中
  • To show a message, we first bind a popup with a custom message and open it

    为了显示消息,我们首先将弹出窗口与自定义消息绑定,然后将其打开
  • Finally we return so the rest of the code doesn’t run, as we don’t have Santa at this point

    最后我们返回,因此其余代码不会运行,因为此时我们没有圣诞老人

This was a section added after published to handle the API resetting, but you can still follow along with the code I added in context of the rest of the rest of the code.

这是发布后添加的用于处理API重置的部分,但是您仍然可以在其余的代码中跟随我添加的代码。

固定圣诞老人 (Pinning Santa)

Edit 12/23: This section was originally written with the previous year's API, but this is still a good example of what you'll expect on the response, so you can follow right along.

编辑12/23:此部分最初是使用上一年的API编写的,但这仍然是您期望得到响应的一个很好的示例,因此您可以继续进行。

And as we can see, since we’re looking at last year’s data, Santa is back home at the North Pole.

正如我们所看到的那样,由于我们正在查看去年的数据,因此圣诞老人回到了北极。

With his location, we can pull that apart, set up a Leaflet marker instance, and add our old friend to the map. Add the following after our last snippet inside the mapEffect function:

通过他的位置,我们可以将其拆开,设置一个Leaflet标记实例,然后将我们的老朋友添加到地图上。 在mapEffect函数内的最后一个片段之后添加以下内容:

const santaLocation = new L.LatLng( lastKnownDestination.location.lat, lastKnownDestination.location.lng );const santaMarker = L.marker( santaLocation, {  icon: L.divIcon({    className: ‘icon’,    html: `
🎅
`, iconSize: 50 })});santaMarker.addTo(leafletElement);

Here we:

在这里,我们:

  • Create a Leaflet LatLng instance with his location

    用他的位置创建一个Leaft LatLng实例
  • Create a Marker instance with our newly created LatLng instance

    使用我们新创建的LatLng实例创建一个Marker实例
  • Add our new Marker to the map

    将我们的新标记添加到地图

If we refresh our page, you’ll have to zoom out and pan up a little bit, but we'll see Santa on the map!

如果我们刷新页面,则必须缩小和平移一点,但是我们会在地图上看到圣诞老人!

Before we move on, let’s give Santa a little holiday cheer to make him easier to find. Find your application.scss file and toss these styles in:

在继续之前,让我们给圣诞老人一个节日的欢呼,使他更容易找到。 找到您的application.scss文件,并将这些样式折腾为:

// In src/assets/stylesheets/application.scss.icon {  & > div {    display: flex;    justify-content: center;    align-items: center;    overflow: hidden;    border-radius: 100%;    box-shadow: 0 3px 4px rgba(0,0,0,.4);    border: none;    transition: all .2s;    &:hover {      box-shadow: 0 4px 8px rgba(0,0,0,.6);    }  }}.icon-santa {  width: 50px;  height: 50px;  font-size: 3em;  background: white;}

This just adds a white circle around him, a little drop shadow, and increases the size a bit to make him a little easier to find on the map.

这只会在他周围添加一个白色圆圈,并带有一点阴影,并增加一点大小,使他在地图上更容易找到。

画出他的路线 (Drawing his route)

The last thing we’re going to do here is draw a path on the map showing his route so we can follow along.

我们在这里要做的最后一件事是在地图上绘制一条路径,显示他的路线,以便我们继续前进。

To get started, let’s update our code and add this last bit after our last snippet in the mapEffect function:

首先,让我们更新代码,并在mapEffect函数中的最后一个片段之后添加最后一点:

// Create a set of LatLng coordinates that make up Santa's routeconst santasRouteLatLngs = destinationsWithPresents.map(destination => {  const { location } = destination;  const { lat, lng } = location;  return new L.LatLng( lat, lng );});// Utilize Leaflet's Polyline to add the route to the mapconst santasRoute = new L.Polyline( santasRouteLatLngs, {  weight: 2,  color: 'green',  opacity: 1,  fillColor: 'green',  fillOpacity: 0.5});// Add Santa to the map!santasRoute.addTo(leafletElement);

What we’re doing:

我们正在做什么:

  • Creating an array of Leaflet LatLng instances that make up Santa’s route

    创建一系列组成圣诞老人路线的Leaft LatLng实例
  • Creating a Leaflet Polyline (a multi-point line) using that routes array

    使用该路由数组创建传单折线(多点线)
  • Make that Polyline green

    使折线变为绿色
  • Add our Polyline to the map

    将折线添加到地图

What we get… is a bunch of squiggly lines!

我们得到的……是一堆弯曲的线条!

This is expected. This gets technical really fast, but Leaflet by default can only understand 1 “portion” of the map as it wraps around in our browser. What this realistically means, is instead of drawing a line around a globe, the coordinates think it goes from one side of the world to the other as it hits the International Dateline. This is a bit out of scope for this tutorial, but you can check out to learn more and see if you can implement the solution to it.

这是预期的。 这在技术上确实非常快,但是默认情况下,Leaflet在我们的浏览器中环绕时只能理解地图的1个“部分”。 实际上,这意味着与其在全球范围内画一条线,不如说坐标在到达国际日期变更线时从世界的一侧延伸到另一侧。 这在本教程中范围 ,但是您可以查看以了解更多信息,并查看是否可以实现该解决方案。

一些快速样式调整 (A few quick style tweaks)

One last thing! And this is completely optional. Let’s make the map a little bit bigger, set the background color to match our oceans, and zoom out a little bit. So let’s make a few changes:

最后一件事! 这是完全可选的。 让我们将地图放大一点,设置背景颜色以匹配我们的海洋,然后缩小一点。 因此,让我们进行一些更改:

// In src/pages/index.jsconst DEFAULT_ZOOM = 1;

We’re setting our default zoom to 1 instead of 2 to allow the map to be zoomed out a bit.

我们将默认缩放比例设置为1而不是2以允许将地图缩小一点。

// In src/assets/stylesheets/pages/_home.scss.page-home {  .map,  .map-base {    height: 80vh;  }}

We’re setting our map to a height of 80vh instead of 50vh to make it take up a little more of our screen.

我们将地图的高度设置为80vh而不是50vh ,以使其占据屏幕的一部分。

// In src/assets/stylesheets/components/_map.scss.map {  &,  .map-base {    background: #acd3de;  }}

We’re setting the background color of our map to #acd3de instead of $blue-grey-50 which allows us to match the color of the oceans on our map.

我们将地图的背景色设置为#acd3de而不是$blue-grey-50 ,这使我们能够匹配地图上的海洋颜色。

What this achieves is being able to see Santa’s full route and Santa on the first view. Additionally, since the map only covers part of the screen, setting the background color of the map allows us to not have a little bit of a weird cutoff.

这样实现的是能够在第一视图上看到圣诞老人的完整路线和圣诞老人​​。 另外,由于地图仅覆盖屏幕的一部分,因此设置地图的背景颜色可使我们没有一点怪异的边界。

想要挑战吗? (Want a challenge?)

To take this 1 step further, follow along with both how we added the routes and Santa to the map and try to see if you can add a marker to each destination location to show where all of the stops are. Bonus, add a popup to each one that says how many presents were delivered to that location!

要进一步执行此步骤,请遵循我们如何将路线和圣诞老人​​添加到地图上,并尝试查看是否可以在每个目的地位置添加标记以显示所有停靠点。 奖励,向每个弹出窗口添加一个弹出窗口,该弹出窗口指示有多少礼物已发送到该位置!

To see the answer with some code organization and how I added the gift markers, check out the final version of the .

要查看某些代码组织的答案以及我如何添加礼物标记,请查看的最终版本。

While you’re there, you can also see how I utilized Leaflet.Antimeridian to fix our map's route.

在那里,您还可以看到我如何利用Leaflet.Antimeridian来修复地图的路线。

我们学到了什么? (What did we learn?)

Building basic apps with a map isn’t nearly as bad as we thought! We learned how to fetch some data from an API, grab the data we need, and draw representations of that data on a map.

用地图构建基本应用程序并没有我们想象的那么糟糕! 我们学习了如何从API中获取一些数据,获取所需的数据以及在地图上绘制该数据的表示形式。

Next time you want to add a map widget to your landing page, try Leaflet. Share what you create on ! Would love to see what you come up with.

下次您要将地图小部件添加到目标网页时,请尝试使用Leaflet。 在分享您创建的内容! 很想知道您的想法。

I hope you and your family have a fantastic holiday season!

希望您和您的家人过一个愉快的假期!

想更多地了解地图? (Want to learn more about maps?)

You can check out a few of my other resources to get started:

您可以查看其他一些资源以开始使用:

Want to read some of my other articles? Check out my blog:

是否想阅读我的其他文章? 看看我的博客: :

翻译自:

gatsby

转载地址:http://gihwd.baihongyu.com/

你可能感兴趣的文章
HNOI2016
查看>>
JVM介绍
查看>>
将PHP数组输出为HTML表格
查看>>
Java中的线程Thread方法之---suspend()和resume() 分类: ...
查看>>
经典排序算法回顾:选择排序,快速排序
查看>>
BZOJ2213 [Poi2011]Difference 【乱搞】
查看>>
c# 对加密的MP4文件进行解密
查看>>
AOP面向切面编程C#实例
查看>>
Win form碎知识点
查看>>
避免使用不必要的浮动
查看>>
第一节:ASP.NET开发环境配置
查看>>
sqlserver database常用命令
查看>>
rsync远程同步的基本配置与使用
查看>>
第二天作业
查看>>
访问属性和访问实例变量的区别
查看>>
Spring MVC 异常处理 - SimpleMappingExceptionResolver
查看>>
props 父组件给子组件传递参数
查看>>
【loj6038】「雅礼集训 2017 Day5」远行 树的直径+并查集+LCT
查看>>
十二种获取Spring的上下文环境ApplicationContext的方法
查看>>
UVA 11346 Probability 概率 (连续概率)
查看>>