Giter Site home page Giter Site logo

d3lm / ngx-drag-to-select Goto Github PK

View Code? Open in Web Editor NEW
293.0 9.0 64.0 2.39 MB

A lightweight, fast, configurable and reactive drag-to-select component for Angular 10 and beyond

Home Page: https://www.npmjs.com/package/ngx-drag-to-select

License: MIT License

TypeScript 85.95% JavaScript 0.59% HTML 6.90% SCSS 6.56%
angular ngx drag select typescript angular2 drag-to-select

ngx-drag-to-select's People

Contributors

angular-cli avatar beeman avatar clarencecastillo avatar cyclist82 avatar d3lm avatar eagleseb avatar ennjin avatar juristr avatar lemmywrap avatar markgoho avatar mattlewis92 avatar pmareke avatar sam-eah avatar timdeschryver avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ngx-drag-to-select's Issues

Selection rectangle not relative to scrollHeight

Had a little fun poking around with your lib and I think its awesome!

Theres only one thing that did not behave as I would've expected:
When a selection container is scrollable and a selection is started the browser starts scrolling when getting close to the edge of the viewport. My expectation was that the starting point of the selection rectangle "sticks" to it's coordinates on the scrollable content. The result being that the selection rectangle grows in size as scrolling happens, selecting more items in the process.

But it's relative to the viewport so scrolling while selecting will deselect items as they move out of the selection rectangle.

drag-to-select-screencap

Automatically scroll the container

Hello,

This module works great, however a really nice feature would be the ability for the drag selection to scroll the container when going out of (visible) bound.

Unless such a feature already exists and I'm using the component incorrectly, which is entirely possible.

Thanks

Feature Request: Add OnSelectionComplete() event

Hi -

I am using ngx-drag-select on a very large number of UI items (hundreds of elements). I need to process the items selected, but the process time takes a rather long time due to the number of objects involved.

The hurdle I'm facing is that currently, I am using the onSelect() event to put the code that does the processing, but since that changes often and rapidly as you drag to select, this is slowing things down to an unacceptable speed.

What would help a lot would be a simple way to know when the drag select is done, at which point, I could simply process the selected items once, instead of over and over a again.

Is this something that can be added? Maybe a simple extra call on MouseUp()?

Thanks! (And happy holidays)

[Question] SHIFT behavior by default

First of all, great project. Just have a question.
I want to drag multiple times and persist those selections, the same we get with Shift pressed, but I want to achieve that as the default behavior.
Is that possible with the current code base?
I tried setting the selected cells programmatically but my cells keep flickering (They have a different color when selected). Each time I start dragging, the status of the previously selected cells is set to 'unselected'.

Support to ngModel

I was trying to use dts-container as form control element but it's not developed for this purpouse.

How hard can be to add this functionality?

Make the demo app responsive

For smartphones and tablets (not including the iPad Pro as it is huge) hide the Desktop Demo and only show the mobile version.

Selection rectangle persists if "alt" is pressed and held mid-drag

Great lib and very nicely executed. Here's a kinda edge-case bug I found:

  • Windows 10
  • Chrome 65

Reproduction

  1. Start dragging in the drag area
  2. Press and hold the alt key
  3. Release the mouse button to stop dragging
  4. Release the alt key

Expected

The selection rectangle disappears once the dragging has ended at step 3 above.

Actual

The selection rectangle persists until a new drag is started.

Demo

2018-04-03_13-09-28

BoundingClientRect not initialized

The boundingClientRect for both SelectContainerComponent and SelectItemDirective is not initialized first and only gets calculated when either the window was resized or the user scrolls either in the container or on the page.

Select items inside a component

I am not able to get back the selected items in the case there is another wrapper component inside the dts-select-container. The SelectContainer uses @ContentChildren to get the $selectableItems. Is there any workaround?
example:

<dts-select-container>
     <parent-component>
         <span  [dtsselectItem]="item"></span>
         <span  [dtsselectItem]="item"></span>
     </parent-component>
</dts-select-container>

Thanks in advance!

Issues with webpack loading the library

I am trying to use the library and I have added it to a feature module. I am using lazy loading, but this module is directly loaded. I am also using webpack (4) as my packager.

