Skip to content

Commit

Permalink
Support dashed line in PathLayer (#898)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress committed Aug 31, 2017
1 parent 3236d11 commit a9ea02e
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 2 deletions.
15 changes: 15 additions & 0 deletions docs/layers/path-layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ Only works if `rounded` is `false`.

Whether the layer should be rendered in high-precision 64-bit mode

##### `justified` (Boolean, optional)

- Default: `false`

Only effective if `getDashArray` is specified. If `true`, adjust gaps for the dashes to align at both ends.

### Data Accessors

##### `getPath` (Function, optional)
Expand Down Expand Up @@ -106,6 +112,15 @@ If the color alpha (the fourth component) is not provided,
Method called to determine the width to draw each path with.
Unit is meters.

##### `getDashArray` (Function, optional)

- Default: `null`

Method called to get the dash array to draw each path with.
Returns an array of two numbers: `[dashSize, gapSize]` relative to the width of the path. Returns `[0, 0]` to draw the path in solid line.

If this accessor is not specified, all paths are drawn as solid lines.

## Source

[src/layers/core/path-layer](https://github.com/uber/deck.gl/tree/4.1-release/src/layers/core/path-layer)
Expand Down
4 changes: 4 additions & 0 deletions docs/whats-new.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ The new `useDevicePixelRatio` prop for DeckGL component can be used to toggle us
Three new props (`highlightColor`, `highlightedObjectIndex` and `autoHighlight`) are added to `Layer` class to support highlighting of a single object in a layer, either automatically on hover or through programmatically specifying a selected object. Note that this highlighting is done on GPU and is thus very performant.


## PathLayer: dashed line support

Added new props (`getDashArray` and `justified`) to render paths as dashed lines.

# deck.gl v4.1

Release date: July 27th, 2017
Expand Down
48 changes: 48 additions & 0 deletions src/layers/core/path-layer/path-layer-fragment.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,55 @@ precision highp float;
uniform float jointType;
uniform float miterLimit;
uniform float alignMode;
varying vec4 vColor;
varying vec2 vCornerOffset;
varying float vMiterLength;
varying vec2 vDashArray;
varying float vPathPosition;
varying float vPathLength;
// mod doesn't work correctly for negative numbers
float mod2(float a, float b) {
return a - floor(a / b) * b;
}
float round(float x) {
return floor(x + 0.5);
}
// if given position is in the gap part of the dashed line
// dashArray.x: solid stroke length, relative to width
// dashArray.y: gap length, relative to width
// alignMode:
// 0 - no adjustment
// o---- ---- ---- ---- o---- -o---- ---- o
// 1 - stretch to fit, draw half dash at each end for nicer joints
// o-- ---- ---- ---- --o-- --o-- ---- --o
bool dash_isFragInGap() {
float solidLength = vDashArray.x;
float gapLength = vDashArray.y;
float unitLength = solidLength + gapLength;
if (unitLength == 0.0) {
return false;
}
unitLength = mix(
unitLength,
vPathLength / round(vPathLength / unitLength),
alignMode
);
float offset = alignMode * solidLength / 2.0;
return gapLength > 0.0 &&
vPathPosition >= 0.0 &&
vPathPosition <= vPathLength &&
mod2(vPathPosition + offset, unitLength) > solidLength;
}
void main(void) {
// if joint is rounded, test distance from the corner
Expand All @@ -40,6 +85,9 @@ void main(void) {
if (jointType == 0.0 && vMiterLength > miterLimit) {
discard;
}
if (vColor.a == 0.0 || dash_isFragInGap()) {
discard;
}
gl_FragColor = vColor;
// use highlight color if this fragment belongs to the selected object.
Expand Down
12 changes: 12 additions & 0 deletions src/layers/core/path-layer/path-layer-vertex-64.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ attribute vec3 instanceRightDeltas;
attribute float instanceStrokeWidths;
attribute vec4 instanceColors;
attribute vec3 instancePickingColors;
attribute vec2 instanceDashArrays;
uniform float widthScale;
uniform float widthMinPixels;
Expand All @@ -44,6 +45,9 @@ uniform float opacity;
varying vec4 vColor;
varying vec2 vCornerOffset;
varying float vMiterLength;
varying vec2 vDashArray;
varying float vPathPosition;
varying float vPathLength;
const float EPSILON = 0.001;
Expand Down Expand Up @@ -163,6 +167,14 @@ vec3 lineJoin(vec2 prevPoint64[2], vec2 currPoint64[2], vec2 nextPoint64[2]) {
vCornerOffset = offsetVec * offsetDirection * offsetScale;
// Generate variables for dash calculation
vDashArray = instanceDashArrays;
vPathLength = L / width;
float isEnd = positions.x;
vec2 offsetFromStartOfPath = mix(vCornerOffset, vCornerOffset + deltaA / width, isEnd);
vec2 dir = mix(dirB, dirA, isEnd);
vPathPosition = dot(offsetFromStartOfPath, dir);
return vec3(vCornerOffset * width, 0.0);
}
Expand Down
12 changes: 12 additions & 0 deletions src/layers/core/path-layer/path-layer-vertex.glsl.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ attribute vec3 instanceRightDeltas;
attribute float instanceStrokeWidths;
attribute vec4 instanceColors;
attribute vec3 instancePickingColors;
attribute vec2 instanceDashArrays;
uniform float widthScale;
uniform float widthMinPixels;
Expand All @@ -42,6 +43,9 @@ uniform float opacity;
varying vec4 vColor;
varying vec2 vCornerOffset;
varying float vMiterLength;
varying vec2 vDashArray;
varying float vPathPosition;
varying float vPathLength;
const float EPSILON = 0.001;
Expand Down Expand Up @@ -150,6 +154,14 @@ vec3 lineJoin(vec3 prevPoint, vec3 currPoint, vec3 nextPoint) {
vCornerOffset = offsetVec * offsetDirection * offsetScale;
// Generate variables for dash calculation
vDashArray = instanceDashArrays;
vPathLength = L / width;
float isEnd = positions.x;
vec2 offsetFromStartOfPath = mix(vCornerOffset, vCornerOffset + deltaA / width, isEnd);
vec2 dir = mix(dirB, dirA, isEnd);
vPathPosition = dot(offsetFromStartOfPath, dir);
return currPoint + vec3(vCornerOffset * width, 0.0);
}
Expand Down
26 changes: 24 additions & 2 deletions src/layers/core/path-layer/path-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ const defaultProps = {
rounded: false,
miterLimit: 4,
fp64: false,
justified: false,

getPath: object => object.path,
getColor: object => object.color || DEFAULT_COLOR,
getWidth: object => object.width || 1
getWidth: object => object.width || 1,
getDashArray: null
};

const isClosed = path => {
Expand Down Expand Up @@ -68,6 +70,7 @@ export default class PathLayer extends Layer {
instanceLeftDeltas: {size: 3, update: this.calculateLeftDeltas},
instanceRightDeltas: {size: 3, update: this.calculateRightDeltas},
instanceStrokeWidths: {size: 1, accessor: 'getWidth', update: this.calculateStrokeWidths},
instanceDashArrays: {size: 2, accessor: 'getDashArray', update: this.calculateDashArrays},
instanceColors: {size: 4, type: GL.UNSIGNED_BYTE, accessor: 'getColor', update: this.calculateColors},
instancePickingColors: {size: 3, type: GL.UNSIGNED_BYTE, update: this.calculatePickingColors}
});
Expand Down Expand Up @@ -117,11 +120,12 @@ export default class PathLayer extends Layer {

draw({uniforms}) {
const {
rounded, miterLimit, widthScale, widthMinPixels, widthMaxPixels
rounded, miterLimit, widthScale, widthMinPixels, widthMaxPixels, justified
} = this.props;

this.state.model.render(Object.assign({}, uniforms, {
jointType: Number(rounded),
alignMode: Number(justified),
widthScale,
miterLimit,
widthMinPixels,
Expand Down Expand Up @@ -288,6 +292,24 @@ export default class PathLayer extends Layer {
});
}

calculateDashArrays(attribute) {
const {data, getDashArray} = this.props;
if (!getDashArray) {
return;
}

const {paths} = this.state;
const {value} = attribute;
let i = 0;
paths.forEach((path, index) => {
const dashArray = getDashArray(data[index], index);
for (let ptIndex = 1; ptIndex < path.length; ptIndex++) {
value[i++] = dashArray[0];
value[i++] = dashArray[1];
}
});
}

calculateColors(attribute) {
const {data, getColor} = this.props;
const {paths} = this.state;
Expand Down

0 comments on commit a9ea02e

Please sign in to comment.