nativescript-community / ui-canvas

Implement Canvas into your NativeScript apps.
https://nativescript-community.github.io/ui-canvas/
Apache License 2.0
31 stars 9 forks source link

How to make ClipPath works on iOS #25

Closed luiguild closed 3 years ago

luiguild commented 3 years ago

Make sure to check the demo app(s) for sample usage

done

Make sure to check the existing issues in this repository

done

Which platform(s) does your issue occur on?

Please, provide the following version numbers that your issue occurs with:

This code result in different renderings in iOS and Android. In Android works perfectly (like always) but in iOS don't (like always)... the entire canvas content disappear, like have's nothing to draw, all others methods are ignored on drawEvent without any errors, he just ignore and block all other (canvas) things to draw on screen

photo_2020-11-07_08-25-22 is not necessary put the iOS screenshot because it's just a red screen, without the clipPath and the black background (sorry for the biggest image, I don't know how to reduce the preview)

(every day I ask to myself why in 2020 we still trying making apps for iOS, holy God)

farfromrefug commented 3 years ago

@luiguild use Direction.CW for now it will work. Will have to find why it does not work without

luiguild commented 3 years ago

Thanks for your support @farfromrefug. I will test this in Monday and then I coming back to report to you.

ronalson commented 3 years ago

Hello @farfromrefug