So I followed the guides and added the module import. Now when I start the webapp I get the following errors:
platform.es5.js:79 Uncaught TypeError: Object(...) is not a function at platform.es5.js:79 at Object../node_modules/ngx-drag-to-select/esm5/ngx-drag-to-select.js (platform.es5.js:81) at __webpack_require__ (bootstrap:88) .....
What is happening here?

The selectedItems input is never used

The selectedItems input is not used inside the dts-select-container component. If the user pass an array with some items already selected, they will not be considered by the component.

This is an example: https://stackblitz.com/edit/ngx-drag-to-select-yqxr4t

In the HomeComponent I'm passing an array with some values:

<dts-select-container [selectedItems]="selected">

but they are not marked as selected in the component. Moreover, if I use the "banana box" syntax, the component will clear the selected array and delete the values that are present in the passed array

doesn't work when scale the parent container

If you use 'transform: scale(x)' to scale your parent container, mouse pointer position is incorrect, and you can not select your items as you like. For example, you can modify Demo Source app.component.html : class 'drag-area' div ' style : transform-origin: 0px 0px 0px; transform: scale(0.6); then you can find this issue.

Multiple styles

Hello, right now is only possible to have one styling configuration (based on the docs):
https://github.com/d3lm/ngx-drag-to-select#overriding-sass-variables

// Example for overriding the color of the selection rectangle
$select-box-color: red;

@import "~ngx-drag-to-select/scss/ngx-drag-to-select";

I'm wondering if it would be possible to have multiple styles, for example:
normal selection: blue box
remove selection: red box

I've managed to do it like so:

style.scss

@import "~ngx-drag-to-select/scss/ngx-drag-to-select";

// Styles for Drag-To-Select : Removing
dts-select-container.removing {
  .dts-select-box {
    $removing-color: #f48fb1;
    color: $removing-color;
    background: rgba( $removing-color, 0.3 );
    border-color: currentColor;
  }
}

html

<dts-select-container [(selectedItems)]="_sToggles" [class.removing]="_isRemoving">
  ...
</dts-select-container>

ts

private _initSelection_ShiftEvents() {
  const keydown$ = fromEvent( window, 'keydown' );
  const keyup$ = fromEvent( window, 'keyup' );

  merge( keydown$, keyup$ ).pipe(
    takeUntil( this.ngUnsubscribe ),
    filter((event: KeyboardEvent) => this._isSelecting && event.key === 'Shift')
  )
  .subscribe((event: KeyboardEvent) => {
    this._isRemoving = event.shiftKey;
    this.chRef.detectChanges();
  });
}

With this, I can have a selection box change color whenever shift key is pressed, works fine in all scenarios I can think of:

  1. Hold Shift, then start drag-select
  2. Start drag-select, and then hold Shift
  3. While drag-selecting, hold/release shift key multiple times (box color changes immediately)

now, the only problem is that this implementation uses .dts-select-box class to style it. So it won't work if this happens to change in the future. Any thoughts?

Info about nested scrollable containers

Add small section about dealing with nested scrollable containers and mention that the consumer of this lib has to call update themselves if you have nested wrappers, other than the body and the select-container itself, that are scrollable.

Hook into the requestAnimationFrame for UI changes

Hi Dom,

First of all kudos on the lib! Looks really nice!

I looked at the code and there was one thing I noticed. You use the auditTime operator to wait 16ms before updating for example the selectedItems or the selectBox. This way, Angular will only update the UI every 16ms which makes sense, 60FPS ftw.

I was just wondering if it would make even more sense to hook the updates you want to do into the requestAnimationFrame hook. Using the subscribeOn operator this should be fairly easy. You could update your code from:

selectBox$.pipe(
  auditTime(AUDIT_TIME),
  withLatestFrom(mousemove$, ...),
  filter(() => this.selectOnDrag),
  filter(({ selectBox }) => selectBox.width > MIN_WIDTH || selectBox.height > MIN_HEIGHT),
  tap(({ selectBox, event }) => this.selectItems(selectBox, event)),
  takeUntil(this.destroy$)
).subscribe();

to

selectBox$.pipe(
  auditTime(AUDIT_TIME),
  withLatestFrom(mousemove$, ...)
  filter(() => this.selectOnDrag),
  filter(({ selectBox }) => selectBox.width > MIN_WIDTH || selectBox.height > MIN_HEIGHT),
  tap(({ selectBox, event }) => this.selectItems(selectBox, event)),
  takeUntil(this.destroy$),
  subscribeOn(animationFrame),
).subscribe();

