JavaScript實(shí)現(xiàn)圖片縮放功能
前言
平常,我們在查看圖片的時(shí)候,都有放大縮小的功能。如下圖
那么,我們?nèi)绾卧诰W(wǎng)頁中,對圖像進(jìn)行縮放呢?
本文,我們來講講如何使用 JavaScript 實(shí)現(xiàn)圖片的縮放。當(dāng)然,我們可以類比到其他的元素,比如視頻的縮放。
更改寬度
是的,很符合第一直覺邏輯的一種實(shí)現(xiàn)方式。電腦上查看相片也是使用的這種模式 - 直接保持外側(cè)容器的框高不變,等比例地更改圖片的尺寸。
我們來簡單舉個(gè)例子:
<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";
})
})()
上面代碼中,我們設(shè)定了外部容器的尺寸是 400 * 300 px,內(nèi)部的圖像的寬度等同外部尺寸。當(dāng)點(diǎn)擊圖片之后,圖像的寬度變?yōu)?nbsp;400 * 4 / 3 px,外部的容器沒有發(fā)生更改。
那么,我們這種直接更改寬度的方法,在全屏的模式下,生效?
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('當(dāng)前瀏覽器不支持部分全屏!')
}
}
也就是通過上面的代碼進(jìn)入到瀏覽器的全屏模式 gotoFullscreen(document.getElementsByClassName("container")[0])。
然而,無論我們怎么設(shè)定圖像的寬度,比如 document.getElementById("image").style.width = "200%",都不會生效的。
我們是否還有其他進(jìn)行縮放的方法在全屏模式下也能夠?qū)崿F(xiàn)呢?
更改 Scale
我們可以保持圖片的實(shí)際的寬高是不變的,然后更改其 scaleX 和 scaleY 來實(shí)現(xiàn)。
<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)`;
})
})()
很明顯,與 更改寬度 小節(jié),唯一不同的點(diǎn)就是 imageDom.style.transform = scale(4/3, 4/3);,我們在點(diǎn)擊圖片的時(shí)候,使用 transform 屬性值 scale(x, y) 對其 x 軸和 y 軸進(jìn)行縮放。
而且,在全屏的模式下,該方法依舊能夠?qū)崿F(xiàn)對圖片的縮放。因?yàn)?strong>圖片的寬度不變。
取舍
兩種方案:更改寬度 和 更改 Scale。我們應(yīng)該選擇 更改 Scale 來對圖像進(jìn)行縮放。因?yàn)椋?/p>
- 更改
Scale涉及的場景比 更改寬度 要廣 - 更改
Scale性能比更改寬度性能優(yōu)越。因?yàn)楦膶挾仁菍?dom進(jìn)行操作,會造成回流和重排,而更改Scale是利用圖形處理器(GPU)來實(shí)現(xiàn)。
更改偏移位置
我們以方案二 - 更改 Scale 為基礎(chǔ)。
當(dāng)我們希望查看點(diǎn)擊點(diǎn)的圖片。我們需要對其進(jìn)行放大,并將點(diǎn)擊點(diǎn)放在外容器的中心點(diǎn)的位置。那么,我們就需要對圖像的位置進(jìn)行處理。
我們可以使用 position: absolute; top: *px; left: *px; 來實(shí)現(xiàn),但是通過我們上面取舍小節(jié)的對比。我們有更好的替代方案 - 使用 translate(x, y) 來實(shí)現(xiàn)。
這里我們使用 typescript 結(jié)合 angular 來實(shí)現(xiàn):
<div id="imageContainer">
<image
id="image"
[style]="{
width: imageRealWidth,
transform: 'scale(' + imageAmplifyMultiple + ', ' + imageAmplifyMultiple + ') translate(' + imageTranslateX + 'px, ' + imageTranslateY + 'px)'
}"
/>
</div>
對應(yīng)的 javascript 如下:
// 放大圖片區(qū)域
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;
// 放大的倍數(shù)
this.imageAmplifyMultiple = this.imageAmplifyMultiple * this.multipleStep;
}
上面的案例中,我們只是進(jìn)行放大功能的展示。
引入鼠標(biāo)滾輪
下面,我們通過引入鼠標(biāo)滾動,修改下 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) {
// 進(jìn)行局部放大
this.amplifyImagePortion(event, true);
}
if(wheel.deltaY < -1) {
// 進(jìn)行局部縮小
this.amplifyImagePortion(event, true, 'minify');
}
// 重置框選數(shù)據(jù)
this.resetCheckBoxVariables();
})
);
}
}
我們監(jiān)聽外部容器選中,滾輪滾動,當(dāng)正向滾動的時(shí)候,我們對圖片進(jìn)行局部放大,當(dāng)反向滾動的時(shí)候,我們對圖片進(jìn)行局部縮小。我們這里還引入了 rxjs 中的節(jié)流方法 throttleTime 來優(yōu)化滾輪觸發(fā)事件的時(shí)機(jī)。
對應(yīng)的 amplifyImagePortion 方法我們更改如下
// 放大圖像區(qū)域
public amplifyImagePortion(event, isWheel, direction?: string) { // isWheel 是否是鼠標(biāo)滾動
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
}
// 計(jì)算兩點(diǎn)之間的距離
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;
}
// 縮小的倍數(shù)
if(direction == 'minify') {
this.imageAmplifyMultiple = this.imageAmplifyMultiple * (1 / this.multipleStep);
} else {
// 放大的倍數(shù) - 默認(rèn)
this.imageAmplifyMultiple = this.imageAmplifyMultiple * this.multipleStep;
}
}
multipleStep是放大的倍數(shù),1 / multipleStep是縮小的倍數(shù)。因?yàn)閷挾茸?,我們需要?translate的x軸和y軸的偏移進(jìn)行合理計(jì)算,見上面兩份代碼。
擴(kuò)展
當(dāng)然,我們還可以圖片縮放的功能進(jìn)行擴(kuò)展,比如,對圖片進(jìn)行區(qū)域的框選進(jìn)行縮放;比如,另起一個(gè) canvas 對圖片進(jìn)行繪制縮放等。
以上就是JavaScript實(shí)現(xiàn)圖片縮放功能的詳細(xì)內(nèi)容,更多關(guān)于JavaScript圖片縮放的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript函數(shù)節(jié)流概念與用法實(shí)例詳解
這篇文章主要介紹了JavaScript函數(shù)節(jié)流概念與用法,結(jié)合實(shí)例形式詳細(xì)分析了JavaScript函數(shù)節(jié)流的概念、功能,并分析了函數(shù)節(jié)流的用法與使用技巧,需要的朋友可以參考下2016-06-06
如何使用moment.js獲取本周、前n周、后n周開始結(jié)束日期及動態(tài)計(jì)算周數(shù)
使用了momentjs之后發(fā)現(xiàn)這個(gè)日期處理控件實(shí)在是太強(qiáng)大了,下面這篇文章主要給大家介紹了關(guān)于如何使用moment.js獲取本周、前n周、后n周開始結(jié)束日期及動態(tài)計(jì)算周數(shù)的相關(guān)資料,需要的朋友可以參考下2022-09-09
JS與CSS3實(shí)現(xiàn)圖片響應(yīng)鼠標(biāo)移動放大效果示例
這篇文章主要介紹了JS與CSS3實(shí)現(xiàn)圖片響應(yīng)鼠標(biāo)移動放大效果,結(jié)合實(shí)例形式分析了javascript與css3響應(yīng)鼠標(biāo)事件動態(tài)修改頁面元素屬性實(shí)現(xiàn)圖片放大效果相關(guān)操作技巧,需要的朋友可以參考下2018-05-05
webpack是如何實(shí)現(xiàn)模塊化加載的方法
這篇文章主要介紹了webpack是如何實(shí)現(xiàn)模塊化加載的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
手機(jī)開發(fā)必備技巧:javascript及CSS功能代碼分享
這篇文章主要介紹了手機(jī)開發(fā)必備技巧:javascript及CSS功能代碼分享,本文講解了viewport(可視區(qū)域)操作、鏈接操作、javascript事件等內(nèi)容,需要的朋友可以參考下2015-05-05
隨鼠標(biāo)移動的時(shí)鐘非常漂亮遺憾的是只支持IE
這篇文章主要介紹了隨鼠標(biāo)移動的時(shí)鐘非常漂亮遺憾的是只支持IE,需要的朋友可以參考下2014-08-08

