Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

d2renderer: #579 Circle Arrowhead #634

Merged
merged 22 commits into from
Jan 20, 2023
Merged

Conversation

Paracelsus-Rose
Copy link
Contributor

@Paracelsus-Rose Paracelsus-Rose commented Jan 10, 2023

Circles for arrowheads #579

./ci/test.sh Is failing. Not sure why, all else looks good.

image

@alixander
Copy link
Collaborator

./ci/test.sh Is failing. Not sure why, all else looks good.

what's the error? common issues: we're on go 1.18

@Paracelsus-Rose
Copy link
Contributor Author

    --- FAIL: TestE2E/stable (0.00s)
        --- FAIL: TestE2E/stable/circle_arrowhead (0.13s)
            e2e_test.go:175: unexpected error: diff (rerun with $TESTDATA_ACCEPT=1 or $TA=1 to accept):
                --- /dev/null
                +++ b/testdata/stable/circle_arrowhead/dagre/board.got.json
                @@ -0,0 +1,264 @@
                +{

I assume if I do the test data accept it goes away, just was not sure.

@Paracelsus-Rose
Copy link
Contributor Author

./ci/test.sh Is failing. Not sure why, all else looks good.

what's the error? common issues: we're on go 1.18

image

Did TA=1, not sure if this is correct or not.

Copy link
Collaborator

@alixander alixander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alixander
Copy link
Collaborator

yep, because it has no expected, for new tests you'll want to run with that accept env variable. i'll add that flow to the CONTRIBUTING.md.

@Paracelsus-Rose
Copy link
Contributor Author

Copy link
Collaborator

@alixander alixander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'll need to run the tests with TESTDATA_ACCEPT and then check in the results

Copy link
Contributor

@ejulio-ts ejulio-ts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 thanks @Paracelsus-Rose

Particularly, I found a bit hard to follow some constants in d2svg, not sure if we should change something in general so that we can include some ascii art about them. Most of them are just geometrical stuff for rendering, so having some drawings/examples could be useful in general.

Then, I believe this is related to offset, I wonder why the circles aren't touching the shapes borders.

Finally, I believe it is worth changing some of the test cases to use other shapes, besides squares, just to see how the arrowheads are rendered

@alixander
Copy link
Collaborator

Then, I believe this is related to offset, I wonder why the circles aren't touching the shapes borders.

i think that's right, we don't want it touching the border, but I think we should leave like 1px of padding or something, right now I did notice it's a little too much. i'd be curious to see if no padding looks weird though or if i'm imagining it

@Paracelsus-Rose
Copy link
Contributor Author

Paracelsus-Rose commented Jan 10, 2023

image

I was following the diamond's for render. Here I show what I was looking at locally. I see the crows feet and arrow both touch, the diamond was not and I was not sure. Having the circles touch looks a little strange, the padding I thought made more sense visually from a distance and zoomed in.

This is them touching. Let me know which you prefer.

image

@Paracelsus-Rose
Copy link
Contributor Author

Then, I believe this is related to offset, I wonder why the circles aren't touching the shapes borders.

i think that's right, we don't want it touching the border, but I think we should leave like 1px of padding or something, right now I did notice it's a little too much. i'd be curious to see if no padding looks weird though or if i'm imagining it

image

This is how it currently stands.

@Paracelsus-Rose Paracelsus-Rose requested review from alixander and ejulio-ts and removed request for alixander and ejulio-ts January 10, 2023 20:32
Copy link
Collaborator

@alixander alixander left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screen Shot 2023-01-10 at 12 42 36 PM

i think you have to account for stroke width

@Paracelsus-Rose
Copy link
Contributor Author

Screen Shot 2023-01-10 at 12 42 36 PM

i think you have to account for stroke width

Will need to look around and see what I can come up with. Have not worked with svg's prior to this. I see LineArrowhead is the only other one accounting for it hardcoded in, that and the offset on crows foot. Personally I liked the smallest gap thus far, and not touching the best, but it is not the same as everything else. Will play around and see. Just to make sure, you are saying that it is not pixel perfect on the edge connection there, due to not accounting for stroke width, correct?

@alixander
Copy link
Collaborator

Just to make sure, you are saying that it is not pixel perfect on the edge connection there, due to not accounting for stroke width, correct?

yes.

Personally I liked the smallest gap thus far

i do too, but maybe we'll like the third option best of perfectly touching (after accounting for stroke widths)

@ejulio-ts
Copy link
Contributor

@Paracelsus-Rose

You might want to check this PR for arrowhead overlaps 😂
#48

It took me awhile to get it right (with the web app, d2, tala).
Particularly, you just need to account for edge and arrowhead width, the proper tracing to the shape border happens somewhere else.

What happens in that SVG borders grow in both directions ([in|out]ward) so you need to handle that when computing the overlap
https://stackoverflow.com/questions/7241393/can-you-control-how-an-svgs-stroke-width-is-drawn

@Paracelsus-Rose
Copy link
Contributor Author

@Paracelsus-Rose

You might want to check this PR for arrowhead overlaps joy #48

It took me awhile to get it right (with the web app, d2, tala). Particularly, you just need to account for edge and arrowhead width, the proper tracing to the shape border happens somewhere else.

What happens in that SVG borders grow in both directions ([in|out]ward) so you need to handle that when computing the overlap https://stackoverflow.com/questions/7241393/can-you-control-how-an-svgs-stroke-width-is-drawn

image

Still not right, and it feels so magic number-y now. I wrote out a TS script quick to check my numbers and that just made me even more confused. At least in regards to the cx.

image

Will go back and attack it in a little bit. Svg's are interesting. Been good fun, apologize its been a crackpot job.

@ejulio-ts
Copy link
Contributor

About the diamond offset. I believe this is an issue as it should touch the shape.
About the circle. I believe that should just account for edge stroke width when computing the edge offset, so that things are placed properly.

Consider the diagram below, where * represents the 1px edge/shape and the surround lines represent the offset of shape/edge stroke width

│ * │ note the edge and shape overlap │ * │
│ * │              ▼                  │ * │
│ * └────────────┬───┬────────────────┘ * │  ┬
│ ***************|***|******************* │  | shape stroke width
└────────────────┤ * ├────────────────────┘  ┴
                 │ * │
                 │ * │
                 │ * │
                 │ * │
                 │ * │
                 │ * │
                 │ * │
                 │ * │

                 |---|
            edge stroke width

The arrowhead adjustment I worked on was https://github.com/terrastruct/d2/blob/master/d2renderers/d2svg/d2svg.go#L300-L308

The idea is:

  • By default, the offset is half shape + half edge stroke width (see the diagram above)
  • If there's an arrowhead, then the arrowhead adds edge stroke width to offset because the arrowhead goes at the end of the edge adding 2*half edge stroke width overlap

@gavin-ts
Copy link
Contributor

Consider the diagram below, where * represents the 1px edge/shape and the surround lines represent the offset of shape/edge stroke width

The idea is:

  • By default, the offset is half shape + half edge stroke width (see the diagram above)
  • If there's an arrowhead, then the arrowhead adds edge stroke width to offset because the arrowhead goes at the end of the edge adding 2*half edge stroke width overlap

To expand on that, the end coordinate of the edge will be exactly on the border of the shape, but we need to move it back so the end of where the edge's stroke is rendered matches up to where the end of the shape's stroke is rendered.

So if we have an edge ending at point O at (0,0), shape stroke width is 3, and edge stroke width is 5, it will need to move down (1.5+2.5). Otherwise the default rendering would have the overlap below:

│ *** │ note the edge and shape overlap │ *** │
│ *** │              ▼                  │ *** │
│ *** │           ┌─────┐               │ *** │
│ *** └───────────┼*****┼───────────────┘ *** │  ┬ y=-1.5
│ ****************|*****|******************** │  | 
│ ****************|**O**|******************** │  | shape stroke width = 3
│ ****************|*****|******************** │  | 
└─────────────────┼*****┼─────────────────────┘  ┴ y=1.5
                  │*****│                    
                  │*****│ O: @(0,0) is edge end point (y is equal to bottom coordinate of shape)
                  │*****│                    
                  │*****│                    
                  │*****│                    
                  │*****│                    
                  │*****│                    
                  │*****│                    
                                             
                  |-----|                    
              edge stroke width = 5          
              x=-2.5   x=2.5

after moving down with the offset of 4:

│ *** │ edge and shape ends now line up │ *** │
│ *** │              ▼                  │ *** │
│ *** └─────────────────────────────────┘ *** │  ┬ y=-1.5
│ ******************************************* │  | 
│ ******************************************* │  | shape stroke width = 3
│ ******************************************* │  | 
└─────────────────┬─────┬─────────────────────┘  ┴ y=1.5
                  │*****│                    
                  │*****│                    
                  │**O**│ O: @(0,4)
                  │*****│                    
                  │*****│                    
                  │*****│                    
                  │*****│                    
                  │*****│                    
                  │*****│                    
                                             
                  |-----|                    
              edge stroke width = 5          
              x=-2.5   x=2.5

@Paracelsus-Rose
Copy link
Contributor Author

Paracelsus-Rose commented Jan 15, 2023

@gavin-ts @ejulio-ts
Wrote this today to learn more about SVG's, stroke widths etc. Not sure if more questions were created or answered by doing so. Realizing I am really not accounting for stroke width correct. Will think more on it.

https://stackblitz.com/github/Paracelsus-Rose/svg-circles?file=src%2Fviews%2FSvgCircleView.vue

https://github.com/Paracelsus-Rose/svg-circles

image

Did not think it would become this when I was like, oh that looks easy :-). Cheers yall, its been fun.

