当前位置: 首页 > 编程日记 > 正文

gatsby_如何使用Gatsby和Leaflet创建夏季公路旅行地图绘制应用程序

gatsby

Get ready for the summer by building your own road trip mapping app with this step-by-step guide!

通过此逐步指南,构建自己的公路旅行地图应用,为夏天做好准备!

  • What are we going to build?

    我们要建造什么?

  • What do we need before we get started?

    开始之前需要什么?

  • Step 1: Cleaning up some unneeded code

    第1步:清理一些不需要的代码

  • Step 2: Create our road trip locations

    步骤2:建立公路旅行地点

  • Step 3: Prepare our app with some functions

    步骤3:为我们的应用准备一些功能

  • Step 4: Building our trip path

    步骤4:建立行程

  • Step 5: Styling our map components

    第5步:设置地图组件的样式

  • Want to learn more about maps?

    想更多地了解地图?

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. ❤️

作者的注释:即使我们正在经历一些艰难的时期,我们仍然很乐观,因为我们会一起度过难关并能够享受我们的夏天。 保持安全并洗手。 ❤️

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

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 Leaflet Gatsby Starter 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 Gatsby Starter来简化初始设置。 引导我们的应用程序后,我们将创建位置列表并使用Leaflet的API在地图上绘制路线。

