Add line.dash support to scattermap traces by CloudCorpRecords · Pull Request #8135 · plotly/plotly.js · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions draftlogs/8135_add.md
6 changes: 2 additions & 4 deletions src/traces/scattermap/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,8 @@ module.exports = overrideAll(

line: {
color: lineAttrs.color,
width: lineAttrs.width

// TODO
// dash: dash
width: lineAttrs.width,
dash: lineAttrs.dash
},

connectgaps: scatterAttrs.connectgaps,
Expand Down
14 changes: 13 additions & 1 deletion src/traces/scattermap/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,19 @@ module.exports = function convert(gd, calcTrace) {
'line-opacity': trace.opacity
});

// TODO convert line.dash into line-dasharray
// MapLibre scales line-dasharray lengths by the line width, so reuse
// the px dash lengths from Drawing.dashStyle and convert them back
// to line-width units. 'solid' yields an empty string: no dasharray.
const dashPx = Drawing.dashStyle(trace.line.dash, trace.line.width);
if(dashPx) {
const w = trace.line.width || 1;
const dashArray = dashPx.split(/[\s,]+/)
.map(s => parseFloat(s) / w)
.filter(v => isFinite(v) && v >= 0);
if(dashArray.length) {
line.paint['line-dasharray'] = dashArray;
}
}
}

if (hasCircles) {
Expand Down
2 changes: 1 addition & 1 deletion src/traces/scattermap/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
}

if (subTypes.hasLines(traceOut)) {
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce, { noDash: true });
handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce);
coerce('connectgaps');
}

Expand Down
16 changes: 15 additions & 1 deletion src/types/generated/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8774,7 +8774,21 @@ export interface ScattermapData {
* Minimum: 0
*/
legendwidth?: number;
line?: _internal.ErrorY;
line?: {
/** Sets the line color. */
color?: Color;
/**
* Sets the dash style of lines. Set to a dash type string (*solid*, *dot*, *dash*, *longdash*, *dashdot*, or *longdashdot*) or a dash length list in px (eg *5px,10px,2px,2px*).
* @default 'solid'
*/
dash?: Dash;
/**
* Sets the line width (in px).
* @default 2
* Minimum: 0
*/
width?: number;
};
/** Sets the longitude coordinates (in degrees East). */
lon?: Datum[] | Datum[][] | TypedArray;
marker?: {
Expand Down
38 changes: 38 additions & 0 deletions test/image/mocks/map_line-dash.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"data": [
{
"lat": [30, 20, 10, 20],
"line": { "width": 4 },
"lon": [10, 20, 30, 40],
"mode": "lines",
"name": "solid",
"type": "scattermap"
},
{
"lat": [20, 10, 0, 10],
"line": { "dash": "dash", "width": 4 },
"lon": [10, 20, 30, 40],
"mode": "lines",
"name": "dash",
"type": "scattermap"
},
{
"lat": [10, 0, -10, 0],
"line": { "dash": "dot", "width": 4 },
"lon": [10, 20, 30, 40],
"mode": "lines",
"name": "dot",
"type": "scattermap"
}
],
"layout": {
"autosize": true,
"height": 450,
"map": {
"center": { "lat": 10, "lon": 25 },
"style": "streets",
"zoom": 1.5
},
"width": 700
}
}
42 changes: 42 additions & 0 deletions test/jasmine/tests/scattermap_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,25 @@ describe('scattermap defaults', function() {
expect(fullTrace.marker).toBeDefined();
expect(fullTrace.marker.line).toBeUndefined();
});

it('should default \'line.dash\' to \'solid\' and coerce named dash styles', function() {
const solidTrace = _supply({
mode: 'lines',
lon: [1, 2, 3],
lat: [2, 3, 3]
});

expect(solidTrace.line.dash).toBe('solid', 'default dash');

const dashedTrace = _supply({
mode: 'lines',
lon: [1, 2, 3],
lat: [2, 3, 3],
line: {dash: 'dashdot'}
});

expect(dashedTrace.line.dash).toBe('dashdot', 'coerced dash');
});
});

describe('scattermap convert', function() {
Expand Down Expand Up @@ -592,6 +611,29 @@ describe('scattermap convert', function() {
expect(opts.line.geojson.coordinates).toEqual(lineCoords, 'have correct line coords');
});

it('should convert \'line.dash\' to a MapLibre \'line-dasharray\' paint value', function() {
const dasharrayOf = (line) => {
const opts = _convert(Lib.extendFlat({}, base, {
mode: 'lines',
line: line
}));
return opts.line.paint['line-dasharray'];
};

// 'solid' (the default) leaves line-dasharray unset
expect(dasharrayOf({})).toBe(undefined, 'default solid');
expect(dasharrayOf({dash: 'solid'})).toBe(undefined, 'explicit solid');

// named styles mirror the SVG dash lengths from Drawing.dashStyle,
// expressed in line-width units (MapLibre scales them by line width)
expect(dasharrayOf({dash: 'dash', width: 2})).toEqual([4.5, 4.5], 'dash style');
expect(dasharrayOf({dash: 'dot', width: 4})).toEqual([1, 1], 'dot style');
expect(dasharrayOf({dash: 'longdashdot', width: 2})).toEqual([7.5, 3, 1.5, 3], 'longdashdot style');

// custom px dash lists are honored, converted to line-width units
expect(dasharrayOf({dash: '5px,10px,2px,2px', width: 2})).toEqual([2.5, 5, 1, 1], 'custom px list');
});

it('should correctly convert \'textposition\' to \'text-anchor\' and \'text-offset\'', function() {
var specs = {
'top left': ['top-right', [-0.65, -1.65]],
Expand Down
14 changes: 14 additions & 0 deletions test/plot-schema.json