#原因
参照Openlayers提供的样式加载,发现样式没有mapboxgl加载好看,如果更换mapboxgl版本或者采用自发布地图,还需要调整代码,因此参考mapboxgl底层,重新进行了优化
#思路
传入mapboxgl样式,参考mapboxgl底层样式处理,重新绘制地图
#问题
技术有限,无法将mvt中的Feature的x,y读取为经纬度,有解决的请给我留言
/*
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Ported from Webkit
* http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h
*/
function UnitBezier(p1x, p1y, p2x, p2y) {
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
this.cx = 3.0 * p1x;
this.bx = 3.0 * (p2x - p1x) - this.cx;
this.ax = 1.0 - this.cx - this.bx;
this.cy = 3.0 * p1y;
this.by = 3.0 * (p2y - p1y) - this.cy;
this.ay = 1.0 - this.cy - this.by;
this.p1x = p1x;
this.p1y = p2y;
this.p2x = p2x;
this.p2y = p2y;
}
UnitBezier.prototype.sampleCurveX = function(t) {
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
return ((this.ax * t + this.bx) * t + this.cx) * t;
};
UnitBezier.prototype.sampleCurveY = function(t) {
return ((this.ay * t + this.by) * t + this.cy) * t;
};
UnitBezier.prototype.sampleCurveDerivativeX = function(t) {
return (3.0 * this.ax * t + 2.0 * this.bx) * t + this.cx;
};
UnitBezier.prototype.solveCurveX = function(x, epsilon) {
if (typeof epsilon === 'undefined') epsilon = 1e-6;
var t0, t1, t2, x2, i;
// First try a few iterations of Newton's method -- normally very fast.
for (t2 = x, i = 0; i < 8; i++) {
x2 = this.sampleCurveX(t2) - x;
if (Math.abs(x2) < epsilon) return t2;
var d2 = this.sampleCurveDerivativeX(t2);
if (Math.abs(d2) < 1e-6) break;
t2 = t2 - x2 / d2;
}
// Fall back to the bisection method for reliability.
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0) return t0;
if (t2 > t1) return t1;
while (t0 < t1) {
x2 = this.sampleCurveX(t2);
if (Math.abs(x2 - x) < epsilon) return t2;
if (x > x2) {
t0 = t2;
} else {
t1 = t2;
}
t2 = (t1 - t0) * 0.5 + t0;
}
// Failure.
return t2;
};
UnitBezier.prototype.solve = function(x, epsilon) {
return this.sampleCurveY(this.solveCurveX(x, epsilon));
};
export default UnitBezier;
import UnitBezier from './UnitBezier.js'
import GrahicLayer from './GrahicLayer.js'
function MvtImageryProvider(options) {
options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT);
this._tilingScheme = Cesium.defined(options.tilingScheme) ? options.tilingScheme : new Cesium.WebMercatorTilingScheme({ ellipsoid: options.ellipsoid });
this._tileWidth = Cesium.defaultValue(options.tileWidth, 512);
this._tileHeight = Cesium.defaultValue(options.tileHeight, 512);
this._readyPromise = Cesium.when.resolve(true);
//new
this._layers = options.layers;
this._maximumLevel = options.maximumLevel;
this._minimumLevel = options.minimumLevel;
if (!window.ol) {
throw new DeveloperError('请引入Openlayers类库!');
}
this._ol = window.ol;
this._mvtParser = new this._ol.format.MVT();
this._styleClass = new MapboxStreetsV6MvtStyle(options.style);
this._key = Cesium.defaultValue(options.key, "");
this._url = Cesium.defaultValue(options.url, "https://api.mapbox.com/v4/mapbox.mapbox-streets-v8,mapbox.mapbox-terrain-v2/{z}/{x}/{y}.vector.pbf?access_token={k}");
var sw = this._tilingScheme._rectangleSouthwestInMeters;
var ne = this._tilingScheme._rectangleNortheastInMeters;
var mapExtent = [sw.x, sw.y, ne.x, ne.y];
this._resolutions = ol.tilegrid.resolutionsFromExtent(
mapExtent, 22, this._tileWidth);
this._pixelRatio = 1;
this._transform = [0.125, 0, 0, 0.125, 0, 0];
this._replays = ["Default", "Image", "Polygon", "LineString", "Text"];
this._tileQueue = new Cesium.TileReplacementQueue();
this._cacheSize = 1000;
}
Object.defineProperties(MvtImageryProvider.prototype, {
proxy: {
get: function () {
return undefined;
}
},
tileWidth: {
get: function () {
return this._tileWidth;
}
},
tileHeight: {
get: function () {
return this._tileHeight;
}
},
layers: {
get: function () {
return this._layers;
}
},
maximumLevel: {
get: function () {
// return undefined;
return this._maximumLevel;
}
},
minimumLevel: {
get: function () {
// return undefined;
return this._minimumLevel;
}
},
tilingScheme: {
get: function () {
return this._tilingScheme;
}
},
rectangle: {
get: function () {
return this._tilingScheme.rectangle;
}
},
tileDiscardPolicy: {
get: function () {
return undefined;
}
},
errorEvent: {
get: function () {
return this._errorEvent;
}
},
ready: {
get: function () {
return true;
}
},
readyPromise: {
get: function () {
return this._readyPromise;
}
},
credit: {
get: function () {
return undefined;
}
},
hasAlphaChannel: {
get: function () {
return true;
}
}
});
MvtImageryProvider.prototype.getTileCredits = function (x, y, level) {
return undefined;
};
MvtImageryProvider.prototype.pickFeatures = function (x, y, level, longitude, latitude) {
return undefined;
};
MvtImageryProvider.prototype.requestImage = function (x, y, level, request) {
var cacheTile = findTileInQueue(x, y, level, this._tileQueue);
if (cacheTile != undefined) {
return cacheTile;
}
else {
var that = this;
var url = this._url;
url = url.replace('{x}', x).replace('{y}', y).replace('{z}', level).replace('{k}', this._key);
var resource = Cesium.Resource.createIfNeeded(url);
return resource.fetchArrayBuffer().then(function (arrayBuffer) {
var canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
var vectorContext = canvas.getContext('2d');
var features = that._mvtParser.readFeatures(arrayBuffer);
var styleFun = that._styleClass.getStyle();
var extent = [0, 0, 4096, 4096];
var _replayGroup = new ol.render.canvas.ReplayGroup(0, extent,
8, true, 100);
for (var i = 0; i < features.length; i++) {
var feature =features[i];
if(feature.getType()==='Point' && feature.get('layer').endsWith('_label'))
{
let xy=ol.proj.transform(feature.getFlatCoordinates(),'EPSG:3857','EPSG:4326');
let _x=xy[0]*that._resolutions[level+1]*Cesium.Math.DEGREES_PER_RADIAN
let _y= (90 - 180 / (Math.pow(2, level)) * feature.getFlatCoordinates()[0])/that._resolutions[level]*Cesium.Math.DEGREES_PER_RADIAN
console.log(_x,_y)
}
var styles = styleFun(features[i], that._resolutions[level], level, that._styleClass.style);
for (var j = 0; j < styles.length; j++) {
ol.renderer.vector.renderFeature_(_replayGroup, feature, styles[j], 16);
}
}
_replayGroup.finish();
_replayGroup.replay(vectorContext, that._pixelRatio, that._transform, 0, {}, that._replays, true);
if (that._tileQueue.count > that._cacheSize) {
trimTiles(that._tileQueue, that._cacheSize / 2);
}
canvas.xMvt = x;
canvas.yMvt = y;
canvas.zMvt = level;
that._tileQueue.markTileRendered(canvas);
_replayGroup = null;
return canvas;
}).otherwise(function (error) {
return undefined;
});
}
};
function findTileInQueue(x, y, level, tileQueue) {
var item = tileQueue.head;
while (item != undefined && !(item.xMvt == x && item.yMvt == y && item.zMvt == level)) {
item = item.replacementNext;
}
return item;
};
function removeQueue(tileReplacementQueue, item) {
var previous = item.replacementPrevious;
var next = item.replacementNext;
if (item === tileReplacementQueue._lastBeforeStartOfFrame) {
tileReplacementQueue._lastBeforeStartOfFrame = next;
}
if (item === tileReplacementQueue.head) {
tileReplacementQueue.head = next;
} else {
previous.replacementNext = next;
}
if (item === tileReplacementQueue.tail) {
tileReplacementQueue.tail = previous;
} else {
next.replacementPrevious = previous;
}
item.replacementPrevious = undefined;
item.replacementNext = undefined;
--tileReplacementQueue.count;
}
function trimTiles(tileQueue, maximumTiles) {
var tileToTrim = tileQueue.tail;
while (tileQueue.count > maximumTiles &&
Cesium.defined(tileToTrim)) {
var previous = tileToTrim.replacementPrevious;
removeQueue(tileQueue, tileToTrim);
tileToTrim = previous;
}
};
//=========================官方mapbox-streets-v6 vector样式==================
// Styles for the mapbox-streets-v6 vector tile data set. Loosely based on
// http://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v6.json
function MapboxStreetsV6MvtStyle(style) {
this.style = style
}
MapboxStreetsV6MvtStyle.prototype.getStyle = function () {
var fill = new ol.style.Fill({ color: '' });
var stroke = new ol.style.Stroke({ color: '', width: 1 });
var polygon = new ol.style.Style({ fill: fill });
var strokedPolygon = new ol.style.Style({ fill: fill, stroke: stroke });
var line = new ol.style.Style({ stroke: stroke });
var text = new ol.style.Style({
text: new ol.style.Text({
text: '', fill: fill, stroke: stroke
})
});
var iconCache = {};
function getIcon(iconName) {
var icon = iconCache[iconName];
if (!icon) {
icon = new ol.style.Style({
image: new ol.style.Icon({
src: 'https://cdn.rawgit.com/mapbox/maki/master/icons/' + iconName + '-15.svg',
imgSize: [15, 15]
})
});
iconCache[iconName] = icon;
}
return icon;
}
function getData(index, values, zoom) {
for (let i = index; i < values.length; i += 2) {
const data = values[i];
if (i === values.length - 2 && zoom >= data) {
return values[i + 1]
}
if (zoom <= data) {
return values[i + 1]
}
}
}
function getMatch(paints, cls) {
let _dv = paints[paints.length - 1]
if (paints[1][0] === "get") {
let _v = cls.get(paints[1][1]);
for (let i = 2; i < paints.length; i += 2) {
const _n = paints[i];
if (Array.isArray(_n)) {
if (_n.indexOf(_v) != -1) {
return paints[i + 1]
}
return _dv
} else if (_v === paints[i]) {
return paints[i + 1]
}
}
}
return _dv
}
function getExponential(index, base, values, zoom, cls) {
let curIndex = index
let lowlevel = values[curIndex];
let uplevel = values[values.length - 2];
if (zoom <= lowlevel) {
return values[curIndex + 1]
}
if (zoom >= uplevel) {
return values[values.length - 1]
}
for (let i = index; i < values.length; i += 2) {
curIndex = i;
lowlevel = values[curIndex];
if (i === values.length - 2) {
curIndex = i - 2;
break;
}
if (zoom <= lowlevel) {
break;
}
}
lowlevel = values[curIndex];
uplevel = values[curIndex + 2];
let lowVal = values[curIndex + 1]
let upVal = values[curIndex + 3]
if (Array.isArray(lowVal)) {
lowVal = getPaint(lowVal, zoom, cls)
}
if (Array.isArray(upVal)) {
upVal = getPaint(upVal, zoom, cls)
}
let dif = uplevel - lowlevel
let pro = zoom - lowlevel
let t = (Math.pow(base, pro) - 1) / (Math.pow(base, dif) - 1);
if (dif === 0) {
t = 0
// return lowVal * (1 - t) + upVal * t
} else if (base === 1) {
t = pro / dif
// return lowVal * (1 - t) + upVal * t
}
if (values[1][0] === "cubic-bezier") {
// let cb = getPaint(3, values, zoom);
let ub = new UnitBezier(values[1][1], values[1][2], values[1][3], values[1][4])
t = ub.solve(t)
}
return lowVal * (1 - t) + upVal * t
}
function getInterpolate(paints, level, cls) {
if (paints[1][0] === "linear") {
let _ds = getData(3, paints, level);
// if (Array.isArray(_ds)) {
// _ds = getPaint(_ds, level, cls)
// }
if (typeof _ds === 'number') {
return getExponential(3, 1, paints, level, cls)
}
return _ds
}
else {//if (paints[1][0] === "exponential") {
// let _ds = getData(3, paints, level);
// console.log((Math.pow(paints[1][1],level-getData(3, paints, level))-1)-(Math.pow(paints[1][1],getData(3, paints, level)-level)-1))
return getExponential(3, paints[1][1], paints, level, cls)
}
// else if (paints[1][0] === "cubic-bezier") {
// let _ds = getData(3, paints, level);
// if (Array.isArray(_ds)) {
// return getPaint(_ds, level, cls)
// }
// return paints[paints.length - 1]
// }
return paints;
}
function getCoalesce(index, values, cls) {
for (let i = index; i < values.length; i++) {
const data = values[i];
let f = data[1]
if (f === 'name_en') {
f = 'name_zh-Hans'
}
let _v = cls.get(f)
if (data[0] === "get" && _v) {
return _v
}
}
}
function getPaint(paints, level, cls) {
const start = paints[0];
if (start === 'match') {
let _setp = getMatch(paints, cls)
if (Array.isArray(_setp)) {
return getPaint(_setp, level, cls)
}
return _setp
}
else if (start === 'interpolate') {
let _setp = getInterpolate(paints, level, cls)
if (Array.isArray(_setp)) {
return getPaint(_setp, level, cls)
}
return _setp
}
// return getInterpolate(paints, level, cls)
else if (start === 'step') {
let _setp = getStep(paints, level, cls)
if (Array.isArray(_setp)) {
return getPaint(_setp, level, cls)
}
return _setp
}
else if (start === 'get') {
let f = paints[1]
if (f === 'name_en') {
f = 'name_zh-Hans'
}
let _v = cls.get(f)
return _v
}
else if (start === 'coalesce') {
return getCoalesce(1, paints, cls)
}
return paints;
}
function getStep(paints, level, cls) {
let _v = level
if (paints[1][0] === "get") {
_v = cls[paints[1][1]]
}
for (let i = 3; i < paints.length; i += 2) {
if (_v >= paints[i]) {
return paints[i + 1]
}
}
return paints[2]
}
function getF(filters, cls, level) {
var geom = cls.getGeometry().getType();
switch (filters[0]) {
case "all":
{
for (let i = 1; i < filters.length; i++) {
if (!getF(filters[i], cls, level))
return false;
}
return true;
}
case "match":
{
let _match=getPaint(filters, level, cls);
if (Array.isArray(_match)) {
return getF(_match, cls, level)
}
return _match
if (Array.isArray(_match)) {
console.log(0)
}
return _match
}
case "step":
{
let _setp = getStep(filters, level, cls)
if (Array.isArray(_setp)) {
return getF(_setp, cls, level)
}
return _setp
}
case '==':
{
if (filters[1][0] === "get" && cls.get(filters[1][1]) === filters[2]) {
return true;
} else if (filters[1][0] === "geometry-type" && geom.indexOf(filters[2]) != -1) {
return true;
}
}
break
case '<=':
let v = cls.get(filters[1][1])
if (Array.isArray(filters[2])) {
if (filters[2][0] === "+") {
v += getPaint(filters[2][1], level, cls);
}
}
if (filters[1][0] === "get" && v <= filters[2]) {
return true;
}
break
case '>=':
if (filters[1][0] === "get" && cls.get(filters[1][1]) >= filters[2]) {
return true;
}
break
case '!=':
if (filters[1][0] === "get" && cls.get(filters[1][1]) != filters[2]) {
return true;
} else if (filters[1][0] === "geometry-type" && geom.indexOf(filters[2]) == -1) {
return true;
}
break
}
return false;
}
function getFilter(filters, cls, level) {
return getF(filters, cls, level)
}
var styles = [];
return (feature, resolution, level, style) => {
var length = 0;
var layer = feature.get('layer');
var maki = feature.get('maki');
var geom = feature.getGeometry().getType();
let l_type = 'fill'
if (geom === "Polygon") {
l_type = 'fill'
}
else if (geom.indexOf("LineString") != -1) {
l_type = 'line'
}
else {
l_type = 'symbol'
}
// geom console.log(layer+geom)
let lys = style.layers.filter(p => p["source-layer"] === layer && p.type === l_type).sort((a, b) => a.minzoom || 0 - b.minzoom || 0)
for (let j = 0; j < lys.length; j++) {
const _ly = lys[j];
if ((_ly.filter && !getFilter(_ly.filter, feature, level)) || (_ly.minzoom && _ly.minzoom > level) || (_ly.maxzoom && _ly.maxzoom < level)) {
continue;
}
try {
var fill = new ol.style.Fill({ color: '' });
var stroke = new ol.style.Stroke({ color: '', width: 1 });
var polygon = new ol.style.Style({ fill: fill });
var strokedPolygon = new ol.style.Style({ fill: fill, stroke: stroke });
var line = new ol.style.Style({ stroke: stroke });
var text = new ol.style.Style({
text: new ol.style.Text({
text: '', fill: fill, stroke: stroke
})
});
// _ly.minzoom = _ly.minzoom || 0
// _ly.maxzoom = _ly.maxzoom || 40
//!getFilter(_ly.filter, feature)||
if (_ly.type === "line") {
let color = getPaint(_ly.paint['line-color'], level, feature);
let op = 1
if (_ly.paint['line-opacity']) {
op = getPaint(_ly.paint['line-opacity'], level, feature);
if (op != 1 && color.indexOf('hsla') == -1) {
color = color.replace('hsl', 'hsla').replace(')', ',' + op + ")")
}
else if (op != 1) {
let ss = color.split(',')
ss[ss.length - 1] = op + ")"
color = ss.join()
}
}
stroke.setColor(color);
if (_ly.paint['line-width']) {
let w = getPaint(_ly.paint['line-width'], level, feature);
stroke.setWidth(w);
}
if (_ly.layout['line-cap'])
stroke.setLineCap(getPaint(_ly.layout['line-cap'], level, feature));
if (_ly.layout['line-join'])
stroke.setLineJoin(getPaint(_ly.layout['line-join'], level, feature));
if (_ly.paint['line-dasharray']) {
let das = getPaint(_ly.paint['line-dasharray'], level, feature);
if (das[0] === "literal") {
das = das[1]
}
stroke.setLineDash(das);
}
styles[length++] = line;
}
else if (_ly.type === "fill") {
let color = getPaint(_ly.paint['fill-color'], level, feature);
if (_ly.paint['fill-opacity']) {
let op = getPaint(_ly.paint['fill-opacity'], level, feature);
if (op != 1 && color.indexOf('hsla') == -1) {
color = color.replace('hsl', 'hsla').replace(')', ',' + op + ")")
}
else if (op != 1) {
let ss = color.split(',')
ss[ss.length - 1] = op + ")"
color = ss.join()
}
}
fill.setColor(color);
if (_ly.paint['fill-outline-color']) {
let _color = getPaint(_ly.paint['fill-outline-color'], level, feature);
stroke.setColor(_color);
stroke.setWidth(1);
styles[length++] = strokedPolygon;
} else {
styles[length++] = polygon;
}
}
else if (maki) {
styles[length++] = getIcon(maki);
}
else if (layer.endsWith('_label')) { // 省市县 城市名称 标注
let txtStyle= text.getText();
txtStyle.setText(getPaint(_ly.layout['text-field'], level, feature));
if (_ly.layout['text-size']) {
let fontsize = getPaint(_ly.layout['text-size'], level-4, feature)
txtStyle.setFont('normal ' + fontsize + 'px "Open Sans", "Arial Unicode MS"');
}
if (_ly.layout['text-offset']) {
let off = getPaint(_ly.layout['text-offset'], level, feature)
if (off[0] === "literal") {
off = off[1]
}
txtStyle.setOffsetX(off[0])
txtStyle.setOffsetY(off[1])
}
fill.setColor(getPaint(_ly.paint['text-color'], level, feature));
stroke.setColor('rgba(255,255,255,0.8)');
stroke.setWidth(1);
styles[length++] = text;
}
} catch (e) {
console.log(e)
}
}
styles.length = length
return styles;
};
}
export default MvtImageryProvider;