By adding the subscribeOn(animationFrame), RxJS will schedule this execution to be run as a callback in the requestAnimationFrame and thus just before repainting. I'm not 100% sure if this makes absolute sense in the context of Angular, since you would only update properties on the scope of your component and it still Angular that needs to update the DOM.
But since zone.js monkey-patches requestAnimationFrame, Angular will run CD on this hook so I guess it makes sense.

As I am not 100% sure, any feedback, input is more than welcome.

If we can agree this could enhance the library, I'd be happy to create a PR.

Let me know what you think :)

Upgrade to Angular 7

Now that Angular 7.x is out we should upgrade to the latest version. This should be pretty straight forward using the Angular CLI. Plus, there are no breaking changes.

Optimize performance

As I found, this library is already very fast and with two instances on the same page I get roughly 59 FPS on average. So rendering seems to be quite good. Yet it needs to be investigated where to use micro optimizations such as the animationFrame scheduler as discussed in #9.

Additionally, research is needed where to run things outside of the zone to reduce unnecessary change detection phases. As part of this, one could also look at where to use ChangeDetectionStrategy.OnPush.

Here's a screenshot from a previous analysis.

perf

[Feature Request] Parent Children drag event interactions

This is a feature request (or if it is already achievable, please let me know). Might be related to #70.

Let me describe it briefly:

Here is the StackBlitz for the MWE: https://stackblitz.com/edit/angular-sbkxtf

So as you can see, we have a container and we have some children in it. The container is dts-select-container and the children are draggable="true".

When I start dragging the child:

  1. The select event is fired, so we will see a tiny selection box
  2. The dragstart of the child fired, so we can drag around the child
  3. When we release the mouse, the dragging for the child ended, but at the same time, the selection box is re-activated immediately.

My expected behavior is like Google Drive:
video1

Where dragstart will be firstly fired in the container (so selection box shows up), when some items are selected, dragstart will be fired for those children and some animations shows up, after dragend fired, the selection box will NOT re-activately immediately unless the next dragstart fired. So either dragstart will be fired in the parent or child depends on whether there are selected things.

It is achievable with ngx-drag-to-select?

@d3lm

Find good prefix for the the components and directives

We should find a good prefix that we can use for both the select-container component and select-item directive. So far it uses ngx-select-container and selectItem for the directive. For one, this is not really consistent, and second, it's hard to distinguish an ngx prefix from components from other libraries. It would be great if we found a unique prefix specifically for this library so that it's easy to tell its components and directives apart from other libs out there, most of which also use an ngx prefix.

Let me start with a suggestion. How about dts which stands for drag-to-select. That's the most obvious one but maybe not the most ideal.

Maybe anyone else has a better idea? Would love to get some feedback on this.

Drag rectangle doesn't take into consideration page scrolling.

This is a bit hard to explain and I can't really provide screenshots for it, but here it goes.

Case 1:
Dragging while the page is scrolled to top.
Expected behavior: Rectangle starts where mouse clicks and drags where the mouse goes.
Actual behavior: Same as expected (Y)

Case 2:
Dragging while the page is scrolled.
Reproduction steps:

  1. Scroll down a bit
  2. Try to drag.

Expected behavior: Rectangle starts where mouse clicks and drags where the mouse goes.
Actual behavior: Rectangle starts where the mouse would have been if we hadn't scrolled down, and it drags relatively to its start position.

So basically what I think is happening is that the start position of the rectangle when we drag isn't taking into consideration the page scrollY.

Does that make sense? I'll be happy to provide more information.

Positions don't update correctly on transform changes

Hey!
Whenever the transform value of a tracked item changes, e.g. from translateX(100px) to translateX(200px), the selection rectangle seems to just stick with the initially calculated position.
That results in the selection rectangle behaving in unexpected ways, i.e. selecting an item outside the rectangle or not selecting an item even if it is inside.

I created a repository with a minimal reproduction here.

Thanks in advance!

Is there a way to programatically enable/disable an element as selectable?

Just to be clear, I'm not asking about changing something from selected to not selected and back again. Rather, I want to make specific element selectable/not selectable via code.

According to the docs, you make a DOM element "Selectable" by wrapping all the items you want to be selectable in a "" element, and then you also need to add the [dtsSelectItem]="item" tag to the element(s) in question.

