976 lines
41 KiB
JavaScript
976 lines
41 KiB
JavaScript
import { __esDecorate, __runInitializers } from 'tslib';
|
|
import { Directionality } from '@angular/cdk/bidi';
|
|
import * as i0 from '@angular/core';
|
|
import { Input, ViewEncapsulation, ChangeDetectionStrategy, Component, inject, DOCUMENT, NgZone, ChangeDetectorRef, DestroyRef, EventEmitter, ViewChild, Injector, Injectable, ElementRef, booleanAttribute, Directive, NgModule } from '@angular/core';
|
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
import { Subject, fromEvent } from 'rxjs';
|
|
import { filter, take, switchMap, takeUntil } from 'rxjs/operators';
|
|
import { NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';
|
|
import { CdkDragHandle, CdkDrag } from '@angular/cdk/drag-drop';
|
|
import { ESCAPE, LEFT_ARROW, RIGHT_ARROW, hasModifierKey } from '@angular/cdk/keycodes';
|
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
import { fadeMotion } from 'ng-zorro-antd/core/animation';
|
|
import { fromEventOutsideAngular, isNotNil } from 'ng-zorro-antd/core/util';
|
|
import * as i1 from 'ng-zorro-antd/icon';
|
|
import { NzIconModule } from 'ng-zorro-antd/icon';
|
|
import { OverlayRef, createOverlayRef, createGlobalPositionStrategy, createBlockScrollStrategy } from '@angular/cdk/overlay';
|
|
import { ComponentPortal } from '@angular/cdk/portal';
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
class NzImageGroupComponent {
|
|
nzScaleStep = null;
|
|
images = [];
|
|
addImage(image) {
|
|
this.images.push(image);
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.0", type: NzImageGroupComponent, isStandalone: true, selector: "nz-image-group", inputs: { nzScaleStep: "nzScaleStep" }, exportAs: ["nzImageGroup"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageGroupComponent, decorators: [{
|
|
type: Component,
|
|
args: [{
|
|
selector: 'nz-image-group',
|
|
exportAs: 'nzImageGroup',
|
|
template: '<ng-content></ng-content>',
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
encapsulation: ViewEncapsulation.None
|
|
}]
|
|
}], propDecorators: { nzScaleStep: [{
|
|
type: Input
|
|
}] } });
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
const NZ_CONFIG_MODULE_NAME$1 = 'image';
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
class NzImagePreviewOptions {
|
|
nzKeyboard = true;
|
|
nzNoAnimation = false;
|
|
nzMaskClosable = true;
|
|
nzCloseOnNavigation = true;
|
|
nzZIndex;
|
|
nzZoom;
|
|
nzRotate;
|
|
nzFlipHorizontally;
|
|
nzFlipVertically;
|
|
nzScaleStep;
|
|
nzDirection;
|
|
}
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
/**
|
|
* fit content details: https://github.com/NG-ZORRO/ng-zorro-antd/pull/6154#issuecomment-745025554
|
|
*
|
|
* calc position x,y point
|
|
*
|
|
* CASE (width <= clientWidth && height <= clientHeight):
|
|
*
|
|
* ------------- clientWidth -------------
|
|
* | |
|
|
* | ------ width ------ |
|
|
* | | | |
|
|
* | | | |
|
|
* client height | |
|
|
* Height | | |
|
|
* | | | |
|
|
* | ------------------- |
|
|
* | |
|
|
* | |
|
|
* ---------------------------------------
|
|
* fixedPosition = { x: 0, y: 0 }
|
|
*
|
|
*
|
|
*
|
|
* CASE (width > clientWidth || height > clientHeight):
|
|
*
|
|
* ------------- clientWidth -------------
|
|
* | | |
|
|
* | top |
|
|
* | | |
|
|
* |--left--|--------------- width -----------------
|
|
* | | |
|
|
* client | |
|
|
* Height | |
|
|
* | | |
|
|
* | | |
|
|
* | height |
|
|
* | | |
|
|
* ---------| |
|
|
* | |
|
|
* | |
|
|
* | |
|
|
* ----------------------------------------
|
|
*
|
|
*
|
|
* - left || top > 0
|
|
* left -> 0 || top -> 0
|
|
*
|
|
* - (left + width) < clientWidth || (top + height) < clientHeight
|
|
* - left | top + width | height < clientWidth | clientHeight -> Back left | top + width | height === clientWidth | clientHeight
|
|
*
|
|
* DEFAULT:
|
|
* - hold position
|
|
*
|
|
*/
|
|
function getFitContentPosition(params) {
|
|
let fixPos = {};
|
|
if (params.width <= params.clientWidth && params.height <= params.clientHeight) {
|
|
fixPos = {
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
}
|
|
if (params.width > params.clientWidth || params.height > params.clientHeight) {
|
|
fixPos = {
|
|
x: fitPoint(params.left, params.width, params.clientWidth),
|
|
y: fitPoint(params.top, params.height, params.clientHeight)
|
|
};
|
|
}
|
|
return fixPos;
|
|
}
|
|
function getOffset(node) {
|
|
const box = node.getBoundingClientRect();
|
|
const docElem = document.documentElement;
|
|
// use docElem.scrollLeft to support IE
|
|
return {
|
|
left: box.left + (window.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || document.body.clientLeft || 0),
|
|
top: box.top + (window.pageYOffset || docElem.scrollTop) - (docElem.clientTop || document.body.clientTop || 0)
|
|
};
|
|
}
|
|
function getClientSize() {
|
|
const width = document.documentElement.clientWidth;
|
|
const height = window.innerHeight || document.documentElement.clientHeight;
|
|
return {
|
|
width,
|
|
height
|
|
};
|
|
}
|
|
function fitPoint(start, size, clientSize) {
|
|
const startAddSize = start + size;
|
|
const offsetStart = (size - clientSize) / 2;
|
|
let distance = null;
|
|
if (size > clientSize) {
|
|
if (start > 0) {
|
|
distance = offsetStart;
|
|
}
|
|
if (start < 0 && startAddSize < clientSize) {
|
|
distance = -offsetStart;
|
|
}
|
|
}
|
|
else {
|
|
if (start < 0 || startAddSize > clientSize) {
|
|
distance = start < 0 ? offsetStart : -offsetStart;
|
|
}
|
|
}
|
|
return distance;
|
|
}
|
|
|
|
const initialPosition = {
|
|
x: 0,
|
|
y: 0
|
|
};
|
|
const NZ_DEFAULT_SCALE_STEP = 0.5;
|
|
const NZ_DEFAULT_ZOOM = 1;
|
|
const NZ_DEFAULT_ROTATE = 0;
|
|
class NzImagePreviewComponent {
|
|
document = inject(DOCUMENT);
|
|
ngZone = inject(NgZone);
|
|
cdr = inject(ChangeDetectorRef);
|
|
nzConfigService = inject(NzConfigService);
|
|
config = inject(NzImagePreviewOptions);
|
|
sanitizer = inject(DomSanitizer);
|
|
destroyRef = inject(DestroyRef);
|
|
_defaultNzZoom = NZ_DEFAULT_ZOOM;
|
|
_defaultNzScaleStep = NZ_DEFAULT_SCALE_STEP;
|
|
_defaultNzRotate = NZ_DEFAULT_ROTATE;
|
|
images = [];
|
|
index = 0;
|
|
isDragging = false;
|
|
visible = true;
|
|
animationStateChanged = new EventEmitter();
|
|
scaleStepMap = new Map();
|
|
previewImageTransform = '';
|
|
previewImageWrapperTransform = '';
|
|
operations = [
|
|
{
|
|
icon: 'close',
|
|
onClick: () => {
|
|
this.onClose();
|
|
},
|
|
type: 'close'
|
|
},
|
|
{
|
|
icon: 'zoom-in',
|
|
onClick: () => {
|
|
this.onZoomIn();
|
|
},
|
|
type: 'zoomIn'
|
|
},
|
|
{
|
|
icon: 'zoom-out',
|
|
onClick: () => {
|
|
this.onZoomOut();
|
|
},
|
|
type: 'zoomOut'
|
|
},
|
|
{
|
|
icon: 'rotate-right',
|
|
onClick: () => {
|
|
this.onRotateRight();
|
|
},
|
|
type: 'rotateRight'
|
|
},
|
|
{
|
|
icon: 'rotate-left',
|
|
onClick: () => {
|
|
this.onRotateLeft();
|
|
},
|
|
type: 'rotateLeft'
|
|
},
|
|
{
|
|
icon: 'swap',
|
|
onClick: () => {
|
|
this.onHorizontalFlip();
|
|
},
|
|
type: 'flipHorizontally'
|
|
},
|
|
{
|
|
icon: 'swap',
|
|
onClick: () => {
|
|
this.onVerticalFlip();
|
|
},
|
|
type: 'flipVertically',
|
|
rotate: 90
|
|
}
|
|
];
|
|
zoomOutDisabled = false;
|
|
position = { ...initialPosition };
|
|
previewRef;
|
|
closeClick = new EventEmitter();
|
|
imageRef;
|
|
imagePreviewWrapper;
|
|
zoom = this.config.nzZoom ?? this._defaultNzZoom;
|
|
rotate = this.config.nzRotate ?? this._defaultNzRotate;
|
|
scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;
|
|
flipHorizontally = this.config.nzFlipHorizontally ?? false;
|
|
flipVertically = this.config.nzFlipVertically ?? false;
|
|
get animationDisabled() {
|
|
return this.config.nzNoAnimation ?? false;
|
|
}
|
|
get maskClosable() {
|
|
const defaultConfig = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME$1) || {};
|
|
return this.config.nzMaskClosable ?? defaultConfig.nzMaskClosable ?? true;
|
|
}
|
|
constructor() {
|
|
this.updateZoomOutDisabled();
|
|
this.updatePreviewImageTransform();
|
|
this.updatePreviewImageWrapperTransform();
|
|
}
|
|
ngOnInit() {
|
|
fromEventOutsideAngular(this.imagePreviewWrapper.nativeElement, 'mousedown')
|
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
.subscribe(() => {
|
|
this.isDragging = true;
|
|
});
|
|
fromEventOutsideAngular(this.imagePreviewWrapper.nativeElement, 'wheel')
|
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
.subscribe(event => {
|
|
this.ngZone.run(() => this.wheelZoomEventHandler(event));
|
|
});
|
|
fromEventOutsideAngular(this.document, 'keydown')
|
|
.pipe(filter(event => event.keyCode === ESCAPE), takeUntilDestroyed(this.destroyRef))
|
|
.subscribe(() => {
|
|
this.ngZone.run(() => {
|
|
this.onClose();
|
|
this.markForCheck();
|
|
});
|
|
});
|
|
}
|
|
setImages(images, scaleStepMap) {
|
|
if (scaleStepMap)
|
|
this.scaleStepMap = scaleStepMap;
|
|
this.images = images;
|
|
this.markForCheck();
|
|
}
|
|
switchTo(index) {
|
|
this.index = index;
|
|
this.markForCheck();
|
|
}
|
|
next() {
|
|
if (this.index < this.images.length - 1) {
|
|
this.reset();
|
|
this.index++;
|
|
this.updatePreviewImageTransform();
|
|
this.updatePreviewImageWrapperTransform();
|
|
this.updateZoomOutDisabled();
|
|
this.markForCheck();
|
|
}
|
|
}
|
|
prev() {
|
|
if (this.index > 0) {
|
|
this.reset();
|
|
this.index--;
|
|
this.updatePreviewImageTransform();
|
|
this.updatePreviewImageWrapperTransform();
|
|
this.updateZoomOutDisabled();
|
|
this.markForCheck();
|
|
}
|
|
}
|
|
markForCheck() {
|
|
this.cdr.markForCheck();
|
|
}
|
|
onClose() {
|
|
this.visible = false;
|
|
this.closeClick.emit();
|
|
}
|
|
onZoomIn() {
|
|
const zoomStep = this.scaleStepMap.get(this.images[this.index].src ?? this.images[this.index].srcset) ?? this.scaleStep;
|
|
this.zoom += zoomStep;
|
|
this.updatePreviewImageTransform();
|
|
this.updateZoomOutDisabled();
|
|
}
|
|
onZoomOut() {
|
|
if (this.zoom > 1) {
|
|
const zoomStep = this.scaleStepMap.get(this.images[this.index].src ?? this.images[this.index].srcset) ?? this.scaleStep;
|
|
this.zoom -= zoomStep;
|
|
this.updatePreviewImageTransform();
|
|
this.updateZoomOutDisabled();
|
|
if (this.zoom <= 1) {
|
|
this.reCenterImage();
|
|
}
|
|
}
|
|
}
|
|
onRotateRight() {
|
|
this.rotate += 90;
|
|
this.updatePreviewImageTransform();
|
|
}
|
|
onRotateLeft() {
|
|
this.rotate -= 90;
|
|
this.updatePreviewImageTransform();
|
|
}
|
|
onSwitchLeft(event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.prev();
|
|
}
|
|
onSwitchRight(event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.next();
|
|
}
|
|
onHorizontalFlip() {
|
|
this.flipHorizontally = !this.flipHorizontally;
|
|
this.updatePreviewImageTransform();
|
|
}
|
|
onVerticalFlip() {
|
|
this.flipVertically = !this.flipVertically;
|
|
this.updatePreviewImageTransform();
|
|
}
|
|
wheelZoomEventHandler(event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.handlerImageTransformationWhileZoomingWithMouse(event, event.deltaY);
|
|
this.handleImageScaleWhileZoomingWithMouse(event.deltaY);
|
|
this.updatePreviewImageWrapperTransform();
|
|
this.updatePreviewImageTransform();
|
|
this.markForCheck();
|
|
}
|
|
onAnimationStart(event) {
|
|
this.animationStateChanged.emit(event);
|
|
}
|
|
onAnimationDone(event) {
|
|
this.animationStateChanged.emit(event);
|
|
}
|
|
onDragEnd(event) {
|
|
this.isDragging = false;
|
|
const width = this.imageRef.nativeElement.offsetWidth * this.zoom;
|
|
const height = this.imageRef.nativeElement.offsetHeight * this.zoom;
|
|
const { left, top } = getOffset(this.imageRef.nativeElement);
|
|
const { width: clientWidth, height: clientHeight } = getClientSize();
|
|
const isRotate = this.rotate % 180 !== 0;
|
|
const fitContentParams = {
|
|
width: isRotate ? height : width,
|
|
height: isRotate ? width : height,
|
|
left,
|
|
top,
|
|
clientWidth,
|
|
clientHeight
|
|
};
|
|
const fitContentPos = getFitContentPosition(fitContentParams);
|
|
if (isNotNil(fitContentPos.x) || isNotNil(fitContentPos.y)) {
|
|
this.position = { ...this.position, ...fitContentPos };
|
|
}
|
|
else if (!isNotNil(fitContentPos.x) && !isNotNil(fitContentPos.y)) {
|
|
this.position = {
|
|
x: event.source.getFreeDragPosition().x,
|
|
y: event.source.getFreeDragPosition().y
|
|
};
|
|
}
|
|
}
|
|
sanitizerResourceUrl(url) {
|
|
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
}
|
|
updatePreviewImageTransform() {
|
|
this.previewImageTransform = `scale3d(${this.zoom * (this.flipHorizontally ? -1 : 1)}, ${this.zoom * (this.flipVertically ? -1 : 1)}, 1) rotate(${this.rotate}deg)`;
|
|
}
|
|
updatePreviewImageWrapperTransform() {
|
|
this.previewImageWrapperTransform = `translate3d(${this.position.x}px, ${this.position.y}px, 0)`;
|
|
}
|
|
updateZoomOutDisabled() {
|
|
this.zoomOutDisabled = this.zoom <= 1;
|
|
}
|
|
handlerImageTransformationWhileZoomingWithMouse(event, deltaY) {
|
|
let scaleValue;
|
|
const imageElement = this.imageRef.nativeElement;
|
|
const elementTransform = getComputedStyle(imageElement).transform;
|
|
const matrixValue = elementTransform.match(/matrix.*\((.+)\)/);
|
|
if (matrixValue) {
|
|
scaleValue = +matrixValue[1].split(', ')[0];
|
|
}
|
|
else {
|
|
scaleValue = this.zoom;
|
|
}
|
|
const x = (event.clientX - imageElement.getBoundingClientRect().x) / scaleValue;
|
|
const y = (event.clientY - imageElement.getBoundingClientRect().y) / scaleValue;
|
|
const halfOfScaleStepValue = deltaY < 0 ? this.scaleStep / 2 : -this.scaleStep / 2;
|
|
this.position.x += -x * halfOfScaleStepValue * 2 + imageElement.offsetWidth * halfOfScaleStepValue;
|
|
this.position.y += -y * halfOfScaleStepValue * 2 + imageElement.offsetHeight * halfOfScaleStepValue;
|
|
}
|
|
handleImageScaleWhileZoomingWithMouse(deltaY) {
|
|
if (this.isZoomedInWithMouseWheel(deltaY)) {
|
|
this.onZoomIn();
|
|
}
|
|
else {
|
|
this.onZoomOut();
|
|
}
|
|
if (this.zoom <= 1) {
|
|
this.reCenterImage();
|
|
}
|
|
}
|
|
isZoomedInWithMouseWheel(delta) {
|
|
return delta < 0;
|
|
}
|
|
reset() {
|
|
this.zoom = this.config.nzZoom ?? this._defaultNzZoom;
|
|
this.scaleStep = this.config.nzScaleStep ?? this._defaultNzScaleStep;
|
|
this.rotate = this.config.nzRotate ?? this._defaultNzRotate;
|
|
this.flipHorizontally = false;
|
|
this.flipVertically = false;
|
|
this.reCenterImage();
|
|
}
|
|
reCenterImage() {
|
|
this.position = { ...initialPosition };
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImagePreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.0", type: NzImagePreviewComponent, isStandalone: true, selector: "nz-image-preview", host: { listeners: { "@fadeMotion.start": "onAnimationStart($event)", "@fadeMotion.done": "onAnimationDone($event)" }, properties: { "class.ant-image-preview-moving": "isDragging", "style.zIndex": "config.nzZIndex", "@.disabled": "config.nzNoAnimation", "@fadeMotion": "visible ? 'enter' : 'leave'" }, classAttribute: "ant-image-preview-root" }, viewQueries: [{ propertyName: "imageRef", first: true, predicate: ["imgRef"], descendants: true }, { propertyName: "imagePreviewWrapper", first: true, predicate: ["imagePreviewWrapper"], descendants: true, static: true }], exportAs: ["nzImagePreview"], ngImport: i0, template: `
|
|
<div class="ant-image-preview-mask"></div>
|
|
|
|
<div class="ant-image-preview-operations-wrapper">
|
|
@if (images.length > 1) {
|
|
<div
|
|
class="ant-image-preview-switch-left"
|
|
[class.ant-image-preview-switch-left-disabled]="index <= 0"
|
|
(click)="onSwitchLeft($event)"
|
|
>
|
|
<nz-icon nzType="left" nzTheme="outline" />
|
|
</div>
|
|
<div
|
|
class="ant-image-preview-switch-right"
|
|
[class.ant-image-preview-switch-right-disabled]="index >= images.length - 1"
|
|
(click)="onSwitchRight($event)"
|
|
>
|
|
<nz-icon nzType="right" nzTheme="outline" />
|
|
</div>
|
|
}
|
|
|
|
<ul class="ant-image-preview-operations">
|
|
@if (images.length > 1) {
|
|
<li class="ant-image-preview-operations-progress">{{ index + 1 }} / {{ images.length }}</li>
|
|
}
|
|
|
|
@for (option of operations; track option) {
|
|
<li
|
|
class="ant-image-preview-operations-operation"
|
|
[class.ant-image-preview-operations-operation-disabled]="zoomOutDisabled && option.type === 'zoomOut'"
|
|
(click)="option.onClick()"
|
|
>
|
|
<nz-icon
|
|
class="ant-image-preview-operations-icon"
|
|
[nzType]="option.icon"
|
|
[nzRotate]="option.rotate ?? 0"
|
|
nzTheme="outline"
|
|
/>
|
|
</li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
|
|
<div
|
|
class="ant-image-preview-wrap"
|
|
tabindex="-1"
|
|
(click)="maskClosable && $event.target === $event.currentTarget && onClose()"
|
|
>
|
|
<div class="ant-image-preview" role="dialog" aria-modal="true">
|
|
<div tabindex="0" aria-hidden="true" class="ant-image-preview-focus-trap"></div>
|
|
<div class="ant-image-preview-content">
|
|
<div class="ant-image-preview-body">
|
|
<div
|
|
class="ant-image-preview-img-wrapper"
|
|
#imagePreviewWrapper
|
|
cdkDrag
|
|
[style.transform]="previewImageWrapperTransform"
|
|
[cdkDragFreeDragPosition]="position"
|
|
(cdkDragEnded)="onDragEnd($event)"
|
|
>
|
|
@for (image of images; track image; let imageIndex = $index) {
|
|
@if (imageIndex === index) {
|
|
<img
|
|
cdkDragHandle
|
|
class="ant-image-preview-img"
|
|
#imgRef
|
|
[attr.src]="sanitizerResourceUrl(image.src)"
|
|
[attr.srcset]="image.srcset"
|
|
[attr.alt]="image.alt"
|
|
[style.width]="image.width"
|
|
[style.height]="image.height"
|
|
[style.transform]="previewImageTransform"
|
|
/>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div tabindex="0" aria-hidden="true" class="ant-image-preview-focus-trap"></div>
|
|
</div>
|
|
</div>
|
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i1.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }], animations: [fadeMotion], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImagePreviewComponent, decorators: [{
|
|
type: Component,
|
|
args: [{
|
|
selector: 'nz-image-preview',
|
|
exportAs: 'nzImagePreview',
|
|
animations: [fadeMotion],
|
|
template: `
|
|
<div class="ant-image-preview-mask"></div>
|
|
|
|
<div class="ant-image-preview-operations-wrapper">
|
|
@if (images.length > 1) {
|
|
<div
|
|
class="ant-image-preview-switch-left"
|
|
[class.ant-image-preview-switch-left-disabled]="index <= 0"
|
|
(click)="onSwitchLeft($event)"
|
|
>
|
|
<nz-icon nzType="left" nzTheme="outline" />
|
|
</div>
|
|
<div
|
|
class="ant-image-preview-switch-right"
|
|
[class.ant-image-preview-switch-right-disabled]="index >= images.length - 1"
|
|
(click)="onSwitchRight($event)"
|
|
>
|
|
<nz-icon nzType="right" nzTheme="outline" />
|
|
</div>
|
|
}
|
|
|
|
<ul class="ant-image-preview-operations">
|
|
@if (images.length > 1) {
|
|
<li class="ant-image-preview-operations-progress">{{ index + 1 }} / {{ images.length }}</li>
|
|
}
|
|
|
|
@for (option of operations; track option) {
|
|
<li
|
|
class="ant-image-preview-operations-operation"
|
|
[class.ant-image-preview-operations-operation-disabled]="zoomOutDisabled && option.type === 'zoomOut'"
|
|
(click)="option.onClick()"
|
|
>
|
|
<nz-icon
|
|
class="ant-image-preview-operations-icon"
|
|
[nzType]="option.icon"
|
|
[nzRotate]="option.rotate ?? 0"
|
|
nzTheme="outline"
|
|
/>
|
|
</li>
|
|
}
|
|
</ul>
|
|
</div>
|
|
|
|
<div
|
|
class="ant-image-preview-wrap"
|
|
tabindex="-1"
|
|
(click)="maskClosable && $event.target === $event.currentTarget && onClose()"
|
|
>
|
|
<div class="ant-image-preview" role="dialog" aria-modal="true">
|
|
<div tabindex="0" aria-hidden="true" class="ant-image-preview-focus-trap"></div>
|
|
<div class="ant-image-preview-content">
|
|
<div class="ant-image-preview-body">
|
|
<div
|
|
class="ant-image-preview-img-wrapper"
|
|
#imagePreviewWrapper
|
|
cdkDrag
|
|
[style.transform]="previewImageWrapperTransform"
|
|
[cdkDragFreeDragPosition]="position"
|
|
(cdkDragEnded)="onDragEnd($event)"
|
|
>
|
|
@for (image of images; track image; let imageIndex = $index) {
|
|
@if (imageIndex === index) {
|
|
<img
|
|
cdkDragHandle
|
|
class="ant-image-preview-img"
|
|
#imgRef
|
|
[attr.src]="sanitizerResourceUrl(image.src)"
|
|
[attr.srcset]="image.srcset"
|
|
[attr.alt]="image.alt"
|
|
[style.width]="image.width"
|
|
[style.height]="image.height"
|
|
[style.transform]="previewImageTransform"
|
|
/>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div tabindex="0" aria-hidden="true" class="ant-image-preview-focus-trap"></div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
encapsulation: ViewEncapsulation.None,
|
|
host: {
|
|
class: 'ant-image-preview-root',
|
|
'[class.ant-image-preview-moving]': 'isDragging',
|
|
'[style.zIndex]': 'config.nzZIndex',
|
|
'[@.disabled]': 'config.nzNoAnimation',
|
|
'[@fadeMotion]': `visible ? 'enter' : 'leave'`,
|
|
'(@fadeMotion.start)': 'onAnimationStart($event)',
|
|
'(@fadeMotion.done)': 'onAnimationDone($event)'
|
|
},
|
|
imports: [NzIconModule, CdkDragHandle, CdkDrag]
|
|
}]
|
|
}], ctorParameters: () => [], propDecorators: { imageRef: [{
|
|
type: ViewChild,
|
|
args: ['imgRef']
|
|
}], imagePreviewWrapper: [{
|
|
type: ViewChild,
|
|
args: ['imagePreviewWrapper', { static: true }]
|
|
}] } });
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
class NzImagePreviewRef {
|
|
previewInstance;
|
|
config;
|
|
overlayRef;
|
|
destroy$ = new Subject();
|
|
constructor(previewInstance, config, overlayRef) {
|
|
this.previewInstance = previewInstance;
|
|
this.config = config;
|
|
this.overlayRef = overlayRef;
|
|
overlayRef
|
|
.keydownEvents()
|
|
.pipe(filter(event => this.config.nzKeyboard &&
|
|
(event.keyCode === ESCAPE || event.keyCode === LEFT_ARROW || event.keyCode === RIGHT_ARROW) &&
|
|
!hasModifierKey(event)))
|
|
.subscribe(event => {
|
|
event.preventDefault();
|
|
if (event.keyCode === ESCAPE) {
|
|
previewInstance.onClose();
|
|
}
|
|
if (event.keyCode === LEFT_ARROW) {
|
|
this.prev();
|
|
}
|
|
if (event.keyCode === RIGHT_ARROW) {
|
|
this.next();
|
|
}
|
|
});
|
|
overlayRef.detachments().subscribe(() => {
|
|
this.overlayRef.dispose();
|
|
});
|
|
previewInstance.closeClick
|
|
.pipe(take(1), switchMap(() => previewInstance.animationStateChanged), filter(event => event.phaseName === 'done'), takeUntil(this.destroy$))
|
|
.subscribe(() => {
|
|
this.close();
|
|
});
|
|
}
|
|
switchTo(index) {
|
|
this.previewInstance.switchTo(index);
|
|
}
|
|
next() {
|
|
this.previewInstance.next();
|
|
}
|
|
prev() {
|
|
this.previewInstance.prev();
|
|
}
|
|
close() {
|
|
this.destroy$.next();
|
|
this.overlayRef.dispose();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
|
|
class NzImageService {
|
|
injector = inject(Injector);
|
|
nzConfigService = inject(NzConfigService);
|
|
directionality = inject(Directionality);
|
|
preview(images, options, zoomMap) {
|
|
return this.display(images, options, zoomMap);
|
|
}
|
|
display(images, config, scaleStepMap) {
|
|
const configMerged = { ...new NzImagePreviewOptions(), ...(config ?? {}) };
|
|
const overlayRef = this.createOverlay(configMerged);
|
|
const previewComponent = this.attachPreviewComponent(overlayRef, configMerged);
|
|
previewComponent.setImages(images, scaleStepMap);
|
|
const previewRef = new NzImagePreviewRef(previewComponent, configMerged, overlayRef);
|
|
previewComponent.previewRef = previewRef;
|
|
return previewRef;
|
|
}
|
|
attachPreviewComponent(overlayRef, config) {
|
|
const injector = Injector.create({
|
|
parent: this.injector,
|
|
providers: [
|
|
{ provide: OverlayRef, useValue: overlayRef },
|
|
{ provide: NzImagePreviewOptions, useValue: config }
|
|
]
|
|
});
|
|
const containerPortal = new ComponentPortal(NzImagePreviewComponent, null, injector);
|
|
const containerRef = overlayRef.attach(containerPortal);
|
|
return containerRef.instance;
|
|
}
|
|
createOverlay(config) {
|
|
const globalConfig = this.nzConfigService.getConfigForComponent(NZ_CONFIG_MODULE_NAME$1) || {};
|
|
return createOverlayRef(this.injector, {
|
|
scrollStrategy: createBlockScrollStrategy(this.injector),
|
|
positionStrategy: createGlobalPositionStrategy(this.injector),
|
|
disposeOnNavigation: config.nzCloseOnNavigation ?? globalConfig.nzCloseOnNavigation ?? true,
|
|
direction: config.nzDirection || globalConfig.nzDirection || this.directionality.value
|
|
});
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageService });
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageService, decorators: [{
|
|
type: Injectable
|
|
}] });
|
|
|
|
const NZ_CONFIG_MODULE_NAME = 'image';
|
|
let NzImageDirective = (() => {
|
|
let _nzDisablePreview_decorators;
|
|
let _nzDisablePreview_initializers = [];
|
|
let _nzDisablePreview_extraInitializers = [];
|
|
let _nzFallback_decorators;
|
|
let _nzFallback_initializers = [];
|
|
let _nzFallback_extraInitializers = [];
|
|
let _nzPlaceholder_decorators;
|
|
let _nzPlaceholder_initializers = [];
|
|
let _nzPlaceholder_extraInitializers = [];
|
|
let _nzScaleStep_decorators;
|
|
let _nzScaleStep_initializers = [];
|
|
let _nzScaleStep_extraInitializers = [];
|
|
return class NzImageDirective {
|
|
static {
|
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
_nzDisablePreview_decorators = [WithConfig()];
|
|
_nzFallback_decorators = [WithConfig()];
|
|
_nzPlaceholder_decorators = [WithConfig()];
|
|
_nzScaleStep_decorators = [WithConfig()];
|
|
__esDecorate(null, null, _nzDisablePreview_decorators, { kind: "field", name: "nzDisablePreview", static: false, private: false, access: { has: obj => "nzDisablePreview" in obj, get: obj => obj.nzDisablePreview, set: (obj, value) => { obj.nzDisablePreview = value; } }, metadata: _metadata }, _nzDisablePreview_initializers, _nzDisablePreview_extraInitializers);
|
|
__esDecorate(null, null, _nzFallback_decorators, { kind: "field", name: "nzFallback", static: false, private: false, access: { has: obj => "nzFallback" in obj, get: obj => obj.nzFallback, set: (obj, value) => { obj.nzFallback = value; } }, metadata: _metadata }, _nzFallback_initializers, _nzFallback_extraInitializers);
|
|
__esDecorate(null, null, _nzPlaceholder_decorators, { kind: "field", name: "nzPlaceholder", static: false, private: false, access: { has: obj => "nzPlaceholder" in obj, get: obj => obj.nzPlaceholder, set: (obj, value) => { obj.nzPlaceholder = value; } }, metadata: _metadata }, _nzPlaceholder_initializers, _nzPlaceholder_extraInitializers);
|
|
__esDecorate(null, null, _nzScaleStep_decorators, { kind: "field", name: "nzScaleStep", static: false, private: false, access: { has: obj => "nzScaleStep" in obj, get: obj => obj.nzScaleStep, set: (obj, value) => { obj.nzScaleStep = value; } }, metadata: _metadata }, _nzScaleStep_initializers, _nzScaleStep_extraInitializers);
|
|
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
}
|
|
document = inject(DOCUMENT);
|
|
nzConfigService = inject(NzConfigService);
|
|
elementRef = inject(ElementRef);
|
|
nzImageService = inject(NzImageService);
|
|
cdr = inject(ChangeDetectorRef);
|
|
directionality = inject(Directionality);
|
|
destroyRef = inject(DestroyRef);
|
|
_nzModuleName = NZ_CONFIG_MODULE_NAME;
|
|
nzSrc = '';
|
|
nzSrcset = '';
|
|
nzDisablePreview = __runInitializers(this, _nzDisablePreview_initializers, false);
|
|
nzFallback = (__runInitializers(this, _nzDisablePreview_extraInitializers), __runInitializers(this, _nzFallback_initializers, null));
|
|
nzPlaceholder = (__runInitializers(this, _nzFallback_extraInitializers), __runInitializers(this, _nzPlaceholder_initializers, null));
|
|
nzScaleStep = (__runInitializers(this, _nzPlaceholder_extraInitializers), __runInitializers(this, _nzScaleStep_initializers, null));
|
|
dir = __runInitializers(this, _nzScaleStep_extraInitializers);
|
|
backLoadImage;
|
|
status = 'normal';
|
|
backLoadDestroy$ = new Subject();
|
|
parentGroup = inject(NzImageGroupComponent, { optional: true });
|
|
get previewable() {
|
|
return !this.nzDisablePreview && this.status !== 'error';
|
|
}
|
|
ngOnInit() {
|
|
this.backLoad();
|
|
if (this.parentGroup) {
|
|
this.parentGroup.addImage(this);
|
|
}
|
|
if (this.directionality) {
|
|
this.directionality.change?.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(direction => {
|
|
this.dir = direction;
|
|
this.cdr.detectChanges();
|
|
});
|
|
this.dir = this.directionality.value;
|
|
}
|
|
}
|
|
onPreview() {
|
|
if (!this.previewable) {
|
|
return;
|
|
}
|
|
if (this.parentGroup) {
|
|
// preview inside image group
|
|
const previewAbleImages = this.parentGroup.images.filter(e => e.previewable);
|
|
const previewImages = previewAbleImages.map(e => ({ src: e.nzSrc, srcset: e.nzSrcset }));
|
|
const previewIndex = previewAbleImages.findIndex(el => this === el);
|
|
const scaleStepMap = new Map();
|
|
previewAbleImages.forEach(imageDirective => {
|
|
scaleStepMap.set(imageDirective.nzSrc ?? imageDirective.nzSrcset, imageDirective.nzScaleStep ?? this.parentGroup.nzScaleStep ?? this.nzScaleStep ?? NZ_DEFAULT_SCALE_STEP);
|
|
});
|
|
const previewRef = this.nzImageService.preview(previewImages, {
|
|
nzDirection: this.dir
|
|
}, scaleStepMap);
|
|
previewRef.switchTo(previewIndex);
|
|
}
|
|
else {
|
|
// preview not inside image group
|
|
const previewImages = [{ src: this.nzSrc, srcset: this.nzSrcset }];
|
|
this.nzImageService.preview(previewImages, {
|
|
nzDirection: this.dir,
|
|
nzScaleStep: this.nzScaleStep ?? NZ_DEFAULT_SCALE_STEP
|
|
});
|
|
}
|
|
}
|
|
getElement() {
|
|
return this.elementRef;
|
|
}
|
|
ngOnChanges(changes) {
|
|
const { nzSrc } = changes;
|
|
if (nzSrc) {
|
|
this.getElement().nativeElement.src = nzSrc.currentValue;
|
|
this.backLoad();
|
|
}
|
|
}
|
|
/**
|
|
* use internal Image object handle fallback & placeholder
|
|
*
|
|
* @private
|
|
*/
|
|
backLoad() {
|
|
this.backLoadImage = this.document.createElement('img');
|
|
this.backLoadImage.src = this.nzSrc;
|
|
this.backLoadImage.srcset = this.nzSrcset;
|
|
this.status = 'loading';
|
|
// unsubscribe last backLoad
|
|
this.backLoadDestroy$.next();
|
|
this.backLoadDestroy$.complete();
|
|
this.backLoadDestroy$ = new Subject();
|
|
if (this.backLoadImage.complete) {
|
|
this.status = 'normal';
|
|
this.getElement().nativeElement.src = this.nzSrc;
|
|
this.getElement().nativeElement.srcset = this.nzSrcset;
|
|
}
|
|
else {
|
|
if (this.nzPlaceholder) {
|
|
this.getElement().nativeElement.src = this.nzPlaceholder;
|
|
this.getElement().nativeElement.srcset = '';
|
|
}
|
|
else {
|
|
this.getElement().nativeElement.src = this.nzSrc;
|
|
this.getElement().nativeElement.srcset = this.nzSrcset;
|
|
}
|
|
// The `nz-image` directive can be destroyed before the `load` or `error` event is dispatched,
|
|
// so there's no sense to keep capturing `this`.
|
|
fromEvent(this.backLoadImage, 'load')
|
|
.pipe(takeUntil(this.backLoadDestroy$), takeUntilDestroyed(this.destroyRef))
|
|
.subscribe(() => {
|
|
this.status = 'normal';
|
|
this.getElement().nativeElement.src = this.nzSrc;
|
|
this.getElement().nativeElement.srcset = this.nzSrcset;
|
|
});
|
|
fromEvent(this.backLoadImage, 'error')
|
|
.pipe(takeUntil(this.backLoadDestroy$), takeUntilDestroyed(this.destroyRef))
|
|
.subscribe(() => {
|
|
this.status = 'error';
|
|
if (this.nzFallback) {
|
|
this.getElement().nativeElement.src = this.nzFallback;
|
|
this.getElement().nativeElement.srcset = '';
|
|
}
|
|
});
|
|
}
|
|
}
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "20.3.0", type: NzImageDirective, isStandalone: true, selector: "img[nz-image]", inputs: { nzSrc: "nzSrc", nzSrcset: "nzSrcset", nzDisablePreview: ["nzDisablePreview", "nzDisablePreview", booleanAttribute], nzFallback: "nzFallback", nzPlaceholder: "nzPlaceholder", nzScaleStep: "nzScaleStep" }, host: { listeners: { "click": "onPreview()" } }, exportAs: ["nzImage"], usesOnChanges: true, ngImport: i0 });
|
|
};
|
|
})();
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageDirective, decorators: [{
|
|
type: Directive,
|
|
args: [{
|
|
selector: 'img[nz-image]',
|
|
exportAs: 'nzImage',
|
|
host: {
|
|
'(click)': 'onPreview()'
|
|
}
|
|
}]
|
|
}], propDecorators: { nzSrc: [{
|
|
type: Input
|
|
}], nzSrcset: [{
|
|
type: Input
|
|
}], nzDisablePreview: [{
|
|
type: Input,
|
|
args: [{ transform: booleanAttribute }]
|
|
}], nzFallback: [{
|
|
type: Input
|
|
}], nzPlaceholder: [{
|
|
type: Input
|
|
}], nzScaleStep: [{
|
|
type: Input
|
|
}] } });
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
class NzImageModule {
|
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.0", ngImport: i0, type: NzImageModule, imports: [NzImageDirective, NzImagePreviewComponent, NzImageGroupComponent], exports: [NzImageDirective, NzImagePreviewComponent, NzImageGroupComponent] });
|
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageModule, providers: [NzImageService], imports: [NzImagePreviewComponent] });
|
|
}
|
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.0", ngImport: i0, type: NzImageModule, decorators: [{
|
|
type: NgModule,
|
|
args: [{
|
|
imports: [NzImageDirective, NzImagePreviewComponent, NzImageGroupComponent],
|
|
exports: [NzImageDirective, NzImagePreviewComponent, NzImageGroupComponent],
|
|
providers: [NzImageService]
|
|
}]
|
|
}] });
|
|
|
|
/**
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
|
|
*/
|
|
|
|
/**
|
|
* Generated bundle index. Do not edit.
|
|
*/
|
|
|
|
export { NZ_CONFIG_MODULE_NAME$1 as NZ_CONFIG_MODULE_NAME, NZ_DEFAULT_SCALE_STEP, NzImageDirective, NzImageGroupComponent, NzImageModule, NzImagePreviewComponent, NzImagePreviewOptions, NzImagePreviewRef, NzImageService, getClientSize, getFitContentPosition, getOffset };
|
|
//# sourceMappingURL=ng-zorro-antd-image.mjs.map
|