feat:image previewer

pr675
黄云飞 4 years ago
parent 586b0321ae
commit ddf732dbcb

@ -109,6 +109,96 @@
opacity: 0.5;
}
.image-previewer {
position: fixed;
left: 0;
top: 0;
z-index: 1000;
width: 100%;
height: 100%;
overflow: hidden;
background: #f2f4f7;
display: flex;
align-items: center;
justify-content: center;
animation: previewerAnimation .3s;
}
@keyframes previewerAnimation {
0% {
opacity: 0.1;
}
100% {
opacity: 1;
}
}
.image-previewer .image-close {
width: 24px;
height: 24px;
display: inline-block;
position: absolute;
right: 50px;
top: 30px;
z-index: 99;
cursor: pointer;
background: url(../images/close.svg) no-repeat;
background-size: 100% 100%;
transition: all .3s;
border-radius: 50%;
}
.image-previewer .image-close:hover {
background-color: #e2e6ed;
}
.image-previewer img {
cursor: move;
}
.image-previewer .image-menu {
height: 50px;
position: absolute;
bottom: 50px;
z-index: 99;
display: flex;
align-items: center;
justify-content: center;
}
.image-previewer .image-menu i {
width: 32px;
height: 32px;
margin-right: 15px;
cursor: pointer;
display: inline-block;
background-repeat: no-repeat;
background-size: 100% 100%;
transition: all .3s;
border-radius: 50%;
}
.image-previewer .image-menu i:hover {
background-color: #e2e6ed;
}
.image-previewer .image-menu i.zoom-in {
background-image: url(../images/zoom-in.svg);
}
.image-previewer .image-menu i.zoom-out {
background-image: url(../images/zoom-out.svg);
}
.image-previewer .image-menu i.rotate {
background-image: url(../images/rotate.svg);
}
.image-previewer .image-menu i.original-size {
background-image: url(../images/original-size.svg);
}
.table-tool__row {
position: absolute;
width: 12px;

@ -0,0 +1 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path d="M23.97 7l1.415 1.414-7.779 7.778 7.779 7.779-1.414 1.414-7.779-7.779-7.778 7.779L7 23.97l7.778-7.779L7 8.414 8.414 7l7.778 7.778L23.971 7z" fill="#3D4757" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 254 B

@ -0,0 +1 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path d="M4 4h24v24H4V4zm2 2v20h20V6H6zm4 5h2v10h-2V11zm5 2h2v2h-2v-2zm0 4h2v2h-2v-2zm5-6h2v10h-2V11z" fill="#3D4757"/></svg>

After

Width:  |  Height:  |  Size: 188 B

@ -0,0 +1 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><g fill="#3D4757" fill-rule="evenodd"><path d="M16 4c6.627 0 12 5.373 12 12a11.97 11.97 0 01-4 8.944V23h-.86A9.968 9.968 0 0026 16c0-5.523-4.477-10-10-10S6 10.477 6 16c0 5.185 3.947 9.449 9 9.95v2.009C8.84 27.451 4 22.291 4 16 4 9.373 9.373 4 16 4z" fill-rule="nonzero"/><path d="M19.879 27.328l1.767-6.717 4.95 4.95z"/></g></svg>

After

Width:  |  Height:  |  Size: 393 B

@ -0,0 +1 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path d="M14 14v-4h2v4h4v2h-4v4h-2v-4h-4v-2h4zm8.749 10.163A11.952 11.952 0 0115 27C8.373 27 3 21.627 3 15S8.373 3 15 3s12 5.373 12 12c0 2.954-1.067 5.658-2.837 7.749l4.908 4.908-1.414 1.414-4.908-4.908zM15 25c5.523 0 10-4.477 10-10S20.523 5 15 5 5 9.477 5 15s4.477 10 10 10z" fill="#3D4757"/></svg>

After

Width:  |  Height:  |  Size: 362 B

@ -0,0 +1 @@
<svg width="32" height="32" xmlns="http://www.w3.org/2000/svg"><path d="M22.749 24.163A11.952 11.952 0 0115 27C8.373 27 3 21.627 3 15S8.373 3 15 3s12 5.373 12 12c0 2.954-1.067 5.658-2.837 7.749l4.908 4.908-1.414 1.414-4.908-4.908zM15 25c5.523 0 10-4.477 10-10S20.523 5 15 5 5 9.477 5 15s4.477 10 10 10zm-5-11h10v2H10v-2z" fill="#3D4757"/></svg>

After

Width:  |  Height:  |  Size: 344 B

@ -12,6 +12,7 @@ export class ImageParticle {
private curElement: IElement | null
private curPosition: IElementPosition | null
private imageCache: Map<string, HTMLImageElement>
// 拖拽改变尺寸
private resizerSelection: HTMLDivElement
private resizerHandleList: HTMLDivElement[]
private resizerImageContainer: HTMLDivElement
@ -21,6 +22,9 @@ export class ImageParticle {
private mousedownX: number
private mousedownY: number
private curHandleIndex: number
// 预览选区
private previewerContainer: HTMLDivElement | null
private previewerImage: HTMLImageElement | null
constructor(draw: Draw) {
this.container = draw.getContainer()
@ -30,6 +34,7 @@ export class ImageParticle {
this.curElement = null
this.curPosition = null
this.imageCache = new Map()
// 图片尺寸缩放
const { resizerSelection, resizerHandleList, resizerImageContainer, resizerImage } = this._createResizerDom()
this.resizerSelection = resizerSelection
this.resizerHandleList = resizerHandleList
@ -40,6 +45,10 @@ export class ImageParticle {
this.mousedownX = 0
this.mousedownY = 0
this.curHandleIndex = 0 // 默认右下角
// 图片预览
resizerSelection.ondblclick = this._dblclick.bind(this)
this.previewerContainer = null
this.previewerImage = null
}
private _createResizerDom(): IImageParticleCreateResult {
@ -54,7 +63,7 @@ export class ImageParticle {
handleDom.style.background = this.options.resizerColor
handleDom.classList.add(`handle-${i}`)
handleDom.setAttribute('data-index', String(i))
handleDom.onmousedown = this._handleMousedown.bind(this)
handleDom.onmousedown = this._mousedown.bind(this)
resizerSelection.append(handleDom)
resizerHandleList.push(handleDom)
}
@ -69,7 +78,7 @@ export class ImageParticle {
return { resizerSelection, resizerHandleList, resizerImageContainer, resizerImage }
}
private _handleMousedown(evt: MouseEvent) {
private _mousedown(evt: MouseEvent) {
this.canvas = this.draw.getPage()
if (!this.curPosition || !this.curElement) return
const { scale } = this.options
@ -156,6 +165,119 @@ export class ImageParticle {
evt.preventDefault()
}
private _dblclick() {
this._drawPreviewer()
document.body.style.overflow = 'hidden'
}
private _drawPreviewer() {
const previewerContainer = document.createElement('div')
previewerContainer.classList.add('image-previewer')
// 关闭按钮
const closeBtn = document.createElement('i')
closeBtn.classList.add('image-close')
closeBtn.onclick = () => {
this._clearPreviewer()
}
previewerContainer.append(closeBtn)
// 图片
const imgContainer = document.createElement('div')
imgContainer.classList.add('image-container')
const img = document.createElement('img')
img.src = this.curElement?.value || ''
img.draggable = false
imgContainer.append(img)
this.previewerImage = img
previewerContainer.append(imgContainer)
// 操作栏
let scaleSize = 1
let rotateSize = 0
let translateX = 0
let translateY = 0
const menuContainer = document.createElement('div')
menuContainer.classList.add('image-menu')
const zoomIn = document.createElement('i')
zoomIn.classList.add('zoom-in')
zoomIn.onclick = () => {
scaleSize += 0.1
this._setPreviewerTransform(scaleSize, rotateSize, translateX, translateY)
}
menuContainer.append(zoomIn)
const zoomOut = document.createElement('i')
zoomOut.onclick = () => {
if (scaleSize - 0.1 <= 0.1) return
scaleSize -= 0.1
this._setPreviewerTransform(scaleSize, rotateSize, translateX, translateY)
}
zoomOut.classList.add('zoom-out')
menuContainer.append(zoomOut)
const rotate = document.createElement('i')
rotate.classList.add('rotate')
rotate.onclick = () => {
rotateSize += 1
this._setPreviewerTransform(scaleSize, rotateSize, translateX, translateY)
}
menuContainer.append(rotate)
const originalSize = document.createElement('i')
originalSize.classList.add('original-size')
originalSize.onclick = () => {
scaleSize = 1
rotateSize = 0
translateX = 0
translateY = 0
this._setPreviewerTransform(scaleSize, rotateSize, translateX, translateY)
}
menuContainer.append(originalSize)
previewerContainer.append(menuContainer)
this.previewerContainer = previewerContainer
document.body.append(previewerContainer)
// 拖拽调整位置
let startX = 0
let startY = 0
let isAllowDrag = false
img.onmousedown = (evt) => {
isAllowDrag = true
startX = evt.x
startY = evt.y
previewerContainer.style.cursor = 'move'
}
previewerContainer.onmousemove = (evt: MouseEvent) => {
if (!isAllowDrag) return
translateX += (evt.x - startX)
translateY += (evt.y - startY)
startX = evt.x
startY = evt.y
this._setPreviewerTransform(scaleSize, rotateSize, translateX, translateY)
}
previewerContainer.onmouseup = () => {
isAllowDrag = false
previewerContainer.style.cursor = 'auto'
}
previewerContainer.onwheel = (evt) => {
evt.preventDefault()
if (evt.deltaY < 0) {
// 放大
scaleSize += 0.1
} else {
// 缩小
if (scaleSize - 0.1 <= 0.1) return
scaleSize -= 0.1
}
this._setPreviewerTransform(scaleSize, rotateSize, translateX, translateY)
}
}
public _setPreviewerTransform(scale: number, rotate: number, x: number, y: number) {
if (!this.previewerImage) return
this.previewerImage.style.transform = `scale(${scale}) rotate(${rotate * 90}deg) translate(${x}px,${y}px)`
}
private _clearPreviewer() {
this.previewerContainer?.remove()
this.previewerContainer = null
document.body.style.overflow = 'auto'
}
public getImageCache(): Map<string, HTMLImageElement> {
return this.imageCache
}

Loading…
Cancel
Save