成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

在Vue中使用WebSocket+HighCharts+Canvas實(shí)現(xiàn)高性能的頻譜瀑布圖

張紅新 / 4233人閱讀

摘要:水平值,以像素計(jì),在畫布上放置圖像的位置。規(guī)定要使用的圖像畫布或視頻。要使用的圖像的高度。實(shí)現(xiàn)縮放頻譜圖已經(jīng)做好縮放操作,并把起始點(diǎn)和結(jié)束點(diǎn)傳遞給父組件,再有父組件傳遞給瀑布圖組件,動(dòng)態(tài)修改的剪切屬性。

作者:codexu

_

廢話不多說,先上成品圖:

再來個(gè)迷你動(dòng)圖:

可能很多同學(xué)不知道頻譜圖和瀑布圖,其實(shí)我也不懂...但是咱們前端就是負(fù)責(zé)把數(shù)據(jù)按照規(guī)則顯示出來就好(上方折線圖為頻譜圖,下方那一坨為瀑布圖)。

技術(shù)選型

框架:Vue(這并不重要,反正我也不會多說這塊)

數(shù)據(jù)傳輸:WebSocket

頻譜圖:HighCharts

瀑布圖:Canvas

為什么使用 WebSocket ?

因?yàn)樾枰?wù)器實(shí)時(shí)傳輸數(shù)據(jù),要求達(dá)到30幀,每幀動(dòng)畫由 1024 個(gè)點(diǎn)組成,肯定要比 Ajax 輪詢舒服的多,而且這個(gè)項(xiàng)目對于瀏覽器兼容沒什么要求。

為什么使用 HighCharts 繪制頻譜圖?

做了個(gè)測試,HighCharts 與 ECharts,雖然說 canvas 的性能要比 svg 強(qiáng),但同時(shí)渲染覺得 HighCharts 更加流暢(HighCharts 需要付費(fèi))。

瀑布圖為什么使用 Canvas ?

雖然說用數(shù)據(jù)可視化圖表庫很方便,但是考慮到此項(xiàng)目苛刻的性能要求,使用類似瀑布圖的只有大型熱力圖:

用熱力圖做,請放心,不會卡成 PPT,瀏覽器5秒后準(zhǔn)時(shí)直接崩潰。

組件功能拆分

整個(gè)組件拆分為三部分:

父組件:負(fù)責(zé) WebSocket 與服務(wù)器實(shí)時(shí)通訊、處理二進(jìn)制數(shù)據(jù)、控制渲染頻率、控制開始和暫停、刷新組件。

子組件 > 頻譜圖(HighCharts):提供 addData 方法,獲取數(shù)據(jù)即渲染一幀,提供觸發(fā)縮放事件,發(fā)送給父組件。

子組件 > 瀑布圖(Canvas):與頻譜圖一樣提供 addData 方法,頻譜圖發(fā)生縮放事件后,對應(yīng)其選取的位置進(jìn)行縮放。

父組件 WebSocket 鏈接服務(wù)器

因?yàn)椴僮鞑⒉皇呛芏?,直接使用原生方式?/p>

this.socket = new WebSocket("ws://192.168.2.250:8100/socket")
this.socket.onopen = () => {...}
this.socket.onclose = () => {...}

與后端對接好發(fā)送的指令,這里我們定義了三個(gè):

// 開始獲取數(shù)據(jù)
this.socket.send("start")
// 暫停獲取數(shù)據(jù)
this.socket.send("pause")
// 恢復(fù)獲取數(shù)據(jù)
this.socket.send("resume")

監(jiān)聽 onmessage 事件:

this.socket.onmessage = (event) => {
  const reader = new FileReader()
  reader.readAsArrayBuffer(event.data)
  reader.onload = e => {
    if (e.target.readyState === FileReader.DONE) {
      // 處理二進(jìn)制數(shù)據(jù)
    }
  }
}
處理二進(jìn)制數(shù)據(jù)

