<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      Wechart 餅圖

      2018-07-31 11:10  【當耐特】  閱讀(3308)  評論(0)    收藏  舉報

      預覽

      Pie

      眾所周知 Cax 既能開發游戲、又能開發圖表。本文將從餅圖開始 Wechart 的圖表之旅。
      Wechart 完全基于 Group 體系構建(自定義 Element) ,易維護,可擴展,任何場景可插拔使用。

      快速開始

      創建餅圖實例:

      const pie = new Pie([
          { name: 'WeChat', value: 10 },
          { name: 'Canvas', value: 15 },
          { name: 'Cax', value: 23 },
          { name: 'Tencent', value: 7 },
          { name: 'Wepay', value: 22 }
      ], {
              processing: (item) => { 
                  return item.value 
              },
              x: 200,
              y: 200,
              r: 160,
              circleColor: 'white',
              textOffsetY: -12,
              font: '20px Arial',
              color: (index) => {
                  return ['#4BC0C0', '#FF6485', '#FFA07A', '#ADACB9', '#A37AC1'][index]
              },
              label: (item) => {
                  return item.name
              },
              tooltip: (item) => {
                  return item.name + '<br/>' + item.value
              }
          }
      )
      

      上面各項配置項很清晰明了,不做解釋,開發者可自行修改參數看餅圖的變化,下面把餅圖添加到舞臺:

      const stage = new cax.Stage(640, 400, 'body')
      stage.add(pie)
      stage.update()
      

      stage 是最大的容器,通過 add 方法往里面加對象,然后 update 舞臺就能顯示。

      顯示和隱藏餅圖:

      pie.show()
      pie.hide()
      

      實現原理

      看到上面的 DEMO 可以會有幾方面技術需要講解:

      • Pie 對象和 Group 的關系
      • Cax 扇形繪制
      • 展開和收縮動畫實現
      • 文字和文字走線顯示在對應扇形的中間
      • 顯示兼容 PC 和 Mobile
      • 交互兼容 PC 和 Mobile
      • 漸變和點擊彈出和移除收縮實現
      • Tooltip 實現

      Pie 對象和 Group 的關系

      先看 cax 內置的 Group 對象, Group 用于分組, group 也可以嵌套 group,父容器的屬性會疊加在子屬性上, 比如:

      • group 的 x 是 100, group 里的 bitmap 的 x 是 200, 最后 bitmap 渲染到 stage 上的 x 是 300
      • group 的 alpha 是 0.7, group 里的 bitmap 的 alpha 是 0.6, 最后 bitmap 渲染到 stage 上的 alpha 是 0.42
      const group = new cax.Group()
      const rect = new cax.Rect(100, 100 {
        fillStyle: 'black'
      })
      group.add(rect)
      stage.add(group)
      stage.update()
      

      Pie 對象正是自定義 Element,繼承自 Group:

      class Pie extends Group {
        constructor (data, option) {
          super()
      

      一般情況下,稍微復雜組合體都建議使用繼承自 Group,這樣利于擴展也方便管理自身內部的元件。
      可以看到小游戲的 DEMO 里的 Player、Bullet、Enemy、Background 全都是繼承自 Group。

      扇形繪制

      Cax 內置 Graphics,可以使用連綴 Canvas API 的方式繪制圖形:

      const sector = new cax.Graphics()
      sector
          .beginPath()
          .moveTo(0, 0)
          .arc(0, 0, 30, 0, Math.PI/2)
          .closePath()
          .fillStyle('green')
          .fill()
          .strokeStyle('red')
          .lineWidth(2)
          .stroke()
      
      stage.add(sector)
      

      這里假設你已經創建好了舞臺。效果如下:

      sector.png

      所以一個餅圖就是把圓分成若干個扇形。怎么分? arc 方法傳入動態數據:

      let current = 0
      
      data.forEach((item, index) => {
          const sector = new cax.Graphics()
          sector
              .beginPath()
              .moveTo(0, 0)
              .arc(0, 0, 30, current, current += Math.PI * 2 * item.value / totalValue)
              .closePath()
              .fillStyle('green')
              .fill()
              .strokeStyle('red')
              .lineWidth(2)
              .stroke()
      })
      

      其中 totalValue 為所有 item.value 的和。可以看到上面是平分一個圓。那么怎么平分一個扇形?能運動平分的角度嗎?

      展開和收縮動畫實現

      看這行代碼:

      .arc(0, 0, 30, current, current += Math.PI * 2 * item.value / totalValue)
      

      把 Math.PI * 2 改成 totalAngle 動態變量就可以!

      let totalAngle = 0
      ...
      ...
      .arc(0, 0, 30, current, current += totalAngle * item.value / totalValue)
      

      運動 totalAngle 并且進行重繪:

       cax.To.get(option)
            .to({ totalAngle: Math.PI * 2 }, option.duration, option.easing)
            .progress((object) => {
              current = option.begin
              sectorGroup.forEach((item, index) => {
                item
                  .clear()
                  .beginPath()
                  .moveTo(0, 0)
                  .arc(0, 0, r, current, current += object.totalAngle * option.processing(item) / totalValue)
                  .closePath()
                  .fillStyle(option.color(index))
                  .fill()
                  .strokeStyle(option.circleColor)
                  .lineWidth(2)
                  .stroke()
                  .closePath()
              })
            })
          ...
          ...
          ...
      

      使用 cax 內置的 to2to 運動能力。這里需要提醒的是,progress 方法會不斷地執行,為了防止 sector 的 graphics path 不斷疊加,在循環執行的代碼里一定要調用 clear 來清除 graphics 的以前的 Canvas 繪制命令。

      文字和文字走線

      文字和走線分四種情況:

      if (angle >= 0 && angle < Math.PI / 2) {
              
      } else if (angle >= Math.PI / 2 && angle < Math.PI) {
          
      } else if (angle >= Math.PI && angle < Math.PI + Math.PI / 2) {
          
      } else 
      
      }
      

      需要注意的是:

      • 落在左邊的文字的 x 坐標需要減去文件的寬度。 Cax 內置的 Text 可以使用 getWidth() 方法獲取到文字的寬度
      • 走線的第一根線角度也分兩種情況,1、3象限平行,2、4象限平行,走線的第二根先角度都是平行于 y 軸(如上圖所示,相同顏色圈中的線是平行的)

      顯示與交互兼容 PC 和 Mobile

      從 javascript 里會發現 canvas 的寬高是 640*400:

      const stage = new cax.Stage(640, 400, 'body')
      

      就和我們平時使用兩倍圖一樣,在移動端通過 media 把 canvas 變成一半寬度:

       @media screen and (max-width: 500px) {  
              canvas {
                  width : 320px
              }
      }
      

      這個時候會出現一個問題!因為 cax 會把 canvas 上的事件過度給 cax 內置對象,事件發生的坐標因為 canvas 寬高的變化而變化了, 移動端點擊事件觸發位置不準確了!這個時候需要 scaleEventPoint 方法來校正坐標:

      if (window.innerWidth <= 500) {
          stage.scaleEventPoint(0.5, 0.5)
      }
      

      搞定!這樣不管是在 PC 鼠標還是移動 Mobile 觸摸都能精準觸發事件。

      漸變和點擊彈出和移除收縮實現

      function fadeIn(obj) {
        obj.alpha = 0
        To.get(obj).to({ alpha: 1 }, 600).start()
      }
      
      function fadeOut(obj) {
        obj.alpha = 1
        To.get(obj).to({ alpha: 0 }, 600).start()
      }
      
      function bounceIn(obj, from, to) {
        from = from || 0
        obj.from = from
        To.get(obj).to({ scaleX: to || 1, scaleY: to || 1 }, 300, cax.easing.bounceOut).start()
      }
      
      function bounceOut(obj, from, to) {
        from = from || 1
        obj.from = from
        To.get(obj).to({ scaleX: to || 0, scaleY: to || 0 }, 300, cax.easing.bounceOut).start()
      }
      

      基于 cax 內置的 to2to 動畫引擎封裝了四個方法。

      Tooltip 實現

      sector.hover(function (evt) {
          bounceIn(sector, 1, 1.1)
          tooltip.style.left = (evt.pureEvent.pageX + 5) + 'px'
          tooltip.style.top = (evt.pureEvent.pageY + 5) + 'px'
          tooltip.innerHTML = option.tooltip(data[index])
          tooltip.style.display = 'block'
      }, function (evt) {
          bounceOut(sector, 1.1, 1)
          tooltip.style.display = 'none'
      }, function (evt) {
          tooltip.style.left = (evt.pureEvent.pageX + 5) + 'px'
          tooltip.style.top = (evt.pureEvent.pageY + 5) + 'px'
      })
      

      Cax 內置對象擁有 hover(over, out, move) 方法來監聽鼠標或者手指 over、out 和 move。

      Tooltip 也是完全基于 DOM 來實現的,這樣可以浮在 Canvas 外面,而不會限制在 Canvas 里面。

      Star && Follower

      誰在使用?

      Tencent Wechat Tencent QQ

      License

      MIT

      主站蜘蛛池模板: 亚洲国产欧美一区二区好看电影| 国产成人一区二区三区视频免费 | 国产精品成人网址在线观看| 亚洲高清乱码午夜电影网| 疏勒县| 免费观看成人毛片a片| 精品国产中文字幕在线| 肉大榛一进一出免费视频| 成人aⅴ综合视频国产| 国产一区二区三中文字幕| 国产亚洲精品久久久久5区| 内射无套内射国产精品视频| 福利一区二区不卡国产| 精品久久精品午夜精品久久| 男女性高爱潮免费网站| 日本免费一区二区三区久久| 丰满少妇呻吟高潮经历| 蜜臀av无码一区二区三区| 欧美丰满熟妇乱XXXXX网站| 亚洲高清 一区二区三区| 亚洲高清WWW色好看美女| 九九热精品免费在线视频| 国产成人无码免费网站| 欧洲亚洲精品免费二区| yw尤物av无码国产在线观看| 国产乱人伦AV在线麻豆A| 在线精品国产中文字幕| 色偷偷亚洲女人天堂观看| 久久精品国产亚洲欧美| 亚洲色大成网站WWW永久麻豆| 亚洲国产精品久久综合网| 无码专区 人妻系列 在线| 一二三三免费观看视频| 亚洲精品综合一区二区三区| 国产女主播喷水视频在线观看 | 久久发布国产伦子伦精品| 综合激情网一区二区三区| 黄又色又污又爽又高潮 | 嗯灬啊灬把腿张开灬动态图| 四虎成人在线观看免费| 久久精品a亚洲国产v高清不卡|