1
- import { extent } from "d3" ;
1
+ import { max , extent } from "d3" ;
2
2
import { projectionAspectRatio } from "./projection.js" ;
3
3
import { isOrdinalScale } from "./scales.js" ;
4
4
import { offset } from "./style.js" ;
5
5
6
+ // A heuristic to determine the default margin. Ordinal scales usually reclaim
7
+ // more space. We can also gauge the “type of contents” (domain, ticks?) and
8
+ // decide whether it’s small, medium or large. We don’t want it to match the
9
+ // contents exactly because it shouldn’t wobble when the scale changes a little.
10
+ function autoMarginH ( { type, domain, ticks} = { } ) {
11
+ if ( type === "point" || type === "band" ) return sizeHeuristicH ( ticks ?? domain ) ;
12
+ return sizeHeuristicH ( ( ticks ?? domain ?? [ ] ) . map ( String ) ) ;
13
+ }
14
+
15
+ function sizeHeuristicH ( values = [ ] ) {
16
+ const l = max ( values , ( d ) => d . length ) ; // TODO text metrics approximation?
17
+ return l >= 10 ? 120 : l >= 4 ? 80 : 40 ;
18
+ }
19
+
6
20
export function createDimensions ( scales , marks , options = { } ) {
7
21
// Compute the default margins: the maximum of the marks’ margins. While not
8
22
// always used, they may be needed to compute the default height of the plot.
@@ -11,7 +25,9 @@ export function createDimensions(scales, marks, options = {}) {
11
25
marginBottomDefault = 0.5 + offset ,
12
26
marginLeftDefault = 0.5 - offset ;
13
27
14
- for ( const { marginTop, marginRight, marginBottom, marginLeft} of marks ) {
28
+ for ( let { marginTop, marginRight, marginBottom, marginLeft} of marks ) {
29
+ if ( marginLeft === "auto" ) marginLeft = autoMarginH ( scales . y ) ;
30
+ if ( marginRight === "auto" ) marginRight = autoMarginH ( scales . y ) ;
15
31
if ( marginTop > marginTopDefault ) marginTopDefault = marginTop ;
16
32
if ( marginRight > marginRightDefault ) marginRightDefault = marginRight ;
17
33
if ( marginBottom > marginBottomDefault ) marginBottomDefault = marginBottom ;
0 commit comments