import Displayable, { DisplayableProps,
|
CommonStyleProps,
|
DEFAULT_COMMON_STYLE,
|
DisplayableStatePropNames,
|
DEFAULT_COMMON_ANIMATION_PROPS
|
} from './Displayable';
|
import BoundingRect from '../core/BoundingRect';
|
import { ImageLike, MapToType } from '../core/types';
|
import { defaults, createObject } from '../core/util';
|
import { ElementCommonState } from '../Element';
|
|
export interface ImageStyleProps extends CommonStyleProps {
|
image?: string | ImageLike
|
x?: number
|
y?: number
|
width?: number
|
height?: number
|
sx?: number
|
sy?: number
|
sWidth?: number
|
sHeight?: number
|
}
|
|
export const DEFAULT_IMAGE_STYLE: CommonStyleProps = defaults({
|
x: 0,
|
y: 0
|
}, DEFAULT_COMMON_STYLE);
|
|
export const DEFAULT_IMAGE_ANIMATION_PROPS: MapToType<ImageProps, boolean> = {
|
style: defaults<MapToType<ImageStyleProps, boolean>, MapToType<ImageStyleProps, boolean>>({
|
x: true,
|
y: true,
|
width: true,
|
height: true,
|
sx: true,
|
sy: true,
|
sWidth: true,
|
sHeight: true
|
}, DEFAULT_COMMON_ANIMATION_PROPS.style)
|
};
|
|
export interface ImageProps extends DisplayableProps {
|
style?: ImageStyleProps
|
|
onload?: (image: ImageLike) => void
|
}
|
|
export type ImageState = Pick<ImageProps, DisplayableStatePropNames> & ElementCommonState
|
|
function isImageLike(source: unknown): source is HTMLImageElement {
|
return !!(source
|
&& typeof source !== 'string'
|
// Image source is an image, canvas, video.
|
&& (source as HTMLImageElement).width && (source as HTMLImageElement).height);
|
}
|
|
class ZRImage extends Displayable<ImageProps> {
|
|
style: ImageStyleProps
|
|
// FOR CANVAS RENDERER
|
__image: ImageLike
|
// FOR SVG RENDERER
|
__imageSrc: string
|
|
onload: (image: ImageLike) => void
|
|
/**
|
* Create an image style object with default values in it's prototype.
|
* @override
|
*/
|
createStyle(obj?: ImageStyleProps) {
|
return createObject(DEFAULT_IMAGE_STYLE, obj);
|
}
|
|
private _getSize(dim: 'width' | 'height') {
|
const style = this.style;
|
|
let size = style[dim];
|
if (size != null) {
|
return size;
|
}
|
|
const imageSource = isImageLike(style.image)
|
? style.image : this.__image;
|
|
if (!imageSource) {
|
return 0;
|
}
|
|
const otherDim = dim === 'width' ? 'height' : 'width';
|
let otherDimSize = style[otherDim];
|
if (otherDimSize == null) {
|
return imageSource[dim];
|
}
|
else {
|
return imageSource[dim] / imageSource[otherDim] * otherDimSize;
|
}
|
}
|
|
getWidth(): number {
|
return this._getSize('width');
|
}
|
|
getHeight(): number {
|
return this._getSize('height');
|
}
|
|
getAnimationStyleProps() {
|
return DEFAULT_IMAGE_ANIMATION_PROPS;
|
}
|
|
getBoundingRect(): BoundingRect {
|
const style = this.style;
|
if (!this._rect) {
|
this._rect = new BoundingRect(
|
style.x || 0, style.y || 0, this.getWidth(), this.getHeight()
|
);
|
}
|
return this._rect;
|
}
|
}
|
|
ZRImage.prototype.type = 'image';
|
|
export default ZRImage;
|