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

Add an option to selection objects only when 100% intersect #4508

Merged
merged 5 commits into from
Nov 29, 2017

Conversation

JSteunou
Copy link
Contributor

@JSteunou JSteunou commented Nov 27, 2017

Because today selection works as soon as an object intersects with the selection rect. but some use cases require a distance of 100% before a selection can happen.

A common pattern for these kind of option (like jquery.ui selectable) is a distance ratio but the tools classes around intersection computing does not yet return distance of intersection in % so a simple boolean to act like 0 or 100 is fine, non breaking (because false by default) and open the path to a future possibility to a distance ratio.

I'm just not sure about the naming, open to any suggestion on it.

close #3102

@JSteunou
Copy link
Contributor Author

JSteunou commented Nov 27, 2017

In the future this could easily be replaced by

selectionFullyContained = this.selectionDistance >= 100 and a little currentObject.getIntersectsWithRect(selectionX1Y1, selectionX2Y2).distance >= this.selectionDistance

@@ -178,6 +178,13 @@
*/
selectionLineWidth: 1,

/**
* Selection only shapes that intersect to 100%
Copy link
Member

Choose a reason for hiding this comment

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

Select only shapes that are fully contained in the dragged selection rectangle.

currentObject.containsPoint(selectionX1Y1) ||
currentObject.containsPoint(selectionX2Y2)
(!this.selectionFullyContained && currentObject.containsPoint(selectionX1Y1)) ||
(!this.selectionFullyContained && currentObject.containsPoint(selectionX2Y2))
Copy link
Member

Choose a reason for hiding this comment

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

please put !this.selectionFullyContained in a var with a shorter name and with the negated name, helps reading. like var allowIntersect = !this.selectionFullyContained helps minification too. this.selectionFullyContained does not get minified.

@asturur
Copy link
Member

asturur commented Nov 27, 2017

this is usefull, but you have to write tests.
If you do not know how i can help

@asturur
Copy link
Member

asturur commented Nov 27, 2017

If you look a bit around i think this was also surfaced in an issue if i remember correctly.

@JSteunou
Copy link
Contributor Author

I do need help for the tests, I'm not familiar with those in fabric.

Related issue can be #3773 but not sure and #3102 for sure.

@asturur
Copy link
Member

asturur commented Nov 27, 2017

I m a bit busy today, i ll leave an example of a test that may work, you can then for another from it.

@asturur
Copy link
Member

asturur commented Nov 28, 2017

about tests:

first you need to install fabric.
so clone the repo and run npm install ./ being sure that canvas did not error during installation.
run npm run build to get a build in your own branch that contains the latest code.
run npm run test and verify that everything pass.

this is the expected output.

> [email protected] test /Users/abogazzi/fabric/fabric.js
> node test.js


Testing  /Users/abogazzi/fabric/fabric.js/dist/fabric.js ...
jpeg toDataURL not supported
Error loading http://www.google.com/non-existing
done

Summary:
┌─────────────────────────────────────────────────┬────────┬────────┬───────┬─────────┐
│ File                                            │ Failed │ Passed │ Total │ Runtime │
├─────────────────────────────────────────────────┼────────┼────────┼───────┼─────────┤
│ /Users/abogazzi/fabric/fabric.js/dist/fabric.js │ 0      │ 4777   │ 4777  │ 33815   │
└─────────────────────────────────────────────────┴────────┴────────┴───────┴─────────┘

Global summary:
┌───────┬───────┬────────────┬────────┬────────┬─────────┐
│ Files │ Tests │ Assertions │ Failed │ Passed │ Runtime │
├───────┼───────┼────────────┼────────┼────────┼─────────┤
│ 1     │ 1026  │ 4777       │ 0      │ 4777   │ 33815   │
└───────┴───────┴────────────┴────────┴────────┴─────────┘

Coverage:
┌─────────────────────────────────────────────────┬────────────────────┬────────────────────┬────────────────────┬────────────────────┐
│ File                                            │ Statements         │ Branches           │ Functions          │ Lines              │
├─────────────────────────────────────────────────┼────────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ /Users/abogazzi/fabric/fabric.js/dist/fabric.js │ 67.01% (5306/7918) │ 62.16% (3256/5238) │ 76.75% (1030/1342) │ 67.07% (5301/7904) │
└─────────────────────────────────────────────────┴────────────────────┴────────────────────┴────────────────────┴────────────────────┘

Global coverage:
┌───────┬────────────────────┬────────────────────┬────────────────────┬────────────────────┐
│ Files │ Statements         │ Branches           │ Functions          │ Lines              │
├───────┼────────────────────┼────────────────────┼────────────────────┼────────────────────┤
│ 1     │ 67.01% (5306/7918) │ 62.16% (3256/5238) │ 76.75% (1030/1342) │ 67.07% (5301/7904) │
└───────┴────────────────────┴────────────────────┴────────────────────┴────────────────────┘

After you start from this point, since this is a selection test and fall in the Canvas case, check this file:

test/unit/canvas.js

at line 450 you find:

  QUnit.test('_collectObjects collects object contained in area', function(assert) {
    var rect1 = new fabric.Rect({ width: 10, height: 10, top: 0, left: 0 });
    var rect2 = new fabric.Rect({ width: 10, height: 10, top: 0, left: 10 });
    var rect3 = new fabric.Rect({ width: 10, height: 10, top: 10, left: 0 });
    var rect4 = new fabric.Rect({ width: 10, height: 10, top: 10, left: 10 });
    canvas.add(rect1, rect2, rect3, rect4);
    canvas._groupSelector = {
      top: 15,
      left: 15,
      ex: 1,
      ey: 1
    };
    var collected = canvas._collectObjects();
    assert.equal(collected.length, 4, 'a rect that contains all objects collects them all');
    assert.equal(collected[3], rect1, 'contains rect1 as last object');
    assert.equal(collected[2], rect2, 'contains rect2');
    assert.equal(collected[1], rect3, 'contains rect3');
    assert.equal(collected[0], rect4, 'contains rect4 as first object');
  });

  QUnit.test('_collectObjects do not collects object if area is outside', function(assert) {
    var rect1 = new fabric.Rect({ width: 10, height: 10, top: 0, left: 0 });
    var rect2 = new fabric.Rect({ width: 10, height: 10, top: 0, left: 10 });
    var rect3 = new fabric.Rect({ width: 10, height: 10, top: 10, left: 0 });
    var rect4 = new fabric.Rect({ width: 10, height: 10, top: 10, left: 10 });
    canvas.add(rect1, rect2, rect3, rect4);
    canvas._groupSelector = {
      top: 1,
      left: 1,
      ex: 24,
      ey: 24
    };
    var collected = canvas._collectObjects();
    assert.equal(collected.length, 0, 'a rect outside objects do not collect any of them');
  });

There are 4 existing tests that creates 4 rects ( for simplicity ) and that create a fake _groupSelector for testing purposes.

What you have to do is test that with false those test do not change.
And then write a couple of specific tests to show that the new parameter do not include objects that are partially touched by selection. so play a bit with the top,left,width,height of shapes to create different use cases.

Give tests a relevant title and also give asserts a string to identify them when they fail.

run npm run test at will to see if they pass.
When you are done, to do not commit up the rebuilded fabricjs i usually do:

git checkout master dist to restore the dist folder to the current master.

@JSteunou
Copy link
Contributor Author

JSteunou commented Nov 29, 2017

ok added.

but JQunit is really not my favorite to work with :( I tried to encapsulate my tests inside a module to add its own before/after but then the all canvas tests beforeEach/afterEach were not triggered anymore 😞

@asturur
Copy link
Member

asturur commented Nov 29, 2017

i do not like JQunit as well. i find jest or better in running, writing, stubbing / mocking

But i learned it last year, and no one is going to rewrite this test suite probably

@asturur asturur merged commit 7b64898 into fabricjs:master Nov 29, 2017
thiagocunha pushed a commit to thiagocunha/fabric.js that referenced this pull request Nov 18, 2019
…#4508)

* Add an option to selection objects only when 100% intersect

* Better description

* Cache property negation

* Add unit tests

* Remove boundary tests, not specific to this option
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.

Multi selection condition on the canvas
2 participants