JavaScript+Canvas創(chuàng)建一個(gè)獨(dú)特的字符畫生成器
在本篇文章中,我將分享如何使用 Canvas 和 JavaScript 創(chuàng)建一個(gè)獨(dú)特的字符畫生成器。通過此生成器,我們可以將圖片轉(zhuǎn)換為由字符構(gòu)成的作品,并通過一些JavaScript屬性讓這些字符動(dòng)起來。結(jié)合現(xiàn)代的 Web 技術(shù),我們?cè)诰W(wǎng)頁上動(dòng)態(tài)地生成字符畫,并且通過添加一些動(dòng)畫效果,使其更富有趣味性。
準(zhǔn)備工作
首先,我們需要一些基礎(chǔ)的 HTML 結(jié)構(gòu)和 JavaScript 代碼,用于加載圖片并創(chuàng)建 Canvas。
<body> <div class="glass"> <img id="myImg" src="./xxx.png" style="display: none;"></img> <div id="canvasDiv"> <canvas id="canvas" width="600" height="600" style="display: none;"></canvas> </div> <div id="textDiv" class="textDiv" style="line-height: 0.9;"></div> </div> <script> // ...(后續(xù)代碼將在下文詳細(xì)介紹) </script> </body>
圖片和canvas都不需要展示,設(shè)置它們?yōu)?code>display: none;
圖片加載與轉(zhuǎn)換
在 window.onload
事件中,我們加載圖片并將其繪制到 Canvas 上。為了保持生成的字符畫不失真,我們需要進(jìn)行一些調(diào)整。
window.onload = () => { canvas = document.getElementById("canvas"); ctx = canvas.getContext("2d"); const img = document.querySelector('#myImg'); changeImg(img); let newimgText = imgText.split('</br>').map((e) => "<div class='amiDiv' style='display:flex'>" + e + "</div>") .join(''); document.getElementById("textDiv").innerHTML = newimgText; };
首先獲取canvas
標(biāo)簽,并且創(chuàng)建一個(gè)2D渲染上下文ctx
,以便后續(xù)使用。接下來,該代碼獲取圖片,并且將其作為參數(shù)傳遞給changeImg
函數(shù),該函數(shù)將會(huì)對(duì)這個(gè)圖片進(jìn)行處理,將其轉(zhuǎn)換為字符畫并將結(jié)果存儲(chǔ)在全局變量imgText
中。然后,定義新的字符串變量newimgText
,將imgText
字符串每一行分隔開,方便一會(huì)兒分別給每一行添加動(dòng)態(tài)效果。
Canvas 操作與字符生成
在 changeImg
函數(shù)中,我們使用 Canvas 獲取圖片像素信息,并逐個(gè)讀取每個(gè)像素的RGB值,計(jì)算出對(duì)應(yīng)的灰度值并映射到字符上。同時(shí),我們也可以調(diào)整字符大小控制顯示圖像的精度。
function changeImg(img) { // 清空字符畫 imgText = ""; // 先記錄比率,如果寬,那么先縮放寬,再用比率算出長(zhǎng),反之同理,這里是保證不超過不超過設(shè)定規(guī)模 let rate = img.width / img.height; if (rate > 1) { img.style.width = IMAGE_SIZE + 'px'; img.style.height = IMAGE_SIZE / rate + 'px'; img.width = IMAGE_SIZE; img.height = IMAGE_SIZE / rate; } else { img.style.height = IMAGE_SIZE + 'px'; img.style.width = IMAGE_SIZE * rate + 'px'; img.height = IMAGE_SIZE; img.width = IMAGE_SIZE * rate; } ctx.clearRect(0, 0, canvas.width, canvas.height) // 將圖片繪制在canvas上 ctx.drawImage(img, 0, 0, img.width, img.height); // 獲取像素信息 let pixelInfo; try { pixelInfo = ctx.getImageData(0, 0, img.width, img.height); } catch { console("圖片有問題!"); } // 數(shù)值越小,精度越高 let size = 2; // 設(shè)置zoom縮放 document.querySelector("#textDiv").style.zoom = size / 6; // 生成主體,逐個(gè)讀取字符 for (let i = 0; i < img.height; i = i + size) { for (let j = 0; j < img.width; j = j + size) { const curPoint = (i * img.width + j) * 4; // ×4是因?yàn)椋?為r,2為g,3為b,4為a,四個(gè)是一組rgba值 const [r, g, b] = pixelInfo.data.slice(curPoint, curPoint + 3); const gray = r * 0.3 + g * 0.6 + b * 0.1; // 計(jì)算灰度值 const color = `rgba(${r},${g},$)`; // 保存像素點(diǎn)rgb值 toText(gray, color) } imgText += "</br>"; } }
拼接字符畫
將字符拼接成一行一行的文本。
function toText(g, color) { if (color) imgText += `<span style='color:${color}'>`; if (g == 255) imgText += " "; else imgText += "@"; if (color) imgText += "</span>"; }
添加動(dòng)態(tài)效果
最后,使用JavaScript的正弦函數(shù)來控制每個(gè)文字元素的位置和偏移量,從而實(shí)現(xiàn)字符畫龍?jiān)陧撁嫔系膭?dòng)態(tài)效果。
const container = document.querySelectorAll(".amiDiv"); // 創(chuàng)建曲線運(yùn)動(dòng) function createCurve(func, range) { container.forEach(e => { const points = getCurvePoints(func, range, e.children.length, e.clientWidth); for (let i = 0; i < points.length; i++) { e.children[i].style.transform = `translateY(${points[i]}px)`; } }); } let offset = 0; createCurve((x) => Math.sin(x), [offset, offset + 2 * Math.PI]); setInterval(() => { offset += 0.1; createCurve((x) => Math.sin(x), [offset, offset + 2 * Math.PI]); }, 30); // 輔助函數(shù):獲取曲線上的點(diǎn) function getCurvePoints(curveFunc, range, number, xLength) { if (number < 1) { return []; } if (number === 1) { return [0]; } const piece = (range[1] - range[0]) / (number - 1); const result = []; const scale = xLength / (range[1] - range[0]); for (let i = 0; i < number; i++) { result.push(-curveFunc(i * piece + range[0]) * scale); } return result; }
在這個(gè)龍年,愿我們的代碼如同神龍一般威猛,技術(shù)如同飛龍一般翱翔,最后祝大家新的一年:龍行龘龘,前程?hào)T朤!
到此這篇關(guān)于JavaScript+Canvas創(chuàng)建一個(gè)獨(dú)特的字符畫生成器的文章就介紹到這了,更多相關(guān)JavaScript Canvas字符畫生成器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript仿新浪游戲頻道鼠標(biāo)懸停顯示子菜單效果
這篇文章主要介紹了Javascript仿新浪游戲頻道鼠標(biāo)懸停顯示子菜單效果,涉及鼠標(biāo)事件及頁面元素結(jié)點(diǎn)的遍歷技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08JS中實(shí)現(xiàn)一個(gè)下載進(jìn)度條及播放進(jìn)度條的代碼
這篇文章主要介紹了JS中實(shí)現(xiàn)一個(gè)下載進(jìn)度條及播放進(jìn)度條的代碼,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06JS+DIV+CSS實(shí)現(xiàn)的經(jīng)典標(biāo)簽切換效果代碼
這篇文章主要介紹了JS+DIV+CSS實(shí)現(xiàn)的經(jīng)典標(biāo)簽切換效果代碼,涉及JavaScript基于鼠標(biāo)事件針對(duì)頁面元素動(dòng)態(tài)變換的實(shí)現(xiàn)技巧,頁面美觀實(shí)用,需要的朋友可以參考下2015-09-09微信小程序?qū)崿F(xiàn)動(dòng)態(tài)渲染Markdown示例詳解
這篇文章主要為大家介紹了微信小程序?qū)崿F(xiàn)動(dòng)態(tài)渲染Markdown示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08js實(shí)現(xiàn)簡(jiǎn)單點(diǎn)贊操作
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)簡(jiǎn)單點(diǎn)贊操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03JavaScript setTimeout使用閉包功能實(shí)現(xiàn)定時(shí)打印數(shù)值
這篇文章主要介紹了JavaScript setTimeout使用閉包功能實(shí)現(xiàn)定時(shí)打印數(shù)值 的相關(guān)資料,需要的朋友可以參考下2015-12-12ie支持function.bind()方法實(shí)現(xiàn)代碼
在 google 一番技術(shù)資料后,發(fā)現(xiàn) firefox 原生支持一個(gè) bind 方法,該方法很好的滿足了我們的初衷,調(diào)用方法與 call 和 apply 一樣,只是定義完成后,在后期調(diào)用時(shí)該方法才會(huì)執(zhí)行,需要的朋友可以了解下2012-12-12js一維數(shù)組、多維數(shù)組和對(duì)象的混合使用方法
這篇文章主要介紹了js一維數(shù)組、多維數(shù)組和對(duì)象的混合使用方法,需要的朋友可以參考下2016-04-04