哇,地图应用? (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 read more about how mapping works first.

对。 如果您以前从未玩过地图,请不要气!! 它并不像您想象的那么糟糕。 如果您想开始使用映射基础知识,则可以阅读有关映射如何首先工作的更多信息 。

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

If you followed along with my last tutorial for building a Santa Tracker, you can follow the same steps to get started. If not, we’ll want to make sure we have the following set up:

如果您遵循了我的上一本有关构建Santa Tracker的教程,则可以按照相同的步骤开始。 如果没有,我们将确保我们进行以下设置:

  • node or yarn - I'll be using yarn, but you can substitute with npm where appropriate

    节点或毛线 -我将使用毛线,但是您可以在适当的地方用npm代替

  • Gatsby’s CLI - yarn global add gatsby-cli

    盖茨比(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 my previous tutorial.

如果您不确定上述项目之一,可以尝试查看上一教程的开头。

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 Leaflet and React Leaflet.

我们还想为我们的地图建立基础。 我们可以利用我组合在一起的Leaflet Gatsby Starter来做到这一点,它为我们提供了Leaflet和React Leaflet的基本设置。

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-trip
yarn 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!

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

步骤1:清理一些不需要的代码 (Step 1: Cleaning up some unneeded code)

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组件:

<Map {…mapSettings} />

Now that we have those pieces cleared out, we can remove all of the following imports and variables from the top of our file:

现在,我们已经清除了这些部分,可以从文件顶部删除以下所有导入和变量:

  • useRef

    useRef
  • Marker

    记号笔
  • promiseToFlyTo

    promiseToFlyTo
  • getCurrentLocation

    getCurrentLocation
  • gatsby_astronaut

    gatsby_astronaut
  • timeToZoom

    timeToZoom
  • timeToOpenPopupAfterZoom

    timeToOpenPopupAfterZoom
  • timeToUpdatePopupAfterZoom

    timeToUpdatePopupAfterZoom
  • ZOOM

    放大
  • popupContentHello

    popupContentHello
  • popupContentGatsby

    popupContentGatsby
  • markerRef

    markerRef

After, our map should still work, but not do anything.

之后,我们的地图应该仍然有效,但是什么也没做。

Follow along with the commit

跟着提交

步骤2:建立公路旅行地点 (Step 2: Create our road trip locations)

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) ,现在应该在数组中看到所有位置数据!

Follow along with the commit

跟着提交

步骤3:为我们的应用准备一些功能 (Step 3: Prepare our app with some functions)

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文件的底部,以便在下一步中使用它们。

createTripPointsGeoJson (createTripPointsGeoJson)

Our first function is going to take the array of our locations and return a GeoJSON document, with our locations mapped into an individual Feature. We’ll use this function to create the individual points on our map.

我们的第一个函数将获取我们的位置数组,并返回一个GeoJSON文档 ,并将我们的位置映射到一个单独的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?

那么上面发生了什么?

  • We take an argument of locations, which will be our array of destinations

    我们接受一个关于位置的参数,这将是我们的目的地数组
  • We return an object with some dynamic properties associated with it

    我们返回一个具有一些动态属性的对象
  • Within the object, we map our locations to individual Feature objects

    在对象内,我们将位置映射到各个Feature对象

  • Each object includes a Point shape using our coordinates

    使用我们的坐标,每个对象都包含一个Point形状

  • It additionally includes our properties that store our metadata

    它还包括存储我们的元数据的属性

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表示我们在旅途中要停靠的位置。

createTripLinesGeoJson (createTripLinesGeoJson)

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。

tripStopPointToLayer (tripStopPointToLayer)

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 => `<li>${ what }</li>`);let listString = ‘’;let imageString = ‘’;if ( Array.isArray(list) && list.length > 0 ) {listString = list.join(‘’);listString = `<p>Things we will or have done…</p><ul>${listString}</ul>`}if ( image ) {imageString = `<span class=“trip-stop-image” style=“background-image: url(${image})”>${placename}</span>`;}const text = `<div class=“trip-stop”>${ imageString }<div class=“trip-stop-content”><h2>${placename}</h2><p class=“trip-stop-date”>${date}</p>${ listString }</div></div>`;const popup = L.popup({maxWidth: 400}).setContent(text);const layer = L.marker( latlng, {icon: L.divIcon({className: ‘icon’,html: `<span class=“icon-trip-stop”></span>`,iconSize: 20}),riseOnHover: true}).bindPopup(popup);return layer;
}

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.

    我们接受两个参数, featurelatlng 。 Leaflet将这两个值传递给我们以在我们的函数中使用。

  • We destructure our feature, allowing us to assign our metadata into variables

    我们对功能进行了分解,从而可以将元数据分配给变量
  • 2 string variables are initialized that we’ll use for our HTML

    初始化了两个将用于HTML的字符串变量
  • If we include a todo property as an array, we add a new list with each item inside.

    如果我们包含一个todo属性作为数组,我们将在其中添加每个项目的新列表。

  • If we include an image, we create an image tag.

    如果包含图像,则会创建一个图像标签。
  • With our newly created HTML strings, we construct the entirety of what will be our popup card for each strop

    使用我们新创建HTML字符串,我们将为每个strop构造整个弹出卡
  • 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实例。 这将代表地图上的点。

  • Inside of the Marker creation, we create a basic HTML tag that well use to style the marker

    在创建标记的内部,我们创建了一个基本HTML标记,该标记可用于标记的样式
  • We then bind our popup to this new Marker instance. This will allow the popup to be associated with that individual Marker

    然后,我们将弹出窗口绑定到这个新的Marker实例。 这将使弹出窗口与该单独的标记相关联
  • Finally, we return our newly created layer

    最后,我们返回新创建的图层

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.

一旦添加了所有这些功能,我们的地图就应该是同一件事,基本上什么也没有发生。

Follow along with the commit

跟着提交

步骤4:建立行程 (Step 4: Building our trip path)

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,我们将在下一步中进行介绍。

Follow along with the commit

跟着提交

第5步:设置地图组件的样式 (Step 5: Styling our map components)

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.

保存这些样式后,您现在应该在地图上看到代表每个位置的点。 此外,您应该能够单击这些点中的每一个,以打开一个包含有关停靠点信息的弹出窗口。

Follow along with the commit

跟着提交

可选的最后一步:样式调整 (Optional Last Step: Style Tweaks)

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 this commit which shows each code change I made.

完全可选的最后一件事是进行一些样式调整,使您的网站更具个性。 我将不做详细介绍,但是如果您想继续并进行一些修饰,则可以执行此提交 ,其中显示了我所做的每个代码更改。

Follow along with the commit

跟着提交

是的,我们做到了! (Yay, we did it!)

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!

