Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add autotickangles property #6790

Merged
merged 36 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
264617b
drawLabels: don't attempt to re-fix label if it is already rotated by…
my-tien Nov 22, 2023
9170f25
axis autotickangles property
my-tien Nov 22, 2023
eb3c456
autotickangles: consider number of lines when calculating min angle
my-tien Nov 22, 2023
60aa918
Change 10.json to test autotickangles
my-tien Nov 22, 2023
b70ff86
autotickangles draftlog file
my-tien Nov 22, 2023
be99b12
Achieve compatibility with ES5
my-tien Nov 23, 2023
8ec9a45
Add `noAutotickangles` option for `handleTickLabelDefaults` calls out…
my-tien Nov 23, 2023
3fa1c78
drawLabels: don't assume autotickangles exists on axis.
my-tien Nov 23, 2023
6d2501b
Fix typo noAutickangles → noAutotickangles in ternay layout_defaults
my-tien Nov 23, 2023
3f08ba8
Remove unnecessary coerceNumber property from autotickangles
my-tien Nov 24, 2023
7ff8d92
Replace suspicious infinite loop test with check to never decrease th…
my-tien Nov 24, 2023
9473029
Fix backwards-compatibility
my-tien Nov 24, 2023
4b23f99
New 10.png baseline image for testing autotickangles
my-tien Nov 25, 2023
361f61b
Choose angle with smallest absolute cosine instead of largest absolut…
my-tien Nov 29, 2023
6d3e7bd
use info_array instead of data_array for autotickangles
my-tien Nov 29, 2023
896c247
Convert prevAngle to radians as well for calculations.
my-tien Dec 5, 2023
aa6d492
Use the radians representation of prevAngle only for comparison (to f…
my-tien Dec 5, 2023
8ebf1a2
For the backwards-compatible auto angle calculation also only use rad…
my-tien Dec 5, 2023
0fdf52e
Revert description change for tickangle because other charts reusing …
my-tien Dec 8, 2023
a9b9cc8
Update description in test/plot-schema.json as well.
my-tien Dec 8, 2023
b8a8860
update plot-schema.json by running npm run schema after having starte…
my-tien Dec 8, 2023
c0e2758
Update draftlogs/6790_add.md
my-tien Dec 8, 2023
cdae996
Revert 264617bffe0252b11638e7446c6f3d562df70774 and 7ff8d92650d35f0be…
my-tien Dec 19, 2023
80dedea
Revert "Fix backwards-compatibility"
my-tien Jan 24, 2024
a5b1f3a
Add 0 to default autotickangles array
my-tien Jan 25, 2024
5f3f32c
Don't assume autotickangles exists on axis.
my-tien Jan 25, 2024
f544c2a
update baseline images and plot schema
my-tien Jan 25, 2024
7d8e607
- only coerce autotickangles for x axes with auto tickangle
alexcjohnson Jan 26, 2024
e20de82
fix colorbar noAutotickangles
alexcjohnson Jan 26, 2024
4d4e056
better colorbar fix: noAutotickangles only for vertical
alexcjohnson Jan 26, 2024
84bd54b
allow autotickangles for polar radial axes
alexcjohnson Jan 26, 2024
f646c15
schema update
my-tien Jan 26, 2024
1d47d05
new baseline image for polar_polygon-grids with rotated axis labels
my-tien Jan 26, 2024
2f6cd6f
fix jasmine tests
alexcjohnson Jan 26, 2024
c51791e
Update test/jasmine/tests/plots_test.js
archmoj Jan 26, 2024
b293a11
Update draftlogs/6790_add.md
archmoj Jan 26, 2024
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/6790_add.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add `autotickangles` to cartesian axes [[#6790](https://github.com/plotly/plotly.js/pull/6790)], with thanks to @my-tien for the contribution!
archmoj marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 5 additions & 1 deletion src/components/colorbar/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ module.exports = function colorbarDefaults(containerIn, containerOut, layout) {
handleTickValueDefaults(colorbarIn, colorbarOut, coerce, 'linear');

var font = layout.font;
var opts = {outerTicks: false, font: font};
var opts = {
noAutotickangles: true,
outerTicks: false,
font: font
};
if(ticklabelposition.indexOf('inside') !== -1) {
opts.bgColor = 'black'; // could we instead use the average of colors in the scale?
}
Expand Down
1 change: 1 addition & 0 deletions src/components/colorbar/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ function mockColorBarAxis(gd, opts, zrange) {
var axisOptions = {
letter: letter,
font: fullLayout.font,
noAutotickangles: letter === 'y',
noHover: true,
noTickson: true,
noTicklabelmode: true,
Expand Down
36 changes: 28 additions & 8 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3472,13 +3472,13 @@ axes.drawLabels = function(gd, ax, opts) {

var fullLayout = gd._fullLayout;
var axId = ax._id;
var axLetter = axId.charAt(0);
var cls = opts.cls || axId + 'tick';

var vals = opts.vals.filter(function(d) { return d.text; });

var labelFns = opts.labelFns;
var tickAngle = opts.secondary ? 0 : ax.tickangle;

var prevAngle = (ax._prevTickAngles || {})[cls];

var tickLabels = opts.layer.selectAll('g.' + cls)
Expand Down Expand Up @@ -3719,21 +3719,22 @@ axes.drawLabels = function(gd, ax, opts) {
// check for auto-angling if x labels overlap
// don't auto-angle at all for log axes with
// base and digit format
if(vals.length && axLetter === 'x' && !isNumeric(tickAngle) &&
if(vals.length && ax.autotickangles &&
(ax.type !== 'log' || String(ax.dtick).charAt(0) !== 'D')
) {
autoangle = 0;
autoangle = ax.autotickangles[0];

var maxFontSize = 0;
var lbbArray = [];
var i;

var maxLines = 1;
tickLabels.each(function(d) {
maxFontSize = Math.max(maxFontSize, d.fontSize);

var x = ax.l2p(d.x);
var thisLabel = selectTickLabel(this);
var bb = Drawing.bBox(thisLabel.node());
maxLines = Math.max(maxLines, svgTextUtils.lineCount(thisLabel));

lbbArray.push({
// ignore about y, just deal with x overlaps
Expand Down Expand Up @@ -3780,12 +3781,31 @@ axes.drawLabels = function(gd, ax, opts) {
var pad = !isAligned ? 0 :
(ax.tickwidth || 0) + 2 * TEXTPAD;

var rotate90 = (tickSpacing < maxFontSize * 2.5) || ax.type === 'multicategory' || ax._name === 'realaxis';
// autotickangles
var adjacent = tickSpacing;
var opposite = maxFontSize * 1.25 * maxLines;
var hypotenuse = Math.sqrt(Math.pow(adjacent, 2) + Math.pow(opposite, 2));
var maxCos = adjacent / hypotenuse;
var autoTickAnglesRadians = ax.autotickangles.map(
function(degrees) { return degrees * Math.PI / 180; }
);
var angleRadians = autoTickAnglesRadians.find(
function(angle) { return Math.abs(Math.cos(angle)) <= maxCos; }
);
if(angleRadians === undefined) {
// no angle with smaller cosine than maxCos, just pick the angle with smallest cosine
angleRadians = autoTickAnglesRadians.reduce(
function(currentMax, nextAngle) {
return Math.abs(Math.cos(currentMax)) < Math.abs(Math.cos(nextAngle)) ? currentMax : nextAngle;
}
, autoTickAnglesRadians[0]
);
}
var newAngle = angleRadians * (180 / Math.PI /* to degrees */);

// any overlap at all - set 30 degrees or 90 degrees
for(i = 0; i < lbbArray.length - 1; i++) {
if(Lib.bBoxIntersect(lbbArray[i], lbbArray[i + 1], pad)) {
autoangle = rotate90 ? 90 : 30;
autoangle = newAngle;
break;
}
}
Expand All @@ -3807,7 +3827,7 @@ axes.drawLabels = function(gd, ax, opts) {
// by rotating 90 degrees, do not attempt to re-fix its label overlaps
// as this can lead to infinite redraw loops!
if(ax.automargin && fullLayout._redrawFromAutoMarginCount && prevAngle === 90) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it is safe to remove this block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed this because of the first comment at the top of this PR. Have you checked that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I see the PR description. But still I thought that it might be something @alexcjohnson could have a second look.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH, this isn't even related to the feature I made. The discussion only started because I changed the check prevAngle === 90 to also consider negative 90.
If you are unsure about it, I can also just revert those changes and leave it as it was before, so that you can properly figure out how the prevention of infinite redraws should really work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexcjohnson What do you suggest here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back to look at where this block was originally introduced, it was in #4216 back in v1.49.5 (2019). Adapting the first codepen shown there to the latest release and to this PR, neither shows an infinite loop AFAICT, so that's great. But the current PR has some history-dependent behavior that the latest release does not.

Here's on the latest release: https://codepen.io/alexcjohnson/pen/YzBovrN - the angle starts 30 degrees, then changes to 90 degrees when we shrink the width, then goes back to 30 degrees when we go back to the original width (this is font-dependent, so it's possible on other machines the specific widths will need to be adjusted)

And here's on this branch: https://codepen.io/alexcjohnson/pen/abXgKad - note the angle stays at 90 degrees at the end. It doesn't go back down until you get wide enough to go back to 0 degrees.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed my changes for now, so the old behavior is restored.

autoangle = 90;
autoangle = prevAngle;
seq.push(function() {
positionLabels(tickLabels, prevAngle);
});
Expand Down
14 changes: 14 additions & 0 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,20 @@ module.exports = {
'vertically.'
].join(' ')
},
autotickangles: {
valType: 'info_array',
freeLength: true,
items: {
valType: 'angle'
},
dflt: [0, 30, 90],
editType: 'ticks',
description: [
'When `tickangle` is set to *auto*, it will be set to the first',
'angle in this array that is large enough to prevent label',
'overlap.'
].join(' ')
},
tickprefix: {
valType: 'string',
dflt: '',
Expand Down
3 changes: 2 additions & 1 deletion src/plots/cartesian/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
visibleDflt: visibleDflt,
reverseDflt: reverseDflt,
autotypenumbersDflt: autotypenumbersDflt,
splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[axId]
splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[axId],
noAutotickangles: axLetter === 'y'
};

coerce('uirevision', layoutOut.uirevision);
Expand Down
7 changes: 6 additions & 1 deletion src/plots/cartesian/tick_label_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ module.exports = function handleTickLabelDefaults(containerIn, containerOut, coe
coerce('ticklabelstep');
}

if(!options.noAng) coerce('tickangle');
if(!options.noAng) {
var tickAngle = coerce('tickangle');
if(!options.noAutotickangles && tickAngle === 'auto') {
coerce('autotickangles');
}
}

if(axType !== 'category') {
var tickFormat = coerce('tickformat');
Expand Down
1 change: 1 addition & 0 deletions src/plots/gl3d/layout/axis_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) {
letter: axName[0],
data: options.data,
showGrid: true,
noAutotickangles: true,
noTickson: true,
noTicklabelmode: true,
noTicklabelstep: true,
Expand Down
2 changes: 2 additions & 0 deletions src/plots/polar/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ var radialAxisAttrs = {
].join(' ')
},

autotickangles: axesAttrs.autotickangles,

side: {
valType: 'enumerated',
// TODO add 'center' for `showline: false` radial axes
Expand Down
3 changes: 2 additions & 1 deletion src/plots/polar/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ function handleDefaults(contIn, contOut, coerce, opts) {
color: dfltFontColor,
size: dfltFontSize,
family: dfltFontFamily
}
},
noAutotickangles: axName === 'angularaxis'
});

handleTickMarkDefaults(axIn, axOut, coerceAxis, {outerTicks: true});
Expand Down
1 change: 1 addition & 0 deletions src/plots/smith/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ function handleDefaults(contIn, contOut, coerce, opts) {
}

handleTickLabelDefaults(axIn, axOut, coerceAxis, axOut.type, {
noAutotickangles: true,
noTicklabelstep: true,
noAng: !isRealAxis,
noExp: true,
Expand Down
2 changes: 1 addition & 1 deletion src/plots/ternary/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ function handleAxisDefaults(containerIn, containerOut, options, ternaryLayoutOut

handleTickValueDefaults(containerIn, containerOut, coerce, 'linear');
handlePrefixSuffixDefaults(containerIn, containerOut, coerce, 'linear');
handleTickLabelDefaults(containerIn, containerOut, coerce, 'linear');
handleTickLabelDefaults(containerIn, containerOut, coerce, 'linear', { noAutotickangles: true });
handleTickMarkDefaults(containerIn, containerOut, coerce,
{ outerTicks: true });

Expand Down
1 change: 1 addition & 0 deletions src/traces/carpet/ab_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function mimickAxisDefaults(traceIn, traceOut, fullLayout, dfltColor) {
var axOut = Template.newContainer(traceOut, axName);

var defaultOptions = {
noAutotickangles: true,
noTicklabelstep: true,
tickfont: 'x',
id: axLetter + 'axis',
Expand Down
5 changes: 4 additions & 1 deletion src/traces/indicator/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ function supplyDefaults(traceIn, traceOut, defaultColor, layout) {
coerceGaugeAxis('visible');
traceOut._range = coerceGaugeAxis('range', traceOut._range);

var opts = {outerTicks: true};
var opts = {
noAutotickangles: true,
outerTicks: true
};
handleTickValueDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear');
handlePrefixSuffixDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear', opts);
handleTickLabelDefaults(axisIn, axisOut, coerceGaugeAxis, 'linear', opts);
Expand Down
1 change: 1 addition & 0 deletions src/traces/indicator/plot.js
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,7 @@ function mockAxis(gd, opts, zrange) {
var axisOptions = {
letter: 'x',
font: fullLayout.font,
noAutotickangles: true,
noHover: true,
noTickson: true
};
Expand Down
Binary file modified test/image/baselines/10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/automargin-zoom.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/domain_ref_axis_types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/finance_subplots_categories.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/grid_subplot_types.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/period_positioning6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/polar_polygon-grids.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/tick-increment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/ticklabelposition-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/waterfall_and_bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 14 additions & 13 deletions test/image/mocks/10.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
-0.255461150807681,
-0.25597595662203515
],
"name": "Trial 1",
"name": "Trial 1 Very Long<br>multiline label",
"boxpoints": "all",
"pointpos": -1.5,
"jitter": 0,
Expand Down Expand Up @@ -45,7 +45,7 @@
2.2237747316232417,
2.0456528234898133
],
"name": "Trial 2",
"name": "Trial 2 Very Long<br>multiline label",
"boxpoints": "all",
"pointpos": -1.5,
"jitter": 0,
Expand Down Expand Up @@ -77,7 +77,7 @@
1.114484992405051,
0.577777449231605
],
"name": "Trial 3",
"name": "Trial 3 Very Long<br>multiline label",
"boxpoints": "all",
"pointpos": -1.5,
"jitter": 0,
Expand Down Expand Up @@ -109,7 +109,7 @@
3.01289053296517,
2.8335761244537614
],
"name": "Trial 4",
"name": "Trial 4 Very Long<br>multiline label",
"boxpoints": "all",
"pointpos": -1.5,
"jitter": 0,
Expand Down Expand Up @@ -141,7 +141,7 @@
5.687207835036456,
5.718713550485276
],
"name": "Trial 5",
"name": "Trial 5 Very Long<br>multiline label",
"boxpoints": "all",
"pointpos": -1.5,
"jitter": 0,
Expand Down Expand Up @@ -173,7 +173,7 @@
6.146408206163261,
6.726224574612897
],
"name": "Trial 6",
"name": "Trial 6 Very Long<br>multiline label",
"boxpoints": "all",
"pointpos": -1.5,
"jitter": 0,
Expand All @@ -194,12 +194,12 @@
},
{
"x": [
"Trial 1",
"Trial 2",
"Trial 3",
"Trial 4",
"Trial 5",
"Trial 6"
"Trial 1 Very Long<br>multiline label",
"Trial 2 Very Long<br>multiline label",
"Trial 3 Very Long<br>multiline label",
"Trial 4 Very Long<br>multiline label",
"Trial 5 Very Long<br>multiline label",
"Trial 6 Very Long<br>multiline label"
],
"y": [
-0.16783142774745008,
Expand Down Expand Up @@ -262,7 +262,8 @@
"showticklabels": true,
"tick0": 0,
"dtick": 1,
"tickangle": 0,
"tickangle": "auto",
"autotickangles": [5, -25],
"anchor": "y",
"autorange": true
},
Expand Down
29 changes: 22 additions & 7 deletions test/jasmine/tests/axes_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4268,16 +4268,22 @@ describe('Test axes', function() {
var op = parts[0];

var method = {
'=': 'toBe',
'=': 'toBeCloseTo',
'~=': 'toBeWithin',
grew: 'toBeGreaterThan',
shrunk: 'toBeLessThan',
initial: 'toBe'
initial: 'toBeCloseTo'
}[op];

var val = op === 'initial' ? initialSize[k] : previousSize[k];
var msgk = msg + ' ' + k + (parts[1] ? ' |' + parts[1] : '');
var args = op === '~=' ? [val, 1.1, msgk] : [val, msgk, ''];
var args = [val];
if(op === '~=') {
args.push(1.1);
} else if(method === 'toBeCloseTo') {
args.push(3);
}
args.push(msgk);

expect(actual[k])[method](args[0], args[1], args[2]);
}
Expand Down Expand Up @@ -4313,7 +4319,7 @@ describe('Test axes', function() {
width: 600, height: 600
})
.then(function() {
expect(gd._fullLayout.xaxis._tickAngles.xtick).toBe(30);
expect(gd._fullLayout.xaxis._tickAngles.xtick).toBeCloseTo(30, 3);

var gs = gd._fullLayout._size;
initialSize = Lib.extendDeep({}, gs);
Expand Down Expand Up @@ -4485,13 +4491,22 @@ describe('Test axes', function() {
var op = parts[0];

var method = {
'=': 'toBe',
'=': 'toBeCloseTo',
'~=': 'toBeWithin',
grew: 'toBeGreaterThan',
shrunk: 'toBeLessThan',
initial: 'toBeCloseTo'
}[op];

var val = initialSize[k];
var msgk = msg + ' ' + k + (parts[1] ? ' |' + parts[1] : '');
var args = op === '~=' ? [val, 1.1, msgk] : [val, msgk, ''];
var args = [val];
if(op === '~=') {
args.push(1.1);
} else if(method === 'toBeCloseTo') {
args.push(3);
}
args.push(msgk);

expect(actual[k])[method](args[0], args[1], args[2]);
}
Expand Down Expand Up @@ -4526,7 +4541,7 @@ describe('Test axes', function() {
width: 600, height: 600
})
.then(function() {
expect(gd._fullLayout.xaxis._tickAngles.xtick).toBe(30);
expect(gd._fullLayout.xaxis._tickAngles.xtick).toBeCloseTo(30, 3);

var gs = gd._fullLayout._size;
initialSize = Lib.extendDeep({}, gs);
Expand Down
5 changes: 4 additions & 1 deletion test/jasmine/tests/plots_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,10 @@ describe('Test Plots with automargin and minreducedwidth/height', function() {
assert('height', '100');
})
.then(function() {
return Plotly.relayout(gd, 'minreducedwidth', 100);
// force tickangle to 90 so when we increase the width the x axis labels
// don't revert to 30 degrees, giving us a larger height
// this is a cool effect, but not what we're testing here!
return Plotly.relayout(gd, {minreducedwidth: 100, 'xaxis.tickangle': 90});
})
.then(function() {
assert('width', '100');
Expand Down
Loading