terrastruct / d2

D2 is a modern diagram scripting language that turns text to diagrams.
https://d2lang.com
Mozilla Public License 2.0
16.63k stars 417 forks source link

shapes: Add C4 Model shapes / Presets #1277

Open iAdanos opened 1 year ago

iAdanos commented 1 year ago

It would be great to have default shapes for full C4 Model. It's required sometimes by company's processes and standards.

Example shapes implementation can be found in draw.io's code

alixander commented 1 year ago

these should all easily be composable in D2, once we allow setting label position. Except for the unique person shape. i don't want there to be two person shapes. i doubt the shape being different would go against a company requirement.

now that imports and classes are feature, i think D2 can start offering some third party plugin ecosystem. E.g. you can download the "c4 package" which defines a bunch of stuff that your diagram can import. i guess globs would make this even more powerful (the package can say "make all person shapes this color and style"), so will wait for that before making any moves here

Screen Shot 2023-06-09 at 11 52 13 AM
goto1134 commented 1 year ago

I think most of the shapes are already there. Check out the following code in my exporter to D2 from the structurizr language: https://github.com/goto1134/structurizr-d2-exporter/blob/main/lib/src/main/kotlin/io/github/goto1134/structurizr/export/d2/ElementExt.kt#L16

Here is the list of shapes: https://structurizr.com/help/shapes. And also represented as code here: https://github.com/structurizr/java/blob/master/structurizr-core/src/com/structurizr/view/Shape.java.

While I believe adding the absent shapes should not be hard, could you elaborate on why these windows, mobile phones, and robots matter? Do you use them? How widely are they adopted from your point of view?

bo-ku-ra commented 1 year ago

can this whole d2 source be defined as a new person shape?

# ----------------------------------------------------------------------
# D2 - Declarative Diagramming https://d2lang.com/tour/intro/
# ----------------------------------------------------------------------
vars:"d2 v0.6.0" {
  name: {
  label:"foobar"
  style.border-radius: 60
  width: 300
  height: 150
  }
}
# ----------------------------------------------------------------------

grid-columns: 1
grid-rows: 2
grid-gap: 0

head: "" {
  style.opacity: 0
  grid-columns: 3
  grid-gap: 0
  leftside: "" {
    style.opacity: 0
  }
  center: "" {
    shape: circle
    width: 130
  }
  rightside: "" {
    style.opacity: 0
  }
}
body : ${name}
oefe commented 1 month ago

I tried to make a reusable version of the person shape by @bo-ku-ra:

vars: {
    person-shape: {
      label: ""
      grid-columns: 1
      grid-rows: 2
      grid-gap: 0
      style.opacity: 0.0
      head: {
        label: ""
        style.opacity: 0
        grid-columns: 3
        grid-gap: 0
        leftside: {
          style.opacity: 0
        }
        center: {
          label: ""
          shape: circle
          width: 130
        }
        rightside: {
          style.opacity: 0
        }
      }
      body: {
        label: ""
        style.border-radius: 60
      }
    }
  }

  dora {
    ...${person-shape}
    body.description: |md
    ## Dora

    [Person]

    Some person.

    Their name starts with "D"
    |
  }

  emily {
    ...${person-shape}
    body.description: |md
    ## Emily

    [Person]

    Some person.

    Their name starts with "E"
    |
  }

  dora->emily: "Friends"

This almost works, except that the heads are below the body:

image

This is a bit puzzling, as it works in the original version, and body is clearly after head, so the grid layout should put it below.

Maybe the ...${person-shape} construct doesn't preserve the order of map keys?

So close...

Playground link

bo-ku-ra commented 1 month ago

they appear to be replaced in the order of appearance. strange.

vars: {
  person-shape: {
    label: ""
    grid-columns: 1
    grid-rows: 2
    grid-gap: 0
    style.opacity: 0.0
    head: {
      label: ""
      style.opacity: 0
      grid-columns: 3
      grid-gap: 0
      leftside: {
        style.opacity: 0
      }
      center: {
        label: ""
        shape: circle
        width: 130
      }
      rightside: {
        style.opacity: 0
      }
    }
    body: {
      label: ""
      style.border-radius: 60
    }
  }
}

dora: {
  ...${person-shape}
  head.label: null
  body.description: |md
    ## Dora

    [Person]

    Some person.

    Their name starts with "D"
  |
}

emily: {
  ...${person-shape}
  head.label: null
  body.description: |md
    ## Emily

    [Person]

    Some person.

    Their name starts with "E"
  |
}

dora -> emily: "Friends"

https://play.d2lang.com/?script=rJIxa_swEMV3fYrD-a8WyT_QQUOnpHOh3UoHxbrGB7Jk7pQGk-S7F1tu4qaUUtrF5h6693486dWyGDgogBZZYiilti1mBcDbDXoDRTFMWyZXVtHvmiAGFheN414M_L8IW9samA-zpM6jjq2tKHUG5jrLNVr3nnKd83lplD8CLKfqJBHA40sScngJ-NLyNP4rDAl5unDNBDBWUxFXHs_qnlyqDSyW15ZM2_pnGPm7ia77rppNZIdcsnW0EwM38_P-SZ2UcpFtttBa_ztMr7Y_05evR-Ow817lUO1QKqY2UQwGjo0bTGczWEW2ahie7ger5zw9xAbHd6Oz8lgjMQTbIEiynAT2lGooVj3-sUfDhnz3h2zr3u93cOszXN8blLcwQhZ3TBicFOotAAD__w%3D%3D&layout=dagre&

oefe commented 1 month ago

Well, I guess that's a useable workaround until we have a better solution

alixander commented 1 month ago

Maybe the ...${person-shape} construct doesn't preserve the order of map keys?

Hm that looks like a bug, will investigate. Thank you

edit: dev notes: looks like this is related to https://github.com/terrastruct/d2/issues/1721 , the way D2 compiles vars needs to be rewritten

edit 2: nvm it's fixed, will be good in next release