中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用Vue制作一個像素繪板

發布時間:2022-11-04 09:12:29 來源:億速云 閱讀:164 作者:iii 欄目:開發技術

本篇內容介紹了“如何用Vue制作一個像素繪板”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

技術棧

  • [vue + vuex + vue-router] 頁面渲染 + 數據共享 + 路由跳轉

  • [axios] 以 Promise 的方式使用 HTTP 請求

  • [stylus] CSS 預處理

  • [element-ui] UI 庫

  • [Webpack] 打包上面這些東西

  • [koa 2 & koa-generator] NodeJS 框架和框架腳手架

  • [mongodb & mongoose] 數據庫和操作數據庫的庫

  • [node-canvas] 服務端數據副本記錄

  • [Socket.io] 實時推送

  • [pm2] Node 服務部署

  • [nginx] 部署靜態資源訪問服務(HTTPS),代理請求

  • [letsencrypt] 生成免費的 HTTPS 證書

Webpack 之所以也被列出來,是因為本項目作為項目 luwuer.com 的一個模塊,需要 webpack 來實現獨立打包

node-canvas

安裝

node-canvas 是我目前遇到過最難安裝的依賴,以至于我根本不想在 Windows 下安裝他,它的功能依賴很多系統下默認不存在的包,在 Github 上也能看到很多 issue 的標簽是 installation help。以 CentOS 7 純凈版為例,在安裝它之前你需要安裝以下這些依賴,值得注意的是 npm 文檔上提供的命令沒有 cairo 。

# centos 前置條件
sudo yum install gcc-c++ cairo cairo-devel pango-devel libjpeg-turbo-devel giflib-devel
# 安裝本體
yarn add canvas -D

還有一個不明所以的坑,如果前置條件準備就緒后,安裝本體仍然一直卡取包這一步(不報錯),此時需要單獨更新一下 npm

使用示例

參考文檔很容易就能掌握基本用法,下方例子中先取到像素點數據生成 ImageData ,然后通過 putImageData 把歷史數據畫到 canvas 。

const {
 createCanvas,
 createImageData
} = require('canvas')

const canvas = createCanvas(canvasWidth, canvasHeight)
const ctx = canvas.getContext('2d')

// 初始化
const init = callback => {
 Dot.queryDots().then(data => {
  let imgData = new createImageData(
   Uint8ClampedArray.from(data),
   canvasWidth,
   canvasHeight
  )

  // 移除 Smooth
  ctx.mozImageSmoothingEnabled = false
  ctx.webkitImageSmoothingEnabled = false
  ctx.msImageSmoothingEnabled = false
  ctx.imageSmoothingEnabled = false
  ctx.putImageData(imgData, 0, 0, 0, 0, canvasWidth, canvasHeight)

  successLog('canvas render complete !')

  callback()
 })
}

Socket.io

本項目在設計上有兩個必須用到推送的地方,一是其他用戶的建點信息,二是所有用戶發送的聊天消息。

client

// socket.io init
// transports: [ 'websocket' ]
window.socket = io.connect(window.location.origin.replace(/https/, 'wss'))

// 接收圖片
window.socket.on('dataUrl', data => {
 this.imageObject.src = data.url
 this.loadInfo.push('渲染圖像...')

 this.init()
})

// 接收其他用戶建點
window.socket.on('newDot', data => {
 this.saveDot(
  {
   x: data.index % this.width,
   y: Math.floor(data.index / this.width),
   color: data.color
  },
  false
 )
})

// 接收所有人的最新推送消息
window.socket.on('newChat', data => {
 if (this.msgs.length === 50) {
  this.msgs.shift()
 }

 this.msgs.push(data)
})

server /bin/www

let http = require('http');
let io = require('socket.io')
let server = http.createServer(app.callback())
let ws = io.listen(server)
server.listen(port)

