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

chore(Object) removed code for options we dont want to use in _getTransformedDimensions #9620

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

asturur
Copy link
Member

@asturur asturur commented Jan 21, 2024

Description

It happened already that we tried to use _getTransformedDimensions with generic overriding options to work around issues, and then we disagreed on that being a good practice.
This PR reduces the options that are accepted by _getTransformedDimensions to the one we really use.

In Action

Copy link

codesandbox bot commented Jan 21, 2024

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

Copy link
Contributor

github-actions bot commented Jan 21, 2024

Build Stats

file / KB (diff) bundled minified
fabric 907.421 (-0.477) 304.314 (-0.237)

Copy link
Contributor

Coverage after merging _getTransformedDimension-cleanup into master will be

82.77%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
index.node.ts14.29%100%0%25%23, 26, 29, 41, 44, 47
src
   ClassRegistry.ts100%100%100%100%
   Collection.ts94.85%94.83%87.10%97.14%109, 112, 215–216, 241–242
   CommonMethods.ts96.55%87.50%100%100%9
   Intersection.ts100%100%100%100%
   Observable.ts87.76%85.29%87.50%89.58%134–135, 160–161, 32–33, 41, 50, 78, 89
   Point.ts100%100%100%100%
   Shadow.ts98.36%95.65%100%100%178
   cache.ts97.06%90%100%100%57
   config.ts74.14%65%66.67%82.76%131, 139, 139, 139, 139, 139–141, 152–154, 30
   constants.ts100%100%100%100%
src/LayoutManager
   LayoutManager.ts87.50%89.29%76.92%90%133–134, 136–137, 137, 137, 137, 137, 231, 289–290, 301, 46
   constants.ts100%100%100%100%
src/LayoutManager/LayoutStrategies
   ClipPathLayout.ts82.05%72.22%100%88.89%30–31, 42, 54, 57–58, 65
   FitContentLayout.ts100%100%100%100%
   FixedLayout.ts20%0%0%40%20–21, 23, 23, 23, 23, 23
   LayoutStrategy.ts86%64.71%100%96.15%36, 43, 43, 43, 51, 71–72
   utils.ts91.67%85.71%100%100%28, 34
src/Pattern
   Pattern.ts90.54%93.94%80%90.32%119, 130, 139, 32, 36
src/brushes
   BaseBrush.ts100%100%100%100%
   CircleBrush.ts0%0%0%0%108, 108, 108, 110, 112, 114–116, 118–121, 128–129, 13, 136, 138, 23–24, 32–36, 40–44, 51–54, 62–66, 68, 76, 76, 76, 76, 76–77, 79, 79, 79–82, 84, 92–93, 95, 97–99
   PatternBrush.ts97.06%87.50%100%100%21
   PencilBrush.ts91.06%82.35%100%93.81%122–123, 152, 152–154, 176, 176, 276, 280, 285–286, 68–69, 84–85
   SprayBrush.ts0%0%0%0%107, 107, 107, 107, 107–108, 110–111, 118–119, 121, 123–127, 136, 140–141, 141, 148, 148, 148–151, 153–156, 160–161, 163, 165–168, 17, 171, 178–179, 18, 181, 183–184, 186, 193–194, 196–197, 20, 200, 200, 207, 207, 21, 211, 22, 22, 22–24, 28, 32, 39, 46, 53, 60, 67, 84–86, 94–96, 98–99
src/canvas
   Canvas.ts78.66%77.04%82.14%79.33%1001–1003, 1006–1007, 1011–1012, 1123–1125, 1128–1129, 1202, 1314, 1435, 158, 183, 289, 289–294, 299, 322–323, 328–333, 353, 353, 353–354, 354, 354–355, 363, 368–369, 369, 369–370, 372, 381, 387–388, 388, 388, 42, 431, 439, 443, 443, 443–444, 446, 46, 528–529, 529, 529–530, 536, 536, 536–538, 558, 560, 560, 560–561, 561, 561, 564, 564, 564–565, 568, 577–578, 580–581, 583, 583–584, 586–587, 599–600, 600, 600–601, 603–608, 614, 621, 658, 658, 658, 660, 662–667, 673, 679, 679, 679–680, 682, 685, 690, 703, 731, 783–784, 784, 784, 784, 784, 784, 787–788, 791, 791–793, 796–797, 879, 886, 886, 886, 899, 928–929, 929, 929–931, 934–935, 935, 935, 937, 945, 945, 945–947, 947, 947, 954–955, 963–964, 964, 964–965, 971, 973
   CanvasOptions.ts100%100%100%100%
   SelectableCanvas.ts90.22%87.30%94.55%91.74%1004, 1012, 1123, 1125, 1127–1128, 1199, 1220–1221, 1239–1240, 460–461, 463–464, 464, 464, 513–514, 591, 596, 666, 671–672, 699–700, 724, 727–730, 730, 730–731, 731, 731, 737–738, 740, 760–761, 766–770, 772, 807–808, 811, 811, 811–812, 931, 931–932, 935, 955, 955
   StaticCanvas.ts96.51%93.04%98.91%98.28%1014, 1024, 1075–1077, 1080, 1115–1116, 1192, 1201, 1201, 1205, 1205, 1252–1253, 179–180, 196, 554, 566–567, 897–898, 898, 898–899
   StaticCanvasOptions.ts100%100%100%100%
   TextEditingManager.ts86%71.43%91.67%91.67%17, 17, 17–18, 18, 18
src/canvas/DOMManagers
   CanvasDOMManager.ts95.52%70%100%100%21–22, 29
   StaticCanvasDOMManager.ts97.50%88.89%100%100%33
   util.ts86.67%80.56%83.33%93.94%14, 26, 63–64, 67, 67, 74, 93–94