這塊本來想用大篇幅來寫,但是前幾天看到《為什么視頻網(wǎng)站的視頻鏈接地址是blob?》,寫的很好,自愧不如,請大家轉(zhuǎn)移看懂這塊,別忘了再回來。

控制渲染頻率

服務(wù)器這邊大概一秒鐘發(fā)送過來 400 條左右的數(shù)據(jù),每秒400幀肯定是不現(xiàn)實(shí)了,直接導(dǎo)致丟幀。

解決辦法:建立數(shù)組保存數(shù)據(jù),每次渲染一幀則刪掉此條數(shù)據(jù),當(dāng)少于100條時(shí)發(fā)送 resume 繼續(xù)獲取,當(dāng)超過400條時(shí) 發(fā)送 pause 暫停獲取。

以服務(wù)器這邊的發(fā)送頻率來說,會使 cpu 使用率超過100%,獲取時(shí)會出現(xiàn)一點(diǎn)點(diǎn)卡頓,不過還能接受,畢竟獲取一次可以渲染好幾秒鐘。

this.renderInterval = setInterval(() => {
  if (this.data.length <= 100 && this.socketPause === true) {
    this.socket.send("resume")
    this.socketPause = false
  }
  if (this.data.length >= 400 && this.socketPause === false) {
    this.socket.send("pause")
    this.socketPause = true
  }
  if (this.data.length <= 0) return
  const result = this.data[0]
  this.$refs.frequency.addData(result.data)
  this.$refs.waterFall.addData(result.data.map(item => item[1]))
  this.data.shift()
}, this.refreshInterval)

使用 setInterval 定時(shí)渲染還有個(gè)好處就是可以控制渲染頻率,注意組件右上角的拖動(dòng)條,這樣可以在低配電腦上降低渲染頻率。

頻譜圖

HighCharts 與 ECharts 配置項(xiàng)上有些差異,不過都是配置的問題,看看文檔,很簡單,記得關(guān)閉所有動(dòng)畫。

addData()
this.chart.series[0].setData(data, true, false)

父組件可以通過 $ref.addData() 觸發(fā)渲染一幀

縮放

在配置中 chart.zoomType 設(shè)置為 "x",設(shè)置為 X 軸選擇縮放。

chart.events.selection 配置選擇事件:

selection (event) {
  const pointWidth = (this.xAxisMax - this.xAxisMin) / 1024
  const ponitStart = Math.floor((event.xAxis[0].min - this.xAxisMin) / pointWidth)
  const ponitEnd = Math.floor((event.xAxis[0].max - this.xAxisMin) / pointWidth)
  this.$emit("frequencySelect", [ponitStart, ponitEnd])
},

向父組件發(fā)送已選取的點(diǎn),再通過父組件傳遞給瀑布圖組件。

瀑布圖

這里因?yàn)樾阅茉蛎撾x了某些庫,很多小伙伴到這里就不知該如何去做了,這里是本篇文章的重點(diǎn)。

先了解幾個(gè)概念,很多人接觸過 Canvas,但是這幾個(gè)估計(jì)沒怎么注意過(像素操作):

createImageData()

putImageData()

drawImage() 這個(gè)應(yīng)該都知道

先創(chuàng)建兩個(gè)畫布,一個(gè)用于顯示整體效果(this.canvas),另一個(gè)保存已生成的圖像(this.waterFallDom,不會插入在 dom 上)。

this.canvas = document.createElement("canvas")
this.ctx = this.canvas.getContext("2d")
this.waterFallDom = document.createElement("canvas")
this.waterFallCtx = this.waterFallDom.getContext("2d")
createImageData

createImageData(width,height) 方法創(chuàng)建新的空白 ImageData 對象,兩個(gè)參數(shù),設(shè)置圖像寬高,這里項(xiàng)目需求一共 1024 個(gè)點(diǎn):

const imageData = this.waterFallCtx.createImageData(data.length, 1)

這時(shí)生成了一張 1024 * 1 的空白圖像,我們繼續(xù)要對每一個(gè)像素點(diǎn)進(jìn)行操作上色:

