Как сохранить вертикальную прокрутку и масштабирование и определить горизонтальное и диагональное панорамирование / перелистывание с помощью Hammer. js in Angular 9? - PullRequest
2 голосов
/ 30 марта 2020

Что я хочу

… - это обнаружение панорамирования (или смахивания) с помощью Hammer. js in Angular 9.

Должно работать так:

  • должно быть обнаружено горизонтальное панорамирование
  • должно быть обнаружено диагональное панорамирование с определенными степенями 1
  • вертикальная прокрутка не должна быть предотвращена
  • Пинч для увеличения не должен предотвращаться, так как это вызовет проблемы с доступностью

enter image description here

На изображении green показывает все это по умолчанию браузером и не должно быть предотвращено. blue показывает все, что должно быть предотвращено и обработано Хаммером.

Не знаете, что я имею в виду? Посмотрите демоверсии Swiper. Они работают именно так .

1 Понятно, как определить угол с помощью event.angle. Но я не уверен, как различить guish между предотвращением или не предотвращением события в случае необходимости.

То, что я пробовал

… - это все эти вещи которые я нашел в нескольких вопросах о Stackoverflow и других статьях блога:

import { BrowserModule, HammerModule, HammerGestureConfig, HAMMER_GESTURE_CONFIG } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import * as Hammer from 'hammerjs';

class MyHammerConfig extends HammerGestureConfig {
  // Test #1
  overrides = <any>{
    swipe: { direction: hammer.DIRECTION_HORIZONTAL },
    pinch: { enable: false },
    rotate: { enable: false }
  };

  // Test #2
  overrides = <any>{
    swipe: { direction: Hammer.DIRECTION_ALL  }
  };

  // Test #3
  options = {
    domEvents: true
  }

  // Test #4
  buildHammer(element: HTMLElement) {
    const mc = new Hammer(element, {
      touchAction: 'pan-y'
    });

    return mc;
  }

  // Test #5
  buildHammer(element: HTMLElement) {
    const mc = new Hammer(element, {
        touchAction: 'auto'
     });

     return mc;
  }
}

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HammerModule
  ],
  providers: [
    {
      provide: Window,
      useValue: window
    },
    {
      provide: HAMMER_GESTURE_CONFIG,
      useClass: MyHammerConfig
    }
  ],
  bootstrap: [
    AppComponent
  ]
})

export class AppModule { }

Все эти вещи не работали, так как имели разные результаты и не были согласованы на разных устройствах (например, iPhone против iPad):

  • ✗ Пинч для увеличения не работал
  • ✗ Вертикальная прокрутка не работает
  • ✗ Диагональное панорамирование не может быть обнаружено

Текущее решение

… создает Hammer непосредственно в компоненте, например:

import { Component, OnInit, ViewChild, ElementRef, OnDestroy, ViewChildren, QueryList } from '@angular/core';

import * as Hammer from 'hammerjs';

@Component({
  selector: 'app-hero',
  templateUrl: './hero.component.html',
  styleUrls: ['./hero.component.scss']
})

export class HeroComponent implements OnInit, OnDestroy {
  @ViewChild('list', { static: true }) list: ElementRef;

  private hammertime: Hammer;
  private isLocked: boolean = false;

  ngOnInit() {
    this.initHammer();
  }

  ngOnDestroy() {
    // todo destroy hammertime
  }

  initHammer(): void {
    this.hammertime = new Hammer(this.list.nativeElement, {touchAction : 'auto'});
    this.hammertime.get('pan').set({ direction: Hammer.DIRECTION_HORIZONTAL, threshold: 60 });
    this.hammertime.on('panleft panright', event => {
      if (this.isLocked || event.maxPointers !== 1) {
        return
      };

      this.goto(event.type === 'panLeft' ? 'next' : 'prev');
      this.isLocked = true;

      setTimeout(() => this.isLocked = false, 1000)
    });
  }
}

Это делает много вещей:

  • ✓ работает для увеличения масштаба
  • ✓ работает вертикальная прокрутка
  • ✓ обнаружены горизонтальные пролистывания

Но эти вещи не работают или не хороши:

  • ✗ не способ Angular, не используя HammerModule
  • ✗ нет обнаружения диагонали
  • Hammer -экземпляр this.hammertime и прикрепленные события никогда не уничтожаются
  • ✗ Для предотвращения pan используется тайм-аут Событие от многократного запуска
  • count Количество указателей должно быть снято вручную

Вопросы?

  • Как мне сделать эту работу "Angular "?
  • Как я могу обнаружить диагональное панорамирование?
  • Как правильно уничтожить this.hammertime, когда цель невозможна" на пути Angular "?

1 Ответ

1 голос
/ 01 апреля 2020

Альтернативный подход

… с использованием ZingTouch , как предложено Грэм Ритч ie.

Он делает все эти вещи :

  • ✓ обнаружены горизонтальное и диагональное панорамирование
  • ✓ вертикальная прокрутка не предотвращена
  • ✓ не должно быть затруднено масштабирование

Новое решение

import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';

import ZingTouch from 'zingtouch';

@Component({
  selector: 'app-hero',
  templateUrl: './hero.component.html',
  styleUrls: ['./hero.component.scss']
})

export class HeroComponent implements OnInit, OnDestroy {
  @ViewChild('list', { static: true }) list: ElementRef;

  private zingTouchRegion: ZingTouch.Region;
  private isLocked: boolean = false;

  ngOnInit() {
    this.initZingTouch();
  }

  ngOnDestroy() {
    this.zingTouchRegion.unbind(this.list.nativeElement);
  }

  initZingTouch(): void {
    const area = this.list.nativeElement;
    const gesture = new ZingTouch.Pan({threshold: 10});

    this.zingTouchRegion = new ZingTouch.Region(area, false, false);
    this.zingTouchRegion.bind(area, gesture, event => {
      const angle = event.detail.data[0].directionFromOrigin;

      if ((angle >= 40 && angle <= 140) || (angle >= 220 && angle <= 320)) {
        return;
      }

      event.detail.events[0].originalEvent.preventDefault();

      if (this.isLocked) {
        return
      };

      if (angle > 140 && angle < 220) {
        this.goto('next');
      }

      if (angle > 320 || angle < 40) {
        this.goto('prev');
      }

      this.isLocked = true;
      setTimeout(() => this.isLocked = false, 600)
    });
  }
}
...