1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      基于canvas如何使用貝塞爾曲線平滑擬合折線段

      小編給大家分享一下基于canvas如何使用貝塞爾曲線平滑擬合折線段,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!

      成都創(chuàng)新互聯(lián)公司服務(wù)項(xiàng)目包括五常網(wǎng)站建設(shè)、五常網(wǎng)站制作、五常網(wǎng)頁制作以及五常網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,五常網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到五常省份的部分城市,未來相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!

      為什么要平滑擬合折線段

      先來看下Echarts下折線圖的渲染效果:

      基于canvas如何使用貝塞爾曲線平滑擬合折線段 

      一開始我沒注意到其實(shí)這個(gè)折線段是曲線穿過去的,只認(rèn)為是單純的描點(diǎn)繪圖,所以起初我實(shí)現(xiàn)的“簡(丑)易(陋)”版本是這樣的:

      基于canvas如何使用貝塞爾曲線平滑擬合折線段

      不要關(guān)注樣式,重點(diǎn)就是實(shí)現(xiàn)之后才發(fā)現(xiàn)看起來人家Echarts的實(shí)現(xiàn)描點(diǎn)非常的圓滑,也由此引發(fā)了之后的探討。怎么有規(guī)律的畫平滑曲線?

      效果圖

      先來看下最終模仿的實(shí)現(xiàn):

      因?yàn)槲乙膊恢繣charts內(nèi)部怎么實(shí)現(xiàn)的(逃

      基于canvas如何使用貝塞爾曲線平滑擬合折線段 

      基于canvas如何使用貝塞爾曲線平滑擬合折線段 

      看起來已經(jīng)非常圓潤了,和我們最初的設(shè)想十分接近了。再看下曲線是否穿過了描點(diǎn):

      基于canvas如何使用貝塞爾曲線平滑擬合折線段 

      好的!結(jié)果很明顯現(xiàn)在來重新看下我們的實(shí)現(xiàn)方式。

      實(shí)現(xiàn)過程

      1. 繪制折線圖

      2. 貝塞爾曲線平滑擬合

      模擬數(shù)據(jù)

      var data = [Math.random() * 300];
              for (var i = 1; i < 50; i++) { //按照echarts
                  data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));
              }
              option = {
                  canvas:{
                      id: 'canvas'
                  },
                  series: {
                      name: '模擬數(shù)據(jù)',
                      itemStyle: {
                          color: 'rgb(255, 70, 131)'
                      },
                      areaStyle: {
                          color: 'rgb(255, 158, 68)'
                      },
                      data: data
                  }
              };

      繪制折線圖

      首先初始化一個(gè)構(gòu)造函數(shù)來放置需要用到的數(shù)據(jù):

      function LinearGradient(option) {
          this.canvas = document.getElementById(option.canvas.id)
          this.ctx = this.canvas.getContext('2d')
          this.width = this.canvas.width
          this.height = this.canvas.height
          this.tooltip = option.tooltip
          this.title = option.text
          this.series = option.series //存放模擬數(shù)據(jù)
      }

      繪制折線圖:

      LinearGradient.prototype.draw1 = function() { //折線參考線
          ... 
          //要考慮到canvas中的原點(diǎn)是左上角,
          //所以下面要做一些換算,
          //diff為x,y軸被數(shù)據(jù)最大值和最小值的取值范圍所平分的等份。
          this.series.data.forEach(function(item, index) {
              var x = diffX * index,
                  y = Math.floor(self.height - diffY * (item - dataMin))
              self.ctx.lineTo(x, y) //繪制各個(gè)數(shù)據(jù)點(diǎn)
          })
          ...
      }

      貝塞爾曲線平滑擬合

      貝塞爾曲線的關(guān)鍵點(diǎn)在于控制點(diǎn)的選擇,這個(gè)網(wǎng)站可以動(dòng)態(tài)的展現(xiàn)控制點(diǎn)不同而繪制的不同的曲線。而對于控制點(diǎn)的計(jì)算。。作者還是選擇了百度一下畢竟數(shù)學(xué)不好:)。具體算法有興趣的同學(xué)可以深入了解下,現(xiàn)在直接說下計(jì)算控制點(diǎn)的結(jié)論。

      基于canvas如何使用貝塞爾曲線平滑擬合折線段

      上面的公式涉及到四個(gè)坐標(biāo)點(diǎn),當(dāng)前點(diǎn),前一個(gè)點(diǎn)以及后兩個(gè)點(diǎn),而當(dāng)坐標(biāo)值為下圖展示的時(shí)候繪制出來的曲線如下所示:

      基于canvas如何使用貝塞爾曲線平滑擬合折線段

      不過會(huì)有一個(gè)問題就是起始點(diǎn)和最后一個(gè)點(diǎn)不能用這個(gè)公式,不過那篇文章也給出了邊界值的處理辦法:

      基于canvas如何使用貝塞爾曲線平滑擬合折線段 

      所以在將折線換成平滑曲線的時(shí)候,將邊界值以及其他控制點(diǎn)計(jì)算好之后代入到貝塞爾函數(shù)中就完成了:

      //核心實(shí)現(xiàn)
      this.series.data.forEach(function(item, index) { //找到前一個(gè)點(diǎn)到下一個(gè)點(diǎn)中間的控制點(diǎn)
          var scale = 0.1 //分別對于ab控制點(diǎn)的一個(gè)正數(shù),可以分別自行調(diào)整
          var last1X = diffX * (index - 1),
              last1Y = Math.floor(self.height - diffY * (self.series.data[index - 1] - dataMin)),
              //前一個(gè)點(diǎn)坐標(biāo)
              last2X = diffX * (index - 2),
              last2Y = Math.floor(self.height - diffY * (self.series.data[index - 2] - dataMin)),
              //前兩個(gè)點(diǎn)坐標(biāo)
              nowX = diffX * (index),
              nowY = Math.floor(self.height - diffY * (self.series.data[index] - dataMin)),
              //當(dāng)期點(diǎn)坐標(biāo)
              nextX = diffX * (index + 1),
              nextY = Math.floor(self.height - diffY * (self.series.data[index + 1] - dataMin)),
              //下一個(gè)點(diǎn)坐標(biāo)
              cAx = last1X + (nowX - last2X) * scale,
              cAy = last1Y + (nowY - last2Y) * scale,
              cBx = nowX - (nextX - last1X) * scale,
              cBy = nowY - (nextY - last1Y) * scale 
          if(index === 0) {
              self.ctx.lineTo(nowX, nowY)
              return
          } else if(index ===1) {
              cAx = last1X + (nowX - 0) * scale
              cAy = last1Y + (nowY - self.height) * scale 
          } else if(index === self.series.data.length - 1) {
              cBx = nowX - (nowX - last1X) * scale
              cBy = nowY - (nowY - last1Y) * scale
          } 
              self.ctx.bezierCurveTo(cAx, cAy, cBx, cBy, nowX, nowY);
              //繪制出上一個(gè)點(diǎn)到當(dāng)前點(diǎn)的貝塞爾曲線
          })

      由于我每次遍歷的點(diǎn)都是當(dāng)前點(diǎn),但是文章中給出的公式是計(jì)算會(huì)知道下一個(gè)點(diǎn)的控制點(diǎn)算法,故在代碼實(shí)現(xiàn)中我將所有點(diǎn)的計(jì)算挪前了一位。當(dāng)index = 0時(shí)也就是初始點(diǎn)是不需要曲線繪制的,因?yàn)槲覀兝L制的是從前一個(gè)點(diǎn)到當(dāng)前點(diǎn)的曲線,沒有到0的曲線需要繪制。從index = 1開始我們就可以正常開始繪制,從0到1的曲線,由于index = 1時(shí)是沒有在他前面第二個(gè)點(diǎn)的故其屬于邊界值點(diǎn),也就是需要特殊進(jìn)行計(jì)算,以及最后一個(gè)點(diǎn)。其余均按照正常公式算出AB的xy坐標(biāo)代入貝塞爾函數(shù)即可。

      看完了這篇文章,相信你對“基于canvas如何使用貝塞爾曲線平滑擬合折線段”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


      分享標(biāo)題:基于canvas如何使用貝塞爾曲線平滑擬合折線段
      分享網(wǎng)址:http://ef60e0e.cn/article/jiiijo.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        台南市| 手游| 乐安县| 彩票| 长沙市| 天全县| 柞水县| 嫩江县| 陕西省| 绥中县| 木兰县| 田林县| 光山县| 株洲市| 同仁县| 壤塘县| 沐川县| 剑川县| 邵武市| 花莲市| 濮阳市| 高淳县| 永安市| 灵台县| 沙河市| 盐边县| 十堰市| 莒南县| 广饶县| 洛浦县| 哈巴河县| 荆门市| 宁晋县| 金山区| 吴江市| 大港区| 色达县| 乐陵市| 汝城县| 吕梁市| 灵寿县|