for (let i = 0; i < imageData.data.length; i += 4) {
  const cindex = this.squeeze(data[i / 4], 0, 150)
  const color = this.colormap[cindex]
  imageData.data[i + 0] = color[0]
  imageData.data[i + 1] = color[1]
  imageData.data[i + 2] = color[2]
  imageData.data[i + 3] = 255
}
return imageData

imageData.data 是一個(gè)數(shù)組,每四個(gè)值繪制一個(gè)像素點(diǎn),分別對應(yīng):

R - 紅色 (0-255)

G - 綠色 (0-255)

B - 藍(lán)色 (0-255)

A - alpha 通道 (0-255; 0 是透明的,255 是完全可見的)

this.squeeze是根據(jù)數(shù)據(jù)計(jì)算出 colormap 中對應(yīng)的點(diǎn),這個(gè)不多說:

squeeze (data, outMin, outMax) {
  if (data <= this.minDb) {
    return outMin
  } else if (data >= this.maxDb) {
    return outMax
  } else {
    return Math.round((data - this.minDb) / (this.maxDb - this.minDb) * outMax)
  }
}

colormap 是一個(gè)二維數(shù)組,每個(gè)值代表[r, g, b, a],這里我生成了150個(gè)顏色,是個(gè)漸變色,可以看下圖例。

如何生成 colormap ?

如果你打算手寫也沒什么問題,就是手疼點(diǎn)。這里推薦使用 npm 安裝 colormap

this.colormap = colormap({
  colormap: "jet",
  nshades: 150,
  format: "rba",
  alpha: 1
})

提供了多種配色,具體請參考文檔。

到此,我們就生成了一張 具有顏色 1024 * 1 的圖像,當(dāng)然它還是個(gè)圖像對象。

putImageData

putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight) 將圖像數(shù)據(jù)繪制到畫布上:

imgData: 規(guī)定要放回畫布的 ImageData 對象。

x: ImageData 對象左上角的 x 坐標(biāo),以像素計(jì)。

y: ImageData 對象左上角的 y 坐標(biāo),以像素計(jì)。

dirtyX: 可選。水平值(x),以像素計(jì),在畫布上放置圖像的位置。

dirtyY: 可選。水平值(y),以像素計(jì),在畫布上放置圖像的位置。

dirtyWidth: 可選。在畫布上繪制圖像所使用的寬度。

dirtyHeight: 可選。在畫布上繪制圖像所使用的高度。

this.waterFallCtx.putImageData(imageData, 0, 0)
drawImage

這個(gè)大家比較熟悉,就是把圖像繪制在畫布中,這時(shí)我們就可以把 this.waterFallCtx 繪制到 this.ctx 上了。

drawImage(img,sx,sy,swidth,sheight,x,y,width,height);

img: 規(guī)定要使用的圖像、畫布或視頻。

sx: 可選。開始剪切的 x 坐標(biāo)位置。

sy: 可選。開始剪切的 y 坐標(biāo)位置。

swidth: 可選。被剪切圖像的寬度。

sheight: 可選。被剪切圖像的高度。

x: 在畫布上放置圖像的 x 坐標(biāo)位置。

y: 在畫布上放置圖像的 y 坐標(biāo)位置。

width: 可選。要使用的圖像的寬度。(伸展或縮小圖像)

height: 可選。要使用的圖像的高度。(伸展或縮小圖像)

this.ctx.drawImage(this.waterFallCtx.canvas,0, 0, 1024, 1, 0, 0, width, height)

這里 sx、sy 可以配合頻譜圖做縮放的操作。

width、height 可以被伸縮或縮小,顯示效果比較不錯(cuò),比如只有兩個(gè)像素點(diǎn)的圖像,被拉伸到 1000 個(gè)像素時(shí)并不是兩個(gè)顏色一人一半,而是一條完美的漸變。

現(xiàn)實(shí)動(dòng)態(tài)的瀑布圖

上述我們已經(jīng)把第一行圖像繪制到畫布中,此時(shí)我們可能通過 WebSockt 已經(jīng)拿到了幾百條數(shù)據(jù),每新增一行圖像,前一行圖像就要下一一行:

