diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0c27cb8..5a9237e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,8 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- Fixed a bug where the `Download JSON` button would not download the JSON currently inside the input box.
- Made sure file input would reset when file input dialog was closed.
- Fixed a bug where the styles in `DisplaySettings.roughjs_config` were not applied.
+- Fixed a bug where passing an empty array as objects will crash the program.
+- Fixed a bug where the text may go outside of the box when it has a text font set
### 📚 Documentation and demo website changes
diff --git a/memory-viz/src/automate.ts b/memory-viz/src/automate.ts
index 9c5ec2b..cd182c7 100644
--- a/memory-viz/src/automate.ts
+++ b/memory-viz/src/automate.ts
@@ -252,11 +252,19 @@ function drawAutomatedOtherItems(
x_coord = hor_reach;
}
- const right_most_obj = objs.reduce((prev, curr) =>
- compareByRightness(prev, curr) <= 0 ? prev : curr
+ const defaultObject: DrawnEntity = {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+ };
+ const right_most_obj = objs.reduce(
+ (prev, curr) => (compareByRightness(prev, curr) <= 0 ? prev : curr),
+ defaultObject
);
- const down_most_obj = objs.reduce((prev, curr) =>
- compareByBottomness(prev, curr) <= 0 ? prev : curr
+ const down_most_obj = objs.reduce(
+ (prev, curr) => (compareByBottomness(prev, curr) <= 0 ? prev : curr),
+ defaultObject
);
const canvas_width =
diff --git a/memory-viz/src/memory_model.ts b/memory-viz/src/memory_model.ts
index d5fba9c..a36d9e8 100644
--- a/memory-viz/src/memory_model.ts
+++ b/memory-viz/src/memory_model.ts
@@ -223,9 +223,12 @@ export class MemoryModel {
value: Primitive,
style: Style
): Rect {
+ const renderedText =
+ typeof value === "string" ? `"${value}"` : String(value);
let box_width = Math.max(
this.obj_min_width,
- this.getTextLength(String(value)) + this.obj_x_padding
+ this.getTextLength(renderedText, style.text_value) +
+ this.obj_x_padding
);
this.drawRect(
x,
@@ -303,12 +306,12 @@ export class MemoryModel {
) {
let id_box = Math.max(
this.prop_min_width,
- this.getTextLength(`id${id}`) + 10
+ this.getTextLength(`id${id}`, style.text_id) + 10
);
let type_box = Math.max(
this.prop_min_width,
- this.getTextLength(type) + 10
+ this.getTextLength(type, style.text_type) + 10
);
this.drawRect(x, y, id_box, this.prop_min_height, style.box_id);
@@ -380,7 +383,8 @@ export class MemoryModel {
element_ids.forEach((v) => {
box_width += Math.max(
this.item_min_width,
- this.getTextLength(v === null ? "" : `id${v}`) + 10
+ this.getTextLength(v === null ? "" : `id${v}`, style.text_id) +
+ 10
);
});
@@ -419,7 +423,7 @@ export class MemoryModel {
const idv = v === null ? "" : `id${v}`;
const item_length = Math.max(
this.item_min_width,
- this.getTextLength(idv) + 10
+ this.getTextLength(idv, style.text_id) + 10
);
this.drawRect(curr_x, item_y, item_length, this.item_min_height);
this.drawText(
@@ -482,7 +486,8 @@ export class MemoryModel {
element_ids.forEach((v) => {
box_width += Math.max(
this.item_min_width,
- this.getTextLength(v === null ? "" : `id${v}`) + 10
+ this.getTextLength(v === null ? "" : `id${v}`, style.text_id) +
+ 10
);
});
box_width = Math.max(this.obj_min_width, box_width);
@@ -518,7 +523,7 @@ export class MemoryModel {
const idv = v === null ? "" : `id${v}`;
const item_length = Math.max(
this.item_min_width,
- this.getTextLength(idv) + 10
+ this.getTextLength(idv, style.text_id) + 10
);
this.drawRect(curr_x, item_y, item_length, this.item_min_height);
this.drawText(
@@ -587,11 +592,11 @@ export class MemoryModel {
let key_box = Math.max(
this.item_min_width,
- this.getTextLength(idk + 5)
+ this.getTextLength(idk + 5, style.text_id)
);
let value_box = Math.max(
this.item_min_width,
- this.getTextLength(idv + 5)
+ this.getTextLength(idv + 5, style.text_value)
);
// Draw the rectangles representing the keys.
@@ -632,7 +637,7 @@ export class MemoryModel {
let value_box = Math.max(
this.item_min_width,
- this.getTextLength(idv + 5)
+ this.getTextLength(idv + 5, style.text_value)
);
// Draw the rectangle for values.
@@ -692,14 +697,17 @@ export class MemoryModel {
let box_width = this.obj_min_width;
let longest = 0;
for (const attribute in attributes) {
- longest = Math.max(longest, this.getTextLength(attribute));
+ longest = Math.max(
+ longest,
+ this.getTextLength(attribute, style.text_value)
+ );
}
if (longest > 0) {
box_width = longest + this.item_min_width * 3;
}
box_width = Math.max(
box_width,
- this.prop_min_width + this.getTextLength(name) + 10
+ this.prop_min_width + this.getTextLength(name, style.text_type) + 10
);
let box_height = 0;
@@ -750,7 +758,7 @@ export class MemoryModel {
}
if (stack_frame) {
- let text_length = this.getTextLength(name);
+ let text_length = this.getTextLength(name, style.text_type);
this.drawRect(
x,
y,
@@ -846,8 +854,13 @@ export class MemoryModel {
/**
* Return the length of this text.
* @param s - The given text.
+ * @param textStyle - The style configuration for the text.
*/
- getTextLength(s: string): number {
+ getTextLength(s: string, textStyle?: CSS.PropertiesHyphen): number {
+ if (textStyle?.["font-size"]) {
+ // Note: this assumes font size is in px
+ return s.length * parseInt(textStyle["font-size"]) * 0.6;
+ }
return s.length * 12;
}
diff --git a/memory-viz/src/tests/__snapshots__/cli.spec.tsx.snap b/memory-viz/src/tests/__snapshots__/cli.spec.tsx.snap
index eee4b4e..5289bae 100644
--- a/memory-viz/src/tests/__snapshots__/cli.spec.tsx.snap
+++ b/memory-viz/src/tests/__snapshots__/cli.spec.tsx.snap
@@ -43,18 +43,18 @@ exports[`memory-viz CLI output path should overwrite existing svg when the outpu
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -101,18 +101,18 @@ exports[`memory-viz CLI output path should produce consistent svg when the outpu
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -159,18 +159,18 @@ exports[`memory-viz CLI output path should produce consistent svg when the outpu
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -217,21 +217,21 @@ exports[`memory-viz cli produces consistent svg when provided filepath and a var
}
-
-
+
+
-
-
- "David is cool!"
+
+
+ "David is cool!"
-
-
+
+
-
-
- id19str
+
+
+ id19str
`;
@@ -278,18 +278,18 @@ exports[`memory-viz cli produces consistent svg when provided filepath and outpu
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -336,18 +336,18 @@ exports[`memory-viz cli produces consistent svg when provided filepath and stdou
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -394,18 +394,18 @@ exports[`memory-viz cli produces consistent svg when provided filepath, output,
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -452,18 +452,18 @@ exports[`memory-viz cli produces consistent svg when provided filepath, output,
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -510,18 +510,18 @@ exports[`memory-viz cli produces consistent svg when provided filepath, output,
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -568,18 +568,18 @@ exports[`memory-viz cli produces consistent svg when provided stdin and output 1
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
@@ -626,17 +626,17 @@ exports[`memory-viz cli produces consistent svg when provided stdin and stdout 1
}
-
-
+
+
-
- "David is cool!"
+
+ "David is cool!"
-
+
-
- id19str
+
+ id19str
`;
diff --git a/memory-viz/src/tests/__snapshots__/draw.spec.tsx.snap b/memory-viz/src/tests/__snapshots__/draw.spec.tsx.snap
index e8547af..840e8a5 100644
--- a/memory-viz/src/tests/__snapshots__/draw.spec.tsx.snap
+++ b/memory-viz/src/tests/__snapshots__/draw.spec.tsx.snap
@@ -521,18 +521,18 @@ exports[`draw function renders 'hide_container' style preset 1`] = `
__main__
-
-
+
+
-
- "hide container!"
+
+ "hide container!"
-
- id42str
+
+ id42str
`;
@@ -646,29 +646,29 @@ exports[`draw function renders 'highlight' style preset 1`] = `
}
-
-
+
+
-
- itemid45
+
+ itemid45
-
-
- __main__
+
+
+ __main__
-
-
+
+
-
- "highlight!"
+
+ "highlight!"
-
+
-
- id42str
+
+ id42str
`;
@@ -724,18 +724,18 @@ exports[`draw function renders 'highlight_id' style preset 1`] = `
__main__
-
+
-
- "highlight id!"
+
+ "highlight id!"
-
-
+
+
-
- id42str
+
+ id42str
`;
@@ -788,21 +788,21 @@ exports[`draw function renders 'highlight_type' style preset 1`] = `
itemid45
-
- __main__
+
+ __main__
-
+
-
- "highlight type!"
+
+ "highlight type!"
-
-
- id42str
+
+
+ id42str
`;
@@ -1032,7 +1032,7 @@ exports[`draw function renders a bool using manual layout 1`] = `
`;
exports[`draw function renders a diagram with 'small' width value and a mix stack frame/non-stack frame objects 1`] = `
-
`;
diff --git a/memory-viz/src/tests/draw.spec.tsx b/memory-viz/src/tests/draw.spec.tsx
index c907e5b..fe15628 100644
--- a/memory-viz/src/tests/draw.spec.tsx
+++ b/memory-viz/src/tests/draw.spec.tsx
@@ -786,7 +786,7 @@ describe("draw function", () => {
const message = new RegExp(
"^WARNING: provided width \\(\\d+\\) is smaller than " +
- "the required width \\(\\d+\\). The provided width has been overwritten " +
+ "the required width \\(\\d+(\\.\\d+)?\\). The provided width has been overwritten " +
"in the generated diagram.$"
);
expect(message.test(spy.mock.calls[0][0])).toBe(true);
@@ -907,4 +907,57 @@ describe("draw function", () => {
})
).toThrow(errorMessage);
});
+
+ it("renders an appropriately sized box for a very long string", () => {
+ const objects: DrawnEntity[] = [
+ {
+ id: 1,
+ type: "str",
+ value: "I am a very very very very very very very very very very very very very very very very very very very very very very very very very very very long string",
+ },
+ ];
+ const output: InstanceType = draw(objects, true, {
+ width: 100,
+ roughjs_config: {
+ options: {
+ seed: 12345,
+ },
+ },
+ });
+ const svg = output.serializeSVG();
+ expect(svg).toMatchSnapshot();
+ });
+ it("renders an appropriately sized box for a string with the highlight style", () => {
+ const objects: DrawnEntity[] = [
+ {
+ id: 1,
+ type: "str",
+ value: "I am a very very very very very very very very very very very very very very very very very very very very very very very very very very very long string",
+ style: ["highlight"],
+ },
+ ];
+ const output: InstanceType = draw(objects, true, {
+ width: 100,
+ roughjs_config: {
+ options: {
+ seed: 12345,
+ },
+ },
+ });
+ const svg = output.serializeSVG();
+ expect(svg).toMatchSnapshot();
+ });
+ it("renders an empty svg given an empty array", () => {
+ const objects = [];
+ const output: InstanceType = draw(objects, true, {
+ width: 100,
+ roughjs_config: {
+ options: {
+ seed: 12345,
+ },
+ },
+ });
+ const svg = output.serializeSVG();
+ expect(svg).toMatchSnapshot();
+ });
});