Skip to content

Commit

Permalink
Add interpolate-{hcl,lab} expression operators
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed Aug 14, 2018
1 parent 3d879b2 commit 7d67106
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 7 deletions.
18 changes: 18 additions & 0 deletions docs/components/expression-metadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ const types = {
'stop_input_n: number, stop_output_n: OutputType, ...'
]
}],
'interpolate-hcl': [{
type: 'Color',
parameters: [
'interpolation: ["linear"] | ["exponential", base] | ["cubic-bezier", x1, y1, x2, y2 ]',
'input: number',
'stop_input_1: number, stop_output_1: Color',
'stop_input_n: number, stop_output_n: Color, ...'
]
}],
'interpolate-lab': [{
type: 'Color',
parameters: [
'interpolation: ["linear"] | ["exponential", base] | ["cubic-bezier", x1, y1, x2, y2 ]',
'input: number',
'stop_input_1: number, stop_output_1: Color',
'stop_input_n: number, stop_output_n: Color, ...'
]
}],
length: [{
type: 'number',
parameters: ['string | array | value']
Expand Down
2 changes: 2 additions & 0 deletions src/style-spec/expression/definitions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ const expressions: ExpressionRegistry = {
'collator': CollatorExpression,
'format': FormatExpression,
'interpolate': Interpolate,
'interpolate-hcl': Interpolate,
'interpolate-lab': Interpolate,
'length': Length,
'let': Let,
'literal': Literal,
Expand Down
25 changes: 18 additions & 7 deletions src/style-spec/expression/definitions/interpolate.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import UnitBezier from '@mapbox/unitbezier';

import * as interpolate from '../../util/interpolate';
import { toString, NumberType } from '../types';
import { toString, NumberType, ColorType } from '../types';
import { findStopLessThanOrEqualTo } from '../stops';
import { hcl, lab } from '../../util/color_spaces';

import type { Stops } from '../stops';
import type { Expression } from '../expression';
Expand All @@ -21,13 +22,15 @@ export type InterpolationType =
class Interpolate implements Expression {
type: Type;

operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab';
interpolation: InterpolationType;
input: Expression;
labels: Array<number>;
outputs: Array<Expression>;

constructor(type: Type, interpolation: InterpolationType, input: Expression, stops: Stops) {
constructor(type: Type, operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab', interpolation: InterpolationType, input: Expression, stops: Stops) {
this.type = type;
this.operator = operator;
this.interpolation = interpolation;
this.input = input;

Expand All @@ -54,7 +57,7 @@ class Interpolate implements Expression {
}

static parse(args: Array<mixed>, context: ParsingContext) {
let [ , interpolation, input, ...rest] = args;
let [operator, interpolation, input, ...rest] = args;

if (!Array.isArray(interpolation) || interpolation.length === 0) {
return context.error(`Expected an interpolation type expression.`, 1);
Expand Down Expand Up @@ -101,7 +104,9 @@ class Interpolate implements Expression {
const stops: Stops = [];

let outputType: Type = (null: any);
if (context.expectedType && context.expectedType.kind !== 'value') {
if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
outputType = ColorType;
} else if (context.expectedType && context.expectedType.kind !== 'value') {
outputType = context.expectedType;
}

Expand Down Expand Up @@ -137,7 +142,7 @@ class Interpolate implements Expression {
return context.error(`Type ${toString(outputType)} is not interpolatable.`);
}

return new Interpolate(outputType, interpolation, input, stops);
return new Interpolate(outputType, (operator: any), interpolation, input, stops);
}

evaluate(ctx: EvaluationContext) {
Expand Down Expand Up @@ -166,7 +171,13 @@ class Interpolate implements Expression {
const outputLower = outputs[index].evaluate(ctx);
const outputUpper = outputs[index + 1].evaluate(ctx);

return (interpolate[this.type.kind.toLowerCase()]: any)(outputLower, outputUpper, t); // eslint-disable-line import/namespace
if (this.operator === 'interpolate') {
return (interpolate[this.type.kind.toLowerCase()]: any)(outputLower, outputUpper, t); // eslint-disable-line import/namespace
} else if (this.operator === 'interpolate-hcl') {
return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t));
} else {
return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t));
}
}

eachChild(fn: (Expression) => void) {
Expand Down Expand Up @@ -194,7 +205,7 @@ class Interpolate implements Expression {
interpolation = ["cubic-bezier" ].concat(this.interpolation.controlPoints);
}

const serialized = ["interpolate", interpolation, this.input.serialize()];
const serialized = [this.operator, interpolation, this.input.serialize()];

for (let i = 0; i < this.labels.length; i++) {
serialized.push(
Expand Down
18 changes: 18 additions & 0 deletions src/style-spec/reference/v8.json
Original file line number Diff line number Diff line change
Expand Up @@ -2405,6 +2405,24 @@
}
}
},
"interpolate-hcl": {
"doc": "Produces continuous, smooth results by interpolating between pairs of input and output values (\"stops\"). Works like `interpolate`, but the output type must be `color`, and the interpolation is performed in the Hue-Chroma-Luminance color space.",
"group": "Ramps, scales, curves",
"sdk-support": {
"basic functionality": {
"js": "0.49.0"
}
}
},
"interpolate-lab": {
"doc": "Produces continuous, smooth results by interpolating between pairs of input and output values (\"stops\"). Works like `interpolate`, but the output type must be `color`, and the interpolation is performed in the CIELAB color space.",
"group": "Ramps, scales, curves",
"sdk-support": {
"basic functionality": {
"js": "0.49.0"
}
}
},
"ln2": {
"doc": "Returns mathematical constant ln(2).",
"group": "Math",
Expand Down
40 changes: 40 additions & 0 deletions test/integration/expression-tests/interpolate-hcl/linear/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"expression": [
"interpolate-hcl",
["linear"],
["get", "x"],
1,
"red",
11,
["get", "color"]
],
"inputs": [
[{}, {"properties": {"x": 0, "color": "blue"}}],
[{}, {"properties": {"x": 5, "color": "blue"}}],
[{}, {"properties": {"x": 11, "color": "blue"}}],
[{}, {"properties": {"x": 11, "color": "oops blue"}}]
],
"expected": {
"compiled": {
"result": "success",
"isFeatureConstant": false,
"isZoomConstant": true,
"type": "color"
},
"outputs": [
[1, 0, 0, 1],
[0.870599, -0.0798922, 0.394264, 1],
[0, 0, 1, 1],
{"error": "Could not parse color from value 'oops blue'"}
],
"serialized": [
"interpolate-hcl",
["linear"],
["number", ["get", "x"]],
1,
["rgba", 255, 0, 0, 1],
11,
["to-color", ["get", "color"]]
]
}
}
40 changes: 40 additions & 0 deletions test/integration/expression-tests/interpolate-lab/linear/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"expression": [
"interpolate-lab",
["linear"],
["get", "x"],
1,
"red",
11,
["get", "color"]
],
"inputs": [
[{}, {"properties": {"x": 0, "color": "blue"}}],
[{}, {"properties": {"x": 5, "color": "blue"}}],
[{}, {"properties": {"x": 11, "color": "blue"}}],
[{}, {"properties": {"x": 11, "color": "oops blue"}}]
],
"expected": {
"compiled": {
"result": "success",
"isFeatureConstant": false,
"isZoomConstant": true,
"type": "color"
},
"outputs": [
[1, 0, 0, 1],
[0.599999, 7.22057e-8, 0.4, 1],
[0, 0, 1, 1],
{"error": "Could not parse color from value 'oops blue'"}
],
"serialized": [
"interpolate-lab",
["linear"],
["number", ["get", "x"]],
1,
["rgba", 255, 0, 0, 1],
11,
["to-color", ["get", "color"]]
]
}
}

0 comments on commit 7d67106

Please sign in to comment.