JavaScript实现图片缩放功能
前言
平常,我们在查看图片的时候,都有放大缩小的功能。如下图
那么,我们如何在网页中,对图像进行缩放呢?
本文,我们来讲讲如何使用 JavaScript
实现图片的缩放。当然,我们可以类比到其他的元素,比如视频的缩放。
更改宽度
是的,很符合第一直觉逻辑的一种实现方式。电脑上查看相片也是使用的这种模式 - 直接保持外侧容器的框高不变,等比例地更改图片的尺寸。
我们来简单举个例子:
<div class="container" style="width: 400px; height: 300px;"> <img src="path/to/image.png" id="image" style="width: 400px;" /> </div>
(function(){ const ratio = 4 / 3; // 宽高比例 let imageDom = document.getElementById("image"); imageDom.addEventListener("click", function() { imageDom.style.width = 400 * ratio + "px"; }) })()
上面代码中,我们设定了外部容器的尺寸是 400 * 300 px
,内部的图像的宽度等同外部尺寸。当点击图片之后,图像的宽度变为 400 * 4 / 3 px
,外部的容器没有发生更改。
那么,我们这种直接更改宽度的方法,在全屏的模式下,生效?
public static gotoFullscreen(dom: any): void { if (dom.requestFullscreen) { dom.requestFullscreen() } else if (dom.mozRequestFullScreen) { dom.mozRequestFullScreen() } else if (dom.webkitRequestFullscreen) { dom.webkitRequestFullscreen() } else if (dom.msRequestFullscreen) { dom.msRequestFullscreen() } else { console.error('当前浏览器不支持部分全屏!') } }
也就是通过上面的代码进入到浏览器的全屏模式 gotoFullscreen(document.getElementsByClassName("container")[0])
。
然而,无论我们怎么设定图像的宽度,比如 document.getElementById("image").style.width = "200%"
,都不会生效的。
我们是否还有其他进行缩放的方法在全屏模式下也能够实现呢?
更改 Scale
我们可以保持图片的实际的宽高是不变的,然后更改其 scaleX
和 scaleY
来实现。
<div class="container" style="width: 400px; height: 300px;"> <img src="path/to/image.png" id="image" style="width: 400px;" /> </div>
(function(){ const ratio = 4 / 3; // 框高比例 let imageDom = document.getElementById("image"); imageDom.addEventListener("click", function() { imageDom.style.transform = `scale(4/3, 4/3)`; }) })()
很明显,与 更改宽度
小节,唯一不同的点就是 imageDom.style.transform = scale(4/3, 4/3)
;,我们在点击图片的时候,使用 transform
属性值 scale(x, y)
对其 x
轴和 y
轴进行缩放。
而且,在全屏的模式下,该方法依旧能够实现对图片的缩放。因为图片的宽度不变。
取舍
两种方案:更改宽度
和 更改 Scale
。我们应该选择 更改 Scale
来对图像进行缩放。因为:
- 更改
Scale
涉及的场景比 更改宽度 要广 - 更改
Scale
性能比更改宽度性能优越。因为更改宽度是对dom
进行操作,会造成回流和重排,而更改Scale
是利用图形处理器(GPU)
来实现。
更改偏移位置
我们以方案二 - 更改 Scale
为基础。
当我们希望查看点击点的图片。我们需要对其进行放大,并将点击点放在外容器的中心点的位置。那么,我们就需要对图像的位置进行处理。
我们可以使用 position: absolute; top: *px; left: *px;
来实现,但是通过我们上面取舍小节的对比。我们有更好的替代方案 - 使用 translate(x, y) 来实现
。
这里我们使用 typescript
结合 angular
来实现:
<div id="imageContainer"> <image id="image" [style]="{ width: imageRealWidth, transform: 'scale(' + imageAmplifyMultiple + ', ' + imageAmplifyMultiple + ') translate(' + imageTranslateX + 'px, ' + imageTranslateY + 'px)' }" /> </div>
对应的 javascript
如下:
// 放大图片区域 public amplifyImagePortion(event) { let imageContainerCenterLeft : number; let imageContainerCenterTop : number; let _imageContainer: any = document.getElementById('imageContainer'); if(this.imageIsFullscreen) { // 全屏模式 imageContainerCenterLeft = _imageContainer.getBoundingClientRect().width / 2; imageContainerCenterTop =_imageContainer.getBoundingClientRect().height / 2; } else { // 非全屏的模式下 imageContainerCenterLeft = _imageContainer.getBoundingClientRect().left + _imageContainer.getBoundingClientRect().width / 2; imageContainerCenterTop = _imageContainer.getBoundingClientRect().top + _imageContainer.getBoundingClientRect().height / 2; } let clickPointLeft = event.pageX; let clickPointTop = event.pageY; this.imageTranslateX = (this.imageTranslateX * this.imageAmplifyMultiple + ( imageContainerCenterLeft - clickPointLeft)) / this.imageAmplifyMultiple; this.imageTranslateY = (this.imageTranslateY * this.imageAmplifyMultiple +(imageContainerCenterTop - clickPointTop)) / this.imageAmplifyMultiple; // 放大的倍数 this.imageAmplifyMultiple = this.imageAmplifyMultiple * this.multipleStep; }
上面的案例中,我们只是进行放大功能的展示。
引入鼠标滚轮
下面,我们通过引入鼠标滚动,修改下 amplifyVideoPortion
方法来对图像放大或缩小。
// 滚轮滚动 private mouseWheelFn(event) { if(!this.mouseWheel) { this.mouseWheel = fromEvent(document.getElementById('imageContainer'), 'wheel'); this.subscriptions.push( this.mouseWheel .pipe(throttleTime(50)) .subscribe((wheel: any) => { if(wheel.deltaY > 1) { // 进行局部放大 this.amplifyImagePortion(event, true); } if(wheel.deltaY < -1) { // 进行局部缩小 this.amplifyImagePortion(event, true, 'minify'); } // 重置框选数据 this.resetCheckBoxVariables(); }) ); } }
我们监听外部容器选中,滚轮滚动,当正向滚动的时候,我们对图片进行局部放大,当反向滚动的时候,我们对图片进行局部缩小。我们这里还引入了 rxjs
中的节流方法 throttleTime
来优化滚轮触发事件的时机。
对应的 amplifyImagePortion
方法我们更改如下
// 放大图像区域 public amplifyImagePortion(event, isWheel, direction?: string) { // isWheel 是否是鼠标滚动 let imageContainerCenterLeft : number; let imageContainerCenterTop : number; let _imageContainer: any = document.getElementById('imageContainer'); if(this.imageIsFullscreen) { // 全屏模式下 imageContainerCenterLeft = _imageContainer.getBoundingClientRect().width / 2; imageContainerCenterTop =_imageContainer.getBoundingClientRect().height / 2; } else { // 非全屏的模式下 if(isWheel) { imageContainerCenterLeft = _imageContainer.getBoundingClientRect().left + _imageContainer.getBoundingClientRect().width / 2; imageContainerCenterTop = _imageContainer.getBoundingClientRect().top + _imageContainer.getBoundingClientRect().height / 2; } } let clickPointLeft: number = 0; let clickPointTop: number = 0; if(isWheel) { clickPointLeft = event.pageX; clickPointTop = event.pageY; } else { clickPointLeft = this.checkboxPositionLeft + this.checkboxWidth / 2; clickPointTop = this.checkboxPositionTop + this.checkboxHeight / 2 } // 计算两点之间的距离 let diffX: number = imageContainerCenterLeft - clickPointLeft; let diffY: number = imageContainerCenterTop - clickPointTop; if(!isWheel) { this.imageTranslateX = (this.imageTranslateX * this.imageAmplifyMultiple + diffX) / this.imageAmplifyMultiple; this.imageTranslateY = (this.imageTranslateY * this.imageAmplifyMultiple + diffY) / this.imageAmplifyMultiple; } // 缩小的倍数 if(direction == 'minify') { this.imageAmplifyMultiple = this.imageAmplifyMultiple * (1 / this.multipleStep); } else { // 放大的倍数 - 默认 this.imageAmplifyMultiple = this.imageAmplifyMultiple * this.multipleStep; } }
multipleStep
是放大的倍数,1 / multipleStep
是缩小的倍数。因为宽度变,我们需要对translate
的x
轴和y
轴的偏移进行合理计算,见上面两份代码。
扩展
当然,我们还可以图片缩放的功能进行扩展,比如,对图片进行区域的框选进行缩放;比如,另起一个 canvas
对图片进行绘制缩放等。
以上就是JavaScript实现图片缩放功能的详细内容,更多关于JavaScript图片缩放的资料请关注脚本之家其它相关文章!
最新评论