@Paracelsus-Rose
Copy link
Contributor Author

The above linked stackblitz is where I have it currently. I am thinking there is some assumption I am making there which does not translate to d2. Most recent commit to this PR I tried to mimick the values over, but something is going wrong. Maybe need some new eyes on it, or a fresh head tomorrow.

Here stroke width is accounted for correctly, and all is aligning up on center.
image
image

But in d2svg.go it is not still.
image

Until next time.

@alixander
Copy link
Collaborator

alixander commented Jan 16, 2023

i haven't looked into your code, but there's a few likely offenders:

  1. cx and cy are middle of circle
  2. r is radius (half of length)
  3. svg coordinates are top-left is 0,0 and going right 1 unit and down 1 unit gets you to 1,1.
  4. stroke-width grows from the middle, as demonstrated by my colleague's ascii art
  5. both the circle path (connection arrowhead) and the main path (connection) have stroke-width

@Paracelsus-Rose
Copy link
Contributor Author

image

Appreciate the help @gavin-ts. This seems right now. Do apologize with the confusion. You were also correct, been thinking the last 3 days while I settled in at the new house about what @alixander said, how the SVG's are rendered from 0,0 in the top left. I knew when he said that I was trying to solve a problem on a false pretense. This should be corrected now, anything else which needs to be done let me know. Did not expect to get stuck on this, but wow did I learn a lot about SVG rendering. Yall inspired me to make some fun stuff in the last week. Cheers everyone.

Copy link
Contributor

@gavin-ts gavin-ts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like the test was added twice in a merge, other than that it looks good to go

@alixander
Copy link
Collaborator

sweet, let's try to get this into the release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants