[ {"fn": "plotArea", "name": "d3's usual margins on a 600 x 400 chart", "args": [600, 400, {"top": 20, "right": 20, "bottom": 30, "left": 40}], "expect": {"x": 40, "y": 20, "width": 540, "height": 350}}, {"fn": "plotArea", "name": "no margins is the whole chart", "args": [300, 200, {"top": 0, "right": 0, "bottom": 0, "left": 0}], "expect": {"x": 0, "y": 0, "width": 300, "height": 200}}, {"fn": "plotArea", "name": "fractional sizes round to 2 places; 12.125 is an exact tie and rounds up", "args": [300.5, 200, {"top": 10.25, "right": 5, "bottom": 10, "left": 12.125}], "expect": {"x": 12.13, "y": 10.25, "width": 283.38, "height": 179.75}}, {"fn": "plotArea", "name": "a very small plot is still a plot", "args": [1, 1, {"top": 0, "right": 0, "bottom": 0, "left": 0.5}], "expect": {"x": 0.5, "y": 0, "width": 0.5, "height": 1}}, {"fn": "plotArea", "name": "margins that use up the whole width are an error", "args": [100, 100, {"top": 0, "right": 50, "bottom": 0, "left": 50}], "expectError": "margins leave no room to plot"}, {"fn": "plotArea", "name": "margins wider than the chart are an error", "args": [100, 100, {"top": 60, "right": 0, "bottom": 60, "left": 0}], "expectError": "margins leave no room to plot"}, {"fn": "plotArea", "name": "a negative margin is an error", "args": [100, 100, {"top": 0, "right": -5, "bottom": 0, "left": 0}], "expectError": "margins must not be negative"}, {"fn": "legendRows", "name": "three items on one row; the last ends exactly at maxWidth and does not wrap", "args": [["Revenue", "Costs", "Profit"], 200, 7, 10, 16, 18], "expect": [{"label": "Revenue", "row": 0, "x": 0, "y": 0, "width": 63, "textX": 14}, {"label": "Costs", "row": 0, "x": 79, "y": 0, "width": 49, "textX": 93}, {"label": "Profit", "row": 0, "x": 144, "y": 0, "width": 56, "textX": 158}]}, {"fn": "legendRows", "name": "the item that would pass maxWidth starts a new row", "args": [["Revenue", "Costs", "Profit"], 150, 7, 10, 16, 18], "expect": [{"label": "Revenue", "row": 0, "x": 0, "y": 0, "width": 63, "textX": 14}, {"label": "Costs", "row": 0, "x": 79, "y": 0, "width": 49, "textX": 93}, {"label": "Profit", "row": 1, "x": 0, "y": 18, "width": 56, "textX": 14}]}, {"fn": "legendRows", "name": "an item wider than the legend gets its own row, not an empty row before it", "args": [["A very long label", "B"], 50, 7, 10, 16, 18], "expect": [{"label": "A very long label", "row": 0, "x": 0, "y": 0, "width": 133, "textX": 14}, {"label": "B", "row": 1, "x": 0, "y": 18, "width": 21, "textX": 14}]}, {"fn": "legendRows", "name": "characters are counted as code points, not UTF-8 bytes", "args": [["Café", "€"], 200, 7, 10, 16, 18], "expect": [{"label": "Café", "row": 0, "x": 0, "y": 0, "width": 42, "textX": 14}, {"label": "€", "row": 0, "x": 58, "y": 0, "width": 21, "textX": 72}]}, {"fn": "legendRows", "name": "an empty label is just its swatch", "args": [[""], 100, 7, 10, 16, 18], "expect": [{"label": "", "row": 0, "x": 0, "y": 0, "width": 14, "textX": 14}]}, {"fn": "legendRows", "name": "fractional character width", "args": [["ab", "cd"], 100, 6.5, 10, 5.25, 20], "expect": [{"label": "ab", "row": 0, "x": 0, "y": 0, "width": 27, "textX": 14}, {"label": "cd", "row": 0, "x": 32.25, "y": 0, "width": 27, "textX": 46.25}]}, {"fn": "legendRows", "name": "no labels", "args": [[], 100, 7, 10, 16, 18], "expect": []}, {"fn": "legendRows", "name": "maxWidth must be positive", "args": [["A"], 0, 7, 10, 16, 18], "expectError": "maxWidth must be greater than zero"}, {"fn": "legendRows", "name": "a negative size is an error", "args": [["A"], 100, -1, 10, 16, 18], "expectError": "legend sizes must not be negative"}, {"fn": "avoidCollisions", "name": "of two overlapping labels the first is kept", "args": [[{"x": 0, "y": 0, "width": 50, "height": 10, "priority": 0}, {"x": 40, "y": 0, "width": 50, "height": 10, "priority": 0}], 0], "expect": [true, false]}, {"fn": "avoidCollisions", "name": "a higher priority wins over input order", "args": [[{"x": 0, "y": 0, "width": 50, "height": 10, "priority": 0}, {"x": 40, "y": 0, "width": 50, "height": 10, "priority": 1}], 0], "expect": [false, true]}, {"fn": "avoidCollisions", "name": "touching is not overlapping", "args": [[{"x": 0, "y": 0, "width": 50, "height": 10, "priority": 0}, {"x": 50, "y": 0, "width": 50, "height": 10, "priority": 0}], 0], "expect": [true, true]}, {"fn": "avoidCollisions", "name": "padding turns touching into a clash", "args": [[{"x": 0, "y": 0, "width": 50, "height": 10, "priority": 0}, {"x": 50, "y": 0, "width": 50, "height": 10, "priority": 0}], 2], "expect": [true, false]}, {"fn": "avoidCollisions", "name": "a gap exactly equal to the padding is clear", "args": [[{"x": 0, "y": 0, "width": 50, "height": 10, "priority": 0}, {"x": 0, "y": 12, "width": 50, "height": 10, "priority": 0}], 2], "expect": [true, true]}, {"fn": "avoidCollisions", "name": "a gap smaller than the padding is not", "args": [[{"x": 0, "y": 0, "width": 50, "height": 10, "priority": 0}, {"x": 0, "y": 12, "width": 50, "height": 10, "priority": 0}], 3], "expect": [true, false]}, {"fn": "avoidCollisions", "name": "greedy: hiding the middle label frees the third (hiding every overlapping label would hide all three)", "args": [[{"x": 0, "y": 0, "width": 10, "height": 10, "priority": 0}, {"x": 8, "y": 0, "width": 10, "height": 10, "priority": 0}, {"x": 16, "y": 0, "width": 10, "height": 10, "priority": 0}], 0], "expect": [true, false, true]}, {"fn": "avoidCollisions", "name": "equal top priorities go in input order", "args": [[{"x": 0, "y": 0, "width": 10, "height": 10, "priority": 1}, {"x": 1, "y": 0, "width": 10, "height": 10, "priority": 2}, {"x": 2, "y": 0, "width": 10, "height": 10, "priority": 2}], 0], "expect": [false, true, false]}, {"fn": "avoidCollisions", "name": "zero-size boxes never clash", "args": [[{"x": 5, "y": 5, "width": 0, "height": 0, "priority": 0}, {"x": 5, "y": 5, "width": 0, "height": 0, "priority": 0}], 0], "expect": [true, true]}, {"fn": "avoidCollisions", "name": "no boxes", "args": [[], 0], "expect": []}, {"fn": "avoidCollisions", "name": "negative padding is an error", "args": [[{"x": 0, "y": 0, "width": 1, "height": 1, "priority": 0}], -1], "expectError": "padding must not be negative"}, {"fn": "avoidCollisions", "name": "a box with negative size is an error", "args": [[{"x": 0, "y": 0, "width": -1, "height": 1, "priority": 0}], 0], "expectError": "label boxes must not have negative size"}, {"fn": "plotArea", "name": "height is what the top and bottom leave, width what the left and right leave", "args": [640, 480, {"top": 40, "right": 10, "bottom": 60, "left": 50}], "expect": {"x": 50, "y": 40, "width": 580, "height": 380}}, {"fn": "plotArea", "name": "margins that leave exactly one pixel", "args": [101, 100, {"top": 0, "right": 50, "bottom": 0, "left": 50}], "expect": {"x": 50, "y": 0, "width": 1, "height": 100}}, {"fn": "plotArea", "name": "a negative top margin is an error", "args": [100, 100, {"top": -1, "right": 0, "bottom": 0, "left": 0}], "expectError": "margins must not be negative"}, {"fn": "plotArea", "name": "a chart with no width is an error", "args": [0, 100, {"top": 0, "right": 0, "bottom": 0, "left": 0}], "expectError": "margins leave no room to plot"}, {"fn": "plotArea", "name": "a chart of negative height is an error", "args": [100, -10, {"top": 0, "right": 0, "bottom": 0, "left": 0}], "expectError": "margins leave no room to plot"} ]