Skip to content

Commit d135fff

Browse files
authored
Merge pull request #6990 from plotly/font-weight-integer
Add support for numeric font `weight`
2 parents 8cb1191 + 48d057f commit d135fff

36 files changed

+3855
-1059
lines changed

draftlogs/6990_add.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Add support for numeric text font `weight` [[#6990](https://github.com/plotly/plotly.js/pull/6990)]

src/lib/coerce.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ exports.valObjectMeta = {
100100
requiredOpts: [],
101101
otherOpts: ['dflt', 'min', 'max', 'arrayOk'],
102102
coerceFunction: function(v, propOut, dflt, opts) {
103+
if(isTypedArraySpec(v)) v = decodeTypedArraySpec(v);
104+
103105
if(!isNumeric(v) ||
104106
(opts.min !== undefined && v < opts.min) ||
105107
(opts.max !== undefined && v > opts.max)) {
@@ -114,8 +116,15 @@ exports.valObjectMeta = {
114116
'are coerced to the `dflt`.'
115117
].join(' '),
116118
requiredOpts: [],
117-
otherOpts: ['dflt', 'min', 'max', 'arrayOk'],
119+
otherOpts: ['dflt', 'min', 'max', 'arrayOk', 'extras'],
118120
coerceFunction: function(v, propOut, dflt, opts) {
121+
if((opts.extras || []).indexOf(v) !== -1) {
122+
propOut.set(v);
123+
return;
124+
}
125+
126+
if(isTypedArraySpec(v)) v = decodeTypedArraySpec(v);
127+
119128
if(v % 1 || !isNumeric(v) ||
120129
(opts.min !== undefined && v < opts.min) ||
121130
(opts.max !== undefined && v > opts.max)) {
@@ -156,6 +165,8 @@ exports.valObjectMeta = {
156165
requiredOpts: [],
157166
otherOpts: ['dflt', 'arrayOk'],
158167
coerceFunction: function(v, propOut, dflt) {
168+
if(isTypedArraySpec(v)) v = decodeTypedArraySpec(v);
169+
159170
if(tinycolor(v).isValid()) propOut.set(v);
160171
else propOut.set(dflt);
161172
}
@@ -198,6 +209,8 @@ exports.valObjectMeta = {
198209
requiredOpts: [],
199210
otherOpts: ['dflt', 'arrayOk'],
200211
coerceFunction: function(v, propOut, dflt) {
212+
if(isTypedArraySpec(v)) v = decodeTypedArraySpec(v);
213+
201214
if(v === 'auto') propOut.set('auto');
202215
else if(!isNumeric(v)) propOut.set(dflt);
203216
else propOut.set(modHalf(+v, 360));

src/plots/font_attributes.js

+22-9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ module.exports = function(opts) {
2020
var editType = opts.editType;
2121
var colorEditType = opts.colorEditType;
2222
if(colorEditType === undefined) colorEditType = editType;
23+
24+
var weight = {
25+
editType: editType,
26+
valType: 'integer',
27+
min: 1,
28+
max: 1000,
29+
extras: ['normal', 'bold'],
30+
dflt: 'normal',
31+
description: [
32+
'Sets the weight (or boldness) of the font.'
33+
].join(' ')
34+
};
35+
36+
if(opts.noNumericWeightValues) {
37+
weight.valType = 'enumerated';
38+
weight.values = weight.extras;
39+
weight.extras = undefined;
40+
weight.min = undefined;
41+
weight.max = undefined;
42+
}
43+
2344
var attrs = {
2445
family: {
2546
valType: 'string',
@@ -49,15 +70,7 @@ module.exports = function(opts) {
4970
editType: colorEditType
5071
},
5172

52-
weight: {
53-
editType: editType,
54-
valType: 'enumerated',
55-
values: ['normal', 'bold'],
56-
dflt: 'normal',
57-
description: [
58-
'Sets the weight (or boldness) of the font.'
59-
].join(' ')
60-
},
73+
weight: weight,
6174

6275
style: {
6376
editType: editType,

src/snapshot/tosvg.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ module.exports = function toSVG(gd, format, scale) {
107107

108108
// Drop normal font-weight, font-style and font-variant to reduce the size
109109
var fw = this.style.fontWeight;
110-
if(fw && fw === 'normal') {
110+
if(fw && (fw === 'normal' || fw === '400')) { // font-weight 400 is similar to normal
111111
txt.style('font-weight', undefined);
112112
}
113113
var fs = this.style.fontStyle;

src/traces/scattergl/attributes.js

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var attrs = module.exports = overrideAll({
4141
editType: 'calc',
4242
colorEditType: 'style',
4343
arrayOk: true,
44+
noNumericWeightValues: true,
4445
variantValues: ['normal', 'small-caps'],
4546
description: 'Sets the text font.'
4647
}),

src/traces/scattergl/convert.js

+11-3
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ function convertTextStyle(gd, trace) {
190190
if(
191191
isArrayOrTypedArray(tfs) ||
192192
Array.isArray(tff) ||
193-
Array.isArray(tfw) ||
193+
isArrayOrTypedArray(tfw) ||
194194
Array.isArray(tfy) ||
195195
Array.isArray(tfv)
196196
) {
@@ -207,7 +207,7 @@ function convertTextStyle(gd, trace) {
207207
) * plotGlPixelRatio;
208208

209209
fonti.family = Array.isArray(tff) ? tff[i] : tff;
210-
fonti.weight = Array.isArray(tfw) ? tfw[i] : tfw;
210+
fonti.weight = weightFallBack(isArrayOrTypedArray(tfw) ? tfw[i] : tfw);
211211
fonti.style = Array.isArray(tfy) ? tfy[i] : tfy;
212212
fonti.variant = Array.isArray(tfv) ? tfv[i] : tfv;
213213
}
@@ -216,7 +216,7 @@ function convertTextStyle(gd, trace) {
216216
optsOut.font = {
217217
size: tfs * plotGlPixelRatio,
218218
family: tff,
219-
weight: tfw,
219+
weight: weightFallBack(tfw),
220220
style: tfy,
221221
variant: tfv
222222
};
@@ -225,6 +225,14 @@ function convertTextStyle(gd, trace) {
225225
return optsOut;
226226
}
227227

228+
// scattergl rendering pipeline has limited support of numeric weight values
229+
// Here we map the numbers to be either bold or normal.
230+
function weightFallBack(w) {
231+
if(w <= 1000) {
232+
return w > 500 ? 'bold' : 'normal';
233+
}
234+
return w;
235+
}
228236

229237
function convertMarkerStyle(gd, trace) {
230238
var count = trace._length;

src/traces/scattermapbox/constants.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
// Must use one of the following fonts as the family, else default to 'Open Sans Regular'
4+
// See https://github.com/openmaptiles/fonts/blob/gh-pages/fontstacks.json
5+
var supportedFonts = [
6+
'Metropolis Black Italic',
7+
'Metropolis Black',
8+
'Metropolis Bold Italic',
9+
'Metropolis Bold',
10+
'Metropolis Extra Bold Italic',
11+
'Metropolis Extra Bold',
12+
'Metropolis Extra Light Italic',
13+
'Metropolis Extra Light',
14+
'Metropolis Light Italic',
15+
'Metropolis Light',
16+
'Metropolis Medium Italic',
17+
'Metropolis Medium',
18+
'Metropolis Regular Italic',
19+
'Metropolis Regular',
20+
'Metropolis Semi Bold Italic',
21+
'Metropolis Semi Bold',
22+
'Metropolis Thin Italic',
23+
'Metropolis Thin',
24+
'Open Sans Bold Italic',
25+
'Open Sans Bold',
26+
'Open Sans Extrabold Italic',
27+
'Open Sans Extrabold',
28+
'Open Sans Italic',
29+
'Open Sans Light Italic',
30+
'Open Sans Light',
31+
'Open Sans Regular',
32+
'Open Sans Semibold Italic',
33+
'Open Sans Semibold',
34+
'Klokantech Noto Sans Bold',
35+
'Klokantech Noto Sans CJK Bold',
36+
'Klokantech Noto Sans CJK Regular',
37+
'Klokantech Noto Sans Italic',
38+
'Klokantech Noto Sans Regular'
39+
];
40+
41+
module.exports = {
42+
isSupportedFont: function(a) {
43+
return supportedFonts.indexOf(a) !== -1;
44+
}
45+
};

src/traces/scattermapbox/convert.js

+54-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var Colorscale = require('../../components/colorscale');
1010
var Drawing = require('../../components/drawing');
1111
var makeBubbleSizeFn = require('../scatter/make_bubble_size_func');
1212
var subTypes = require('../scatter/subtypes');
13+
var isSupportedFont = require('./constants').isSupportedFont;
1314
var convertTextOpts = require('../../plots/mapbox/convert_text_opts');
1415
var appendArrayPointValue = require('../../components/fx/helpers').appendArrayPointValue;
1516

@@ -369,11 +370,58 @@ function arrayifyAttribute(values, step) {
369370

370371
function getTextFont(trace) {
371372
var font = trace.textfont;
372-
var str = '';
373-
if(font.weight === 'bold') str += ' Bold';
374-
if(font.style === 'italic') str += ' Italic';
375-
var textFont = font.family;
376-
if(str) textFont = textFont.replace(' Regular', str);
377-
textFont = textFont.split(', ');
373+
var family = font.family;
374+
var style = font.style;
375+
var weight = font.weight;
376+
377+
var parts = family.split(' ');
378+
var isItalic = parts[parts.length - 1] === 'Italic';
379+
if(isItalic) parts.pop();
380+
isItalic = isItalic || style === 'italic';
381+
382+
var str = parts.join(' ');
383+
if(weight === 'bold' && parts.indexOf('Bold') === -1) {
384+
str += ' Bold';
385+
} else if(weight <= 1000) { // numeric font-weight
386+
// See supportedFonts
387+
388+
if(parts[0] === 'Metropolis') {
389+
str = 'Metropolis';
390+
if(weight > 850) str += ' Black';
391+
else if(weight > 750) str += ' Extra Bold';
392+
else if(weight > 650) str += ' Bold';
393+
else if(weight > 550) str += ' Semi Bold';
394+
else if(weight > 450) str += ' Medium';
395+
else if(weight > 350) str += ' Regular';
396+
else if(weight > 250) str += ' Light';
397+
else if(weight > 150) str += ' Extra Light';
398+
else str += ' Thin';
399+
} else if(parts.slice(0, 2).join(' ') === 'Open Sans') {
400+
str = 'Open Sans';
401+
if(weight > 750) str += ' Extrabold';
402+
else if(weight > 650) str += ' Bold';
403+
else if(weight > 550) str += ' Semibold';
404+
else if(weight > 350) str += ' Regular';
405+
else str += ' Light';
406+
} else if(parts.slice(0, 3).join(' ') === 'Klokantech Noto Sans') {
407+
str = 'Klokantech Noto Sans';
408+
if(parts[3] === 'CJK') str += ' CJK';
409+
str += (weight > 500) ? ' Bold' : ' Regular';
410+
}
411+
}
412+
413+
if(isItalic) str += ' Italic';
414+
415+
if(str === 'Open Sans Regular Italic') str = 'Open Sans Italic';
416+
else if(str === 'Open Sans Regular Bold') str = 'Open Sans Bold';
417+
else if(str === 'Open Sans Regular Bold Italic') str = 'Open Sans Bold Italic';
418+
else if(str === 'Klokantech Noto Sans Regular Italic') str = 'Klokantech Noto Sans Italic';
419+
420+
// Ensure the result is a supported font
421+
if(!isSupportedFont(str)) {
422+
str = family;
423+
}
424+
425+
var textFont = str.split(', ');
378426
return textFont;
379427
}

src/traces/scattermapbox/defaults.js

+4-39
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,7 @@ var handleLineDefaults = require('../scatter/line_defaults');
88
var handleTextDefaults = require('../scatter/text_defaults');
99
var handleFillColorDefaults = require('../scatter/fillcolor_defaults');
1010
var attributes = require('./attributes');
11-
12-
// Must use one of the following fonts as the family, else default to 'Open Sans Regular'
13-
// See https://github.com/openmaptiles/fonts/blob/gh-pages/fontstacks.json
14-
var supportedFonts = [
15-
'Metropolis Black Italic',
16-
'Metropolis Black',
17-
'Metropolis Bold Italic',
18-
'Metropolis Bold',
19-
'Metropolis Extra Bold Italic',
20-
'Metropolis Extra Bold',
21-
'Metropolis Extra Light Italic',
22-
'Metropolis Extra Light',
23-
'Metropolis Light Italic',
24-
'Metropolis Light',
25-
'Metropolis Medium Italic',
26-
'Metropolis Medium',
27-
'Metropolis Regular Italic',
28-
'Metropolis Regular',
29-
'Metropolis Semi Bold Italic',
30-
'Metropolis Semi Bold',
31-
'Metropolis Thin Italic',
32-
'Metropolis Thin',
33-
'Open Sans Bold Italic',
34-
'Open Sans Bold',
35-
'Open Sans Extra Bold Italic',
36-
'Open Sans Extra Bold',
37-
'Open Sans Italic',
38-
'Open Sans Light Italic',
39-
'Open Sans Light',
40-
'Open Sans Regular',
41-
'Open Sans Semibold Italic',
42-
'Open Sans Semibold',
43-
'Klokantech Noto Sans Bold',
44-
'Klokantech Noto Sans CJK Bold',
45-
'Klokantech Noto Sans CJK Regular',
46-
'Klokantech Noto Sans Italic',
47-
'Klokantech Noto Sans Regular'
48-
];
11+
var isSupportedFont = require('./constants').isSupportedFont;
4912

5013
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
5114
function coerce(attr, dflt) {
@@ -104,12 +67,14 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
10467
var clusterEnabled = coerce('cluster.enabled', clusterEnabledDflt);
10568

10669
if(clusterEnabled || subTypes.hasText(traceOut)) {
70+
var layoutFontFamily = layout.font.family;
71+
10772
handleTextDefaults(traceIn, traceOut, layout, coerce,
10873
{
10974
noSelect: true,
11075
noFontVariant: true,
11176
font: {
112-
family: supportedFonts.indexOf(layout.font.family) !== -1 ? layout.font.family : 'Open Sans Regular',
77+
family: isSupportedFont(layoutFontFamily) ? layoutFontFamily : 'Open Sans Regular',
11378
weight: layout.font.weight,
11479
style: layout.font.style,
11580
size: layout.font.size,

0 commit comments

Comments
 (0)