1. 程式人生 > >【自己的整理】【jQuery外掛】 使用canvas建立折線圖

【自己的整理】【jQuery外掛】 使用canvas建立折線圖

使用canvas建立折線圖

一個網友的很常規的需求,要根據資料在一個canvas畫布元素上畫一個折線圖,最開始做了一個很土的版本,現在自己想想還是弄個外掛吧於是就有了這篇文章。

建立jquery外掛標準模板

既然是一個外掛就要按照基本法來,所以先要建立一個標準的jquery外掛模板:

<!DOCTYPE html>
<html>
    <head>
        <title>用canvas根據資料建立折線圖</title>
        <script src="http://code.jquery.com/jquery-latest.js"
>
</script> <script> (function($){ var methods = { init:function(options){ var chart = $.extend({ 'ChartTitle': '三人成績折線圖',//表頭 'defaultLineColor':'rgba(0,0,0,0.4)'
,//折線圖的座標以及輔助線顏色 'defaultTextColor':'rgba(0,0,0,0.7)',//字型顏色 'canvasWidth':800,//畫布寬度 'canvasHeight':600,//畫布高度 'chartWidth':600,//圖示寬度 'chartHeight':400,//圖表高度 'x_metric'
:[1,2,3,4,5,6],//月份 下面X軸的計量數 'data':[{ "name":"小紅", "details":[78,89,86,88,79,88],//資料 "color":"rgba(255,127,127,0.7)"//連線以及點的顏色 },{ "name":"小明", "details":[86,77,69,76,60,98], "color":"rgba(127,255,127,0.7)" },//資料二維陣列 { "name":"小蘭", "details":[80,77,66,62,99,65], "color":"rgba(127,127,255,0.7)" }], 'startLine':0,//左邊開始的時候的資料 'endLine':120,//左邊最高點的資料 'line_number':4,//中間畫分成幾格子 'x_name':'月份',//縱座標的數量單位 'y_name':'分數'//橫座標的數量單位 },options); //下面用於檢測是否在已經存在的畫布上畫圖,還是重新生成一個。 var canvasElement,ctx; if($(this) && $(this).prop("tagName") == "CANVAS"){ var jQueryCanvasObject = $(this); console.log(jQueryCanvasObject); canvasElement = jQueryCanvasObject.get(0); console.log(canvasElement); ctx = canvasElement.getContext('2d'); canvasElement.width = chart.canvasWidth; canvasElement.height = chart.canvasHeight; }else if($(this) && typeof($(this).context) != 'undefined'){ var canvasindex = 0; for(var canvasindex;$('#drawChartCanvas'+canvasindex+'').length > 0;canvasindex ++ ){ } $(this).append("<canvas width="+chart.canvasWidth+" height="+chart.canvasHeight+" id='drawChartCanvas"+canvasindex+"'></canvas>"); canvasElement = $("#drawChartCanvas"+canvasindex).get(0); ctx = canvasElement.getContext('2d'); } else{ var canvasindex = 0; for(var canvasindex;$('#drawChartCanvasInBody'+canvasindex+'').length > 0;canvasindex ++ ){ console.log(canvasindex); } $('body').append("<canvas width="+chart.canvasWidth+" height="+chart.canvasHeight+" id='drawChartCanvasInBody"+canvasindex+"'></canvas>"); canvasElement = $("#drawChartCanvasInBody"+canvasindex).get(0); ctx = canvasElement.getContext('2d'); } }, destory:function(){},//destory方法 待補充 animate:function(){}//其他方法 }; $.fn.drawChart = function (method){ if(methods[method]){ return methods[method].apply(this,Array.prototype.slice.call(arguments,1)); }else if(typeof method === 'object' || !method){ return methods.init.apply(this,arguments); }else{ $.error('方法'+method+'在畫折線圖外掛中不存在'); } } })(jQuery);
</script> <script> $(document).ready(function(){$().drawChart()}); </script> </head> <body> </body> </html>

到目前為止只是建立了一個預設的折線圖資料物件chart,其中包含了諸多資訊,比如表頭,表的線條顏色等,可以根據自己的喜好改變其中某部分的設定。
我們要開始畫一個折線圖的時候,最開始畫的應該是橫豎兩條x軸y軸輔助線,加上代表數量的輔助線,以及單位名稱、度量等。我們在外掛中建立一個新的方法把它叫做drawAxis(),這是一個畫輔助線的方法,並不需要用到資料

function drawAxis(ctx,chart){
                    ctx.font = "30px microsoft yahei";
                    ctx.fillStyle = chart.defaultTextColor;
                    ctx.fillText(chart.ChartTitle,chart.canvasWidth/2-100,40);
                    ctx.lineWidth = 4;
                    ctx.strokeStyle = chart.defaultLineColor;
                    ctx.lineCap = "round";
                    var bottomLeft = {'x':(chart.canvasWidth - chart.chartWidth)/2,
                                      'y':(chart.canvasHeight - chart.chartHeight)/2+chart.chartHeight
                                    };//左下角點座標
                    var topRight = {'x':chart.canvasWidth - ((chart.canvasWidth - chart.chartWidth)/2),
                                    'y':(chart.canvasHeight-chart.chartHeight)/2};//右上角點座標
                    ctx.moveTo((chart.canvasWidth-chart.chartWidth)/2,(chart.canvasHeight-chart.chartHeight)/2+chart.chartHeight);//座標軸原點
                    ctx.lineTo((chart.canvasWidth-chart.chartWidth)/2,(chart.canvasHeight-chart.chartHeight)/2);//座標軸y軸上部點
                    var y_metric = chart.chartHeight/chart.line_number;
                    var between = (chart.endLine - chart.startLine)/(chart.line_number);
                    for(var i = 0; i < chart.line_number; i++){
                        ctx.moveTo(bottomLeft.x,bottomLeft.y-i*y_metric);
                        ctx.lineTo(bottomLeft.x+chart.chartWidth,bottomLeft.y-i*y_metric);
                        ctx.font = '20px microsoft yahei';
                        ctx.fillText(Math.floor(between * i + chart.startLine),bottomLeft.x-40,bottomLeft.y-i*y_metric);
                    };
                    for(var i = 0;i < chart.x_metric.length; i++){
                        ctx.moveTo(
                            i*(chart.chartWidth/chart.x_metric.length)+(chart.canvasWidth-chart.chartWidth)/2+(chart.chartWidth/chart.x_metric.length)/2,
                            chart.chartHeight + (chart.canvasHeight-chart.chartHeight)/2
                        );
                        ctx.lineTo(
                            i*(chart.chartWidth/chart.x_metric.length)+(chart.canvasWidth-chart.chartWidth)/2+(chart.chartWidth/chart.x_metric.length)/2,
                            chart.chartHeight + (chart.canvasHeight-chart.chartHeight)/2 + 5
                        );
                        ctx.font = "20px microsoft yahei";
                        ctx.fillText(chart.x_metric[i],
                            i*(chart.chartWidth/chart.x_metric.length)+(chart.canvasWidth-chart.chartWidth)/2+(chart.chartWidth/chart.x_metric.length)/2 - 6,
                            chart.chartHeight + (chart.canvasHeight-chart.chartHeight)/2 + 25
                        );
                    }
                    ctx.stroke();
                    ctx.font = "22px microsoft yahei";
                    ctx.fillText(chart.x_name,topRight.x + 3,bottomLeft.y);
                    ctx.fillText(chart.y_name,bottomLeft.x - 3,topRight.y - 10);
                    for(var i = 0;i < chart.data.length; i++){
                        ctx.strokeStyle = chart.data[i].color;
                        ctx.beginPath();
                        ctx.moveTo(chart.canvasWidth-(chart.canvasWidth-chart.chartWidth)/2, (chart.canvasHeight-chart.chartHeight)/2 +i*25);
                        ctx.lineTo(chart.canvasWidth-(chart.canvasWidth-chart.chartWidth)/2 + 18, (chart.canvasHeight-chart.chartHeight)/2 +i*25);
                        ctx.stroke();
                        ctx.fillText(chart.data[i].name,
                                     chart.canvasWidth-(chart.canvasWidth-chart.chartWidth)/2 + 20, 
                                     (chart.canvasHeight-chart.chartHeight)/2 +i*25 +6
                                    );
                    }
                }

然後我們需要在外掛的初始化方法中加入這個方法

init:function(options){
    //...省略程式碼
    drawAxis(ctx,chart);
}

這樣完成之後我們就可以看到還沒有折線的一個圖示,只有輔助線、表頭、圖例、以及單位等。
這裡寫圖片描述
在我們在自己的本子上畫折線圖的時候,首先是要畫各個點,然後再把這些點用線連起來,那麼我們就可以按照這個思路來操作。
最開始我們先計算一下點的位置:

function initPointPosition(chart){
    var points = [];
    for(var g = 0;g < chart.data.length;g++){
        var pointsGroup = [];
        for(var i = 0;i < chart.data[g].details.length; i++ ){
            //獲取資料
            var tempNumber = chart.data[g].details[i];
            //算出百分比高度位置
            var yPercentHeight = ((tempNumber - chart.startLine)/(chart.endLine-chart.startLine))*chart.chartHeight;
            //確定位置
            var pointPosition = {
                'detail':chart.data[g].details[i],
                'x':chart.chartWidth/(chart.x_metric.length*2)+i*(chart.chartWidth/chart.x_metric.length)+(chart.canvasWidth-chart.chartWidth)/2,
                'y':chart.chartHeight+(chart.canvasHeight-chart.chartHeight)/2-yPercentHeight ,
                'color':chart.data[g].color
            };
            pointsGroup.push(pointPosition);
        }
        points.push(pointsGroup);
    }
    return points;
}

這個方法可以根據資料來返回一個二維物件陣列,陣列內的一級元素表示了有多少組點,而二級物件中包含了點的位置,顏色,以及資料等資訊。當然這還只是資料層面的,我們還需要把這些點畫出來,所以需要加入一個可以把這個二維陣列的點畫出來的方法:

function drawPoints(ctx,points){
    for(var i = 0; i < points.length; i ++){
        for(var j = 0; j < points[i].length; j++){
            ctx.fillStyle = points[i][j].color;
            ctx.beginPath();
            ctx.arc(points[i][j].x,points[i][j].y,4,0,Math.PI*2,true);
            ctx.closePath();
            ctx.fill();
        }
    }
};

我們需要在init(初始化)方法的最後呼叫這個方法:

init:function(options){
    //省略的程式碼
    drawAxis(ctx,chart);
    var points = initPointPosition(chart);
    drawPoints(ctx,points);
}

此時我們再重新整理一下瀏覽器,可以看到點已經呈現在折線圖上面了:
這裡寫圖片描述
這個時候就要把點都連起來,因為之前點的位置已經存在了,所以連點並不難,我們在外掛中加入一個將二維陣列的點連起來的方法:

function drawLine(ctx,points){
    ctx.lineWidth = 3.5;
    for(var i = 0; i < points.length; i++){
        ctx.beginPath();
        for(var j = 0; j < points[i].length-1; j++){
            ctx.strokeStyle = points[i][j].color;
            ctx.moveTo(points[i][j].x,points[i][j].y);
            ctx.lineTo(points[i][j+1].x,points[i][j+1].y);
        }
        ctx.stroke();
    }
};

然後同樣在init方法的最後加入:

init:function(options){
    drawAxis(ctx,chart);
    var points = initPointPosition(chart);
    drawPoints(ctx,points);
    drawLine(ctx,points);
}

此時我們再重新整理一下瀏覽器,可以看到點之間的連線也連好了。
這裡寫圖片描述
這個時候可以看到連線已經完成,但是在折線圖中看不到具體的數值,這個大小的比較還是有些看不出來,所以我們還要在點的旁邊畫上資料,同樣新建一個方法用來繪製具體數值:

function drawData(ctx,points,chart){
    ctx.fillStyle = chart.defaultTextColor;
    ctx.font = "18px microsoft yahei";
    for(var i = 0;i < points.length; i++){
        for(var j = 0;j< points[i].length;j++){
            ctx.fillText(points[i][j].detail,points[i][j].x,points[i][j].y);
        }
    }
}

同理要在init方法最後加入繪製具體數值的方法:

init:function(options){
    //省略的內容
    drawAxis(ctx,chart);
    var points = initPointPosition(chart);
    drawPoints(ctx,points);
    drawData(ctx,points,chart);
}

最後再次重新整理一下瀏覽器,可以看到一個較為完整的折線圖:
這裡寫圖片描述
看起來有些緊湊,想要把它變得不那麼緊湊的話,可以改變一些設定:

<script>
    $().drawChart({"startLine":50,"endLine":100});
</script>

這裡寫圖片描述

測試地址

相關推薦

自己整理jQuery外掛 使用canvas建立折線

使用canvas建立折線圖 一個網友的很常規的需求,要根據資料在一個canvas畫布元素上畫一個折線圖,最開始做了一個很土的版本,現在自己想想還是弄個外掛吧於是就有了這篇文章。 建立jquery外掛標準模板 既然是一個外掛就要按照基本法來,所以先要建立

spring method validation的優化自己動手實現校驗切面

建議首先閱讀筆者的Spring method validation的不足 在【Spring method validation的不足】的文章中,筆者提出瞭如下問題: spring method validation 不支援方法物件檢視的校驗; 方法級別的校驗規則是統

jQuery外掛jqGrid常用語法整理-更新

jqGrid常用語法整理,包含資料獲取、常用函式、觸發事件等 jqGrid表格資料獲取相關語法 獲取表格所有資料  $("#grid").jqGrid("getRowData"); 根據行id獲取表

jQuery Demo圖片切換效果整理

ges 比較 nta containe 水平滾動 :hover 實現 small vertica 圖片的切換效果有很多,比較常見的有水平滾動、垂直滾動、淡入淡出等。我們接下來一一實現這些效果。 1.水平滾動 1) 我們先來實現HTML頁面,代碼很簡單: &l

總結整理overflow: auto/hidden;清除自己

12px borde 清除浮動 nav pre flow 需要 效果 size .top-nav{ font-size: 12px; font-weight: bold; li

總結整理JQuery基礎學習---事件篇

交互 .... over 指針 events 返回值 避免 func 坐標 jQuery鼠標事件之click與dbclick事件 用交互操作中,最簡單直接的操作就是點擊操作。jQuery提供了兩個方法一個是click方法用於監聽用戶單擊操作,另一個方法是dbclick方

jQuery外掛分享Cropper——一個簡單方便的圖片裁剪外掛

原文地址:https://segmentfault.com/a/1190000012344970   外掛介紹 這是一個我在寫以前的專案的途中發現的一個國人寫的jQuery影象裁剪外掛,當時想實現使用者資料的頭像上傳功能,並且能夠預覽圖片,和對圖片進行簡單的裁剪、旋轉,花了不少

常用 JS 外掛01 jQuery Validation 表單驗證外掛

表單驗證框架 jQuery Validation 前端表單驗證框架 頁面引用 <!-- jQuery Validation 1.14.0 --> <script src="/static/assets/plugins/jquery-valida

常用 JS 外掛01 jQuery Valdation 表單驗證外掛

表單驗證框架 jQuery Validation 前端表單驗證框架 頁面引用 <!-- jQuery Validation 1.14.0 --> <script src="/static/assets/plugins/jquery-valida

常用 JS 外掛jQuery zTree 樹形結構外掛

zTree zTree 是一個依靠 jQuery 實現的多功能 “樹外掛”。優異的效能、靈活的配置、多種功能的組合是 zTree 最大優點。 頁面引用 CSS 部分 <link rel="stylesheet" href="/static/assets/

外掛自適應佈局JQuery外掛,rem佈局——和派孔明

//框架檔名Pandora.AutoSize.js (function($) { $.fn.extend({ AutoSize: function() {

jQuery圖片燈箱外掛——lightBox

該外掛可以用圓角的方式展示選擇中的圖片,使用按鈕檢視上下張圖片,在載入圖片時自帶進度條,還能以自動播放的方式瀏覽圖片,呼叫格式如下: $(linkimage).lightBox({options}) 其中linkimage引數為包含圖片的<a>元素名稱,o

react中如何使用jquery外掛

  react的思想是虛擬dom,提倡最好較少dom的操作,可是我們在寫網頁的時候,有些複雜的互動還是離不開jquery外掛的。而且當你把jquery直接拿來用的時候,你會發覺會報錯,要麼是找不到那個外掛,要麼就是沒有報錯,但是就是不能用。尤其是使用webpack打包後,如果將外掛一起打包,那可能會出錯。

常用 JS 外掛jQuery DataTables 自定義查詢

前提 因為需要根據不同的分類查詢資料,可以點選一個按鈕,重新重新整理表格。 js "ajax": { "url": "/article/page", "data":function (d) { d.cid = $("#cid"

常用 JS 外掛jQuery TreeTable 樹表格外掛

TreeTable treeTable 是跨瀏覽器、效能很高的 jQuery 的樹表元件,它使用非常簡單,只需要引用 jQuery 庫和一個 js 檔案,介面也很簡單。 優點: 相容主流瀏覽器:支援 IE6 和 IE6+, Firefox, chrome, Opera,

jQuery HandsontablejQuery外掛-一個非常酷的可編輯表格

jQuery Handsontable 是jQuery外掛中一款非常酷的可編輯的表格,它的描述是:a minimalistic Excel-like data grid editor for HTML, JavaScript & jQuery. (一款類似於Exce

jquery-jqGrid外掛jqGrid 多選 複選框 編輯列

jqGrid 表格外掛- 表格多選複選框,編輯列使用 1、當在JqGrid表格屬性中設定了multiselect:true,這時會在每一行前面出現checkbox。 2、而在點選欄的ch

JQuery UI微調按鈕外掛——spinner

微調按鈕外掛不僅能在文字框中直接輸入數值,還可以通過點選輸入框右側的上下按鈕修改輸入框的值,還支援鍵盤的上下方向鍵改變輸入值,呼叫格式如下: $(selector).spinner({options}

自己整理Vue入門使用

為什麼要用vue 寫這篇部落格的時間,2018年4月20日。我們為什麼要用vue 前端框架層出不窮的今天,選擇一個較為主流同時能讓自己事半功倍的框架是必不可少的,同時vue作為三大主流框架之一發展迅速,如果還沒有選擇好用哪個框架,那不如稍微考慮一下,只要選定

自己整理node.js建立靜態路由以及Router建立路由

node.js路由的設定 靜態路由 首先作為基礎的建立一個靜態路由,是在express中最簡單的路由建立方法,這樣就可以訪問靜態路由下的任何一個存在的檔案。 先要建立一個js檔案,檔案命名隨便,比如我就把它叫做static.js,然後我們需要檢視路由是