// 將已生成的圖像向下移動(dòng)一個(gè)像素
this.waterFallCtx.drawImage(this.waterFallCtx.canvas,
  0, 0, 1024, 300 - 1,
  0, 1, 1024, 300 - 1)

300 是指一共保存 300 行圖像,這些數(shù)據(jù)都不應(yīng)該是固定的,應(yīng)該提前設(shè)置好,這里為了方便演示。

通過調(diào)用自身的圖像,并重新繪制到自己向下偏移 y 軸 1 像素,高度 -1 的圖像。

這樣我們每添加一條數(shù)據(jù),就會多一行新圖像在最上方,已生成的圖像向下移動(dòng)了一個(gè)像素,自此我們的圖像就動(dòng)起來了。

實(shí)現(xiàn)縮放

頻譜圖已經(jīng)做好縮放操作,并把起始點(diǎn)和結(jié)束點(diǎn)傳遞給父組件,再有父組件傳遞給瀑布圖組件,動(dòng)態(tài)修改 drawImage 的剪切屬性。

結(jié)語

既然是使用 Vue 做的這個(gè)項(xiàng)目,我打算抽空做成 Vue 插件,做更多的可配置項(xiàng)。

我曾一度覺得這是個(gè)不能能完成的項(xiàng)目,是自己太年輕了,公司的大佬提點(diǎn)了幾句,就做出來了,在這里分享給大家,不論多難的項(xiàng)目總會有解決的辦法。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/106914.html

相關(guān)文章

  • 前方來報(bào),八月最新資訊--關(guān)于vue2&3最佳文章推薦

    摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個(gè)鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運(yùn),我不曉得。我只曉得,不認(rèn)命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...

    izhuhaodev 評論0 收藏0
  • echarts 與 highcharts

    摘要:渲染能力采用渲染除了對使用,一般來說,更適合繪制圖形元素?cái)?shù)量非常大這一般是由數(shù)據(jù)量大導(dǎo)致的圖表如熱力圖地理坐標(biāo)系或平行坐標(biāo)系上的大規(guī)模線圖或散點(diǎn)圖等,也利于實(shí)現(xiàn)某些視覺特效如交通圖。 一.簡介 echartsecharts是百度公司前端開發(fā)的一個(gè)圖表庫,2013年發(fā)布第一版,主要采用canvas畫圖,目前版本3.8.4;完全免費(fèi); highcharthighcharts是國外的一家公司...

    王笑朝 評論0 收藏0
  • 14個(gè)最好 JavaScript 數(shù)據(jù)可視化庫

    摘要:適用于,演示這是開發(fā)的一個(gè)簡單的可視化庫,它允許你創(chuàng)建所有常用的圖表類型條形圖,樹形圖,折線圖,面積圖等。可以輕松地對折線圖和條形圖進(jìn)行混合和匹配以組合不同的數(shù)據(jù)集,這是非常棒的功能。 翻譯:瘋狂的技術(shù)宅原文:https://www.monterail.com/blo... 本文首發(fā)微信公眾號:jingchengyideng歡迎關(guān)注,每天都給你推送新鮮的前端技術(shù)文章 你的程序有多...

    Mertens 評論0 收藏0
  • 利用AudioContext來實(shí)現(xiàn)網(wǎng)易云音樂鯨魚音效

    摘要:一直覺得網(wǎng)易云音樂的用戶體驗(yàn)是很不錯(cuò)的,很早就注意到了里面的鯨魚音效,如下圖,就是一個(gè)環(huán)形的跟著音樂節(jié)拍跳動(dòng)的特效。 一直覺得網(wǎng)易云音樂的用戶體驗(yàn)是很不錯(cuò)的,很早就注意到了里面的鯨魚音效,如下圖,就是一個(gè)環(huán)形的跟著音樂節(jié)拍跳動(dòng)的特效。 showImg(https://segmentfault.com/img/remote/1460000017090441); gif動(dòng)圖可能效果不太理想...

    cod7ce 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<