无论是什么,如果您喜欢旋转地图,就可以发挥创意并将其应用于下一个项目!

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

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

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

  • How to create a Coronavirus (COVID-19) Dashboard & Map App in React with Gatsby and Leaflet

    如何使用Gatsby和Leaflet在React中创建冠状病毒(COVID-19)仪表盘和地图应用

  • How to set up a custom Mapbox basemap style with React Leaflet and Leaflet Gatsby Starter

    如何使用React Leaflet和Leaflet Gatsby Starter设置自定义Mapbox底图样式

  • Anyone Can Map! Inspiration and an introduction to the world of mapping

    任何人都可以地图! 灵感以及对制图世界的介绍

  • How to Create your own Santa Tracker with Gatsby and React Leaflet

    如何使用Gatsby和React Leaflet创建自己的圣诞老人追踪器

  • How to build a mapping app in React the easy way with Leaflet

    如何使用Leaflet在React中轻松构建地图应用

Follow me for more Javascript, UX, and other interesting things!

  • 🐦 Follow Me On Twitter

    Twitter在Twitter上关注我

  • 📽️ Subscribe To My Youtube

    Subscribe️订阅我的YouTube

  • ✉️ Sign Up For My Newsletter

    ✉️注册我的时事通讯

翻译自: https://www.freecodecamp.org/news/how-to-create-a-summer-road-trip-mapping-app-with-gatsby-and-leaflet/

gatsby

相关文章:

NEFU 1146 又见A+B

又见ab Problem:1146 Time Limit:1000ms Memory Limit:65535K Description 给定两个非负整数A,B,求他们的和。 Input 多组输入&#xff0c;每组输入两个非负整数A和B&#xff08;0<A,B<10^3000&#xff09;&#xff0c;可能会有前缀0&#xff0c;但保证总长度不超过3000…

图的最短路径dijkstra算法

想法是这样的&#xff1a; 1. 最开始要建立4个list&#xff0c;分别存储 a. 所有的Vertex: allVertex[] b. 一个空的Vertex list: emptyVertex[] c. 一个前缀表 previous list(用来回溯路径用): previous[] d. 一个表示最短距离的表(就是表示某个点与0点的最短距离)&#xff1…

JDBC数据源连接池(1)---DBCP

何为数据源呢&#xff1f;也就是数据的来源。我在前面的一篇文章《JDBC原生数据库连接》中&#xff0c;采用了mysql数据库&#xff0c;数据来源于mysql&#xff0c;那么mysql就是一种数据源。在实际工作中&#xff0c;除了mysql&#xff0c;往往还会有Oracle&#xff0c;sql se…

如果成为一名高级安卓开发_什么是高级开发人员,我如何成为一名开发人员?

如果成为一名高级安卓开发Becoming a Senior Developer is something many of us strive for as we continue our code journey and build our career. But what does it actually mean to be a "Senior" Developer?成为一名高级开发人员是我们许多人在继续我们的代…

拍牌神器是怎样炼成的(三)---注册全局热键

要想在上海拍牌的超低中标率中把握机会、占得先机&#xff0c;您不仅需要事先准备好最优的竞拍策略&#xff0c;还要制定若干套应急预案&#xff0c;应对不时之需。既定策略交给计算机自动执行&#xff0c;没有问题。可是谁来召唤应急预案呢&#xff1f;使用全局热键应该是个不…

eclipse 变成中文

官方下载 http://www.eclipse.org/babel/downloads.php 按照自己的eclipse版本下载对应的 复制链接 到eclipse ->help->Install New Software 勾选自己的语言包 如&#xff1a; 等待 安装完成 &#xff0c;无过不好用 更改 右键 属性 更改位置 加后缀 D:\xinle_eclips…

框架模式与设计模式之区别

http://my.oschina.net/u/991183/blog/109854 有很多程序员往往把框架模式和设计模式混淆&#xff0c;认为MVC是一种设计模式。实际上它们完全是不同的概念。框架、设计模式这两个概念总容易被混淆&#xff0c;其实它们之间还是有区别的。框架通常是代码重用&#xff0c;而设计…

村上春树 开始写作_如何克服对写作的恐惧并找到开始的动力

村上春树 开始写作Writing about our work is one of those things that most of us have on our to-do list. But whether its due to procrastination or fear, we never actually get to it. Heres some more motivation and reasons why you should give it a shot!撰写我们…

一个基于组件的动态对象系统

