A few weeks ago, I wrote about a coding problem with the Typogram main app: I Hit a Wall Made of Compound Path. I was trying to surface sub-paths of a compound path to users for selection and modification. In other words, make the sub-shapes of a letter selectable and editable on their own:
To do that, I came up with my own compound path renderer, which renders each sub-paths as a separate path object. However, I ran into the z-index problem - the order of these path objects decides who gets to be rendered on top, and when it is out of order, this wrong rendering happens:
Have you ever experienced this type of moment: when you are troubled by a very complex problem, and searching up and down for a solution to solve it, then someone asked you why you need to solve the problem in the first place, and that was it - there was a lightning bolt that struck your head, and you figured out how to deal with the problem - not by solving it, but by avoiding it?!
Storytime!
Once upon a time, in a company that makes electric cars, there is a mechanical part in the car that has a high failure rate. The engineers tried every method to improve that mechanical part, but it still failed frequently. When the CEO is looped in, he asks: why do we need this part? Can we get rid of it from our cars if it creates so much problem? Gasps were heard from the engineers. It was unimaginable - just getting rid of it? Can we do that? It turned out that they could. After much re-engineering, they successfully removed the part from the car design. No one has to worry about the part being faulty anymore because it is not even there.
Thanks for reading my newsletter. Subscribe for free to get weekly updates about my start-up journey!
In my case, the complexity originated from my ambition to create my renderer of a compound path. Fixing my renderer to support these edge cases is too complex - I searched high and low for solutions but to no avail. So I thought, why do I have to use my renderer? Can I go back to use the default compound path renderer? What do I lose if I do that?
I will lose:
Selectability of the sub-paths.
Since they are not rendered separately as path objects, users can only select them all together or none.
Editability of the sub-paths, such as having a different color fill
Since all subpaths are rendered together as one compound path, which has one fill property, every sub-path has to share the same color.
Even though the compound path was rendered as a single object, the path data can be sliced into multiple pieces. In a way, it is still selectable - instead of selecting a whole object, users can select a slice of path data, starting with the letter M and ending with Z. It needs some implementation on the user interface layer of course, but theoretically, #1 can be solved.
Now it comes to tricky #2 - editability. After the sub-path is resized or reshaped, I can generate a new path data slice and replace the old one:
Codepen link: https://codepen.io/wentin/pen/oNGxpGL
However, changing the subpath’s fill color is a whole different matter and much more complex. The sub-path needs to be on its own to have a fill property, and when it is separated, the z-index problem will come back - should the new path object be rendered on top or underneath the rest of the letter? What if there are sub-paths in front of it?
In the end, I wrote a function to loop through every sibling sub-path and determine whether it is inside the target path. If the sibling path is inside of the target path, then I will mark them as “front”; otherwise, I will mark it as “back.” This will generate three layers for a single compound path - front, target, and back, and their z-index is known to me. #2 is solvable.
Here is a demo – the letter O rendered in Monoton font can be selected as a whole or as parts, and each part can have its own color!
So that is how I got rid of the faulty part of my car. I hope this can be useful to you in solving your coding problem! Let me know if this writing inspires you to better solutions to this issue; I would like to hear it!
❧
See you next week! If you have friends who are interested in founding startups, please consider sharing my newsletter with them!
Paper.js has some of these operations that you could either study, or use directly. Divide seems the most relevant.
https://github.com/paperjs/paper.js/blob/develop/src/path/PathItem.Boolean.js#L1221