What I'd like to do is select some elements, and then make them un-selectable again via code. How can I achieve this?

I'm curious how the tagging works... for example, if I remote the "dts-select-item" class from the element, will that be enough to make it "not selectable"? Or is there a better way of doing this that won't break ngx-drag-to-select?"

No dragging

Hello everybody,

I installed ng-drag-to-select in my project, in app.module.ts I have this :
`import { DragToSelectModule } from 'ngx-drag-to-select';

@NgModule({
declarations: [
AppComponent,
FellowsComponent
],
imports: [
BrowserModule,
AppRoutingModule,
DragToSelectModule.forRoot({
selectedClass: 'my-selected-item',
shortcuts: {
disableSelection: 'alt+meta'
}
})
],
`

and on the web page I have this :
`<dts-select-container #container="dts-select-container"
(select)="someMethod($event)"
[(selectedItems)]="selectedFellows"
[selectOnDrag]="true"
[disabled]="false"
[disableDrag]="true"
[selectMode]="true"
[custom]="true"
[selectWithShortcut]="false">

{{ fellow.name }}

`
it realizes the selection of an element by clicking on it, but nothing happens when I try to drag with the mouse.
Any idea what I forgot ?

By the way is the download zip supposed to be up-to-date ?

Import RxJS operators individually

Hi @d3lm, nice implementation!

Wouldn't it be better to import RxJS operators individually, to avoid including all operators?

import {
  switchMap,
  takeUntil,
  map,
  tap,
  filter,
  auditTime,
  mapTo,
  share,
  withLatestFrom,
  distinctUntilChanged
} from 'rxjs/operators';

Upgrade to Cypress 3.1

Cypress 3.1 introduces parallelization with cypress run --parallel. This works across multiple CI machines.

We should upgrade Cypress and also enable multiple CI machines to execute the tests in parallel on Travis. Travis supports up to 4 machines on a free plan.

Bounding box and resize bug

I see there are a few issues related to this but since I'm seeing still, I figured I'd mention it. Please see the video for a demo and explanation. https://www.youtube.com/watch?v=BVthAyI8eYs

In a nutshell, when I first open the web page, the Bounding box is way off... it doesn't show up where I'm clicking and dragging. Doing anything that causes a resize (e.g. resize the window, press F12 to open the dev tools) "fixes" it.

Suggestion regarding outputs

Hello, thanks for this awesome lib, works perfectly!

I've encountered 1 "challenge" when using this:

I can't get the items from a "add/remove-selection", the only data I can get is the current selectedItems. We could do comparisons and get what was added/removed.
But the problem is that it's not possible to get all items in the "remove-selection" (items that were not already in the selectedItems)

So here are 2 suggestions:

  1. rename current Output select to change

(change): Event that is fired whenever the selection changes. The payload ($event) will be the current list of selected items.

  1. new Output select or selection etc..:

(select): Event that is fired whenever a selection is made. The payload ($event) will contain:

{
    items: any[]; // List of items in this selection
    type: 'normal' | 'add' | 'remove'; // Type of selection
}

Thank you very much!

Add mobile features

It would be great to have dedicated inputs for the select-container to enable a select mode. This mode behaves very similar to the toggleSingleItem shortcut where you can add or remove single items to or from the selection. The difference here is that the user doesn't have to press a shortcut to activate this mode, which wouldn't work on mobile anyways. Hence, a property to enable such mode. The developer is then responsible to enable this mode for a certain media query.

Also, for mobile it's useful to disable the drag functionality. Can also be set via input.

Last but least, a custom flag would be great, to allow for more flexibility when styling the elements. Especially if the look and feel is different for the mobile version.

Clash with ngx-drag-n-drop package

For a project I'm working on, I'm using both this and ngx-drag-n-drop package. And finally, I've run into some issue where both packages clash.

The provided gif kinda explains the issue. When dragging an item to an area, drag to select also starts to silently drag. On item drag start event, I've tried to set both disable and disableDrag properties as true, which seems to work, but after dropping, when I'm setting them both back to true, the drag-to-select box appears after mouse movement.

ezgif-6-2d34dea91306

I know this is not exactly relevant to this package, just thought maybe others have had the same issue and I could really use some help. My attempt at hacking away this issue has been unsuccessful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.