http://hulefei29.iteye.com/blog/1490889 一、静态的痛苦 作为一个项目经验丰富的程序员&#xff0c;你经常会遇到游戏开发过程中的“反复”(iterations)&#xff1a;今天美术将一个静态的模型改为骨骼模型并添加了动画&#xff1b;明天企划会议上决定把所有未拾取武器由…

Lua生成Guid(uuid)

全局唯一标识符&#xff08;GUID&#xff0c;Globally Unique Identifier&#xff09;也称作 UUID(Universally Unique IDentifier) 。GUID是一种由算法生成的二进制长度为128位的数字标识符。GUID主要用于在拥有多个节点、多台计算机的网络或系统中。在理想情况下&#xff0c;…

c:if标签的使用

1、标签的基本介绍 <c:if> 标签必须要有test属性&#xff0c;当test中的表达式结果为true时&#xff0c;则会执行本体内容&#xff1b;如果为false&#xff0c;则不会执行。例如&#xff1a;${requestScope.username admin}&#xff0c;如果requestScope.username等adm…

ecs和eks 比较_如何使用Kubernetes,EKS和NGINX为网站设置DNS

ecs和eks 比较As the creator of Foo, a platform for website quality monitoring, I recently endeavored in a migration to Kubernetes and EKS (an AWS service).作为网站质量监控平台Foo的创建者&#xff0c;我最近努力迁移到Kubernetes和EKS(一种AWS服务)。 Kubernetes…

仅需6步,教你轻易撕掉app开发框架的神秘面纱(1):确定框架方案

遇到的问题 做游戏的时候用的是cocos2dxlua&#xff0c;游戏开发自有它的一套框架机制。而现在公司主要项目要做android和iOS应用。本文主要介绍如何搭建简单易用的App框架。 如何解决 对于新手来说&#xff0c;接触一门新的知识&#xff0c;往往会思考该怎么入手&#xff0c;…

js全局变量污染

一.定义全局变量命名空间 只创建一个全局变量&#xff0c;并定义该变量为当前应用容器&#xff0c;把其他全局变量追加在该命名空间下 var my{}; my.name{big_name:"zhangsan",small_name:"lisi" }; my.work{school_work:"study",family_work:&q…

cached-query 将缓存和查询数据库高速连接起来的轻类库

介绍 我们经常有这种需求&#xff1a;当我们把memcached增加到项目后我还还要写一个 cacheUtils 或者 cacheManager 之类的类来操作memcached。而且一般的操作不外乎是这种操作&#xff1a; 拿到一段sql&#xff0c;先去memcahed里面看下是否有缓存&#xff0c;假设有就直接返回…

全栈Python Flask教程-建立社交网络

Learn how to build a basic social platform with the Python Flask web framework. 了解如何使用Python Flask网络框架构建基本的社交平台。 In this video, we show you how to:在此视频中&#xff0c;我们向您展示如何&#xff1a; how to create a database, 如何创建数…

py执行系统命令

py执行系统命令 1. os.system In [32]: run os.system("date") Thu Jan 28 09:41:25 CST 2016 In [33]: run Out[33]: 0 只能得到返回值&#xff0c;无法得到输出。 2. os.popen In [35]: run os.popen("date") In [36]: run.read Out[36]: <function…

仅需6步,教你轻易撕掉app开发框架的神秘面纱(2):MVP比MVC更好吗

对于程序框架的选择&#xff0c;由于android天然的MVC&#xff0c;本来不需要另外设计直接使用即可。但是我更加钟情于MVP模式&#xff0c;对于其将ui完全与业务逻辑分离的思路很赞同。 那么什么是业务逻辑&#xff1f;个人认为&#xff0c;对数据&#xff08;即MVC中的M&…

一、nginx 安装

添加官方 yum 源 1 vim /etc/yum.repos.d/nginx.rep 输入以下内容&#xff08;OS为你的系统&#xff0c;OSRELEASE 系统版本&#xff09; 1 [nginx] 2 namenginx repo 3 baseurlhttp://nginx.org/packages/mainline/OS/OSRELEASE/$basearch/ 4 gpgcheck0 5 enabled1 列出可安装…

