terrastruct / d2

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

lang: Custom shape types #133

Open modoodalvi opened 1 year ago

modoodalvi commented 1 year ago

Currently following shape types are supported: circle, oval, hexagon, queue, package, cylinder, page, cloud, class, sql_table.

Support creation of own shape types. This can be then also combined with style and shape:image.

As an example:

# definition
type unicorn:shape {
  icon: https://example.com/unicorn.svg 
}
# usage
foo: {shape:unicorn} 
reedhedges commented 1 year ago

Yes, this is very important for people to use and share consistent design vocabularies and communicate with them.

Also need custom type definitions for connectors as well.

It would also be great if these custom types could be included or imported some how, so they could be stored and shared separately (is there a feature request for that yet?)

alixander commented 1 year ago

Re, yep! issue for imports: https://github.com/terrastruct/d2/issues/554

Re, this issue: a shape type in D2 needs:

  1. The SVG path
  2. "Center ports" that routing should go (otherwise will be treated like a rectangle for routing)
  3. A bit for whether its aspect ratio needs to stay 1:1 (set to true on square and circle types)
  4. A bounding box for its labels (e.g. in the cylinder type, the space for labels is not the same as the space for the shape)

Is it custom shapes you want or just avoid repeating the icon definition?

I believe that the class keyword is really what you'd want, which is the works. Anywhere you want to use a custom image, just do foo: { class: unicorn }, and define the class unicorn to have the icon. Maybe you can use that with a shape. Like, your unicorn SVG when combined with shape: circle can center-crop to give a circular image.

If you still believe custom shape types are needed, I'm interested to hear what I might be missing.

reedhedges commented 1 year ago

for myself, I'm looking for the ability to define a new object in terms of existing shape types plus properties (added or overridden). (Not just a new shape with a new SVG image etc.). If class is similar, that would be great.

(Note I am pretty new to using d2 so may be missing some stuff.)

E.g. instead of:

thing1: {
  shape: cloud
  icon: https://icons.terrastruct.com/infra/019-network.svg
}

thing2: {
  shape: cloud
  icon: https://icons.terrastruct.com/infra/019-network.svg
}

obj1: {
  shape: diamond
}

obj2: {
  shape: rectangle
}

thing1 -> obj1: {
  style: {
    stroke-dash: 4
  }
}

thing2 -> obj1: {
  style: {
    stroke-dash: 4
  }
}

obj1 -> obj2

thing3: {
  shape: cloud
  icon: https://icons.terrastruct.com/infra/019-network.svg
  style: {
    fill: yellow
  }
}

obj2 -> thing3

Do something like:

def NetSource: {
  shape: cloud
  icon: https://icons.terrastruct.com/infra/019-network.svg
}

def Update: {
  style: {
    stroke-dash: 4
  }
}

def Combiner: {
  shape: diamond
}

def Processor: {
  shape: rectangle
}

thing1 (NetSource)

obj1 (Combiner)
obj2 (Processor)

thing1 -> obj1 <Update>

thing2 (NetSource) -> obj1 <Update>

obj1 -> obj2

thing3 (NetSource): {
  style: {
    fill: yellow
  }
}

obj2 -> thing3 <Update>

... or however you want to do it.

alixander commented 1 year ago

oh the aliasing use case is interesting, saying "class: Processor" would achieve the same effect but does have different semantics.

modoodalvi commented 1 year ago

Is it custom shapes you want or just avoid repeating the icon definition?

For me, it is the repeating of the icon in the first place.

However, having custom shapes still has its benefits:

  1. You can create shape sets and share them with others. Thinking in the direction of draw.io.
  2. A shape can have an appearance and a behavior. The class would only define the appearance.
Nepo26 commented 1 year ago

For me that would be a good addition for the arrow to reach the shape. As When I define an image there is still a gap with the shape. If defining a shape I think it'll be able to connect correctly.

alixander commented 1 year ago

@Nepo26 oh interesting, so the custom shape i guess would hug the path of the image SVG instead of just a rectangle for the image?

Nepo26 commented 1 year ago

Exactly. Currently what we have is a padded image if we use a class with an svg and an image shape. As is observable in the following. image

What I think that would be ideal is to be able to customize this padding. Or when we define a custom shape it works in the same way. Connecting directly as the following: image