(I'm helping @luiguild with this implementation on iOS.)

This is what we have so far:

With this code:

      const backgroundPaint = new Paint()
      backgroundPaint.setAntiAlias(true)
      backgroundPaint.setColor(new Color(this.backgroundColor))
      backgroundPaint.setStyle(Style.FILL)
      canvas.drawPaint(backgroundPaint)

      canvas.save()

We get a dark overlay:

📷 Click to see print ![Simulator Screen Shot - iPhone 12 mini - 2020-11-09 at 16 50 12](https://user-images.githubusercontent.com/8891651/98589417-02b3f700-22ac-11eb-9ee3-a9480515ce95.png)

However, when trying to add the clipPath we couldn't get the desired output: an dark overlay with circle (see @luiguild's print screen).

      const clipPath = new Path()
      clipPath.addCircle(this.clipX, this.clipY, this.clipRadius, Direction.CW)
      canvas.clipPath(clipPath, Op.DIFFERENCE)

      const backgroundPaint = new Paint()
      backgroundPaint.setAntiAlias(true)
      backgroundPaint.setColor(new Color(this.backgroundColor))
      backgroundPaint.setStyle(Style.FILL)
      canvas.drawPaint(backgroundPaint)

      canvas.save()

Either the hole overlay is suppressed, when using CCW.

📷 Output using `Direction.CCW` ![Simulator Screen Shot - iPhone 12 mini - 2020-11-09 at 16 55 39](https://user-images.githubusercontent.com/8891651/98590003-ed8b9800-22ac-11eb-8c58-51eb5e4138e4.png)

or - when using CW - we get the opposite of what we want

📷 Output using `Direction.CW` ![Simulator Screen Shot - iPhone 12 mini - 2020-11-09 at 16 40 00](https://user-images.githubusercontent.com/8891651/98590029-f67c6980-22ac-11eb-85ec-dad1e2be23fc.png)

I tried also a combination of all Op found here, but none of then work

export enum Op {
    DIFFERENCE,
    INTERSECT,
    REPLACE,
    REVERSE_DIFFERENCE,
    UNION,
    XOR,
}

Any idea of what we are missing?


One thing that I would like to add, but I'm not sure if it is related, is that while running the project on iOS, I noticed this conflict warning below and later I found that it is used here https://github.com/nativescript-community/ui-canvas/blob/242bc26f36153d28e6ca8394c9192b297b0d170f/plugin/platforms/ios/src/BezierUtils.m#L695

~/.../Build/Intermediates.noindex/ArchiveIntermediates/appnativescriptvue/IntermediateBuildFilesPath/.../Objects-normal/arm64/UIBezierPath+Elements.o conflicts with same method from another category
farfromrefug commented 3 years ago

@farfromrefug @luiguild please share a repro example of what you want (android) and what s not working (ios). No be careful Op are not working on iOS for clipPath and i am not sure i can make it work. clipPath are a bit tricky and should be used only if necessary. About the warning i dont se the relation with the linked source.

luiguild commented 3 years ago

Hi @farfromrefug the example working on Android https://github.com/luiguild/nativescript-ui-canvas-test

ronalson commented 3 years ago

this is the output running the demo project on both platforms:

iOS Emulator (same on device) | Android - Galaxy Tab 6S

Screen Shot 2020-11-09 at 7 24 09 PM

farfromrefug commented 3 years ago

@ronalson @luiguild basic support implemented in 4.0.33

ronalson commented 3 years ago

@farfromrefug just confirming that it's now working properly on iOS.

🖼️ See preview ![IMG_0EE4AE351E0B-1](https://user-images.githubusercontent.com/8891651/98702144-d2766200-2358-11eb-9c86-0bcbdb4e4a1f.jpeg)

thanks very much for the super-fast response.

farfromrefug commented 3 years ago

Can we close this ?

luiguild commented 3 years ago

Sure! Thanks!

luiguild commented 3 years ago

@farfromrefug how to do the same thing but now using addRoundRect?

we are trying this:

const clipPath = new Path()
clipPath.addRoundRect(new RectF(200, 400, 200, 400), 10, 10, Direction.CW)
canvas.clipPath(clipPath, Op.DIFFERENCE)

but nothing happen even in iOS or Android, any idea?

luiguild commented 3 years ago

solved using this:

const clipPath = new Path()
const rect = createRectF(
    200,
    400,
    200,
    400
)
clipPath.addRoundRect(
    rect,
    10,
    10,
    Direction.CW
)
canvas.clipPath(clipPath, Op.DIFFERENCE)

thanks again!

farfromrefug commented 3 years ago

@luiguild wait you mean the rectf constructor did not work ?

luiguild commented 3 years ago

@farfromrefug yep, you are right, using the constructor I was unable to do the same thing that when I used the creactRectF method

farfromrefug commented 3 years ago

@luiguild thanks I ll.fix it

luiguild commented 3 years ago

@farfromrefug just to track another thing that is not related, but I figure out right now. I get an error when I try use this:

canvas.save()
const rect = createRectF(
  100,
  100,
  100,
  100
)

canvas.drawRoundRect(
  rect,
  10,
  10,
  fillPaint
)

canvas.restore()

Sometimes I get this

Error: java.lang.Exception: Failed resolving method drawRoundRect on class android.graphics.Canvas

and sometimes this

Error: java.lang.Exception: Failed resolving method drawRoundRect on class android.view.RecordingCanvas
farfromrefug commented 3 years ago

@luiguild ok so first new RectF works. But you did not understand the arguments. You dont pass the width! This is the difference with createRectF

Now about your error i cant really help without more info. That error means you passed arguments to drawRoundRect which are not good and it cant find the method with the arguments you passed. I need to know what you pass in that moment

luiguild commented 3 years ago
const clipPath = new Path()
clipPath.addRoundRect(new RectF(200, 400, 200, 400), 10, 10, Direction.CW)
canvas.clipPath(clipPath, Op.DIFFERENCE)

@farfromrefug no sir, I pass 4 parameters, x: 200, y: 400, width: 200 and height: 400, like in the docs say, 4 parameters: left, top, right and bottom... Look that's the same values pass to the createRectF method. Obviously that's values are symbolic, and I obviously use some variables to fill this values in my app, but the method's contract it's correct...

It's 'the same' case in my second thing about drawRoundRect, the contract it's correct too. 4 parameters, RectF, rx, ry and Paint.

If it's not, help me to figure out whats the discrepancy with my code and the official documentation please. Thank you again.

luiguild commented 3 years ago

@farfromrefug forget it about drawRoundRect, I found the error in my code, It's not in there, I could make it's works! Thanks!