华为技术面试编码题_最佳技术编码面试准备书

华为技术面试编码题Technical coding interviews are notoriously difficult — almost borderline quiz-like for those unprepared. It can sometimes be a daunting task to navigate all the technical coding preparation resources available online, and one might as…

仅需6步,教你轻易撕掉app开发框架的神秘面纱(3):构造具有个人特色的MVP模式

1. MVP的问题 之前我们说过MVP模式最大的问题在于&#xff1a;每写一个Activity/Fragment需要写4个对应的文件&#xff0c;对于一个简易的app框架来说太麻烦了。所以我们需要对MVP进行一定的简化。 关于MVP模式是什么及其简单实现&#xff0c;可以参照&#xff1a;浅谈 MVP i…

Java进阶之自动拆箱与自动装箱

序. java基本类型介绍 java中&#xff0c;基本数据类型一共有8种&#xff0c;详细信息如下表&#xff1a; 类型大小范围默认值byte8-128 - 1270short16-32768 - 327680int32-2147483648-21474836480long64-9233372036854477808-92333720368544778080float32-3.40292347E38-3.40…

Ceilometer Polling Performance Improvement

Ceilometer的数据采集agent会定期对nova/keystone/neutron/cinder等服务调用其API的获取信息&#xff0c;默认是20秒一次&#xff0c; # Polling interval for pipeline file configuration in seconds.# (integer value)#pipeline_polling_interval 20 这在大规模部署中会对O…

vue使用pwa_如何使用HTML,CSS和JavaScript从头开始构建PWA

vue使用pwaProgressive web apps are a way to bring that native app feeling to a traditional web app. With PWAs we can enhance our website with mobile app features which increase usability and offer a great user experience.渐进式Web应用程序是一种将本地应用程…

仅需6步,教你轻易撕掉app开发框架的神秘面纱(4):网络模块的封装

程序框架确定了&#xff0c;还需要封装网络模块。 一个丰富多彩的APP少不了网络资源的支持&#xff0c;毕竟用户数据要存储&#xff0c;用户之间也要交互&#xff0c;用户行为要统计等等。 使用开源框架 俗话说得好&#xff0c;轮子多了路好走&#xff0c;我们不需要自己造轮…

结构体成员数组不定长如何实现

【目的】 定义一个结构体类&#xff0c;其中的成员变量数组长度不定&#xff0c;根据实例化的对象指定长度&#xff0c;所以想到用指针实现 【现状】 指针可以指向任意长度数组&#xff0c;但结构体类只分配指针本身4字节长度&#xff0c;所以无法扩展 1 /**2 ****************…

团队项目:二次开发

至此&#xff0c;我们有了初步的与人合作经验&#xff0c;接下来投入到更大的团队中去。 也具备了一定的个人能力&#xff0c;能将自己的代码进行测试。接下来尝试在别人已有的基础上进行开发。 上一界51冯美欣同学的项目&#xff1a;http://www.cnblogs.com/maxx/ 1.每个团队从…

arduino 呼吸灯_如何改善您的Arduino呼吸机:用于临时COVID-19呼吸机设计的RTS和SCS简介...

arduino 呼吸灯The world as we know it was recently taken by storm. That storm was the outbreak of the COVID-19 pandemic. This has in turn created a shortage of ventilators world wide which has led many people to foray into the world of ventilator design. 我…

reboot 百度网盘资源

提醒&#xff1a;同志们这是记录&#xff0c;视频文件是加密的&#xff0c;请勿下载 基础班第十三期&#xff1a;http://pan.baidu.com/s/1c2GcvKG 密码: 743j 基础班第十四期链接: http://pan.baidu.com/s/1c24AYa8 密码: x2sh 第十五期&#xff1a; https://pan.baidu.com…

仅需6步,教你轻易撕掉app开发框架的神秘面纱(5):数据持久化

遇到的问题 有的时候程序中需要全局皆可访问的变量&#xff0c;比如&#xff1a;用户是否登录&#xff0c;用户个人信息(用户名&#xff0c;地区&#xff0c;生日)&#xff0c;或者一些其他信息如&#xff1a;是否是首次登录&#xff0c;是否需要显示新手引导等等。 其中有些…