diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 064d91bbe..075d05e7d 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -1,6 +1,7 @@ #### Features ๐Ÿš€ - PDF exports are now supported. [#120](https://github.com/terrastruct/d2/issues/120) +- 3D Hexagons are now supported. [#869](https://github.com/terrastruct/d2/issues/869) #### Improvements ๐Ÿงน diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 8cc6452a7..ee1f1df3b 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -615,8 +615,8 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) { switch f.Name { case "style": if obj.Attributes.Style.ThreeDee != nil { - if !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeSquare) && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeRectangle) { - c.errorf(obj.Attributes.Style.ThreeDee.MapKey, `key "3d" can only be applied to squares and rectangles`) + if !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeSquare) && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeRectangle) && !strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeHexagon) { + c.errorf(obj.Attributes.Style.ThreeDee.MapKey, `key "3d" can only be applied to squares, rectangles, and hexagons`) } } if obj.Attributes.Style.DoubleBorder != nil { diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 8a8bb33c3..c249844fc 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1735,7 +1735,7 @@ x.y -> a.b: { text: `SVP1.shape: oval SVP1.style.3d: true`, - expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares and rectangles`, + expErr: `d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key "3d" can only be applied to squares, rectangles, and hexagons`, }, { name: "edge_column_index", text: `src: { diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 87d403ac0..b5d1f7c82 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -731,6 +731,129 @@ func render3dRect(targetShape d2target.Shape) string { fmt.Sprintf("%d,%d", v.X+targetShape.Pos.X, v.Y+targetShape.Pos.Y), ) } + darkerColor, err := color.Darken(targetShape.Fill) + if err != nil { + darkerColor = targetShape.Fill + } + sideShape := d2themes.NewThemableElement("polygon") + sideShape.Fill = darkerColor + sideShape.Points = strings.Join(sidePoints, " ") + sideShape.SetMaskUrl(maskID) + sideShape.Style = targetShape.CSSStyle() + renderedSides := sideShape.Render() + + return borderMask + mainShapeRendered + renderedSides + renderedBorder +} + +func render3dHexagon(targetShape d2target.Shape) string { + moveTo := func(p d2target.Point) string { + return fmt.Sprintf("M%d,%d", p.X+targetShape.Pos.X, p.Y+targetShape.Pos.Y) + } + lineTo := func(p d2target.Point) string { + return fmt.Sprintf("L%d,%d", p.X+targetShape.Pos.X, p.Y+targetShape.Pos.Y) + } + scale := func(n int, f float64) int { + return int(float64(n) * f) + } + halfYFactor := 43.6 / 87.3 + + // draw border all in one path to prevent overlapping sections + var borderSegments []string + // start from the top-left + borderSegments = append(borderSegments, + moveTo(d2target.Point{X: scale(targetShape.Width, 0.25), Y: 0}), + ) + Y_OFFSET := d2target.THREE_DEE_OFFSET / 2 + // The following iterates through the sidepoints in clockwise order from top-left, then the main points in clockwise order from bottom-right + for _, v := range []d2target.Point{ + {X: scale(targetShape.Width, 0.25) + d2target.THREE_DEE_OFFSET, Y: -Y_OFFSET}, + {X: scale(targetShape.Width, 0.75) + d2target.THREE_DEE_OFFSET, Y: -Y_OFFSET}, + {X: targetShape.Width + d2target.THREE_DEE_OFFSET, Y: scale(targetShape.Height, halfYFactor) - Y_OFFSET}, + {X: scale(targetShape.Width, 0.75) + d2target.THREE_DEE_OFFSET, Y: targetShape.Height - Y_OFFSET}, + {X: scale(targetShape.Width, 0.75), Y: targetShape.Height}, + {X: scale(targetShape.Width, 0.25), Y: targetShape.Height}, + {X: 0, Y: scale(targetShape.Height, halfYFactor)}, + {X: scale(targetShape.Width, 0.25), Y: 0}, + {X: scale(targetShape.Width, 0.75), Y: 0}, + {X: targetShape.Width, Y: scale(targetShape.Height, halfYFactor)}, + {X: scale(targetShape.Width, 0.75), Y: targetShape.Height}, + } { + borderSegments = append(borderSegments, lineTo(v)) + } + for _, v := range []d2target.Point{ + {X: scale(targetShape.Width, 0.75), Y: 0}, + {X: targetShape.Width, Y: scale(targetShape.Height, halfYFactor)}, + {X: scale(targetShape.Width, 0.75), Y: targetShape.Height}, + } { + borderSegments = append(borderSegments, moveTo(v)) + borderSegments = append(borderSegments, lineTo( + d2target.Point{X: v.X + d2target.THREE_DEE_OFFSET, Y: v.Y - Y_OFFSET}, + )) + } + border := d2themes.NewThemableElement("path") + border.D = strings.Join(borderSegments, " ") + border.Fill = color.None + _, borderStroke := d2themes.ShapeTheme(targetShape) + border.Stroke = borderStroke + borderStyle := targetShape.CSSStyle() + border.Style = borderStyle + renderedBorder := border.Render() + + var mainPoints []string + for _, v := range []d2target.Point{ + {X: scale(targetShape.Width, 0.25), Y: 0}, + {X: scale(targetShape.Width, 0.75), Y: 0}, + {X: targetShape.Width, Y: scale(targetShape.Height, halfYFactor)}, + {X: scale(targetShape.Width, 0.75), Y: targetShape.Height}, + {X: scale(targetShape.Width, 0.25), Y: targetShape.Height}, + {X: 0, Y: scale(targetShape.Height, halfYFactor)}, + } { + mainPoints = append(mainPoints, + fmt.Sprintf("%d,%d", v.X+targetShape.Pos.X, v.Y+targetShape.Pos.Y), + ) + } + + mainPointsPoly := strings.Join(mainPoints, " ") + // create mask from border stroke, to cut away from the shape fills + maskID := fmt.Sprintf("border-mask-%v", svg.EscapeText(targetShape.ID)) + borderMask := strings.Join([]string{ + fmt.Sprintf(``, + maskID, targetShape.Pos.X, targetShape.Pos.Y-d2target.THREE_DEE_OFFSET, targetShape.Width+d2target.THREE_DEE_OFFSET, targetShape.Height+d2target.THREE_DEE_OFFSET, + ), + fmt.Sprintf(``, + targetShape.Pos.X, targetShape.Pos.Y-d2target.THREE_DEE_OFFSET, targetShape.Width+d2target.THREE_DEE_OFFSET, targetShape.Height+d2target.THREE_DEE_OFFSET, + ), + fmt.Sprintf(``, + strings.Join(borderSegments, ""), borderStyle), + }, "\n") + // render the main hexagon without stroke and the border mask + mainShape := d2themes.NewThemableElement("polygon") + mainShape.X = float64(targetShape.Pos.X) + mainShape.Y = float64(targetShape.Pos.Y) + mainShape.Points = mainPointsPoly + mainShape.SetMaskUrl(maskID) + mainShapeFill, _ := d2themes.ShapeTheme(targetShape) + mainShape.Fill = mainShapeFill + mainShape.Stroke = color.None + mainShape.Style = targetShape.CSSStyle() + mainShapeRendered := mainShape.Render() + + // render the side shapes in the darkened color without stroke and the border mask + var sidePoints []string + for _, v := range []d2target.Point{ + {X: scale(targetShape.Width, 0.25) + d2target.THREE_DEE_OFFSET, Y: -Y_OFFSET}, + {X: scale(targetShape.Width, 0.75) + d2target.THREE_DEE_OFFSET, Y: -Y_OFFSET}, + {X: targetShape.Width + d2target.THREE_DEE_OFFSET, Y: scale(targetShape.Height, halfYFactor) - Y_OFFSET}, + {X: scale(targetShape.Width, 0.75) + d2target.THREE_DEE_OFFSET, Y: targetShape.Height - Y_OFFSET}, + {X: scale(targetShape.Width, 0.75), Y: targetShape.Height}, + {X: targetShape.Width, Y: scale(targetShape.Height, halfYFactor)}, + {X: scale(targetShape.Width, 0.75), Y: 0}, + {X: scale(targetShape.Width, 0.25), Y: 0}, + } { + sidePoints = append(sidePoints, + fmt.Sprintf("%d,%d", v.X+targetShape.Pos.X, v.Y+targetShape.Pos.Y), + ) + } // TODO make darker color part of the theme? or just keep this bypass darkerColor, err := color.Darken(targetShape.Fill) if err != nil { @@ -957,6 +1080,39 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske } } } + case d2target.ShapeHexagon: + if targetShape.ThreeDee { + fmt.Fprint(writer, render3dHexagon(targetShape)) + } else { + if targetShape.Multiple { + multiplePathData := shape.NewShape(shapeType, geo.NewBox(multipleTL, width, height)).GetSVGPathData() + el := d2themes.NewThemableElement("path") + el.Fill = fill + el.Stroke = stroke + el.Style = style + for _, pathData := range multiplePathData { + el.D = pathData + fmt.Fprint(writer, el.Render()) + } + } + + if sketchRunner != nil { + out, err := d2sketch.Paths(sketchRunner, targetShape, s.GetSVGPathData()) + if err != nil { + return "", err + } + fmt.Fprint(writer, out) + } else { + el := d2themes.NewThemableElement("path") + el.Fill = fill + el.Stroke = stroke + el.Style = style + for _, pathData := range s.GetSVGPathData() { + el.D = pathData + fmt.Fprint(writer, el.Render()) + } + } + } case d2target.ShapeText, d2target.ShapeCode: default: if targetShape.Multiple { diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index 615dff3ec..ff7c09820 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -155,6 +155,37 @@ rectangle -> square rectangle.style.3d: true square.style.3d: true +`, + }, + { + name: "hexagon_3d", + script: ` +hexagon: {shape: "hexagon"} +hexagon.style.3d: true +`, + }, + { + name: "3d_fill_and_stroke", + script: ` +hexagon: { + shape: hexagon + style.3d: true + style.fill: honeydew +} + + +rect: { + shape: rectangle + style.3d: true + style.fill: honeydew +} + +square: { + shape: square + style.3d: true + style.fill: honeydew +} +hexagon -> square -> rect `, }, { diff --git a/e2etests/testdata/stable/3d_fill_and_stroke/dagre/board.exp.json b/e2etests/testdata/stable/3d_fill_and_stroke/dagre/board.exp.json new file mode 100644 index 000000000..95e267b57 --- /dev/null +++ b/e2etests/testdata/stable/3d_fill_and_stroke/dagre/board.exp.json @@ -0,0 +1,227 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 0, + "y": 0 + }, + "width": 128, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "honeydew", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 60, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "rect", + "type": "rectangle", + "pos": { + "x": 28, + "y": 363 + }, + "width": 73, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "honeydew", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "rect", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 28, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "square", + "type": "rectangle", + "pos": { + "x": 17, + "y": 169 + }, + "width": 94, + "height": 94, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "honeydew", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "square", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 49, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(hexagon -> square)[0]", + "src": "hexagon", + "srcArrow": "none", + "srcLabel": "", + "dst": "square", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 64, + "y": 69 + }, + { + "x": 64, + "y": 109 + }, + { + "x": 64, + "y": 129 + }, + { + "x": 64, + "y": 169 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(square -> rect)[0]", + "src": "square", + "srcArrow": "none", + "srcLabel": "", + "dst": "rect", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 64, + "y": 263 + }, + { + "x": 64, + "y": 303 + }, + { + "x": 64, + "y": 323 + }, + { + "x": 64, + "y": 363 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/3d_fill_and_stroke/dagre/sketch.exp.svg b/e2etests/testdata/stable/3d_fill_and_stroke/dagre/sketch.exp.svg new file mode 100644 index 000000000..02573519f --- /dev/null +++ b/e2etests/testdata/stable/3d_fill_and_stroke/dagre/sketch.exp.svg @@ -0,0 +1,49 @@ + + +hexagon + +rect + +square + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/3d_fill_and_stroke/elk/board.exp.json b/e2etests/testdata/stable/3d_fill_and_stroke/elk/board.exp.json new file mode 100644 index 000000000..8ae77b5da --- /dev/null +++ b/e2etests/testdata/stable/3d_fill_and_stroke/elk/board.exp.json @@ -0,0 +1,209 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 12, + "y": 12 + }, + "width": 128, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "honeydew", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 60, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "rect", + "type": "rectangle", + "pos": { + "x": 39, + "y": 315 + }, + "width": 73, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "honeydew", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "rect", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 28, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "square", + "type": "rectangle", + "pos": { + "x": 29, + "y": 151 + }, + "width": 94, + "height": 94, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "honeydew", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "square", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 49, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(hexagon -> square)[0]", + "src": "hexagon", + "srcArrow": "none", + "srcLabel": "", + "dst": "square", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 76, + "y": 81 + }, + { + "x": 76, + "y": 151 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + }, + { + "id": "(square -> rect)[0]", + "src": "square", + "srcArrow": "none", + "srcLabel": "", + "dst": "rect", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 76, + "y": 245 + }, + { + "x": 76, + "y": 315 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/3d_fill_and_stroke/elk/sketch.exp.svg b/e2etests/testdata/stable/3d_fill_and_stroke/elk/sketch.exp.svg new file mode 100644 index 000000000..3ea48ed52 --- /dev/null +++ b/e2etests/testdata/stable/3d_fill_and_stroke/elk/sketch.exp.svg @@ -0,0 +1,49 @@ + + +hexagon + +rect + +square + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/3d_sketch_mode/dagre/board.exp.json b/e2etests/testdata/stable/3d_sketch_mode/dagre/board.exp.json new file mode 100644 index 000000000..094c34caf --- /dev/null +++ b/e2etests/testdata/stable/3d_sketch_mode/dagre/board.exp.json @@ -0,0 +1,138 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 0, + "y": 0 + }, + "width": 128, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N5", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 60, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "rect", + "type": "rectangle", + "pos": { + "x": 28, + "y": 169 + }, + "width": 73, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "rect", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 28, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(hexagon -> rect)[0]", + "src": "hexagon", + "srcArrow": "none", + "srcLabel": "", + "dst": "rect", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 64, + "y": 69 + }, + { + "x": 64, + "y": 109 + }, + { + "x": 64, + "y": 129 + }, + { + "x": 64, + "y": 169 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/3d_sketch_mode/dagre/sketch.exp.svg b/e2etests/testdata/stable/3d_sketch_mode/dagre/sketch.exp.svg new file mode 100644 index 000000000..4fbaf9562 --- /dev/null +++ b/e2etests/testdata/stable/3d_sketch_mode/dagre/sketch.exp.svg @@ -0,0 +1,47 @@ + + +hexagon + +rect + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/3d_sketch_mode/elk/board.exp.json b/e2etests/testdata/stable/3d_sketch_mode/elk/board.exp.json new file mode 100644 index 000000000..ee2228676 --- /dev/null +++ b/e2etests/testdata/stable/3d_sketch_mode/elk/board.exp.json @@ -0,0 +1,129 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 12, + "y": 12 + }, + "width": 128, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N5", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 60, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "rect", + "type": "rectangle", + "pos": { + "x": 39, + "y": 151 + }, + "width": 73, + "height": 66, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "B6", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "rect", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 28, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [ + { + "id": "(hexagon -> rect)[0]", + "src": "hexagon", + "srcArrow": "none", + "srcLabel": "", + "dst": "rect", + "dstArrow": "triangle", + "dstLabel": "", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "B1", + "label": "", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N2", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 0, + "labelHeight": 0, + "labelPosition": "", + "labelPercentage": 0, + "route": [ + { + "x": 76, + "y": 81 + }, + { + "x": 76, + "y": 151 + } + ], + "animated": false, + "tooltip": "", + "icon": null, + "zIndex": 0 + } + ] +} diff --git a/e2etests/testdata/stable/3d_sketch_mode/elk/sketch.exp.svg b/e2etests/testdata/stable/3d_sketch_mode/elk/sketch.exp.svg new file mode 100644 index 000000000..b9cf1fad3 --- /dev/null +++ b/e2etests/testdata/stable/3d_sketch_mode/elk/sketch.exp.svg @@ -0,0 +1,47 @@ + + +hexagon + +rect + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/hexagon_3d/dagre/board.exp.json b/e2etests/testdata/stable/hexagon_3d/dagre/board.exp.json new file mode 100644 index 000000000..7abe6c9ff --- /dev/null +++ b/e2etests/testdata/stable/hexagon_3d/dagre/board.exp.json @@ -0,0 +1,48 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 0, + "y": 0 + }, + "width": 128, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N5", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 60, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/stable/hexagon_3d/dagre/sketch.exp.svg b/e2etests/testdata/stable/hexagon_3d/dagre/sketch.exp.svg new file mode 100644 index 000000000..37f515d9d --- /dev/null +++ b/e2etests/testdata/stable/hexagon_3d/dagre/sketch.exp.svg @@ -0,0 +1,45 @@ + + +hexagon + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/hexagon_3d/elk/board.exp.json b/e2etests/testdata/stable/hexagon_3d/elk/board.exp.json new file mode 100644 index 000000000..69e00a8d1 --- /dev/null +++ b/e2etests/testdata/stable/hexagon_3d/elk/board.exp.json @@ -0,0 +1,48 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "hexagon", + "type": "hexagon", + "pos": { + "x": 12, + "y": 12 + }, + "width": 128, + "height": 69, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "N5", + "stroke": "B1", + "shadow": false, + "3d": true, + "multiple": false, + "double-border": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "hexagon", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 60, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/stable/hexagon_3d/elk/sketch.exp.svg b/e2etests/testdata/stable/hexagon_3d/elk/sketch.exp.svg new file mode 100644 index 000000000..5f1cf80e7 --- /dev/null +++ b/e2etests/testdata/stable/hexagon_3d/elk/sketch.exp.svg @@ -0,0 +1,45 @@ + + +hexagon + + + \ No newline at end of file diff --git a/testdata/d2compiler/TestCompile/3d_oval.exp.json b/testdata/d2compiler/TestCompile/3d_oval.exp.json index e237f09c0..997f4d61c 100644 --- a/testdata/d2compiler/TestCompile/3d_oval.exp.json +++ b/testdata/d2compiler/TestCompile/3d_oval.exp.json @@ -5,7 +5,7 @@ "errs": [ { "range": "d2/testdata/d2compiler/TestCompile/3d_oval.d2,1:0:17-1:19:36", - "errmsg": "d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key \"3d\" can only be applied to squares and rectangles" + "errmsg": "d2/testdata/d2compiler/TestCompile/3d_oval.d2:2:1: key \"3d\" can only be applied to squares, rectangles, and hexagons" } ] }