src/color
   Color.ts94.96%91.67%96.30%96.05%233, 258–259, 267–268, 48
   color_map.ts100%100%100%100%
   constants.ts100%100%100%100%
   util.ts85.71%76.92%100%89.74%55–56, 56, 58, 58, 58–59, 61–62, 89
src/controls
   Control.ts94.44%93.10%91.67%96.77%183, 249, 354
   changeWidth.ts100%100%100%100%
   commonControls.ts100%100%100%100%
   controlRendering.ts81.63%78%100%84.78%106, 111, 121, 121, 45, 50, 61, 61, 65–72, 81–82
   drag.ts100%100%100%100%
   fireEvent.ts88.89%75%100%100%13
   polyControl.ts10.87%0%0%16.13%114, 114, 114, 114, 114, 116–119, 119, 122, 129, 24–26, 50–52, 58–59, 61, 71, 77–79, 79, 81, 84, 86, 90–92, 94, 99
   rotate.ts19.57%12.50%50%21.43%41, 45, 51, 51, 51–52, 55–57, 59,

)
)
) {
if (this.strokeUniform || 'skewX' in options || 'skewY' in options) {
Copy link
Member Author

Choose a reason for hiding this comment

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

there are 4 options and only skewX and skewY are in layoutProperties, so we can check specifically.

@jiayihu
Copy link
Contributor

jiayihu commented Feb 2, 2024

At company where I work, we actually use this hack to get the transformed dimensions of an object when only some properties (delta) have been changed by another user. So we call the method with the changed methods to calculate what the dims are going to be.

Of course we can just define a function that does as before. I'm just wondering what would be the rational of reducing the amount of accepted props while not offering a good alternative. Nobody seems to get benefits here.

@asturur
Copy link
Member Author

asturur commented Feb 4, 2024

it wasn't about benefits but just that his shouldn't be done.
This is just a clean up.
getTransformedDimensions supports scaleX scaleY and skewX, skewY because of how the skew mouse handler is written.
Then at some point we extended it to support more stuff and we realized it won't work, once i used with strokeWidth and we agreed was a bad idea and we changed the PR.

I don't need to merge this now if you don't have an alternative, but in general a method that says:
'tell me how big this instance is, but pretending some values are different' doesn't make much sense.
The biggest issue i have with this functionality is also that you have to pass down the values to other utils and support it everywhere down the chain.

You can

  • create a clone of the instance and measure it with different props,
  • or use the Function.call method passing an ad hoc context.
  • or create a wrapper method that support options and change the values and restore them before exiting

All of those are better than this

@jiayihu
Copy link
Contributor

jiayihu commented Feb 5, 2024

The biggest issue i have with this functionality is also that you have to pass down the values to other utils and support it everywhere down the chain.

From a consumer POV this is actually better than the options you suggested, as it doesn't involve doing mutations (unreliable as you depend on the exact implementation of each underlying method) or creating clones (unreliable as well since some internal states may not be cloned correctly since we're dealing with non-trivial classes, not plain objects).

Passing down values is more unconvenient for the maintainer, but far more predictable and reliable for consumer. I wonder if we could borrow some concepts from functional-programming, such as...the Reader Monad? https://dev.to/gcanti/getting-started-with-fp-ts-reader-1ie5.

Just kidding. But it could be an idea for instance starting to extract some props under obj.state, e.g.:

transformState: { x: number, y: number, width: number, height: number, scaleX: number, scaleY: number, angle: number, skewX: number, skewY: number }

Then having methods using this.transformState, so one would' only need to override transformState following your 3rd suggestion. Or the utils just need to accept the transform state as single extra param, if you want to keep them pure.

Could potentially also play nicer with reactive states. I've suggested multiple times to @ShaMan123 the need for some sort of higher-level reactive state like https://preactjs.com/guide/v10/signals/, which avoids the need for getters when you want some properties to be derived from others. For instance, transformed dimensions is a derived state of transformState or invalidating the cache canvas is an effect of changing the state.

@asturur
Copy link
Member Author

asturur commented Feb 5, 2024

i think the solution is very simple, methods work on the instance state, function can work on any passed parameters.

So if this kind of predicting size is really useful, it should be come an util, then the method can call the util with its own state, 'this' while the utility itself can be called with any state object you want.

But again, this shouldn't really have existed in my opinion, i should have never added scaleX, scaleY, skewX and skewY ages ago, but in that moment supporting skew by mouse seemed so cool to me. I do not know why. I think skewing by mouse is mostly useless.

@asturur
Copy link
Member Author

asturur commented Feb 5, 2024

Is your use case measuring changes to the instance size from changing properties? Is that all?

@jiayihu
Copy link
Contributor

jiayihu commented Feb 5, 2024

i think the solution is very simple, methods work on the instance state, function can work on any passed parameters.

True and fabric should limit usage of methods IMO, as it makes overriding harder. You have to ensure the instance state is exactly as expected at each internal method. It's better instead to prepare all the state mutations at once, then call functions passing the state as params.
This makes the code also more easier to reason. Mutations typically happen at event start/end, core logic is pure. And for overriding, you just need to do the mutations accurately at the event start/end indeed.

Is your use case measuring changes to the instance size from changing properties? Is that all?

Yes. I'm just getting the "future" dims passing the changed properties, then I'll use the dims to compute the transform matrix of where the object is gonna be. The transform matrix will then be used as "invariant" thoughout the syncing logic, as it tells where the object MUST be in the end, no matter what's the current transform.
Useful for different reasons, even just to debug current intermediate object transform vs expected final transform.

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.

None yet

2 participants