ws.on('connection', socket => {
 // 建立連接的 client 加入房間 chatroom ,為了下方可以廣播
 socket.join('chatroom')

 socket.emit('dataUrl', {
  url: cv.getDataUrl()
 })

 socket.on('saveDot', async data => {
  // 推送給其他用戶,即廣播
  socket.broadcast.to('chatroom').emit('newDot', data)
  saveDotHandle(data)
 })

 socket.on('newChat', async data => {
  // 推送給所有用戶
  ws.sockets.emit('newChat', data)
  newChatHandle(data)
 })
})

letsencrypt

申請證書

# 獲得程序
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
# 自動生成證書(環境安裝完畢后會有兩次確認),證書目錄 /etc/letsencrypt/live/{輸入的第一個域名} 我這里是 /etc/letsencrypt/live/www.luwuer.com/
./letsencrypt-auto certonly --standalone --email html6@foxmail.com -d www.luwuer.com -d luwuer.com

自動續期

# 進入定時任務編輯
crontab -e
# 提交申請,我這里設置每兩月一次,過期時間為三月
* * * */2 * cd /root/certificate/letsencrypt && ./letsencrypt-auto certonly --renew

nginx

yum install -y nginx

/etc/nginx/config.d/https.conf

server {
 # 使用 HTTP/2,需要 Nginx1.9.7 以上版本
 listen 443 ssl http2 default_server;

 # 開啟HSTS,并設置有效期為“6307200秒”(6個月),包括子域名(根據情況可刪掉),預加載到瀏覽器緩存(根據情況可刪掉)
 add_header Strict-Transport-Security "max-age=6307200; preload";
 # add_header Strict-Transport-Security "max-age=6307200; includeSubdomains; preload";
 # 禁止被嵌入框架
 add_header X-Frame-Options DENY;
 # 防止在IE9、Chrome和Safari中的MIME類型混淆攻擊
 add_header X-Content-Type-Options nosniff;
 # ssl 證書
 ssl_certificate /etc/letsencrypt/live/www.luwuer.com/fullchain.pem;
 ssl_certificate_key /etc/letsencrypt/live/www.luwuer.com/privkey.pem;
 # OCSP Stapling 證書
 ssl_trusted_certificate /etc/letsencrypt/live/www.luwuer.com/chain.pem;
 # OCSP Stapling 開啟,OCSP是用于在線查詢證書吊銷情況的服務,使用OCSP Stapling能將證書有效狀態的信息緩存到服務器,提高TLS握手速度
 ssl_stapling_verify on;
 #OCSP Stapling 驗證開啟
 ssl_stapling on; 
 #用于查詢OCSP服務器的DNS 
 resolver 8.8.8.8 8.8.4.4 valid=300s;
 # DH-Key交換密鑰文件位置
 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
 # 指定協議 TLS
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
 # 加密套件,這里用了CloudFlare's Internet facing SSL cipher configuration
 ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
 # 由服務器協商最佳的加密算法
 ssl_prefer_server_ciphers on;

 server_name ~^(\w+\.)?(luwuer\.com)$; # $1 = 'blog.' || 'img.' || '' || 'www.' ; $2 = 'luwuer.com'
 set $pre $1;
 if ($pre = 'www.') {
  set $pre '';
 }
 set $next $2;
 
 root /root/apps/$pre$next;

 location / {
  try_files $uri $uri/ /index.html;
  index index.html;
 }

 location ^~ /api/ {
  proxy_pass http://43.226.147.135:3000/;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 }
 
 # socket代理配置
 location /socket.io/ {
  proxy_pass http://43.226.147.135:3000;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
 }

 # location /weibo/ {
 #   proxy_pass https://api.weibo.com/;
 # }

 include /etc/nginx/utils/cache.conf;
}

server {
 listen 80;
 server_name www.luwuer.com;
 rewrite ^(.*)$ https://$server_name$request_uri;
}

附錄

數據庫存儲結構思考歷程

首先需求是畫板可以作畫實際大小為 { width: 1024px, height: 512px } ,這就意味著有 1024 * 512 = 524,288 個像素點,或則有 524,288 * 4 = 2,097,152 個表示顏色的數字,這些數據量在不做壓縮的情況下,最小存儲方式是后者剔除掉 rgba 中的 a ,也就是一個長度為 524,288 * 3 = 1,572,864 的數組,如果賦值給變量占用內存大概 1.5M (數據來源于 Chrome Memory)。為了存儲以上結構,我首先分了兩種類型的存儲結構:

以點為對象存儲,也就是說會有 524,288 條數據

  1. 顏色 rbga 存儲,后優化為 rgb 存儲

  2. 顏色 16 進制存儲

整個畫布數據當作一條數據存儲

雖然看起來結構2有點蠢,但起初我確實思考過這樣的結構,那時我還不清楚原來取數據最耗時的不是查詢而是 IO 。
后來我分別測試 1.1 和 1.2 這兩種結構,然后直接否定了結構 2,因為在測試中我發現了 IO 耗時占總耗時超過 98% ,而結構 2 無疑不能因為單條數據取得絕對的性能優勢。

1.1

  • 存儲大小 10M

  • 取出全部數據 8000+ms

  • 全表查詢 150ms (findOne 和 find 對比結果)

  • 其余耗時 20ms (findOne 和 find 對比結果)

1.2

  • 存儲大小 10M

  • 取出全部數據 7500+ms

  • 全表查詢

  • 其余耗時

結構 2 如果取數據不是毫秒級,就是死刑,因為這種結構下單個像素變動就需要存儲整個圖片數據

老實講這個測試結果讓我有些難以接受,問了好幾個認識的后端為什么性能這么差、有沒有解決辦法,但都沒什么結果。更可怕的是,測試是在我 i7 CPU 的臺式電腦上進行的,當我把測試環境放到單核服務器上時,取全表數據的耗時還要乘以 10 。好在只要想一個問題久了,即使有時只是想著這個問題發呆,也總能迸發出一些莫名的靈感。我想到了關鍵之一數據可以只在服務啟動時取出放到內存中,像素發生改變時數據庫和內存數據副本同步修改,于是得以繼續開發下去。最終我選擇了 1.1 的結構,選擇原因和下文的“數據傳輸”有關。

const mongoose = require('mongoose')

let schema = new mongoose.Schema({
 index: {
  type: Number,
  index: true
 },
 r: Number,
 g: Number,
 b: Number
}, {
 collection: 'dots'
})

index 代替 x & y 以及移除 rgba 中的 a 在代碼中再補上,都能顯著降低 collection 的實際存儲大小

在測試過程中其實還有個特別奇怪的問題,就是單核小霸王服務器上,我如果一次性取出所有數據存儲到一個 Array 中,程序會在中途奔潰,沒有任何報錯信息。起初我以為是 CPU 滿荷載久了導致的奔潰(top 查看硬件使用信息),所以還特意新租了一個服務器,想用一個群里的朋友提醒的“分布式”。再后面一段時間,我通過分頁取數據,發現程序總是在取第二十萬零幾百條(一個固定數字)是陡然奔潰,所以為 CPU 證了清白。

Vue的優點

Vue具體輕量級框架、簡單易學、雙向數據綁定、組件化、數據和結構的分離、虛擬DOM、運行速度快等優勢,Vue中頁面使用的是局部刷新,不用每次跳轉頁面都要請求所有數據和dom,可以大大提升訪問速度和用戶體驗。

“如何用Vue制作一個像素繪板”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

vue
AI

尼木县| 宣化县| 芜湖市| 沅陵县| 阿拉善盟| 红河县| 深泽县| 延寿县| 德格县| 崇仁县| 碌曲县| 宜兴市| 潞城市| 荃湾区| 香港| 临湘市| 根河市| 华池县| 敖汉旗| 西平县| 乐都县| 平陆县| 利川市| 澄江县| 迭部县| 洪雅县| 河池市| 海口市| 黄山市| 长岭县| 新沂市| 宁蒗| 温泉县| 奇台县| 德钦县| 梁河县| 上栗县| 太原市| 谢通门县| 西平县| 福海县|