0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

(自分用の備忘録)画像リスト間にOS経由で画像を指定した位置にドロップする最小限のコード

0
Posted at
import { CommonModule } from '@angular/common';
import { Component, ChangeDetectorRef } from '@angular/core'; // ChangeDetectorRefを追加
import {
  CdkDragDrop,
  DragDropModule,
  moveItemInArray,
} from '@angular/cdk/drag-drop';
import { ImageDto } from './model/ImageDto';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, DragDropModule],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  album: ImageDto[] = [
    { src: '/assets/cat.jpg', caption: 'cat', thumb: '/assets/cat.jpg' },
    { src: '/assets/cat2.jpg', caption: 'cat2', thumb: '/assets/cat2.jpg' },
    { src: '/assets/cat3.jpg', caption: 'cat3', thumb: '/assets/cat3.jpg' },
  ];

  // コンストラクタでChangeDetectorRefを注入
  constructor(private cdr: ChangeDetectorRef) {}

  drop(event: CdkDragDrop<ImageDto[]>) {
    moveItemInArray(this.album, event.previousIndex, event.currentIndex);
  }

  // OSからのドロップ
  onNativeDrop(event: DragEvent, index: number) {
    event.preventDefault();
    // this.onPreventDefault(event); // 確実にブラウザ挙動を止める

    const files = event.dataTransfer?.files;
    if (files && files.length > 0) {
      // filesをArray.fromで通常の配列に変換
      Array.from(files).forEach((file) => {
        // if (file.type.match('image.*')) {
        // 画像ファイルを画面に表示できる文字列(データURL)に変換
        const reader = new FileReader();
        reader.onload = (e: any) => {
          const newImage: ImageDto = {
            src: e.target.result,
            caption: file.name,
            thumb: e.target.result,
          };
          // 指定位置indexにnewImageを挿入
          this.album.splice(index, 0, newImage);
          // 画面更新を通知
          // this.cdr.detectChanges();
        };
        reader.readAsDataURL(file);
        // }
      });
    }
  }

  // dragenterとdragoverの両方でpreventDefaultを実行する
  onPreventDefault(event: DragEvent) {
    event.preventDefault();
    event.stopPropagation();
  }
}

<div
  cdkDropList
  cdkDropListOrientation="horizontal"
  (cdkDropListDropped)="drop($event)"
  class="image-list"
  (dragover)="onPreventDefault($event)"
  (drop)="onPreventDefault($event)"
>
  @for (img of album; track img; let i = $index) {
  <div
    cdkDrag
    class="image-wrapper"
    (dragover)="onPreventDefault($event)"
    (dragenter)="onPreventDefault($event)"
    (drop)="onNativeDrop($event, i)"
  >
    <img [src]="img.src" width="100" />

    <div class="custom-placeholder" *cdkDragPlaceholder></div>
  </div>
  }
</div>

<hr />

.image-list {
  display: flex;
  // gap: 50px; //  これをコメントアウト、ドロップできなくなるので
  padding: 20px;
  border: 1px solid #eee;
  min-height: 150px;
  align-items: center;
}

.image-wrapper {
  padding: 0 25px; //  左右に25pxずつ(合計50pxの間隔)
  cursor: grab;

  img {
    display: block;
    pointer-events: none; //  画像自体がイベントを邪魔しないようにする
    border: 2px solid transparent;
    transition: border 0.2s;
  }

  // ドラッグオーバーした時に視覚的にわかりやすくする任意
  &:hover img {
    border-color: #007bff;
  }
}

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?