求评论啊!!!! 也写了 一些东西。。咋就没人评论一下的呢。 。。。。
HTML5 画扇形图
最近 有个需求 做了个平衡论应用 因为是需要打包成 android 和 ios的 用了phonegap 技术。 就是直接开发html5 然后直接生成 ios和android'项目。
然后写代码的时候。 自己写了个花扇形图的类。
(function() {
function Wheel(canvas, options) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.option = {
radius : 311, //半径
centerPoint : {
x : 0,
y : 0
},
data : [{score:0,name:''}],
startRadian : 0,//开始弧度 0-2*Math.PI
color:['#a84ae8','#d04ae7','#e94aae','#e74a77','#e84a49','#e8644b','#e8884b',
'#e8ae4a','#e8d04a','#e2e84a','#bae84a','#7ee84a','#4be859','#4ae889','#4ae8b7','#4ae8e7',
'#4abde9','#4a91e9','#4a59e8','#734ae8'],
needText:true,
needScoreText:true,
font:'16px bold',
bigRate:1.05,
smallRate:0.91
}
this.setOptions(options);
_init.call(this);
}
/**
* 设置值 可以通过设置整个值的json数组 直接绘制出图形
*/
Wheel.prototype.setData = function(data) {
this.option.data = data;
_draw.call(this);
}
Wheel.prototype.getData = function() {
return this.option.data;
}
Wheel.prototype.editName = function(index,name) {
this.option.data[index].name=name;
this.draw();
}
Wheel.prototype.editScore = function(index,score) {
this.option.data[index].score=score;
this.draw();
}
/**设置参数
*
*/
Wheel.prototype.setOptions = function(options) {
for (var i in this.option) {
if (options && options[i]!=undefined) {
this.option[i] = options[i];
}
}
}
/**
*调用画图 进行画图 如修改设置 等需要立即生效时 可以手动调用
*/
Wheel.prototype.draw = function() {
_draw.call(this);
}
Wheel.prototype.deleteSector = function(index) {
this.option.data.splice(index,1);
this.draw();
}
/**
*根据坐标 获取是哪个扇形
*/
Wheel.prototype.getIndexByPoint = function(x, y) {
//471,322
//alert(x+':'+y)
//$('.balanceWheel_logo').text(x+':'+y)
var data = this.option.data;
var defRadian = 2 * Math.PI / data.length;
var index = -1;
for (var i in data) {
var start = this.option.startRadian + defRadian * i;
var end = this.option.startRadian + defRadian * (i - 0 + 1);
if (_drawSector.call(this, data[i].score, data[i].name, start, end,this.option.color[i], x, y)) {
//return i;
index = i;
}
}
return index;
}
Wheel.prototype.addData = function(data) {
this.isd=true;
if(this.option.data.length>=20){
return false;
}
if(!data){
//data={score:0,name:this.option.data.length+1+''}
data={score:0,name:''}
}
this.option.data.push(data);
_draw.call(this);
}
Wheel.prototype.getCanvas = function() {
return this.canvas;
}
Wheel.prototype.setCanvas = function(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.draw();
}
Wheel.prototype.beginChange = function(index) {
this.changeIndex=index;
}
Wheel.prototype.endChange = function() {
this.changeIndex=-1;
}
Wheel.prototype.changeScore = function(point) {
var x=point.x-this.option.centerPoint.x;
var y=point.y-this.option.centerPoint.y;
var len=Math.sqrt(x*x+y*y);
var score=Math.round(len/(this.option.radius/10));
if(this.changeIndex>=0){
this.option.data[this.changeIndex].score=Math.min(score,10);
}
this.draw();
}
//初始化数据
function _init() {
_draw.call(this);
}
//画的核心方法
function _draw() {
var ctx = this.ctx;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
var data = this.option.data;
var defRadian = 2 * Math.PI / data.length;
//画外轮廓线 并且填充背景色
ctx.beginPath();
//ctx.moveTo(this.option.centerPoint.x, this.option.centerPoint.y);
ctx.strokeStyle = '#FFFFFF';
ctx.fillStyle = '#f4f4f4';
ctx.lineWidth = 2;
ctx.arc(this.option.centerPoint.x, this.option.centerPoint.y, this.option.radius, 0, 2*Math.PI, false);
ctx.stroke();
ctx.fill();
for (var i in data) {
var start = this.option.startRadian + defRadian * i;
var end = this.option.startRadian + defRadian * (i - 0 + 1);
_drawSector.call(this, data[i].score, data[i].name, start, end,this.option.color[i]);
}
}
//
/**
* 画扇形
* @param {Object} score 分数 用来控制 扇形半径
* @param {Object} name 名称用来写字
* @param {Object} startRadian 开始弧度
* @param {Object} endRadian 结束弧度
* @param {Object} x 当前点击坐标 用来判断 点击区域
* @param {Object} y
*/
function _drawSector(score, name, startRadian, endRadian,color, x, y) {
var ctx = this.ctx;
//画外轮廓线 并且填充背景色
ctx.beginPath();
ctx.moveTo(this.option.centerPoint.x, this.option.centerPoint.y);
//ctx.strokeStyle = '#FFFFFF';
ctx.fillStyle = '#f4f4f4';
ctx.lineWidth = 2;
ctx.arc(this.option.centerPoint.x, this.option.centerPoint.y, this.option.radius, startRadian, endRadian, false);
ctx.lineTo(this.option.centerPoint.x, this.option.centerPoint.y);
//ctx.stroke();
ctx.fill();
var isPointAted = ctx.isPointInPath(x, y);
//ctx.save();
//画内扇形 填充颜色
ctx.beginPath();
ctx.moveTo(this.option.centerPoint.x, this.option.centerPoint.y);
ctx.arc(this.option.centerPoint.x, this.option.centerPoint.y, score * this.option.radius / 10, startRadian, endRadian, false);
ctx.fillStyle = color;//'#654321';
//color[this.index];
ctx.fill();
_drawText.call(this,score,name,startRadian+(endRadian-startRadian)/2)
if(this.option.data.length>1){
ctx.beginPath();
ctx.moveTo(this.option.centerPoint.x, this.option.centerPoint.y);
ctx.strokeStyle = '#FFFFFF';
ctx.lineWidth = 2;
ctx.arc(this.option.centerPoint.x, this.option.centerPoint.y, this.option.radius, startRadian, endRadian, false);
ctx.lineTo(this.option.centerPoint.x, this.option.centerPoint.y);
ctx.stroke();
}
return isPointAted;
}
function _drawText(score,name,radian) {
var text_inc_x = Math.cos(radian) * (this.option.radius);
var text_inc_y = Math.sin(radian) * (this.option.radius);
var ctx=this.ctx;
ctx.font = this.option.font;//"16px bold";
//ctx.fillStyle = ;
if (text_inc_x >= 0) {
ctx.textAlign = "left";
} else {
ctx.textAlign = "right";
}
if(this.option.needText){
ctx.fillStyle="#b6b6b6";
ctx.fillText(name,text_inc_x*this.option.bigRate+this.option.centerPoint.x,text_inc_y*this.option.bigRate+this.option.centerPoint.y,100);
}
if(this.option.needScoreText){
if (score==10) {
ctx.fillStyle="#ffffff";
}else{
ctx.fillStyle="#b6b6b6";
}
//this.option.font
var textY=ctx.font.substring(0,2)/2;
var offX=0;
ctx.fillText(score,text_inc_x*this.option.smallRate+this.option.centerPoint.x+offX,text_inc_y*this.option.smallRate+this.option.centerPoint.y+textY,100);
}
//
}
window.Wheel = Wheel;
})()
使用方法
var canvas = $('#canvas')[0];
var wheel = new Wheel(canvas, optioons);
有2个参数 第一个是canvas 对象。 第二个是配置 设置。
radius : 311, //半径
centerPoint : {x : 0,y : 0}// 圆形坐标 注意 这个坐标是指圆形相对canvas 左上角的坐标
data : [{score:0,name:''}] 扇形数据 这是一个数组 是有每个数据对象组成 数据对象有2个属性。 分数和名称。 分数是1-10分。
startRadian : 0,//开始弧度 就是第一个扇形的起始位置。 数值范围 0-2*Math.PI
color:['#a84ae8','#d04ae7','#e94aae','#e74a77','#e84a49','#e8644b','#e8884b','#e8ae4a','#e8d04a','#e2e84a','#bae84a','#7ee84a','#4be859','#4ae889','#4ae8b7','#4ae8e7','#4abde9','#4a91e9','#4a59e8','#734ae8'],//扇形颜色 因为这个项目做多分20份 并且颜色固定了。 所以用了这个参数。
needText:true 是否需要在外面写上名称。就是数据的 name值。
needScoreText:是否需要在内环写上分数。就是数据的 score值。
font:'16px bold', 字体大小
bigRate:1.05, 就是外面的字的坐标 是由这个值乘以 半径的出来的。
smallRate:0.91 这是里面的字。
另外提过了一些方法:
setData(data) :设置data值
getData() :获取data值
editName(index,name) 修改某个扇形的名称
editScore (index,score) 修改某个扇形的值(同时改变扇形大小)
setOptions(options) 设置属性。
draw() 画canvas的主方法。 可以手动调用刷新
deleteSector(index) 删除某个扇形
getIndexByPoint(x,y) 获取点击的坐标的扇形index。(注意 这个坐标是相对canvas'的左上角)
addData(data) 增加一个扇形
getCanvas
setCanvas
beginChange :这个事用来标记作用的。 我的项目需要手动拖动 改变扇形大小。 于是 我添加了这个方法。 当touchstart(mousedown)的时候 获取扇形index 并且 调用这个方法 设置index 这样touchmove(mousemove)的时候就知道改变哪个扇形了。即使拖动到外部 或者其他扇形区域 也能记住之前的index。当然 touchend(mouseup)的时候调用下面的 endChange方法。清清除index
endChange
changeScore(point) 这个方法 仍然需要上面2个方法 合作的。 (这里设置的很不合理 暂时 不知道如何改进。) 就是根据touchmove的 坐标 改变 之前几下的扇形的值。 实现拖动打分的效果。
下面附上我对坐标的一些处理 因为各种事件只能获取外部坐标 没法获取canvas内部的坐标 所以需要转化。
function getRealPoint(x, y, canvas) {
var scollTop = getScollPostion();
x = x - canvas.offsetLeft - ($(document).width() - $('.balanceWheel_wrappe').width()) / 2 + scollTop.left;//balanceWheel_wrappe是主界面。
//实际上($(document).width() - $('.balanceWheel_wrappe').width()) / 2就是得到canvas距离左边的距离
// + margin_left;
y = y - canvas.offsetTop + scollTop.top - $('.balanceWheel_top').height(); //跟上面基本一个意思
return {
x : x,
y : y
}
}
//获取滚动条的属性
function getScollPostion() {//滚动条位置
var t, l, w, h;
if (document.documentElement && document.documentElement.scrollTop) {
t = document.documentElement.scrollTop;
l = document.documentElement.scrollLeft;
w = document.documentElement.scrollWidth;
h = document.documentElement.scrollHeight;
} else if (document.body) {
t = document.body.scrollTop;
l = document.body.scrollLeft;
w = document.body.scrollWidth;
h = document.body.scrollHeight;
}
return {
top : t,
left : l,
width : w,
height : h
};
}