package.src.data.bucket.circle_bucket.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapbox-gl Show documentation
Show all versions of mapbox-gl Show documentation
A WebGL interactive maps library
The newest version!
// @flow
import {CircleLayoutArray} from '../array_types';
import {members as layoutAttributes} from './circle_attributes';
import SegmentVector from '../segment';
import {ProgramConfigurationSet} from '../program_configuration';
import {TriangleIndexArray} from '../index_array_type';
import loadGeometry from '../load_geometry';
import toEvaluationFeature from '../evaluation_feature';
import EXTENT from '../extent';
import {register} from '../../util/web_worker_transfer';
import EvaluationParameters from '../../style/evaluation_parameters';
import type {CanonicalTileID} from '../../source/tile_id';
import type {
Bucket,
BucketParameters,
BucketFeature,
IndexedFeature,
PopulateParameters
} from '../bucket';
import type CircleStyleLayer from '../../style/style_layer/circle_style_layer';
import type HeatmapStyleLayer from '../../style/style_layer/heatmap_style_layer';
import type Context from '../../gl/context';
import type IndexBuffer from '../../gl/index_buffer';
import type VertexBuffer from '../../gl/vertex_buffer';
import type Point from '@mapbox/point-geometry';
import type {FeatureStates} from '../../source/source_state';
import type {ImagePosition} from '../../render/image_atlas';
function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
layoutVertexArray.emplaceBack(
(x * 2) + ((extrudeX + 1) / 2),
(y * 2) + ((extrudeY + 1) / 2));
}
/**
* Circles are represented by two triangles.
*
* Each corner has a pos that is the center of the circle and an extrusion
* vector that is where it points.
* @private
*/
class CircleBucket implements Bucket {
index: number;
zoom: number;
overscaling: number;
layerIds: Array;
layers: Array;
stateDependentLayers: Array;
stateDependentLayerIds: Array;
layoutVertexArray: CircleLayoutArray;
layoutVertexBuffer: VertexBuffer;
indexArray: TriangleIndexArray;
indexBuffer: IndexBuffer;
hasPattern: boolean;
programConfigurations: ProgramConfigurationSet;
segments: SegmentVector;
uploaded: boolean;
constructor(options: BucketParameters) {
this.zoom = options.zoom;
this.overscaling = options.overscaling;
this.layers = options.layers;
this.layerIds = this.layers.map(layer => layer.id);
this.index = options.index;
this.hasPattern = false;
this.layoutVertexArray = new CircleLayoutArray();
this.indexArray = new TriangleIndexArray();
this.segments = new SegmentVector();
this.programConfigurations = new ProgramConfigurationSet(options.layers, options.zoom);
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);
}
populate(features: Array, options: PopulateParameters, canonical: CanonicalTileID) {
const styleLayer = this.layers[0];
const bucketFeatures = [];
let circleSortKey = null;
// Heatmap layers are handled in this bucket and have no evaluated properties, so we check our access
if (styleLayer.type === 'circle') {
circleSortKey = ((styleLayer: any): CircleStyleLayer).layout.get('circle-sort-key');
}
for (const {feature, id, index, sourceLayerIndex} of features) {
const needGeometry = this.layers[0]._featureFilter.needGeometry;
const evaluationFeature = toEvaluationFeature(feature, needGeometry);
if (!this.layers[0]._featureFilter.filter(new EvaluationParameters(this.zoom), evaluationFeature, canonical)) continue;
const sortKey = circleSortKey ?
circleSortKey.evaluate(evaluationFeature, {}, canonical) :
undefined;
const bucketFeature: BucketFeature = {
id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature),
patterns: {},
sortKey
};
bucketFeatures.push(bucketFeature);
}
if (circleSortKey) {
bucketFeatures.sort((a, b) => {
// a.sortKey is always a number when in use
return ((a.sortKey: any): number) - ((b.sortKey: any): number);
});
}
for (const bucketFeature of bucketFeatures) {
const {geometry, index, sourceLayerIndex} = bucketFeature;
const feature = features[index].feature;
this.addFeature(bucketFeature, geometry, index, canonical);
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}
update(states: FeatureStates, vtLayer: VectorTileLayer, imagePositions: {[_: string]: ImagePosition}) {
if (!this.stateDependentLayers.length) return;
this.programConfigurations.updatePaintArrays(states, vtLayer, this.stateDependentLayers, imagePositions);
}
isEmpty() {
return this.layoutVertexArray.length === 0;
}
uploadPending() {
return !this.uploaded || this.programConfigurations.needsUpload;
}
upload(context: Context) {
if (!this.uploaded) {
this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, layoutAttributes);
this.indexBuffer = context.createIndexBuffer(this.indexArray);
}
this.programConfigurations.upload(context);
this.uploaded = true;
}
destroy() {
if (!this.layoutVertexBuffer) return;
this.layoutVertexBuffer.destroy();
this.indexBuffer.destroy();
this.programConfigurations.destroy();
this.segments.destroy();
}
addFeature(feature: BucketFeature, geometry: Array>, index: number, canonical: CanonicalTileID) {
for (const ring of geometry) {
for (const point of ring) {
const x = point.x;
const y = point.y;
// Do not include points that are outside the tile boundaries.
if (x < 0 || x >= EXTENT || y < 0 || y >= EXTENT) continue;
// this geometry will be of the Point type, and we'll derive
// two triangles from it.
//
// ┌─────────┐
// │ 3 2 │
// │ │
// │ 0 1 │
// └─────────┘
const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray, feature.sortKey);
const index = segment.vertexLength;
addCircleVertex(this.layoutVertexArray, x, y, -1, -1);
addCircleVertex(this.layoutVertexArray, x, y, 1, -1);
addCircleVertex(this.layoutVertexArray, x, y, 1, 1);
addCircleVertex(this.layoutVertexArray, x, y, -1, 1);
this.indexArray.emplaceBack(index, index + 1, index + 2);
this.indexArray.emplaceBack(index, index + 3, index + 2);
segment.vertexLength += 4;
segment.primitiveLength += 2;
}
}
this.programConfigurations.populatePaintArrays(this.layoutVertexArray.length, feature, index, {}, canonical);
}
}
register('CircleBucket', CircleBucket, {omit: ['layers']});
export default CircleBucket;