d2 icon indicating copy to clipboard operation
d2 copied to clipboard

shapes: Add C4 Model shapes / Presets

Open iAdanos opened this issue 2 years ago • 7 comments

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

iAdanos avatar May 02 '23 16:05 iAdanos

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

alixander avatar Jun 09 '23 18:06 alixander

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?

goto1134 avatar Sep 19 '23 17:09 goto1134

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}

bo-ku-ra avatar Sep 21 '23 01:09 bo-ku-ra

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

oefe avatar Aug 14 '24 13:08 oefe

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&

bo-ku-ra avatar Aug 14 '24 14:08 bo-ku-ra

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

oefe avatar Aug 14 '24 19:08 oefe

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

alixander avatar Aug 16 '24 05:08 alixander