Add circle render type

As specified in:
https://github.com/mapbox/mapbox-gl-style-spec/blob/v8-circle/reference/v8.json

Part of #1740.
This commit is contained in:
Bruno de Oliveira Abinader
2015-06-17 10:56:18 +03:00
committed by John Firebaugh
parent d1100f34de
commit 98534631e0
29 changed files with 497 additions and 6 deletions

View File

@@ -45,6 +45,20 @@ struct LineProperties {
}
};
struct CircleProperties {
inline CircleProperties() {}
float radius = 5.0f;
Color color = {{ 0, 0, 0, 1 }};
float opacity = 1.0f;
std::array<float, 2> translate = {{ 0, 0 }};
TranslateAnchorType translateAnchor = TranslateAnchorType::Map;
float blur = 0;
inline bool isVisible() const {
return radius > 0 && color[3] > 0 && opacity > 0;
}
};
struct SymbolProperties {
inline SymbolProperties() {}
@@ -100,6 +114,7 @@ struct BackgroundProperties {
typedef mapbox::util::variant<
FillProperties,
LineProperties,
CircleProperties,
SymbolProperties,
RasterProperties,
BackgroundProperties,

View File

@@ -27,6 +27,7 @@ enum class StyleLayerType : uint8_t {
Unknown,
Fill,
Line,
Circle,
Symbol,
Raster,
Background
@@ -36,6 +37,7 @@ MBGL_DEFINE_ENUM_CLASS(StyleLayerTypeClass, StyleLayerType, {
{ StyleLayerType::Unknown, "unknown" },
{ StyleLayerType::Fill, "fill" },
{ StyleLayerType::Line, "line" },
{ StyleLayerType::Circle, "circle" },
{ StyleLayerType::Symbol, "symbol" },
{ StyleLayerType::Raster, "raster" },
{ StyleLayerType::Background, "background" },

View File

@@ -0,0 +1,13 @@
#include <mbgl/geometry/circle_buffer.hpp>
#include <mbgl/platform/gl.hpp>
#include <climits>
using namespace mbgl;
void CircleVertexBuffer::add(vertex_type x, vertex_type y, float ex, float ey) {
vertex_type *vertices = static_cast<vertex_type *>(addElement());
vertices[0] = (x * 2) + ((ex + 1) / 2);
vertices[1] = (y * 2) + ((ey + 1) / 2);
}

View File

@@ -0,0 +1,27 @@
#ifndef MBGL_GEOMETRY_CIRCLE_BUFFER
#define MBGL_GEOMETRY_CIRCLE_BUFFER
#include <mbgl/geometry/buffer.hpp>
namespace mbgl {
class CircleVertexBuffer : public Buffer<
4 // 2 bytes per short * 4 of them.
> {
public:
typedef int16_t vertex_type;
/*
* Add a vertex to this buffer
*
* @param {number} x vertex position
* @param {number} y vertex position
* @param {number} ex extrude normal
* @param {number} ey extrude normal
*/
void add(vertex_type x, vertex_type y, float ex, float ey);
};
}
#endif // MBGL_GEOMETRY_CIRCLE_BUFFER

View File

@@ -5,6 +5,7 @@
#include <mbgl/geometry/glyph_atlas.hpp>
#include <mbgl/renderer/fill_bucket.hpp>
#include <mbgl/renderer/line_bucket.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/platform/log.hpp>
#include <mbgl/util/constants.hpp>
@@ -139,15 +140,22 @@ void TileWorker::parseLayer(const StyleLayer& layer, const GeometryTile& geometr
std::unique_ptr<Bucket> bucket;
if (styleBucket.type == StyleLayerType::Fill) {
switch (styleBucket.type) {
case StyleLayerType::Fill:
bucket = createFillBucket(*geometryLayer, styleBucket);
} else if (styleBucket.type == StyleLayerType::Line) {
break;
case StyleLayerType::Line:
bucket = createLineBucket(*geometryLayer, styleBucket);
} else if (styleBucket.type == StyleLayerType::Symbol) {
break;
case StyleLayerType::Circle:
bucket = createCircleBucket(*geometryLayer, styleBucket);
break;
case StyleLayerType::Symbol:
bucket = createSymbolBucket(*geometryLayer, styleBucket);
} else if (styleBucket.type == StyleLayerType::Raster) {
break;
case StyleLayerType::Raster:
return;
} else {
default:
Log::Warning(Event::ParseTile, "unknown bucket render type for layer '%s' (source layer '%s')",
styleBucket.name.c_str(), styleBucket.source_layer.c_str());
}
@@ -203,6 +211,17 @@ std::unique_ptr<Bucket> TileWorker::createLineBucket(const GeometryTileLayer& la
return bucket->hasData() ? std::move(bucket) : nullptr;
}
std::unique_ptr<Bucket> TileWorker::createCircleBucket(const GeometryTileLayer& layer,
const StyleBucket& bucket_desc) {
auto bucket = std::make_unique<CircleBucket>(circleVertexBuffer,
triangleElementsBuffer);
// Circle does not have layout properties to apply.
addBucketGeometries(bucket, layer, bucket_desc.filter);
return bucket->hasData() ? std::move(bucket) : nullptr;
}
std::unique_ptr<Bucket> TileWorker::createSymbolBucket(const GeometryTileLayer& layer,
const StyleBucket& bucket_desc) {
auto bucket = std::make_unique<SymbolBucket>(*collision, id.overscaling);

View File

@@ -6,6 +6,7 @@
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/fill_buffer.hpp>
#include <mbgl/geometry/line_buffer.hpp>
#include <mbgl/geometry/circle_buffer.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/style/filter_expression.hpp>
@@ -52,6 +53,7 @@ private:
std::unique_ptr<Bucket> createFillBucket(const GeometryTileLayer&, const StyleBucket&);
std::unique_ptr<Bucket> createLineBucket(const GeometryTileLayer&, const StyleBucket&);
std::unique_ptr<Bucket> createCircleBucket(const GeometryTileLayer&, const StyleBucket&);
std::unique_ptr<Bucket> createSymbolBucket(const GeometryTileLayer&, const StyleBucket&);
template <class Bucket>
@@ -68,6 +70,7 @@ private:
FillVertexBuffer fillVertexBuffer;
LineVertexBuffer lineVertexBuffer;
CircleVertexBuffer circleVertexBuffer;
TriangleElementsBuffer triangleElementsBuffer;
LineElementsBuffer lineElementsBuffer;

View File

@@ -0,0 +1,92 @@
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/renderer/painter.hpp>
#include <mbgl/shader/circle_shader.hpp>
using namespace mbgl;
CircleBucket::CircleBucket(CircleVertexBuffer& vertexBuffer,
TriangleElementsBuffer& elementsBuffer)
: vertexBuffer_(vertexBuffer)
, elementsBuffer_(elementsBuffer)
, vertexStart_(vertexBuffer_.index())
, elementsStart_(elementsBuffer_.index()) {
}
CircleBucket::~CircleBucket() {
// Do not remove. header file only contains forward definitions to unique pointers.
}
void CircleBucket::upload() {
vertexBuffer_.upload();
elementsBuffer_.upload();
uploaded = true;
}
void CircleBucket::render(Painter& painter,
const StyleLayer& layer_desc,
const TileID& id,
const mat4& matrix) {
painter.renderCircle(*this, layer_desc, id, matrix);
}
bool CircleBucket::hasData() const {
return !triangleGroups_.empty();
}
void CircleBucket::addGeometry(const GeometryCollection& geometryCollection) {
for (auto& circle : geometryCollection) {
for(auto & geometry : circle) {
auto x = geometry.x;
auto y = geometry.y;
// this geometry will be of the Point type, and we'll derive
// two triangles from it.
//
// ┌─────────┐
// │ 4 3 │
// │ │
// │ 1 2 │
// └─────────┘
//
vertexBuffer_.add(x, y, -1, -1); // 1
vertexBuffer_.add(x, y, 1, -1); // 2
vertexBuffer_.add(x, y, 1, 1); // 3
vertexBuffer_.add(x, y, -1, 1); // 4
if (!triangleGroups_.size() || (triangleGroups_.back()->vertex_length + 4 > 65535)) {
// Move to a new group because the old one can't hold the geometry.
triangleGroups_.emplace_back(std::make_unique<TriangleGroup>());
}
TriangleGroup& group = *triangleGroups_.back();
auto index = group.vertex_length;
// 1, 2, 3
// 1, 4, 3
elementsBuffer_.add(index, index + 1, index + 2);
elementsBuffer_.add(index, index + 3, index + 2);
group.vertex_length += 4;
group.elements_length += 2;
}
}
}
void CircleBucket::drawCircles(CircleShader& shader) {
char* vertexIndex = BUFFER_OFFSET(vertexStart_ * vertexBuffer_.itemSize);
char* elementsIndex = BUFFER_OFFSET(elementsStart_ * elementsBuffer_.itemSize);
for (auto& group : triangleGroups_) {
assert(group);
if (!group->elements_length) continue;
group->array[0].bind(shader, vertexBuffer_, elementsBuffer_, vertexIndex);
MBGL_CHECK_ERROR(glDrawElements(GL_TRIANGLES, group->elements_length * 3, GL_UNSIGNED_SHORT, elementsIndex));
vertexIndex += group->vertex_length * vertexBuffer_.itemSize;
elementsIndex += group->elements_length * elementsBuffer_.itemSize;
}
}

View File

@@ -0,0 +1,46 @@
#ifndef MBGL_RENDERER_CIRCLE_BUCKET
#define MBGL_RENDERER_CIRCLE_BUCKET
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/map/geometry_tile.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/circle_buffer.hpp>
#include <mbgl/style/style_bucket.hpp>
#include <mbgl/style/style_layout.hpp>
namespace mbgl {
class CircleVertexBuffer;
class CircleShader;
class CircleBucket : public Bucket {
using TriangleGroup = ElementGroup<3>;
public:
CircleBucket(CircleVertexBuffer &vertexBuffer, TriangleElementsBuffer &elementsBuffer);
~CircleBucket() override;
void upload() override;
void render(Painter&, const StyleLayer&, const TileID&, const mat4&) override;
bool hasData() const;
void addGeometry(const GeometryCollection&);
void drawCircles(CircleShader& shader);
private:
CircleVertexBuffer& vertexBuffer_;
TriangleElementsBuffer& elementsBuffer_;
const size_t vertexStart_;
const size_t elementsStart_;
std::vector<std::unique_ptr<TriangleGroup>> triangleGroups_;
};
} // namespace mbgl
#endif // MBGL_RENDERER_CIRCLE_BUCKET

View File

@@ -27,6 +27,7 @@
#include <mbgl/shader/sdf_shader.hpp>
#include <mbgl/shader/dot_shader.hpp>
#include <mbgl/shader/box_shader.hpp>
#include <mbgl/shader/circle_shader.hpp>
#include <mbgl/util/constants.hpp>
#include <mbgl/util/mat3.hpp>
@@ -66,6 +67,7 @@ void Painter::setup() {
assert(sdfGlyphShader);
assert(sdfIconShader);
assert(dotShader);
assert(circleShader);
// Blending
@@ -100,6 +102,7 @@ void Painter::setupShaders() {
if (!sdfIconShader) sdfIconShader = std::make_unique<SDFIconShader>();
if (!dotShader) dotShader = std::make_unique<DotShader>();
if (!collisionBoxShader) collisionBoxShader = std::make_unique<CollisionBoxShader>();
if (!circleShader) circleShader = std::make_unique<CircleShader>();
}
void Painter::resize() {

View File

@@ -38,6 +38,7 @@ struct FrameData;
class DebugBucket;
class FillBucket;
class LineBucket;
class CircleBucket;
class SymbolBucket;
class RasterBucket;
@@ -50,6 +51,7 @@ class LineShader;
class LinejoinShader;
class LineSDFShader;
class LinepatternShader;
class CircleShader;
class PatternShader;
class IconShader;
class RasterShader;
@@ -106,6 +108,7 @@ public:
void renderDebugText(DebugBucket& bucket, const mat4 &matrix);
void renderFill(FillBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
void renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
void renderCircle(CircleBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
void renderSymbol(SymbolBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
void renderRaster(RasterBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix);
void renderBackground(const StyleLayer &layer_desc);
@@ -227,6 +230,7 @@ public:
std::unique_ptr<SDFIconShader> sdfIconShader;
std::unique_ptr<DotShader> dotShader;
std::unique_ptr<CollisionBoxShader> collisionBoxShader;
std::unique_ptr<CircleShader> circleShader;
StaticVertexBuffer backgroundBuffer = {
{ -1, -1 }, { 1, -1 },

View File

@@ -0,0 +1,49 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/circle_bucket.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/style/style_layer.hpp>
#include <mbgl/style/style_layout.hpp>
#include <mbgl/map/sprite.hpp>
#include <mbgl/map/tile_id.hpp>
#include <mbgl/map/map_data.hpp>
#include <mbgl/shader/circle_shader.hpp>
using namespace mbgl;
void Painter::renderCircle(CircleBucket& bucket,
const StyleLayer& layer_desc,
const TileID& id,
const mat4& matrix) {
// Abort early.
if (pass == RenderPass::Opaque) return;
config.stencilTest = false;
const CircleProperties& properties = layer_desc.getProperties<CircleProperties>();
mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);
Color color = properties.color;
color[0] *= properties.opacity;
color[1] *= properties.opacity;
color[2] *= properties.opacity;
color[3] *= properties.opacity;
// Antialiasing factor: this is a minimum blur distance that serves as
// a faux-antialiasing for the circle. since blur is a ratio of the circle's
// size and the intent is to keep the blur at roughly 1px, the two
// are inversely related.
float antialiasing = 1 / data.pixelRatio / properties.radius;
useProgram(circleShader->program);
circleShader->u_matrix = vtxMatrix;
circleShader->u_exmatrix = projMatrix;
circleShader->u_color = color;
circleShader->u_blur = std::max(properties.blur, antialiasing);
circleShader->u_size = properties.radius;
bucket.drawCircles(*circleShader);
}

View File

@@ -0,0 +1,10 @@
uniform vec4 u_color;
uniform float u_blur;
uniform float u_size;
varying vec2 v_extrude;
void main() {
float t = smoothstep(1.0 - u_blur, 1.0, length(v_extrude));
gl_FragColor = u_color * (1.0 - t);
}

View File

@@ -0,0 +1,23 @@
// set by gl_util
uniform float u_size;
attribute vec2 a_pos;
uniform mat4 u_matrix;
uniform mat4 u_exmatrix;
varying vec2 v_extrude;
void main(void) {
// unencode the extrusion vector that we snuck into the a_pos vector
v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
vec4 extrude = u_exmatrix * vec4(v_extrude * u_size, 0, 0);
// multiply a_pos by 0.5, since we had it * 2 in order to sneak
// in extrusion data
gl_Position = u_matrix * vec4(a_pos * 0.5, 0, 1);
// gl_Position is divided by gl_Position.w after this shader runs.
// Multiply the extrude by it so that it isn't affected by it.
gl_Position += extrude * gl_Position.w;
}

View File

@@ -0,0 +1,21 @@
#include <mbgl/shader/circle_shader.hpp>
#include <mbgl/shader/shaders.hpp>
#include <mbgl/platform/gl.hpp>
#include <cstdio>
using namespace mbgl;
CircleShader::CircleShader()
: Shader(
"circle",
shaders[CIRCLE_SHADER].vertex,
shaders[CIRCLE_SHADER].fragment
) {
a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program, "a_pos"));
}
void CircleShader::bind(char *offset) {
MBGL_CHECK_ERROR(glEnableVertexAttribArray(a_pos));
MBGL_CHECK_ERROR(glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 4, offset));
}

View File

@@ -0,0 +1,27 @@
#ifndef MBGL_SHADER_CIRCLE_SHADER
#define MBGL_SHADER_CIRCLE_SHADER
#include <mbgl/shader/shader.hpp>
#include <mbgl/shader/uniform.hpp>
namespace mbgl {
class CircleShader : public Shader {
public:
CircleShader();
void bind(char *offset);
UniformMatrix<4> u_matrix = {"u_matrix", *this};
UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
Uniform<std::array<float, 4>> u_color = {"u_color", *this};
Uniform<float> u_size = {"u_size", *this};
Uniform<float> u_blur = {"u_blur", *this};
private:
int32_t a_pos = -1;
};
}
#endif // MBGL_SHADER_CIRCLE_SHADER

View File

@@ -21,6 +21,13 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = {
{ PropertyKey::LineGapWidth, defaultStyleProperties<LineProperties>().gap_width },
{ PropertyKey::LineBlur, defaultStyleProperties<LineProperties>().blur },
{ PropertyKey::CircleRadius, defaultStyleProperties<CircleProperties>().radius },
{ PropertyKey::CircleColor, defaultStyleProperties<CircleProperties>().color },
{ PropertyKey::CircleOpacity, defaultStyleProperties<CircleProperties>().opacity },
{ PropertyKey::CircleTranslate, defaultStyleProperties<CircleProperties>().translate },
{ PropertyKey::CircleTranslateAnchor, defaultStyleProperties<CircleProperties>().translateAnchor },
{ PropertyKey::CircleBlur, defaultStyleProperties<CircleProperties>().blur },
{ PropertyKey::IconOpacity, defaultStyleProperties<SymbolProperties>().icon.opacity },
{ PropertyKey::IconSize, defaultStyleProperties<SymbolProperties>().icon.size },
{ PropertyKey::IconColor, defaultStyleProperties<SymbolProperties>().icon.color },

View File

@@ -27,6 +27,13 @@ enum class PropertyKey {
LineMiterLimit,
LineRoundLimit,
CircleRadius,
CircleColor,
CircleOpacity,
CircleTranslate,
CircleTranslateAnchor,
CircleBlur,
SymbolPlacement,
SymbolSpacing,
SymbolAvoidEdges,

View File

@@ -19,6 +19,8 @@ bool StyleLayer::isVisible() const {
return getProperties<FillProperties>().isVisible();
case StyleLayerType::Line:
return getProperties<LineProperties>().isVisible();
case StyleLayerType::Circle:
return getProperties<CircleProperties>().isVisible();
case StyleLayerType::Symbol:
return getProperties<SymbolProperties>().isVisible();
case StyleLayerType::Raster:
@@ -204,6 +206,18 @@ void StyleLayer::applyStyleProperties<LineProperties>(const float z, const TimeP
applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), now, zoomHistory);
}
template <>
void StyleLayer::applyStyleProperties<CircleProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<CircleProperties>();
CircleProperties& circle = properties.get<CircleProperties>();
applyTransitionedStyleProperty(PropertyKey::CircleRadius, circle.radius, z, now, zoomHistory);
applyTransitionedStyleProperty(PropertyKey::CircleColor, circle.color, z, now, zoomHistory);
applyTransitionedStyleProperty(PropertyKey::CircleOpacity, circle.opacity, z, now, zoomHistory);
applyTransitionedStyleProperty(PropertyKey::CircleTranslate, circle.translate, z, now, zoomHistory);
applyStyleProperty(PropertyKey::CircleTranslateAnchor, circle.translateAnchor, z, now, zoomHistory);
applyTransitionedStyleProperty(PropertyKey::CircleBlur, circle.blur, z, now, zoomHistory);
}
template <>
void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const TimePoint& now, const ZoomHistory &zoomHistory) {
properties.set<SymbolProperties>();
@@ -255,6 +269,7 @@ void StyleLayer::updateProperties(float z, const TimePoint& now, ZoomHistory &zo
switch (type) {
case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now, zoomHistory); break;
case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now, zoomHistory); break;
case StyleLayerType::Circle: applyStyleProperties<CircleProperties>(z, now, zoomHistory); break;
case StyleLayerType::Symbol: applyStyleProperties<SymbolProperties>(z, now, zoomHistory); break;
case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now, zoomHistory); break;
case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now, zoomHistory); break;

View File

@@ -834,6 +834,13 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) {
parseOptionalProperty<PiecewiseConstantFunction<Faded<std::vector<float>>>>("line-dasharray", Key::LineDashArray, klass, value, "line-dasharray-transition");
parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("line-pattern", Key::LineImage, klass, value, "line-pattern-transition");
parseOptionalProperty<Function<float>>("circle-radius", Key::CircleRadius, klass, value);
parseOptionalProperty<Function<Color>>("circle-color", Key::CircleColor, klass, value);
parseOptionalProperty<Function<float>>("circle-opacity", Key::CircleOpacity, klass, value);
parseOptionalProperty<Function<std::array<float,2>>>("circle-translate", Key::CircleTranslate, klass, value);
parseOptionalProperty<Function<TranslateAnchorType>>("circle-translate-anchor", Key::CircleTranslateAnchor, klass, value);
parseOptionalProperty<Function<float>>("circle-blur", Key::CircleBlur, klass, value);
parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value);
parseOptionalProperty<PropertyTransition>("icon-opacity-transition", Key::IconOpacity, klass, value);
parseOptionalProperty<Function<float>>("icon-size", Key::IconSize, klass, value);

View File

@@ -5,6 +5,7 @@ namespace mbgl {
template<> const FillProperties &defaultStyleProperties() { static const FillProperties p; return p; }
template<> const LineProperties &defaultStyleProperties() { static const LineProperties p; return p; }
template<> const CircleProperties &defaultStyleProperties() { static const CircleProperties p; return p; }
template<> const SymbolProperties &defaultStyleProperties() { static const SymbolProperties p; return p; }
template<> const RasterProperties &defaultStyleProperties() { static const RasterProperties p; return p; }
template<> const BackgroundProperties &defaultStyleProperties() { static const BackgroundProperties p; return p; }

View File

@@ -0,0 +1,7 @@
{
"default": {
"log": [
[1, "WARNING", "ParseStyle", "value of 'circle-blur' must be a number, or a number function"]
]
}
}

View File

@@ -0,0 +1,18 @@
{
"version": 8,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxzoom": 14
}
},
"layers": [{
"id": "circle_blur_example",
"type": "circle",
"source": "mapbox",
"paint": {
"circle-blur": null
}
}]
}

View File

@@ -0,0 +1,7 @@
{
"default": {
"log": [
[1, "WARNING", "ParseStyle", "color value must be a string"]
]
}
}

View File

@@ -0,0 +1,18 @@
{
"version": 8,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxzoom": 14
}
},
"layers": [{
"id": "circle_color_example",
"type": "circle",
"source": "mapbox",
"paint": {
"circle-color": null
}
}]
}

View File

@@ -0,0 +1,7 @@
{
"default": {
"log": [
[1, "WARNING", "ParseStyle", "value of 'circle-opacity' must be a number, or a number function"]
]
}
}

View File

@@ -0,0 +1,18 @@
{
"version": 8,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxzoom": 14
}
},
"layers": [{
"id": "circle_opacity_example",
"type": "circle",
"source": "mapbox",
"paint": {
"circle-opacity": null
}
}]
}

View File

@@ -0,0 +1,7 @@
{
"default": {
"log": [
[1, "WARNING", "ParseStyle", "value of 'circle-radius' must be a number, or a number function"]
]
}
}

View File

@@ -0,0 +1,18 @@
{
"version": 8,
"sources": {
"mapbox": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v1,mapbox.mapbox-streets-v5",
"maxzoom": 14
}
},
"layers": [{
"id": "circle_radius_example",
"type": "circle",
"source": "mapbox",
"paint": {
"circle-radius": null
}
}]
}