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

feat(IText): Swap flashing Rate of Editing Cursor for better feedback #9823

Closed
wants to merge 11 commits into from
Closed

feat(IText): Swap flashing Rate of Editing Cursor for better feedback #9823

wants to merge 11 commits into from

Conversation

milonic
Copy link
Contributor

@milonic milonic commented Apr 24, 2024

This commit adjusts the initial flashing speed of the cursor when editing text.

At the moment, when you click on text being edited, the cursor will only begin flashing after its delay has occurred. By swaping the "toValues" around, this makes the cursor begin to flash more quickly provided better feedback to the user.

This commit adjusts the initial flashing speed of the cursor when editing text.

At the moment, when you click on text being edited, the cursor will only begin flashing after its delay has occurred. By swaping the "toValues" around, this makes the cursor begin to flash more quickly provided better feedback to the user.
Copy link

codesandbox bot commented Apr 24, 2024

Review or Edit in CodeSandbox

Open the branch in Web EditorVS CodeInsiders

Open Preview

@ShaMan123
Copy link
Contributor

Funny timing
I noticed the same this week and changed some code on a project I work on

@asturur
Copy link
Member

asturur commented Apr 24, 2024

I do not think there is a way to test this properly apart manual verification.
Can you delete the bak file?

@milonic
Copy link
Contributor Author

milonic commented Apr 24, 2024

Deleted

@asturur
Copy link
Member

asturur commented Apr 24, 2024

I didn't run the code yet, but basically is going to take longer to fade and quicker to get back to full opacity.
i have to watch but i think is fine.
Add also a changelog in the CHANGELOG.md file, exactly as you see for the other PRs, same schema.
I ll adjust the PR title so you can see the format

@asturur asturur changed the title Adjust Flashing Rate of Editing Cursor feat(IText): Swap flashing Rate of Editing Cursor for better feedback Apr 24, 2024
@asturur
Copy link
Member

asturur commented Apr 25, 2024

I have been staring at the cursor long enough to say this could make sense.
The description is a bit unclear and i want to clarify a second.
The cursor start at opacity 1 and before the change the first tick of around 600ms is at opacity 1. so it stays 600ms solid, then it goes back to opacity 0 in 300ms, then it goes back up to 600ms solid and the cycle continue.

There is an additional forced delay, called cursor delay that is imposed when the cursor is moved between places and is used to do not have the cursor flashing until is steady.

It make sense that the first animation is the one that fades out since if we want a dealy we can just add it explicity, but what is changing here is also that we swap also the speed of fading. In my opinion we should also swap the duration of the animation.

@asturur
Copy link
Member

asturur commented Apr 25, 2024

image

here i made a picture to better explain the 3 changes this code brings.
the top line is master, the line below is your code changes.

