Skip to content

Commit

Permalink
Add ['heatmap-density'] expression (#5350)
Browse files Browse the repository at this point in the history
* Add ['heatmap-density'] expression

* Fix lint
  • Loading branch information
anandthakker authored and mourner committed Sep 29, 2017
1 parent 403dd72 commit 5059738
Show file tree
Hide file tree
Showing 11 changed files with 37 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/style-spec/function/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const definitions = require('./definitions');
const evaluationContext = require('./evaluation_context');
const {
isFeatureConstant,
isZoomConstant
isGlobalPropertyConstant
} = require('./is_constant');

import type { Type } from './types.js';
Expand Down Expand Up @@ -76,7 +76,7 @@ function compileExpression(
function: compiled,
functionSource: compilationContext.getPrelude(),
isFeatureConstant: isFeatureConstant(parsed),
isZoomConstant: isZoomConstant(parsed),
isZoomConstant: isGlobalPropertyConstant(parsed, ['zoom']),
expression: parsed
};
}
Expand Down
13 changes: 8 additions & 5 deletions src/style-spec/function/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const extend = require('../util/extend');
module.exports.function = convertFunction;
module.exports.value = convertValue;

function convertFunction(parameters, propertySpec) {
function convertFunction(parameters, propertySpec, name) {
let expression;

parameters = extend({}, parameters);
Expand All @@ -31,7 +31,10 @@ function convertFunction(parameters, propertySpec) {
throw new Error('Unimplemented');
}

if (zoomAndFeatureDependent) {
if (name === 'heatmap-color') {
assert(zoomDependent);
expression = convertZoomFunction(parameters, propertySpec, stops, ['heatmap-density']);
} else if (zoomAndFeatureDependent) {
expression = convertZoomAndPropertyFunction(parameters, propertySpec, stops, defaultExpression);
} else if (zoomDependent) {
expression = convertZoomFunction(parameters, propertySpec, stops);
Expand Down Expand Up @@ -178,16 +181,16 @@ function convertPropertyFunction(parameters, propertySpec, stops, defaultExpress
return expression;
}

function convertZoomFunction(parameters, propertySpec, stops) {
function convertZoomFunction(parameters, propertySpec, stops, input = ['zoom']) {
const type = getFunctionType(parameters, propertySpec);
let expression;
let isStep = false;
if (type === 'interval') {
expression = ['curve', ['step'], ['zoom']];
expression = ['curve', ['step'], input];
isStep = true;
} else if (type === 'exponential') {
const base = parameters.base !== undefined ? parameters.base : 1;
expression = ['curve', ['exponential', base], ['zoom']];
expression = ['curve', ['exponential', base], input];
} else {
throw new Error(`Unknown zoom function type "${type}"`);
}
Expand Down
3 changes: 2 additions & 1 deletion src/style-spec/function/definitions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ CompoundExpression.register(expressions, {
'id': [ ValueType, [], () =>
`('id' in $feature) ? $feature.id : null`
],
'zoom': [ NumberType, [], () => '$globalProperties.zoom' ],
'zoom': [ NumberType, [], () => '$globalProperties.zoom || 0' ],
'heatmap-density': [ NumberType, [], () => '$globalProperties.heatmapDensity || 0' ],
'+': defineBinaryMathOp('+', true),
'*': defineBinaryMathOp('*', true),
'-': {
Expand Down
4 changes: 2 additions & 2 deletions src/style-spec/function/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type StylePropertySpecification = {
type StylePropertyValue = null | string | number | Array<string> | Array<number>;
type FunctionParameters = DataDrivenPropertyValueSpecification<StylePropertyValue>

function createFunction(parameters: FunctionParameters, propertySpec: StylePropertySpecification): StyleFunction {
function createFunction(parameters: FunctionParameters, propertySpec: StylePropertySpecification, name: string): StyleFunction {
if (typeof parameters === 'string' && propertySpec.type === 'color') {
const color = parseColor(parameters);
return {
Expand All @@ -86,7 +86,7 @@ function createFunction(parameters: FunctionParameters, propertySpec: StylePrope
if (parameters.expression) {
expr = parameters.expression;
} else {
expr = convert.function(parameters, propertySpec);
expr = convert.function(parameters, propertySpec, name);
isConvertedStopFunction = true;
if (parameters && typeof parameters.default !== 'undefined') {
defaultValue = parameters.default;
Expand Down
8 changes: 4 additions & 4 deletions src/style-spec/function/is_constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ function isFeatureConstant(e: Expression) {
return result;
}

function isZoomConstant(e: Expression) {
if (e instanceof CompoundExpression && e.name === 'zoom') { return false; }
function isGlobalPropertyConstant(e: Expression, properties: Array<string>) {
if (e instanceof CompoundExpression && properties.indexOf(e.name) >= 0) { return false; }
let result = true;
e.eachChild((arg) => {
if (result && !isZoomConstant(arg)) { result = false; }
if (result && !isGlobalPropertyConstant(arg, properties)) { result = false; }
});
return result;
}

module.exports = {
isFeatureConstant,
isZoomConstant,
isGlobalPropertyConstant,
};
5 changes: 3 additions & 2 deletions src/style-spec/function/parse_expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function parseExpression(expr: mixed, context: ParsingContext): ?Expression {
function isConstant(expression: Expression) {
// requires within function body to workaround circular dependency
const {CompoundExpression} = require('./compound_expression');
const {isZoomConstant, isFeatureConstant} = require('./is_constant');
const {isGlobalPropertyConstant, isFeatureConstant} = require('./is_constant');
const Var = require('./definitions/var');

if (expression instanceof Var) {
Expand All @@ -106,7 +106,8 @@ function isConstant(expression: Expression) {
return false;
}

return isZoomConstant(expression) && isFeatureConstant(expression);
return isFeatureConstant(expression) &&
isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density']);
}

module.exports = parseExpression;
9 changes: 5 additions & 4 deletions src/style/light.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const StyleDeclaration = require('./style_declaration');
const StyleTransition = require('./style_transition');

import type AnimationLoop from './animation_loop';
import type {GlobalProperties} from './style_layer';

const TRANSITION_SUFFIX = '-transition';
const properties = ['anchor', 'color', 'position', 'intensity'];
Expand Down Expand Up @@ -42,7 +43,7 @@ class Light extends Evented {
}, lightOpts);

for (const prop of properties) {
this._declarations[prop] = new StyleDeclaration(specifications[prop], lightOpts[prop]);
this._declarations[prop] = new StyleDeclaration(specifications[prop], lightOpts[prop], prop);
}

return this;
Expand Down Expand Up @@ -70,7 +71,7 @@ class Light extends Evented {
}
}

getLightValue(property: string, globalProperties: {zoom: number}) {
getLightValue(property: string, globalProperties: GlobalProperties) {
if (property === 'position') {
const calculated: any = this._transitions[property].calculate(globalProperties),
cartesian = util.sphericalToCartesian(calculated);
Expand All @@ -95,7 +96,7 @@ class Light extends Evented {
} else if (value === null || value === undefined) {
delete this._declarations[key];
} else {
this._declarations[key] = new StyleDeclaration(specifications[key], value);
this._declarations[key] = new StyleDeclaration(specifications[key], value, key);
}
}
}
Expand All @@ -111,7 +112,7 @@ class Light extends Evented {
const spec = specifications[property];

if (declaration === null || declaration === undefined) {
declaration = new StyleDeclaration(spec, spec.default);
declaration = new StyleDeclaration(spec, spec.default, property);
}

if (oldTransition && oldTransition.declaration.json === declaration.json) return;
Expand Down
4 changes: 2 additions & 2 deletions src/style/style_declaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ class StyleDeclaration {
minimum: number;
function: StyleFunction;

constructor(reference: any, value: any) {
constructor(reference: any, value: any, name: string) {
this.value = util.clone(value);
this.isFunction = createFunction.isFunctionDefinition(value);

// immutable representation of value. used for comparison
this.json = JSON.stringify(this.value);

this.minimum = reference.minimum;
this.function = createFunction(this.value, reference);
this.function = createFunction(this.value, reference, name);
}

calculate(globalProperties: {+zoom?: number} = {}, feature?: Feature) {
Expand Down
9 changes: 5 additions & 4 deletions src/style/style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import type {Feature} from '../style-spec/function';
import type RenderTexture from '../render/render_texture';

export type GlobalProperties = {
zoom: number
zoom?: number,
heatmapDensity?: number
};

export type FeatureProperties = {
Expand Down Expand Up @@ -117,7 +118,7 @@ class StyleLayer extends Evented {
} else {
const key = `layers.${this.id}.layout.${name}`;
if (this._validate(validateStyle.layoutProperty, key, name, value, options)) return;
this._layoutDeclarations[name] = new StyleDeclaration(this._layoutSpecifications[name], value);
this._layoutDeclarations[name] = new StyleDeclaration(this._layoutSpecifications[name], value, name);
}
this._updateLayoutValue(name);
}
Expand Down Expand Up @@ -161,7 +162,7 @@ class StyleLayer extends Evented {
delete this._paintDeclarations[klass || ''][name];
} else {
if (this._validate(validateStyle.paintProperty, validateStyleKey, name, value, options)) return;
this._paintDeclarations[klass || ''][name] = new StyleDeclaration(this._paintSpecifications[name], value);
this._paintDeclarations[klass || ''][name] = new StyleDeclaration(this._paintSpecifications[name], value, name);
}
}
}
Expand Down Expand Up @@ -284,7 +285,7 @@ class StyleLayer extends Evented {
const spec = this._paintSpecifications[name];

if (declaration === null || declaration === undefined) {
declaration = new StyleDeclaration(spec, spec.default);
declaration = new StyleDeclaration(spec, spec.default, name);
}

if (oldTransition && oldTransition.declaration.json === declaration.json) return;
Expand Down
2 changes: 1 addition & 1 deletion src/style/style_layer/heatmap_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class HeatmapStyleLayer extends StyleLayer {
if (name === 'heatmap-color') {
const len = this.colorRampData.length;
for (let i = 4; i < len; i += 4) {
const pxColor = this.getPaintValue('heatmap-color', {zoom: i / len});
const pxColor = this.getPaintValue('heatmap-color', {heatmapDensity: i / len});
const alpha = pxColor[3];
// the colors are being unpremultiplied because getPaintValue returns
// premultiplied values, and the Texture class expects unpremultiplied ones
Expand Down
5 changes: 3 additions & 2 deletions src/style/style_transition.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const interpolate = require('../style-spec/util/interpolate');

import type StyleDeclaration from './style_declaration';
import type {Feature} from '../style-spec/function';
import type {GlobalProperties} from '../style/style_layer';

const fakeZoomHistory = { lastIntegerZoom: 0, lastIntegerZoomTime: 0, lastZoom: 0 };

Expand Down Expand Up @@ -58,7 +59,7 @@ class StyleTransition {
/*
* Return the value of the transitioning property.
*/
calculate(globalProperties?: {zoom: number}, feature?: Feature, time?: number) {
calculate(globalProperties?: GlobalProperties, feature?: Feature, time?: number) {
const value = this._calculateTargetValue(globalProperties, feature);

if (this.instant())
Expand All @@ -74,7 +75,7 @@ class StyleTransition {
return this.interp(oldValue, value, t);
}

_calculateTargetValue(globalProperties?: {zoom: number}, feature?: Feature) {
_calculateTargetValue(globalProperties?: GlobalProperties, feature?: Feature) {
if (!this.zoomTransitioned)
return this.declaration.calculate(globalProperties, feature);

Expand Down

0 comments on commit 5059738

Please sign in to comment.