JavaScript实现图片缩放功能

 更新时间:2024年07月10日 08:45:23   作者:Jimmy  
本文,我们来讲讲如何使用 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

我们可以保持图片的实际的宽高是不变的,然后更改其 scaleXscaleY 来实现。

<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 是缩小的倍数。因为宽度变,我们需要对 translatex 轴和 y 轴的偏移进行合理计算,见上面两份代码。

扩展

当然,我们还可以图片缩放的功能进行扩展,比如,对图片进行区域的框选进行缩放;比如,另起一个 canvas 对图片进行绘制缩放等。

以上就是JavaScript实现图片缩放功能的详细内容,更多关于JavaScript图片缩放的资料请关注脚本之家其它相关文章!

相关文章

最新评论