the 3 changes are:

  • reduced delay at the start ( because we don't do a wasted to 1 to 1 animation of 0.6 + 0.1 secs
  • permance of 0.1 sec in off state rather than on state.
  • change of the slope for disappearing vs reappering

Can you please try to explain which one ( or more than one ) from the 3 is bringing the improved experience in your opinion?

@milonic
Copy link
Contributor Author

milonic commented Apr 25, 2024

I've just noticed that cursorDelay is only being applied to a keyboard event.

If I set cursorDelay to 2000 and press a key, there is a 2 second delay before fadeout. If I move the cursor with the mouse, there's no delay from a mouse up event.

Surely it should be the same. Always starting at 1, then slight delay before fading out?

As it is right now, on focus, there is a long delay before the cursor begins to fade out. What I think should happen is this:

  1. Focus
  2. After cursorDelay (500ms) begin to fade out
  3. Fade in as soon as opacity is 0
  4. Repeat

I'll have a look and see why only keyboard events honor cursorDelay.

In essence, there's too much delay before the cursor begins to fade. Swapping the toValues seemed to help but maybe only for mouse events?

@asturur
Copy link
Member

asturur commented Apr 25, 2024

i have noticed the same about the delay.
That is an explicit call 'initDelayedCursor(true/false) and we should use true consistently when the cursor change position, but that will be it's on PR.

But to answer my question your point is that you just want to remove the extra initial 600ms of wait before the cursor start to fade after the alread 1000ms of delay we apply.

@@ -160,7 +160,7 @@ export abstract class ITextBehavior<
private _onTickComplete() {
this._currentTickCompleteState?.abort();
this._currentTickCompleteState = this._animateCursor({
toValue: 0,
toValue: 1,
duration: this.cursorDuration / 2,
delay: 100,
Copy link
Member

Choose a reason for hiding this comment

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

because of the above comment here eventually we need to remove delay completely and make the duration as the full cursorDuration.

@asturur
Copy link
Member

asturur commented Apr 26, 2024

@milonic test the current code, if is what you expected we can merge it

@milonic
Copy link
Contributor Author

milonic commented Apr 26, 2024

Yes, that seems to be working fine.

However, I'm confused about the ternary inside initDelayedCursor() that sets the delay to 1 if the restart flag is set, this renders cursorDelay useless if the last event was onMouseUp.

My question is, what's the point of this? My experience is that the cursor blinks the same regardless of keyboard or mouse event.

Would it be better to

  1. Remove the ternary code (keyboard and mouse then have same delay)
  2. Remove cursorDelay and cursorDuration and replace with cursorBlinkRate
  3. Set cursorBlinkRate to 500

@asturur
Copy link
Member

asturur commented Apr 26, 2024

The value of cursorBlink rate it is what it is and can bet tweaked, there is no reason to change the default value.
The difference between cursor and keyboard needs to be addressed, in a follow up so.
The ternary is there because if you don't use the delay from the keyboard or the mouse you will get the 100ms of full opacity time that you get during the normal blink, if the delay is activated ( usually the first blink on a new position ) you will get the delay ( 1000 or 500 or whatever you set ) but you won't get the delay + 100 ms as you are getting today.

@asturur
Copy link
Member

asturur commented Apr 26, 2024

if you look at how it works today:
image

Before you get the first blink you get:
the delay ( 1000) + the first wasted animation ( 600ms ) + delay that was used in the fade animation ( 100 )

after you will get only the custom delay or the 100 ms.

@asturur
Copy link
Member

asturur commented Apr 26, 2024

Well ok apparently we broke some behaviour

@milonic
Copy link
Contributor Author

milonic commented Apr 27, 2024

I'm intrigued. What's happening?

@asturur
Copy link
Member

asturur commented Apr 27, 2024

Nothing really broke but the tests we have rely on some sort of strict timing and now are failing.
I'll write more specific tests merge them and then have this pr pass on those

@asturur
Copy link
Member

asturur commented Apr 27, 2024

#9829

@asturur
Copy link
Member

asturur commented Apr 28, 2024

I completed the changes to tests i want to rebase this PR on:
#9829
I ll wait a couple of days to see if it gets any comments, then we can move on.

I m sorry both of your prs hit some small hiccup but they are both good we will do them as soon as normally possible

Copy link
Contributor

@ShaMan123 ShaMan123 left a comment

Choose a reason for hiding this comment

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

I have suggested changes that span beyond the scope of this PR.
If you don't wish to cater them that is fine.

delay,
toValue: 0,
duration: this.cursorDuration / 2,
delay: delay || 100,
Copy link
Contributor

Choose a reason for hiding this comment

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

This means that of I pass 0 to the delay it will be 100.
So use ?? instead of better off make it a default value in the method signature.

Copy link
Member

Choose a reason for hiding this comment

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

yes delay 0 is not allowed on purpose. The cursor has to stay opaque for 100ms at least as it was before non configurable. Is the flat part of the original curve between the swaps, you can only make longer the first one as it is today

Copy link
Contributor

Choose a reason for hiding this comment

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

In that case I would change the param from delay to something else and handle the delay value internally.

Copy link
Member

@asturur asturur Apr 29, 2024

Choose a reason for hiding this comment

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

i think it should me delay: Math.max(delay, 100) so there is no confusion anymore.

delay,
toValue: 0,
duration: this.cursorDuration / 2,
delay: delay || 100,
onComplete: this._onTickComplete,
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel strongly against recursive/looping methods calling each other.
IMO a recursive/looping method should call ONLY itself.
Spreading recursion across multiple methods is confusing and is prone for inifinte loops.

Copy link
Contributor

Choose a reason for hiding this comment

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

Therefore, I suggest to make it a single function accepting a boolean flagging the state

Copy link
Member

Choose a reason for hiding this comment

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

Just open an issue with label enanchement, the first one that can do it will do it if there is a real improvement of some kind, i can't see one that make me jump at it.
If you look it from a different point of view tick and tickComplete are 2 wrappers around animateCursor, and is just animateCursor calling itself with configuration A or B.

The issue with not having 2 methods is that you have to use that boolean to determine the 3 conditions every time you call the single method and you don't have a single place where to determine the first delay ( delay || 100 ) so it will be harder to track which is the start of the animation.
Today that is done implicitly by calling _onTick bound without parameters by onComplete

Copy link
Member

@asturur asturur Apr 29, 2024

Choose a reason for hiding this comment

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

I have other questions on this code more than the double methods:

  • why do we need to track the 2 animations with 2 separate states ( they are running only in sequence )
  • why onTickComplete does a pre abort check while onTick doesnt

but also those are out of scope for the animation timing tweak

Copy link
Member

Choose a reason for hiding this comment

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

here is a tracking issue #9835

@asturur
Copy link
Member

asturur commented Apr 30, 2024

Ok as i hoped generic unit tests are now passing, and the only failing one are the snapshot of the animation itself where the train of 1 is disappeared

@asturur
Copy link
Member

asturur commented Apr 30, 2024

@milonic do you know how to update the snapshot tests in jest?
npm run test:jest -- -u and then commit the changes.
You have to pull down the latest version of the branch since i merged master in

@milonic
Copy link
Contributor Author

milonic commented May 1, 2024

Never used jest, and as I expected and as always it doesn't work as I think it should:

fabric@6.0.0-rc1 test:jest
jest -u

No tests found, exiting with code 1
Run with --passWithNoTests to exit with code 0
No files found in /home/andy/git/node_modules/fabric.
Make sure Jest's configuration does not exclude this directory.
To set up Jest, make sure a package.json file exists.
Jest Documentation: https://jestjs.io/docs/configuration
Pattern: - 0 matches

Run me through what I need to do

@asturur
Copy link
Member

asturur commented May 1, 2024

So you should have cloned the repo somewhere and you should also have done npm install already.

'npm run test:jest' should give you a test run and 'npm run test:jest -- -u' should give you an update of the failing snapshots.
If it doesn't work i have no idea.

You should just be in the main fabricJS package folder where package.json is, just to be clear.
If it doesn't work i ll do it for you.
Are you on windows?

@milonic
Copy link
Contributor Author

milonic commented May 2, 2024

So, here's what I'm doing:

cd /home/andy;

mkdir git2;

cd git2;

npm install fabric@beta;

npm WARN deprecated abab@2.0.6: Use your platform's native atob() and btoa() methods instead
npm WARN deprecated domexception@4.0.0: Use your platform's native DOMException instead

added 114 packages in 10s

8 packages are looking for funding
  run `npm fund` for details

cd node_modules/fabric;

npm install chalk;

npm WARN deprecated abab@2.0.6: Use your platform's native atob() and btoa() methods instead
npm WARN deprecated consolidate@0.16.0: Please upgrade to consolidate v1.0.0+ as it has been modernized with several long-awaited fixes implemented. Maintenance is supported by Forward Email at https://forwardemail.net ; follow/watch https://github.com/ladjs/consolidate for updates and release changelog
npm WARN deprecated domexception@4.0.0: Use your platform's native DOMException instead
npm WARN deprecated core-js@2.6.12: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.

added 1064 packages, and audited 1065 packages in 51s

97 packages are looking for funding
  run `npm fund` for details

1 moderate severity vulnerability

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

npm run build;

> fabric@6.0.0-rc1 build
> npm run cli -- build


> fabric@6.0.0-rc1 cli
> node ./scripts/index.mjs build


./fabric.ts → dist, dist...
created dist, dist in 26.3s

./index.ts → dist/index.mjs, dist/index.min.mjs, dist/index.js, dist/index.min.js...
created dist/index.mjs, dist/index.min.mjs, dist/index.js, dist/index.min.js in 24.6s

./index.node.ts → dist/index.node.mjs, dist/index.node.cjs...
created dist/index.node.mjs, dist/index.node.cjs in 17.9s

npm run test:jest -- -u;

> fabric@6.0.0-rc1 test:jest
> jest -u

No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
No files found in /home/andy/git2/node_modules/fabric.
Make sure Jest's configuration does not exclude this directory.
To set up Jest, make sure a package.json file exists.
Jest Documentation: https://jestjs.io/docs/configuration
Pattern:  - 0 matches

ls -l;

total 804
-rw-r--r--   1 root root    133 May  2 10:46 babel-jest.config.js
-rw-r--r--   1 root root    577 May  2 10:46 bower.json
-rw-r--r--   1 root root 152388 May  2 10:46 CHANGELOG.md
drwxr-xr-x   2 root root      6 May  2 10:51 cli_output
-rw-r--r--   1 root root   1577 May  2 10:46 CODE_OF_CONDUCT.md
-rw-r--r--   1 root root  13829 May  2 10:46 CONTRIBUTING.md
drwxr-xr-x   4 root root   4096 May  2 10:46 dist
-rw-r--r--   1 root root   5920 May  2 10:46 fabric.ts
-rw-r--r--   1 root root   1299 May  2 10:46 index.node.ts
-rw-r--r--   1 root root     26 May  2 10:46 index.ts
-rw-r--r--   1 root root   6529 May  2 10:46 jest.config.js
-rw-r--r--   1 root root   4033 May  2 10:46 jest.extend.ts
-rw-r--r--   1 root root    147 May  2 10:46 jest.setup.ts
drwxr-xr-x   2 root root     83 May  2 10:46 lib
-rw-r--r--   1 root root    961 May  2 10:46 LICENSE
drwxr-xr-x 580 root root  16384 May  2 10:47 node_modules
-rw-r--r--   1 root root   5485 May  2 10:47 package.json
-rw-r--r--   1 root root 492950 May  2 10:47 package-lock.json
-rw-r--r--   1 root root   2486 May  2 10:46 playwright.config.ts
-rw-r--r--   1 root root   2381 May  2 10:46 playwright.setup.ts
-rw-r--r--   1 root root    540 May  2 10:46 publish.js
-rw-r--r--   1 root root    329 May  2 10:46 publish-next.js
-rw-r--r--   1 root root   9983 May  2 10:46 README.md
-rw-r--r--   1 root root   3369 May  2 10:46 rollup.config.mjs
-rw-r--r--   1 root root    553 May  2 10:46 rollup.test.config.js
drwxr-xr-x   2 root root    161 May  2 10:46 scripts
-rw-r--r--   1 root root    110 May  2 10:46 SECURITY.md
drwxr-xr-x  18 root root   4096 May  2 10:46 src
-rw-r--r--   1 root root  10679 May  2 10:46 tsconfig.json
-rw-r--r--   1 root root    172 May  2 10:46 typedoc.config.json

As you can see package.json is definitely there, what am I doing wrong?

Although my development environment is Windows, the above is done on a Linux server

@asturur
Copy link
Member

asturur commented May 2, 2024

i think you are doing it wrong.
You should run the tests from where you push code.
So for example:

cd /home/andy
git clone git@github.com:milonic/fabric.js.git
// this will create your fabric.js folder of your fork
cd fabric.js
npm install
// create a branch, commit, try, push etc etc.
// from your local branch then you can run
npm run test:jest 

@asturur
Copy link
Member

asturur commented May 2, 2024

in the published package, the one you install with npm fabric there isn't the jest config inside and other things are missing too. That is meant for installing/rebuilding but not for developing over

@milonic
Copy link
Contributor Author

milonic commented May 2, 2024

NOW it makes sense..... my apologies

@milonic
Copy link
Contributor Author

milonic commented May 2, 2024

So, I can see it fail with "IText cursor animation snapshot › initDelayedCursor true - with NO delay"

What are the tests looking at, what are we comparing them with?

@asturur
Copy link
Member

asturur commented May 3, 2024

So, I can see it fail with "IText cursor animation snapshot › initDelayedCursor true - with NO delay"

What are the tests looking at, what are we comparing them with?

those tests are snapshotting the cursor opacity over time.
What you should see is that the initial unwanted wait of a series of 1 is gone now.
All other tests are still passing.
That is why i refactored tests before, because they were relying on timings of settimeout, while now are a bit more deterministic.

update the snapshot so we can review it

@milonic
Copy link
Contributor Author

milonic commented May 3, 2024

Is this something you can do?

I've been working on Github for several hours now and it's just getting worse for me.

I literally have no idea what I'm doing with it and there are now files all over the place and commits are showing that I did not want to be uploaded etc etc. I'm running out of patience, so sorry!

Here's something I was trying to post: https://jsfiddle.net/milonic/57e8au32/27/ - it helps fix issues with double and triple click on text and also helps fix a text drag drop issue.

You are more than welcome to the code but I'm unable to get Github to do anything correctly and I'm just making a mess of things.

I may come back to this when I'm feeling a little better but at the moment I'm pretty much done.

@milonic milonic closed this by deleting the head repository May 3, 2024
@asturur
Copy link
Member

asturur commented May 3, 2024

since this is busted now i reopened it here #9848

@asturur
Copy link
Member

asturur commented May 3, 2024

your commits are still there

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.

3 participants