最近項目有個需求根據后端提供的圖片旋轉角度在頁面上顯示正向的圖片,要求寬度是固定的高度自適應並且保證圖片不能變形,一開始采用的是img的形式,img旋轉之后不但坐標會混亂處理着麻煩,而且90度和270度的圖片旋轉成正向還會有空白滾動條的問題,最后決定用canvas實現。
這里繪制的圖片要剛好鋪滿整個canvas,所以canvas的寬高就是圖片的寬高,圖片的高度是要與寬等比例不能變形的,canvas的寬等於父容器的clientWidth,圖片可能很高會有滾動條(naturalWidth:圖片的原始寬,naturalWidth:圖片的原始高),根據寬高比 width/height = canvas.width/canvas.height 計算得出canvas.height ,canvas本身是無法實現滾動條效果,所以需要個它添加一個父容器。
HTML:
<div class="wrap"> <canvas id="canvas"></canvas> </div>
CSS
<style> .wrap{ width: 500px; height: 300px; overflow-y: scroll; } </style>
js部分:
首先獲取父容器和canvas,生成canvas的繪圖環境,通過new Image()對象生成一個圖片對象實例,對象實例通過src賦值圖片,之后一切操作都放到onload 函數里面,圖片加載完成后進行,不在這里面進行就無法獲取到圖片的原始尺寸。獲取原始尺寸后通過寬高比列計算出需要設置圖片的高度,在這里也是canvas的高度。
圖片旋轉角度為0時:直接計算完成通過ctx.drawImage方法繪制即可。
<script> let wrap = document.querySelector('.wrap') let canvas = document.querySelector('#canvas'); let ctx = canvas.getContext('2d'); canvas.width = wrap.clientWidth; const img = new Image(); img.src = 'img/bg.jpg'; img.onload = function(){ let width = this.naturalWidth; let height = this.naturalHeight; canvas.height = canvas.width * height / width; ctx.drawImage(img, 0, 0, canvas.width, canvas.height); } </script>
效果:
圖片旋轉角度為90和270度時:因為這里牽涉到旋轉所以要先知道canvas默認旋轉中心點是哪里。根據下面圖片可以直接看到中心點在左上角。因為是旋轉90和270所以圖片的寬高是互換的。
這里的計算 canvas.height = canvas.width * height / width; 要改成 canvas.height = canvas.width * width / height;
默認中心點在左上角一轉就拋出畫布范圍里,為了方便操作和調試先把旋轉中心點拉到中心來。
ctx.translate(canvas.width * 0.5, canvas.height * 0.5);
這是拉到中心為旋轉的效果,然后給它旋轉放正,這里可以正270度和負90度都可以把圖片放正,我選擇正270度。
旋轉后效果
可以看到圖片角度沒問題了,寬高再拉回來一半就可以了
const img = new Image();
img.src = 'img/bg1.jpg';
img.onload = function(){
let width = this.naturalWidth;
let height = this.naturalHeight;
canvas.height = canvas.width * width / height;
ctx.translate(canvas.width * 0.5, canvas.height * 0.5);
ctx.rotate(1.5 * Math.PI);
ctx.drawImage(img, - canvas.height / 2, - canvas.width / 2, canvas.height, canvas.width);
}
圖片旋轉角度為180時:和90度的操作一樣,只不過寬高不會互換罷了。
const img = new Image(); img.src = 'img/bg2.jpg'; img.onload = function(){ let width = this.naturalWidth; let height = this.naturalHeight; canvas.height = canvas.width * height / width; ctx.translate(canvas.width * 0.5, canvas.height * 0.5); ctx.rotate(1 * Math.PI); ctx.drawImage(img, - canvas.width / 2, - canvas.height / 2, canvas.width, canvas.height); }
全部代碼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin: 0; padding: 0; } .wrap{ width: 500px; height: 300px; overflow-y: scroll; margin: 20px; } </style> </head> <div class="wrap"> <canvas id="canvas"></canvas> </div> <body> <script> let wrap = document.querySelector('.wrap') let canvas = document.querySelector('#canvas'); let ctx = canvas.getContext('2d'); canvas.width = wrap.clientWidth; const img = new Image(); img.src = 'img/bg1.jpg'; let angle = 3;//旋轉角度 1:90度,2:180度,3:270 img.onload = function(){ let width = this.naturalWidth; let height = this.naturalHeight; if(angle === 0){ canvas.height = canvas.width * height / width; ctx.drawImage(img, 0, 0, canvas.width, canvas.height); }else if(angle === 1 || angle === 3){ canvas.height = canvas.width * width / height; ctx.translate(canvas.width * 0.5, canvas.height * 0.5); angle === 1 ? ctx.rotate(0.5 * Math.PI) : ctx.rotate(1.5 * Math.PI); ctx.drawImage(img, - canvas.height / 2, - canvas.width / 2, canvas.height, canvas.width); }else{ canvas.height = canvas.width * height / width; ctx.translate(canvas.width * 0.5, canvas.height * 0.5); ctx.rotate(1 * Math.PI); ctx.drawImage(img, - canvas.width / 2, - canvas.height / 2, canvas.width, canvas.height); } } </script> </body> </html>