Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 一区二区三区在线免费观看视频 ,精品久久网站,国产在线91

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          用Canvas來處理好一個餅圖

          擊上方藍字關注“小鄭搞碼事”,每天都能學到知識,搞懂一個問題!

          Canvas是HTML5提供的新標簽,通過JavaScript可以在Canvas元素上繪制圖片并實現動畫效果,今天展示一下Canvas繪制一個簡單餅圖的基本過程。

          看一下最終的效果:

          實現上面圖中的餅圖效果,首先在HTML引入Canvas標簽,代碼如下:

          然后說一下具體的繪制過程:

          1、在JavaScript文件,創建PieChart類,并在其構造函數中獲取Canvas的Context環境。

          2、添加PieChart類原型方法load用于載入餅圖所使用的數據,并計算餅圖的數據總量,用于之后渲染餅圖時分配每個數據所對應的扇形比例。

          3、添加PieChart類原型方法render用于對餅圖進行渲染,_generateLegend內部函數用于創建餅圖對應的圖例,當存在legend參數調用_generateLegend生成餅圖圖例。

          4、最后,引入需要繪制的數據創建餅圖對象即可完成餅圖繪制。

          JavaScript代碼如下:

          總結一下:

          在目前來看在移動端利用2d放射變換來實現的動畫比較實惠的還是canvas 2d了。在大部分機型上canvas都能獲得更好的渲染性能(在硬件加速情況下,瀏覽器會將繪圖命令切換成gpu硬件來執行),并且現在的硬件加速支持程度也比較好。所以如果需要運動的物體多的話建議用canvas。

          注:需要源代碼運行的可以私信喲!!

          25年過去了,Brooks博士著名的“沒有銀彈”的論斷依舊沒有被打破。HTML5也是一樣。但這并不妨礙HTML5是一個越來越有威力的“炸蛋”:發展迅速、勢不可擋。隨著HTML5技術的普及,用HTML5做可視化呈現的項目越來越多了。HTML5的優勢明顯:網頁上直接運行無需插件、手機平板方便兼容、代碼開發和維護相對容易,等等。一大波一大波的做Java、.NET甚至C++桌面的程序老手們都紛紛開始研究javascript了,而初出茅廬的新一代程序猿更是義無反顧的直奔HTML5這個技術大熱點而來。

          HTML5涵蓋的技術點很多,甚至延伸到了前端、后端、通訊等各個層面。前端的canvas繪圖這塊無疑是它的核心內容。Canvas的API雖然不是很復雜很強大,但是做一般的2d繪圖基本都夠用了。基于這些API,一大堆的2d繪圖組件紛紛出爐。Echarts、d3.js都是很不錯的項目。 Echarts主要是chart組件,而d3相對雜一些,很多呈現方式很有創意,值得研究。

          概述

          研究d3的起因是最近有一個項目,用戶截了一張效果圖讓我們用HTML5做一下:

          看著很眼熟,搜了一下,感覺就是d3例子中的sunburst效果,程序在這里:

          http://bl.ocks.org/mbostock/4063423

          看上去似乎也不難,就是一圈一圈的餅圖,把樹狀結構數據按占比一層一層繪制上去就行了。所以引起了自己動手做一個的興趣。“sunburst”英文里應該是“云開日出”的意思,類似強烈的光芒從云層背后透射出來,不知為何中文里大多把它翻譯成“日落”。比如這把Fender Telecaster吉他型號是Brown Sunburst款,就會被大家翻譯成“日落色”。

          關于日出和日落更喜歡哪一個的問題,網上還真有這樣的調查。有意思的是,選擇喜歡日落的遠多于選擇日出的。日出代表希望,日落代表成熟,都是一種美,哪個更美要看你個人的心境,因為它的美麗是由心生。為了不在這個問題上站錯對,我們還是給他重新起一個更加響亮霸氣的中文名字:“彩虹爆炸圖”,怎么樣?

          仔細研究一下彩虹爆炸圖的結構,無非就是一個樹形結構,并采用發射狀的布局。根節點在中間(也可以認為沒有唯一的根,而是一堆根節點圍繞在第一圈),一次向外發散排列。每一個節點有名稱、數值。節點可以按照自身數值在扇區所占比例進行繪制,這樣就不用管節點具體數值有多大多小了。

          這種圖最先是由布朗大學教授John T. Stasko設計。

          http://www.cc.gatech.edu/~john.stasko/

          經過一天的折騰,終于做出了一個還算過得去的“彩虹爆炸圖”。先上個圖看看:

          主要功能包括了:

          可以通過json來定義數據和樣式(類似百度的echarts那樣);

          顏色可以固定,也可以自動彩虹色;

          自動計算數值及角度占比;

          動態顯示導航路徑;

          鼠標動態高亮顯示路徑;

          動畫飛入、展開導航路徑;

          文字顯示及角度控制;

          全矢量,可鼠標縮放、平移,不失真;

          下面重點碼一下折騰過程中的幾個重點:

          一、定義節點對象

          首先定義每一個小扇片節點。每個扇片可以用一段餅圖來繪制。為了簡單方便,這里用了最簡單高效偷懶的方法:用一個半徑很粗的線畫一段角度的arc,即可。如下圖:

          另外還有文字等內容。所以定義它的json結構大概如下:

          var item = {name: '名稱', color: 'red', angle: '45', …};

          此外,下一圈的數據,可直接定義為這個節點的“孩子節點”,直接在item中定義一個data的子節點數據:

          var item = {name: '名稱', color: 'red', angle: '45', data:[

          {name:’孩子一’, color:’green’,…},

          {name:’孩子二’, color:’yellow’,…},

          ]};

          這樣就可以組成一個樹狀結構。接下來要在canvas上繪制圖形了。為了方便,這里直接使用了矢量圖進行定義:

          twaver.Util.registerImage('node', {

          v: [{

          shape: 'circle',

          r: ...

          lineColor: function(data,view){return data.getClient("lineColor");},

          lineWidth: ...

          startAngle: ...

          endAngle: ...

          },{

          shape: 'text',

          textBaseline: 'middle',

          textAlign: ...

          text: ...

          x: ...

          y: ...

          font: ...

          fill: ...

          rotate: ...

          visible: ...

          shadow: ...

          }],

          });

          矢量圖中定義了2個圖形元素:一個arc弧線、一個文字對象,分別用于畫node和繪制其文字。顏色、字體、是否可見、陰影、對齊、位置、線寬、角度…等等均在上面的定義中用一個function動態獲取。例如,這個節點的半徑,通過下面的方法,就可以在圖形的lineColor屬性中保存并驅動,需要修改,直接修改lineColor這個client屬性即可,而不用去修改繪圖參數,非常方便:

          r:function(data,view){return data.getClient("lineColor");}

          這里有一個比較啰嗦的地方是:每個扇片的角度需要根據每個item定義的原始值進行計算角度占比。而且,對于太小的扇片,可以給一定的最小值(例如 1度),保證能視覺上看到它。否則,顯示10000和1兩個數值,由于對比過大,可能就杯具了,因為1連1度都占不到,顯示效果會非常差。還有,每個扇片之間應該盡量留有一定的空隙。如果連續繪制,就會連成一片,沒有“分片”感。這些可以在代碼中進行簡單控制。

          二、文字控制

          文字控制也比較啰嗦。首先是對齊方式。最簡單的方式當然是讓文字在所在扇片處,直接居中、旋轉。這樣文字會在徑向的中間位置,如下圖:

          但這樣顯示感覺并不是很完美。對于中文來說,如果能統一靠近圓心方向的位置對齊,會更好看一些。這樣,即使文字過長,也會向外延伸,不會和里面的重疊。如下圖:

          還有,當文字在左半圓時,如果不做特殊處理,文字旋轉會導致文字大頭朝下,閱讀起來有把脖子歪斷的風險。所以應該動態判斷,如果文字在左側,應該文字再增加旋轉180度。同時左側的文字對齊也要特殊考慮,應該變成右對齊,才能保持徑向的整齊一致。

          文字還有一個細節就是顏色和陰影的問題。不使用陰影,單純的使用顏色(例如白色),則在一些方向上的節點的文字會看不清楚,因為我們做的是彩虹爆炸圖,各個方向顏色都不一樣,而且還會隨著圈數增加而變淡顏色,所以幾乎不可能用一個固定的顏色(例如白色或黑色)能保證文字在所有地方都能和node顏色搭配并看清楚。所以思來想去還是使用了陰影效果。

          聯想了一下我們看美劇時候的字幕,似乎也是同樣的問題。視頻字幕要顯示在千變萬化的視頻場景里面,視頻場景的顏色完全隨機出現無從知曉,要想讓字幕看清楚,必然也會想一些辦法解決。我們仔細觀察一下視頻字幕:

          仔細觀察,字幕是白色文字加了一圈黑色外框,這樣就不怕任何場景了。我們在文字定義時也模擬一下,設置陰影和陰影偏移試一試:

          fill:'white',

          shadow: {

          offsetX: 2,

          offsetY: 2,

          blur: 4,

          color: 'black',

          },

          看一下使用前和使用后的效果對比:

          使用陰影后不但文字更清晰了,而且也增加了立體感,效果還是不錯的。下面圖顯示在應用在節點上的效果:

          可見不論什么顏色,都能比較好的勾勒出文字輪廓,保持清晰可讀。

          三、生成彩虹顏色

          關于顏色,是一個有趣的話題。對于廣大程序猿來說,顏色是一個既簡單又困難的東西。我們隨手就能寫下’red’, ‘green’, ‘orange’, ‘yellow’這樣的色彩斑斕的顏色,還能保證沒有語法錯誤;我們還會寫’#FF55AA’、’#0c0’、’RGB(0,204,0)’、’ RGB(0%,80%,0%)’這樣的各種顏色寫法;我們也明白RGBA的含義和用途。但是,我們很少能把一個demo寫的顏色很好看、很搭配。關于顏色和配色以后再專門討論。這里我們只想自動生成一圈彩虹一樣的顏色。用我們熟悉的RGB方法好像比較困難了。于是想起了那個HSV的顏色定義方法,它貌似很適合解決這個問題。

          HSV顏色模型定義了色調H、飽和度S和亮度V,由A. R. Smith在1978年創建的一種顏色空間。其中H用一圈360度表示所有顏色,從紅色開始按逆時針方向計算,紅色為0度。飽和度S從0到1,越大越飽和。亮度V從0到255(也可以轉換為從0到1,方便使用),越大越明亮,越小越暗淡。

          Js里面并沒有直接處理HSV顏色的函數。不過用下面的代碼很方便可以從hsv轉為rgb:

          寫一個對應的js函數也很簡單:

          /* h, s, v (0 ~ 1) */

          function getHSVColor(h, s, v) {

          var r, g, b, i, f, p, q, t;

          if (h && s === undefined && v === undefined) {

          s = h.s, v = h.v, h = h.h;

          }

          i = Math.floor(h * 6);

          f = h * 6 - i;

          p = v * (1 - s);

          q = v * (1 - f * s);

          t = v * (1 - (1 - f) * s);

          switch (i % 6) {

          case 0: r = v, g = t, b = p; break;

          case 1: r = q, g = v, b = p; break;

          case 2: r = p, g = v, b = t; break;

          case 3: r = p, g = q, b = v; break;

          case 4: r = t, g = p, b = v; break;

          case 5: r = v, g = p, b = q; break;

          }

          var rgb='#'+toHex(r * 255)+toHex(g * 255)+toHex(b * 255);

          return rgb;

          }

          再回到我們的彩虹爆炸圖。每一個節點對應的所在角度(中心角度)決定了它自己的顏色值。所以,我們可以直接根據這個角度得到顏色的h。然后,為了讓彩虹逐漸一圈一圈變淡,再把s飽和度從1逐圈遞減(例如0.1),產生變淡的效果。為了防止圈太多最后看不清,減到0.2到0.3左右可以停止遞減。

          var fromAngle=node.getClient(‘fromAngle’);

          var toAngle=node.getClient(‘toAngle’);

          var level=node.getClient(‘level’);//節點在第幾圈

          var h = (fromAngle+to)/2 % 360 /360; //中心角度,并轉換為弧度

          var s = Math.max(0.2, 1-level*0.1);//每圈s遞減0.1,直到0.2為止

          var v=1;

          var color=getHSVColor(h, s, v);

          這樣就獲得了一圈顏色。實驗效果如下:

          如果相對某個節點的顏色做特殊處理,例如強制為橙色來凸顯,我們可以在數據中定義時加個標記,設置顏色時候直接使用而不用計算即可。

          {name:'浦東新區', value: 2600, color: '#FE9A2E'}

          接下來要實現鼠標劃過節點,自動計算路徑、高亮路徑節點、暗淡非路徑節點。為了方便路徑尋找,程序把每個節點的下一圈子數據定義為子節點,子節點通過getParent函數可以直接獲得父對象。這樣,通過不斷getParent就可以獲得整個路徑上的節點,并修改其顏色為預設顏色,實現高亮效果:

          var node=highlightedNode;

          while(node){

          node.setClient(‘color’, node.getClient(‘color.original’));

          node=node.getParent;

          }

          對于非路徑節點的顏色,可以設置為預設顏色但飽和度為0.1的淡顏色 ,讓它變淡,以便突出高亮路徑:

          var color = getHSVColor(h, 0.1, v);

          node.setClient(‘color’, color);

          四、動畫效果

          最后,為了圖形更生動,使用了一些動畫效果。首先想到的就是圖形出來時候,用動畫從小到大發散開來,會很動感。這樣做需要用動畫函數來驅動每一個節點的半徑位置,從0增加到所在的半徑位置,如果大家一起設置,整個圖就會動起來。這里用了一個動畫函數來驅動,并使用了網上常用的easing函數來控制,避免線性的動畫太死板:

          new Animate({

          from: 0,

          to: 1,

          dur: 3000+level*100,

          easing: 'elasticOut',

          onUpdate: function (value) {

          node.setLocation('pie.location’, value);

          },

          }).play;

          上面定義的動畫,用3秒鐘跑完,用'elasticOut'的easing方式。每一幀,修改node的位置信息。這樣就完成了橡皮筋一樣的環形彈出散開效果。

          另外,導航條的出來也比較突兀,這里也使用一下動畫,讓它從左到右慢慢伸出:

          new Animate({

          from: {x:x1, y:y1},

          to: {x:x2, y:y2},

          delay:50,

          type: 'point',

          dur: 1000,

          easing: 'bounceOut',

          onUpdate: function (value) {

          node.setCenterLocation(value.x, value.y);

          和上一個動畫的不同之處在于這里使用了{x、y}的point結構,每一幀直接更新節點位置。同時設置了50毫秒的delay,讓動畫有一點點粘性停滯,不至于太突兀。效果不錯。

          至此,彩虹爆炸圖基本上就做的差不多了。使用起來也很簡單,只要準備一些json數據就可以了,下面是一些有趣的數據做出來的效果。感興趣的同學可以到這里索取代碼。

          實際應用在項目中的示意圖。如果你也希望項目中用一下彩虹爆炸圖,歡迎給我發郵件索取:info@servasoft.com

          推薦微信:中國大數據

          推薦理由:一手新鮮,絕對干貨

          ath 是 SVG 基本形狀中最強大的一個,不僅可以實現我們上一篇《HTML5(七)——SVG基礎入門》中,介紹的 SVG 預定義的 line、rect、circle、ellipse、line、polyline、polygon 六種基本形狀。還可以實現更復雜的效果,我們就開始學習 path 如何應用。

          一、path 路徑詳解

          1.1、path 命令

          path 用于定義一個路徑,其中命令就是控制這條路徑的,以下命令就是可用于路徑數據:

          注:以上所有命令大小寫都可以,區別是大寫命令表示絕對定位,小寫表示相對定位。

          1.2、path 使用

          使用語法:<path d=" M x1 y1 L x2 y2 H x3.... " stroke="red"></path>

          d:引出路徑,d 中的值由多條命令組合而成。

          圓弧在實際場景中應用非常廣泛,A 命令中參數較多,large-arc 和 sweep 較難理解,詳細介紹下。

          使用語法:<path d="M x y A rx ry x-axis-rotation large-arc sweep x y"></path>

          如上圖所示,A 到 B 兩個點再加半徑,可以繪制出 4 條弧線,具體選哪一條呢?就是由 large-arc (是否是大弧)和 sweep(是否逆時針旋轉) 兩個參數決定。

          large-arc = 1 表示弧度大于等于180,反之就是小于180。

          sweep = 0 表示逆時針旋轉,反正順時針旋轉。

          所以上述 4 條弧線分別對應的兩個參數為:

          • 1:(0 0)
          • 2:(0,1)
          • 3:(1,1)
          • 4:(1,0)

          eg:使用 path 繪制一條直線、半圓、直線,連接起來形成一個拱橋,代碼如下:

          <svg  version="1.1" height="400" width="550">
           <path d="
            M 0 100  //(0,100)是起點
            L 100 100  // 畫一條直接到 (100,100)
            A 100 100 0 1 1 300 100  // 畫一段圓弧
            L 400 100 //畫一條直線到 (400,100)
          " stroke="black" stroke-width="1" fill="none"></path>    
          </svg>

          運行結果如下:

          可以自己修改上述 A 中 參數觀察半圓的變化。

          1.3、js 操作path

          我們經常使用js動態添加、移除元素等,可以實現更炫酷的特效,那js能動態操作path嗎?如何操作呢?

          我們使用js動態繪制一個與上邊案例eg1一樣的path。

          <svg  version="1.1" height="400" width="550" id="svg"></svg>
          <script >
           window.onload = function(){
            let svg = document.getElementById("svg")
            let path = document.createElement("path")
            path.setAttribute('d',"M 0 100  L 100 100  A 100 100 0 1 1 300 100   L 400 100")
            svg.appendChild(path)
          }
          </script>

          運行代碼,我們發現沒有報錯,也沒有顯示任何結果。

          添加:alert(path),打印出 [object HTMLUnknownElement]。

          說明 html 把 path 當作普通的 html 標簽解析了,發現并不認識該標簽,所以頁面沒有任何效果,此時我們需要介紹一個新的創建元素方法。

          createElementNS介紹

          createElementNS 是創建一個具有指定的命名空間URI和限定名稱的元素。

          使用語法:document.createElementNS(namespaceURI, qualifiedName[, options]);

          • namespaceURI 指定與元素相關聯的命名空間URI的字符串。創建的元素的namespaceURI (en-US)屬性使用namespaceURI的值進行初始化。
          • qualifiedName指定要創建的元素的類型的字符串。 創建的元素的nodeName (en-US)屬性使用qualifiedName的值進行初始化。
          • options可選的一個可選的包含單個屬性的ElementCreationOptions對象,其值是預先使用customElements.define()定義的自定義元素的標簽名稱。為了向后兼容自定義元素規范的早期版本,一些瀏覽器允許您在此使用字符串替代對象,其中字符串的值是自定義元素的標簽名稱。

          生成path元素代碼:

          let path = document.createElementNS(
            "http://www.w3.org/2000/svg",
            "path"
          )

          js操作屬性時,html元素與SVG元素區別:

          普通html元素可以使用兩種方法:

          1. setAttribute(x,val) / getAttribute(x)
          2. obj.x

          SVG操作方法只有一種

          1. setAttribute(x,val) / getAttribute(x)

          eg3:圖表中餅圖是特別常見的,我們就先使用 js 動態地繪制一個扇形圓弧。

          <svg  version="1.1" height="400" width="550" id="svg"></svg>
          <script >
           function d2a(n){
            return Math.PI*n/180
           }
           function pie(ang1,ang2,r,cx,cy){
            let svg = document.getElementById("svg")
            let path = document.createElementNS("http://www.w3.org/2000/svg","path")
            let arr = []
            let x1 = cx + Math.sin(d2a(ang1))*r
            let y1 = cy - Math.cos(d2a(ang1))*r
            let x2 = cx + Math.sin(d2a(ang2))*r
            let y2 = cy - Math.cos(d2a(ang2))*r
            arr.push(`M ${cx} ${cy} L ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2} `)
            arr.push("Z")
            path.setAttribute('d',arr.join(' '))
            svg.appendChild(path)
           }
           window.onload = function(){
            pie(20,180,200,200,200)
           }
          </script>

          運行結果如圖所示:

          如果有興趣,可以自己修改開始角度和結束角度,可以繪制出很多種不同效果的圓弧。

          二、樣式以及優先級

          上述代碼

          <path d="
            M 0 100  //(0,100)是起點
            L 100 100  // 畫一條直接到 (100,100)
          " stroke="black" stroke-width="1" fill="none"></path>

          上述屬性可以分為兩類:

          • 只能為屬性 - 決定圖形或路徑形狀的
          • 可以放樣式 - 視覺上的效果

          如 troke、fill等是控制視覺上的效果,這樣的屬性可以放入 style 樣式中。所以上述代碼可以改寫為:

          <path d="
            M 0 100  //(0,100)是起點
            L 100 100  // 畫一條直接到 (100,100)
          " style="stroke:black;stroke-width:1;fill:none"></path>

          該樣式可以放到 head 的 style 中,代碼為:

          path{
           fill:none;
           stroke:black;
           stroke-width:1
          }

          還可以通過 class、id、標簽等添加樣式,他們的優先級分別為:

          屬性< * < 標簽 < class < id < 行間

          path 的樣式控制同樣適用于 SVG 預定義的 rect、circle、ellipse 等元素。

          如果覺得還不錯!

          點個關注,下篇解密 SVG 動畫 !


          主站蜘蛛池模板: 亚洲一区二区无码偷拍| 国产精品夜色一区二区三区| 国产短视频精品一区二区三区| 鲁大师成人一区二区三区| 91精品国产一区二区三区左线 | 最新中文字幕一区二区乱码| 国产精品一区二区久久不卡| 精品一区二区三区3d动漫| 国产一区二区三区播放心情潘金莲 | 亚洲中文字幕乱码一区| 91精品一区二区三区久久久久| 爆乳熟妇一区二区三区| 日韩精品一区二区三区视频| 日韩精品午夜视频一区二区三区| 精品欧洲av无码一区二区| 精品国产乱子伦一区二区三区| 国产福利一区二区三区| 男插女高潮一区二区| 国产大秀视频在线一区二区| 麻豆国产一区二区在线观看| 亚洲一区二区三区高清视频| 国产精品合集一区二区三区 | 亚洲日本va午夜中文字幕一区| 国模私拍一区二区三区| 国产激情一区二区三区| 综合人妻久久一区二区精品| 国产剧情国产精品一区| 精品一区二区三区波多野结衣| 日韩内射美女人妻一区二区三区| 亚洲一区二区三区日本久久九| 农村乱人伦一区二区| 无码国产精品一区二区免费式直播| 精品国产一区二区三区不卡| 交换国产精品视频一区| 国产精品无码一区二区三区在| 无码日韩精品一区二区人妻 | 成人国产精品一区二区网站公司 | 亚洲福利视频一区二区三区| 亚洲AV无码一区二区三区牛牛| 日本人的色道www免费一区 | 中文字幕一区在线观看视频|