Skip to content

Commit

Permalink
Add *-sort-key layout property for circle, fill, line (#8467)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahk authored and ansis committed Jul 18, 2019
1 parent 387a32d commit f2ee03f
Show file tree
Hide file tree
Showing 18 changed files with 499 additions and 49 deletions.
3 changes: 2 additions & 1 deletion src/data/bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export type BucketFeature = {|
properties: Object,
type: 1 | 2 | 3,
id?: any,
+patterns: {[string]: {"min": string, "mid": string, "max": string}}
+patterns: {[string]: {"min": string, "mid": string, "max": string}},
sortKey?: number
|};

/**
Expand Down
48 changes: 43 additions & 5 deletions src/data/bucket/circle_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import EvaluationParameters from '../../style/evaluation_parameters';
import type {
Bucket,
BucketParameters,
BucketFeature,
IndexedFeature,
PopulateParameters
} from '../bucket';
Expand Down Expand Up @@ -72,17 +73,54 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
this.segments = new SegmentVector();
this.programConfigurations = new ProgramConfigurationSet(layoutAttributes, options.layers, options.zoom);
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);

}

populate(features: Array<IndexedFeature>, options: PopulateParameters) {
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, index, sourceLayerIndex} of features) {
if (this.layers[0]._featureFilter(new EvaluationParameters(this.zoom), feature)) {
const geometry = loadGeometry(feature);
this.addFeature(feature, geometry, index);
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
const sortKey = circleSortKey ?
circleSortKey.evaluate(feature, {}) :
undefined;

const bucketFeature: BucketFeature = {
id: feature.id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry,
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);
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}

update(states: FeatureStates, vtLayer: VectorTileLayer, imagePositions: {[string]: ImagePosition}) {
Expand Down Expand Up @@ -115,7 +153,7 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
this.segments.destroy();
}

addFeature(feature: VectorTileFeature, geometry: Array<Array<Point>>, index: number) {
addFeature(feature: BucketFeature, geometry: Array<Array<Point>>, index: number) {
for (const ring of geometry) {
for (const point of ring) {
const x = point.x;
Expand All @@ -133,7 +171,7 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
// │ 0 1 │
// └─────────┘

const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray);
const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray, feature.sortKey);
const index = segment.vertexLength;

addCircleVertex(this.layoutVertexArray, x, y, -1, -1);
Expand Down
50 changes: 34 additions & 16 deletions src/data/bucket/fill_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class FillBucket implements Bucket {
layerIds: Array<string>;
stateDependentLayers: Array<FillStyleLayer>;
stateDependentLayerIds: Array<string>;
patternFeatures: Array<BucketFeature>;

layoutVertexArray: FillLayoutArray;
layoutVertexBuffer: VertexBuffer;
Expand All @@ -53,7 +54,6 @@ class FillBucket implements Bucket {
segments: SegmentVector;
segments2: SegmentVector;
uploaded: boolean;
features: Array<BucketFeature>;

constructor(options: BucketParameters<FillStyleLayer>) {
this.zoom = options.zoom;
Expand All @@ -62,6 +62,7 @@ class FillBucket implements Bucket {
this.layerIds = this.layers.map(layer => layer.id);
this.index = options.index;
this.hasPattern = false;
this.patternFeatures = [];

this.layoutVertexArray = new FillLayoutArray();
this.indexArray = new TriangleIndexArray();
Expand All @@ -70,37 +71,55 @@ class FillBucket implements Bucket {
this.segments = new SegmentVector();
this.segments2 = new SegmentVector();
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);

}

populate(features: Array<IndexedFeature>, options: PopulateParameters) {
this.features = [];
this.hasPattern = hasPattern('fill', this.layers, options);
const fillSortKey = this.layers[0].layout.get('fill-sort-key');
const bucketFeatures = [];

for (const {feature, index, sourceLayerIndex} of features) {
if (!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom), feature)) continue;

const geometry = loadGeometry(feature);
const sortKey = fillSortKey ?
fillSortKey.evaluate(feature, {}) :
undefined;

const patternFeature: BucketFeature = {
const bucketFeature: BucketFeature = {
id: feature.id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry,
properties: feature.properties,
type: feature.type,
patterns: {}
patterns: {},
sortKey
};

if (typeof feature.id !== 'undefined') {
patternFeature.id = feature.id;
}
bucketFeatures.push(bucketFeature);
}

if (fillSortKey) {
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;

if (this.hasPattern) {
this.features.push(addPatternDependencies('fill', this.layers, patternFeature, this.zoom, options));
const patternFeature = addPatternDependencies('fill', this.layers, bucketFeature, this.zoom, options);
// pattern features are added only once the pattern is loaded into the image atlas
// so are stored during populate until later updated with positions by tile worker in addFeatures
this.patternFeatures.push(patternFeature);
} else {
this.addFeature(patternFeature, geometry, index, {});
this.addFeature(bucketFeature, geometry, index, {});
}

const feature = features[index].feature;
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}
Expand All @@ -111,9 +130,8 @@ class FillBucket implements Bucket {
}

addFeatures(options: PopulateParameters, imagePositions: {[string]: ImagePosition}) {
for (const feature of this.features) {
const {geometry} = feature;
this.addFeature(feature, geometry, feature.index, imagePositions);
for (const feature of this.patternFeatures) {
this.addFeature(feature, feature.geometry, feature.index, imagePositions);
}
}

Expand Down Expand Up @@ -202,6 +220,6 @@ class FillBucket implements Bucket {
}
}

register('FillBucket', FillBucket, {omit: ['layers', 'features']});
register('FillBucket', FillBucket, {omit: ['layers', 'patternFeatures']});

export default FillBucket;
50 changes: 34 additions & 16 deletions src/data/bucket/line_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class LineBucket implements Bucket {
layerIds: Array<string>;
stateDependentLayers: Array<any>;
stateDependentLayerIds: Array<string>;
features: Array<BucketFeature>;
patternFeatures: Array<BucketFeature>;

layoutVertexArray: LineLayoutArray;
layoutVertexBuffer: VertexBuffer;
Expand All @@ -117,8 +117,8 @@ class LineBucket implements Bucket {
this.layers = options.layers;
this.layerIds = this.layers.map(layer => layer.id);
this.index = options.index;
this.features = [];
this.hasPattern = false;
this.patternFeatures = [];

this.layoutVertexArray = new LineLayoutArray();
this.indexArray = new TriangleIndexArray();
Expand All @@ -129,33 +129,52 @@ class LineBucket implements Bucket {
}

populate(features: Array<IndexedFeature>, options: PopulateParameters) {
this.features = [];
this.hasPattern = hasPattern('line', this.layers, options);
const lineSortKey = this.layers[0].layout.get('line-sort-key');
const bucketFeatures = [];

for (const {feature, index, sourceLayerIndex} of features) {
if (!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom), feature)) continue;

const geometry = loadGeometry(feature);
const sortKey = lineSortKey ?
lineSortKey.evaluate(feature, {}) :
undefined;

const patternFeature: BucketFeature = {
const bucketFeature: BucketFeature = {
id: feature.id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry,
properties: feature.properties,
type: feature.type,
patterns: {}
patterns: {},
sortKey
};

if (typeof feature.id !== 'undefined') {
patternFeature.id = feature.id;
}
bucketFeatures.push(bucketFeature);
}

if (lineSortKey) {
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;

if (this.hasPattern) {
this.features.push(addPatternDependencies('line', this.layers, patternFeature, this.zoom, options));
const patternBucketFeature = addPatternDependencies('line', this.layers, bucketFeature, this.zoom, options);
// pattern features are added only once the pattern is loaded into the image atlas
// so are stored during populate until later updated with positions by tile worker in addFeatures
this.patternFeatures.push(patternBucketFeature);
} else {
this.addFeature(patternFeature, geometry, index, {});
this.addFeature(bucketFeature, geometry, index, {});
}

const feature = features[index].feature;
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}
Expand All @@ -166,9 +185,8 @@ class LineBucket implements Bucket {
}

addFeatures(options: PopulateParameters, imagePositions: {[string]: ImagePosition}) {
for (const feature of this.features) {
const {geometry} = feature;
this.addFeature(feature, geometry, feature.index, imagePositions);
for (const feature of this.patternFeatures) {
this.addFeature(feature, feature.geometry, feature.index, imagePositions);
}
}

Expand Down Expand Up @@ -623,6 +641,6 @@ function calculateFullDistance(vertices: Array<Point>, first: number, len: numbe
return total;
}

register('LineBucket', LineBucket, {omit: ['layers', 'features']});
register('LineBucket', LineBucket, {omit: ['layers', 'patternFeatures']});

export default LineBucket;
Loading

0 comments on commit f2ee03f

Please sign in to comment.