(一) 安装
yarn add leaflet
(二) 使用
(1) 在index.html中添加地图显示的容器
index.html
<div id="map" style="width:1000px; height:700px; display:block; margin: 10px"></div>
也可以把leaflet的css文件引入index.html ----- 则在js页面不引入
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.1.0/dist/leaflet.css" integrity="sha512-wcw6ts8Anuw10Mzh9Ytw4pylW8+NAD4ch3lqm9lzAsTxg0GFeJgoAtxuCLREZSC5lUXdVyo/7yfsqFjQ4S+aKw==" crossorigin="" />
(2) 引入并使用
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import L from 'leaflet'; // 引入leaflet js
import 'leaflet/dist/leaflet.css'; // 引入leaflet css
class App extends Component {
constructor(props) {
super(props)
this.map = null // 初始化map属性
}
componentDidMount() {
const MAP = this.map = L.map('map', { // 加载leaflet中心类 --- map类
center: [39.9788, 116.30226], // L.map(容器id, 配置项 )
zoom: 18
})
L.tileLayer('http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}', {
subdomains: "1234",
attribution: '高德地图'
}).addTo(this.map); // 把瓦片图层添加到map上,map需要加载地图图层,即显示的内容
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
</div>
);
}
}
export default App;
map 常用配置项
const MAP = this.map = L.map('map', { // L.map(DOM, options)
center: [39.9788, 116.30226], // 初始化地图的地理中心
zoom: 18, // 缩放
zoomControl: true, // 缩放控制开启和关闭
attributionControl: true, // 属性控制,可以通过 L.tileLayer().getAttribution()得到
dragging: true, // 拖动控制
layers: [tileX], // 初始化加载的图层 ---- 重要重要重要
maxZoom: 18, // 最大缩放
minZoom: 1, // 最小缩放
crs: L.CRS.EPSG3857, //要使用的坐标参考系统,默认的坐标参考系,互联网地图主流坐标系
// crs: L.CRS.EPSG4326, //WGS 84坐标系,GPS默认坐标系
})
crs 是 Coordinate Reference System 的缩写 ------- 坐标参考系统
TileLayer常用配置项
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}{r}.png?{foo}', {foo: 'bar'}).addTo(..)
{s}: subdomains 表示可用的子域
{z}: zoom 表示缩放
{x}, {y}: tile coordinates 表示坐标
{r} : can be used to add "@2x" to the URL to load retina tiles
L.tileLayer(url, options)
const tileX = L.tileLayer(url, {
subdomains: "1234",
attribution: '高德地图'
});
marker,popup,tooltip
const marker = L.marker([39.9788, 116.30226]).addTo(this.map); // 添加marker到地图
marker.bindPopup('点击marker,显示popup') // 给marker绑定Popup,点击marker时显示
marker.bindTooltip("my tooltip text") // 给marker绑定tooltip,hover时显示
const marker2 = L.marker([39.9790, 116.30248], { // marker的属性配置
title: '这是marker2的title',
icon:L.icon({ // 更换maker的图标
iconUrl: 'my-icon.png',
iconSize: [38, 95],
iconAnchor: [22, 94],
popupAnchor: [-3, -76],
shadowUrl: 'my-icon-shadow.png',
shadowSize: [68, 95],
shadowAnchor: [22, 94]
})
}).addTo(this.map)
circle,polyline,polygon多边形,rectangle矩形
L.circle([39.9788, 116.30226], {radius: 50}).addTo(this.map); // 圆
var latlngs = [
[39.9790, 116.30248],
[39.9790, 116.30270],
[39.9793, 116.30270],
[39.9790, 116.30290],
];
var latlngs2 = [
[39.9790, 116.30208],
[39.9790, 116.30250],
[39.9793, 116.30250],
[39.9790, 116.30208],
];
var latlngs3 = [
[45.51, -122.68],
[37.77, -122.43],
[34.04, -118.2]
];
var polyline = L.polyline(latlngs, {color: 'red'}).addTo(this.map); // 线条
this.map.fitBounds(polyline.getBounds()); //填充边界,定位地图
var latlngs = [latlngs];
var polygon = L.polygon(latlngs2, {color: 'green'}).addTo(this.map); // 多边形
this.map.fitBounds(polygon.getBounds());
var polyline = L.polyline(latlngs3, {color: 'red'}).addTo(this.map);
// define rectangle geographical bounds
// geographical 地里的
var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
// create an orange rectangle
L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
// zoom the map to the rectangle bounds
map.fitBounds(bounds);
添加图片做为地图
let imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
let imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
// 注意: bounds是边界,是 ( southWest ) 和 ( northEast ) 的值
L.imageOverlay(imageUrl, imageBounds).addTo(map);
获取用户当前的位置信息
地理位置 API 通过 navigator.geolocation 提供
- navigator.geolocation 获取地理位置
- getCurrentPosition 函数获取用户当前定位位置。
const xyz = navigator.geolocation.getCurrentPosition((x) => {
const xi = x.coords.latitude;
const yi = x.coords.longitude;
L.marker([xi, yi]).addTo(MAP); // 用marker显示在地图上
});
切换不同图层
class App extends Component {
constructor(props) {
super(props);
this.map = null
}
componentDidMount() {
const gaode = L.tileLayer('...', {
subdomains: "1234",
attribution: '高德地图'
})
const mapbox = L.tileLayer( '...', {
attribution: '谷歌地图',
subdomains: "1234",
})
var mymap = this.map = L.map('map', {
center: [39.9788, 116.30226],
zoom: 18,
layers: [mapbox],
drawControl: true
})
L.control.layers({ // L.control.layers
'高德地图': gaode,
'谷歌地图': mapbox,
}).addTo(this.map)
}
把GeoJSON中的 coordinates 转换成 LatLng
const aaa = [39.9788, 116.30226];
const bbb = L.GeoJSON.coordsToLatLng(aaa);
console.log(bbb)
// LatLng {lat: 116.30226, lng: 39.9788}
const ccc = L.GeoJSON.latLngToCoords(bbb);
console.log(ccc)
// [39.9788, 116.30226]
GeoJSON对象
GeoJSON是一种对各种地理数据结构进行编码的格式。
GeoJSON对象可以表示几何、特征或者特征集合。(geometry, feature, featureCollection
GeoJSON支持这几种 几何类型:点、线、面、多点、多线、多面和几何集合。
GeoJSON里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。
- GeoJSON对象必须由一个名字为"type"的成员。这个成员的值是由GeoJSON对象的类型所确定的字符串。
type成员的值必须是下面之一:"Point"点, "MultiPoint"多点, "LineString", "MultiLineString", "Polygon", "MultiPolygon", "GeometryCollection"几何集合, "Feature", 或者 "FeatureCollection"特征集合
- GeoJSON对象可能有一个可选的"crs"成员,它的值必须是一个坐标参考系统的对象
crs 是 Coordinate Reference System 的缩写 ------- 坐标参考系统
- GeoJSON对象可能有一个"bbox"成员,它的值必须是边界框数组
boundary边界
(1) 几何对象 geometry
geometry对象包含 ( type属性 ) 和 ( coordinates属性 - 总是数组 )
几何是一种GeoJSON对象,这时type成员的值是下面字符串之一:"Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", 或者"GeometryCollection"。
除了“GeometryCollection”外的其他任何类型的GeoJSON几何对象必须由一个名字为"coordinates"的成员。coordinates成员的值总是数组。这个数组里的元素的结构由几何类型来确定。
(2) 位置 coordinates
coordinates 总是数组 (数组或者嵌套数组)
位置是基本的几何结构。几何对象的"coordinates"成员由一个位置(这儿是几何点)、位置数组(线或者几何多点),位置数组的数组(面、多线)或者位置的多维数组(多面)组成。
位置由数字数组表示。必须至少两个元素,可以有更多元素。元素的顺序必须遵从x,y,z顺序(投影坐标参考系统中坐标的东向、北向、高度或者地理坐标参考系统中的坐标长度、纬度、高度
(3) 特征对象 Feature
Feature对象必须包含 ( geometry属性 ) 和 ( properties属性 )
类型为"Feature"的GeoJSON对象是特征对象。
- 特征对象必须由一个名字为"geometry"的成员,这个几何成员的值是上面定义的几何对象或者JSON的null值。
- 特征对戏那个必须有一个名字为“properties"的成员,这个属性成员的值是一个对象(任何JSON对象或者JSON的null值)。
- 如果特征是常用的标识符,那么这个标识符应当包含名字为“id”的特征对象成员。
(4) 特征集合对象 FeatureCollection
FeatureCollection对象必须包含 ( features属性 ),是一个数组
类型为"FeatureCollection"的GeoJSON对象是特征集合对象。
- 类型为"FeatureCollection"的对象必须由一个名字为"features"的成员。与“features"相对应的值是一个数组。这个数组中的每个元素都是上面定义的特征对象
{ "type": "FeatureCollection", // GeoJSON对象必须有个type属性,这里值是 特征集合
"features": [
{ "type": "Feature", // Feature<Point>
"geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, // Geometry<Point>
"properties": {"prop0": "value0"}
},
{ "type": "Feature", // 线数据
"geometry": {
"type": "LineString",
"coordinates": [
[102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
]
},
"properties": {
"prop0": "value0",
"prop1": 0.0
}
},
{ "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": {"this": "that"}
}
}
]
}
// 2018.6.9更 -------------- // 复习面向对象
// 构造函数
// 1. 首字母大写
// 2. 函数内部使用this代表将要生成的实例对象
// 3. 使用new命令,执行构造函数,返回实例对象
// 忘记写 new命令
// 在构造函数内部使用 'use strict'严格模式,在忘记new命令时,就会报错
// return
// 构造函数内部,如果有return语句,
// 1. return 后面跟一个对象,new命令就会返回该对象
// 2. return 后满跟的不是一个对象, new就会返回this指代的实例对象
// 对普通函数使用new命令,return后面跟的不是对象,会返回一个空对象
// new命令总是返回一个对象,实例对象,或者return 指定的对象, 普通函数使用new命令,返回空对象或者return 指定的对象
// Object.create() 创建实例对象
// 1.构造函数为模板,可以生成实例对象,但有时,拿不到实例对象,只能通过现有的对象为模板,生成实例对象
// ------------------------------------------------
// this
// this不管用在什么场合,都是返回一个对象
// this是属性和方法当前所在的对象
// 对象的属性可以赋值给另一个对象,所以,属性所在的当前对象是可变的,即 this的指向是可变的
// 只要函数被赋值给另一个变量,this的指向就会变
// 总结
// this是函数运行时所在的对象 !!!!
// 在js中一切皆对象,运行环境也是对象,所以,函数都在某个对象中运行
// this就是函数运行时所在的对象
// this的使用场合
// 1.全局环境
// 全局环境使用this, this指的是顶层对象,即window对象
// 2.构造函数
// 在构造函数中,this指向将要生成的实例对象
// 3.对象的方法
// 在对象的方法中,this指向方法运行时,所在的对象
// 注意
// 如果this所在的方法不在对象的第一层,this只是指向当前一层的对象,而不会继承更上面的层 !!
// 如果,将嵌套对象内部的方法赋值给一个变量,this依然会指向全局对象window
// 嵌套的this
// 使用一个变量固定this的值,然后内层函数调用这个变量,是非常常见的做法
// Function.prototype.call(参数1, 参数2, ....)
// 函数实例的call方法,可以指定函数内部this的指向,然后在所指定的作用域中,调用该函数
// call()方法的参数是一个 对象, 如果参数是空,null, undefined,则默认传入全局对象
// call()方法可以传入多个参数,第一个参数是所要绑定的对象,后面的参数是函数调用时传入的参数
// call()方法会自动调用函数 ---- bind()方法则不会自动调用
// Function.prototype.apply(参数1, [参数2, 参数3 , ...])
// apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。
// 唯一的区别就是,它接收一个数组作为函数执行时的参数
// Function.prototype.bind(参数1, 参数2, ....)
// bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数
算法:
- 找出数组中最大的元素
var a = [1,11,111,30,40];
const b = Math.max.apply(null, a); // Math.max() 是一个函数
console.log(b) // 111
Function.prototype.apply(需要绑定的对象,数组参数) // 第一个参数时null和undefined时,绑定全局对象
- 将数组的 ( 空元素 ) 替换成 ( undefined )
Array.apply(null, ['a', ,'b'])
// [ 'a', undefined, 'b' ]
prototype对象
- 构造函数的缺点
同一个构造函数的多个实例,无法共享属性。(造成系统资源的浪费)
构造函数的属性和方法都会生成在实例对象上
const A = function() {
this.name = function() {
console.log('not equal')
}
};
const b = new A();
const c = new A();
console.log(b.name === c.name) // false
// 构造函数的name方法,会定义在实例对象上,即 每个实例都会生成name方法
原型对象prototype
原型对象的所有属性和方法都能被实例对象所共享js规定,每一个函数都有一个prototype属性,指向一个对象
对于普通函数来说,该属性基本无用。但是,对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。
- 对于构造函数来说,构造函数的prototype属性,会在构造函数生成实例对象的时候,自动成为实例对象的原型对象!!!
// 对于构造函数,prototype属性会在生成实例对象的时候,成为实例对象的原型对象
// 原型对象的属性和方法,被实例对象所共享 - 原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。
- 当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法。
如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
总结: 原型对象的作用就是定义所有实例对象所共享的属性和方法,这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象。
function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white'; // 任何函数的prototype属性都指向一个对象
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color // 'white'
cat2.color // 'white'
// 对于构造函数,prototype属性会在生成实例对象的时候,成为实例对象的原型对象
// 原型对象的属性和方法,被实例对象所共享
原型链
- JavaScript 规定,所有对象都有自己的原型对象(prototype)。
一方面,任何一个对象,都可以充当其他对象的原型;
另一方面,由于原型对象也是对象,所以它也有自己的原型。
因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……
- 如果一层层上溯,所有对象的原型最终可以上溯到Object.prototype
( 即Object构造函数的prototype属性 )
- 所有对象都继承了Object.prototype属性上的 属性和方法
这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。 - Object.prototype的原型是null,由于null没有任何属性,所以原型链到此为止。
3.读取属性时,如果本身对象没有该属性,就是上溯到该对象的原型对象上寻找,如果还没有,就一个向上到Object.prototype,如果还没有就返回 undefined
4.自身和原型有同名属性时,优先读取自身对象上的属性 ------ 这叫做"覆盖"。
5. constructor 属性
prototype对象默认有一个constructor属性,指向prototype对象所在的构造函数
function P() {}
P.prototype.constructor === P // true
- constructor属性定义在prototype对象上,因此,可以被实例对象所继承
const A = function() {
console.log('这是一个构造函数')
};
const b = new A();
console.log( A.prototype.constructor === b.constructor ); //true
console.log( A.prototype.constructor === A); //true
console.log( b.constructor === A); //true
console.log( b.hasOwnProperty('constructor')); // false ------- 不是自身属性
- constructor属性的作用
- 1.constructor属性的作用,可以得知,实例对象到底是由哪个构造函数产生的
- 有了constructor,就可以从一个实例对象新建另一个实例对象
const A = function() {
console.log('这是构造函数A');
};
const b = new A();
const c = new b.constructor(); // b.constructor === A === A.prototype.constructor
console.log( c instanceof A ); // c 是 A 的实例 ----- 注意 instanceof 是小写 of
- 修改原型对象时,一般要同时修改 constructor 属性
- constructor.name构造函数的名称
function Foo() {}
var f = new Foo();
f.constructor.name // "Foo"
8. instanceof 运算符
instanceof 返回一个boolean布尔值,表示对象是否是构造函数的实例
var v = new Vehicle();
v instanceof Vehicle // true
// instanceof是 实例的意思
instanceof运算符的左边是实例对象,右边是构造函数。
- instanceof会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。
因此,下面两种写法是等价的。
var v = new Vehicle();
v instanceof Vehicle
// 等同于
Vehicle.prototype.isPrototypeOf(v)
特例:
instanceof的原理是检查右边构造函数的prototype属性,是否在左边对象的原型链上。
有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。
instanceof的用处:
instanceof运算符的一个用处,是判断值的类型。
注意,instanceof运算符只能用于对象,不适用原始类型的值。
var x = [1, 2, 3];
var y = {};
x instanceof Array // true
y instanceof Object // true
console.log(typeof x) // object ---- 注意:数组的typeof是object
-----------------------------------------------
注意: instanceof只能用于对象,不能用于原始类型的值
var s = 'hello';
s instanceof String // false
object对象的相关方法
Object.getPrototypeOf()
Object.getPrototypeOf方法返回参数对象的原型。这是获取原型对象的标准方法。
- Object.getPrototypeOf() 返回参数对象的原型对象
var F = function () {};
var f = new F();
Object.getPrototypeOf(f) === F.prototype // true
-----------------------------------------------------------------
const a = {};
const b = {name: 'wang'};
a.__proto__ = b;
console.log(a.name) // wang
// a.__proto__ = b 等价于 Object.setPrototypeOf(a,b); !!!!!!!!!
- 注意:
根据语言标准,proto属性只有浏览器才需要部署,其他环境可以没有这个属性。它前后的两根下划线,表明它本质是一个内部属性,不应该对使用者暴露。因此,应该尽量少用这个属性,而是用Object.getPrototypeof()和Object.setPrototypeOf(),进行原型对象的读写操作。
获取实例对象的原型对象有三种方法
1. obj.__proto__
2. obj.constructor.prototype
3. Object.getPrototypeOf(obj)
上面三种方法之中,前两种都不是很可靠。
__proto__属性只有浏览器才需要部署,其他环境可以不部署。
而obj.constructor.prototype在手动改变原型对象时,可能会失效。
Object.getOwnPropertyNames()
Object.getOwnPropertyNames方法返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名。
Object.prototype.hasOwnProperty()
hasOwnProperty ------------- 自身属性
对象实例的hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。
hasOwnProperty方法是 JavaScript 之中唯一一个处理对象属性时,不会遍历原型链的方法。!!!!!!!!!!
- hasOwnProterty是唯一一个处理对象属性时,不会遍历原型链的方法 !!!
in 运算符 ------------------- 不区分自身属性和继承属性
in运算符返回一个布尔值,表示一个对象是否具有某个属性。它不区分该属性是对象自身的属性,还是继承的属性。
对象的拷贝
如果要拷贝一个对象,需要做到下面两件事情。
- 确保拷贝后的对象,与原对象具有同样的原型。
- 确保拷贝后的对象,与原对象具有同样的实例属性。
- 拷贝对象需要做到两点,与元对象具有相同的原型和相同的实例属性