highchart 图表之自定义属性的应用

有时候很多场景可能对于图表自身所带的数据不能满足当前业务的需求,例如目前图表api里提供了有namexycolor 等属性。我们在tooltiplabellegend 等对象的formatter里可以使用到这些属性,但有时候我们还需要额外的属性或者扩展字段,有些小伙伴就不知道如何处理了!下面就给大家讲解下。

Demo 场景之一

需求:我需要图表 渲染完毕后 ,鼠标移到某个点上,tooltip里既要显示y轴的值,又要显示y轴值所占总数的百分比,另外点击这个点又能发生一个跳转,或者根据某个字段传值去弹出一个层展示一个新的列表,遇到这样的需求该如何处理?

效果图

解决方案

  • series 数据代码(series 里我们增加了自定义的属性totals和url 2个 )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    series: [{
    name:"www.peng8.net",
    data: [{
    name: 'Point 1',
    url:'http://www.peng8.net',
    totals:"20%",
    y: 1
    }, {
    name: 'Point 2',
    url:'http://www.peng8.net',
    totals:"30%",
    y: 5
    }, {
    name: 'Point 3',
    url:'http://www.peng8.net',
    totals:"40%",
    y: 5
    }, {
    name: 'Point 4',
    url:'http://www.peng8.net',
    totals:"50%",
    y: 5
    }]
    }]
  • tooltip 关键代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    tooltip:{
    formatter:function(){

    var htm="";
    htm+="标题:"+this.series.name+"<br />";
    htm+="X轴:"+this.x+"<br />";
    htm+="Y轴:"+this.y+"<br />";
    htm+="所占百分比:"+this.point.totals+"<br />";
    return htm;
    }
    }

    这段代码用来格式化tooltip的显示,formatter函数里对tooltip里的内容进行了重组,并调用了自定义的属性 totals

  • events事件处理代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    plotOptions:{
    line:{
    cursor:"pointer",
    point:{
    events:{
    click:function(){
    window.open(this.options.url);
    }
    }
    }
    }
    }

    events 里,我们在line的click事件里 调用了 url 属性,点击图表中的点,打开自定义的链接url

在线完整DEMO:传送门


总结:这个例子难度基本没有,其实重点在于如何去取到我们自定义的属性,我们可以在任何地方要活用一个东西 叫 this ,例如在 事件里 用 console.log(this); 去打印当前的对象,然后看看对象里有哪些属性和方法我们可以用,然后一层一层往里面找,熟练掌握后 就能对任何属性 包括图表自身的,或者自己定义的属性 灵活操作!

如何在highchart中绘制自定义元素

highcharts 为我们提供了丰富的扩展接口,今天就给大家讲讲在highcharts中指定的位置画我们想要的按钮、图片、图形、文字等。

关于highchart 扩展方法

我们先来看看highchart自身提供的画图扩展方法 Renderer,只有了解了如何画图,我们才能在图表上绘制想要的图形,方法有如下几个,不清楚的可以上官网查看API传送门

  • arc() 用来画弧线图

    参数 (Number centerX, Number centerY, Number outerRadius, Number innerRadius, Number start, Number end)
    centerX和centerY分别对应x,y的坐标,outerRadius 外弧的半径,innerRadius内弧的半径,start和end 通常为 -Math.PI/2,-Math.PI,或者0 表示弧的方向 。

  • circle() 用来画圆形图

    参数(Number centerX, Number centerY, Number radius)
    centerX 表示x轴坐标,centerY表示y轴坐标,radius表示半径

  • g() 用来构建一个群组将元素包裹,参数只有一个 传入 名称即可

    渲染后会默认变成 “highcharts-“+ name

  • image() 用来嵌入一张图片

    参数(String source, Number x, Number y, Number width, Number height)
    source 图片路径,x,y为坐标,width和height为图片的宽和高

  • path() 用来画路径图

    这个方法参数稍微有点复杂,需要参考svg的一些路径命令 ,传统门

  • rect() 用来画区域方形图

    参数(Number x, Number y, Number width, Number height, Number cornerRadius)
    x,y分别为x和y轴坐标,width和height为所画区域的宽高,cornerRadius表示图形的圆角

  • text() 用来画文本字符
    参数 (String str, Number x, Number y)
    x,y分别为x和y轴坐标,str表示需要绘制的字符串文本

    查看更多

如何使用highmaps制作中国地图

带你走进 Highmaps ,本篇介绍highmap的基本用法

起初因为highmaps对中国地图的支持不够友好,没有台湾,澳门等,你懂的,政治问题。于是放弃了highmaps ,使用了echart的maps,毕竟国产功能也很齐全,但相比highmap,感觉echart相对比较臃肿,而且没有highmap流畅舒服。随着highmaps不断完善,highmaps已经解决了所谓的政治地域问题,特意为中国地图出了三个js版本。
China 、China with Hong Kong and Macau、China with Hong Kong, Macau, and Taiwan
先来个预览图:
全国地图

北京市地图展开详情

查看更多

highchart如何实现点击标题复制到剪切板

有人突然问我如何选中highchart图表的标题,然后复制到剪切板,我思考了一会,highchart图表是有svg构成的,借助于图表的事件功能就能获取到标题,甚至图表里的任何数据,那么如何复制到剪切板就是本次为大家要介绍的zClipZeroClipboard,这2者都能实现剪切的功能。

这里我就谈谈 highchartZeroClipboard 实现 图表的标题复制到剪切板

  • 需要借助ZeroClipboard.jsZeroClipboard.swf
  • 需要highchart 事件扩展的插件customEvents.js传送门

具体实现

  • ZeroClipboard的初始化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var client=null;
    function initClipboard() {
    client = new ZeroClipboard( document.getElementById("sp_title") );
    //client.clip(document.getElementById("d_clip_button"))
    client.on( "ready", function( readyEvent ) {
    client.on( "aftercopy", function( event ) {
    alert("您复制的内容为: " + event.data["text/plain"] );
    } );
    client.on( 'copy', function(event) {
    event.clipboardData.setData('text/plain',event.target.innerHTML);
    } );
    } );
    }

new ZeroClipboard() 需要指定需要绑定的DOM元素,图表的标题采用html格式,ID为 “sp_title”。setData() 是给 ZeroClipboard渲染出来的flash对象赋值,这里将点击对象的innerHTML赋值给了flash。ZeroClipboard.swf 需与 ZeroClipboard.js在同一个目录下,若不在同一个目录初始化时必须为ZeroClipboard 指定swf 路径。

ZeroClipboard 的详细介绍请参考官网 点击此处传送

  • highchart的初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    $('#chart').highcharts({
    title:{
    useHTML: true,
    text: '<span class="chart-title" id="sp_title">highchart自定义事件</span>',
    events: {
    dblclick: function () {
    //这里是双击事件
    },
    click: function () {
    //这里是标题的单击事件;
    },
    contextmenu: function () {
    //这里是标题的右击事件
    }
    }
    }
    });
  • 最后示意图
    点击标题复制到剪切板

如有不懂的,可以留言或者微博联系我!

EasyUI datagrid实现翻页客户端保存checkbox状态

1、首先设置datagrid属性的idField主键,这里假如为id,若idField为其他的,记住下面的代码里的 id也要做相应的修改。

2、建立一个全局的javascript数组var checkedItems = [],用来存放选中checkbox的值。

3、核心方法,addcheckItem()removeAllItem(rows)removeSingleItem(rowIndex, rowData)当选中或者取消checkbox时触发。

  用来将checkbox的主键值保存在checkedItems数组,或者从数组中删除对应的id值,findCheckedItem(ID)这个函数用来查找数组中是否存在checkbox的值,存在则返回id值,不存在则返回-1.

4、什么时候调用这些方法呢?分别在datagridonCheckAll: addcheckItem,onCheck: addcheckItem,onUncheckAll: removeAllItem,onUncheck: removeSingleItem 这四个事件中调用对应的方法。

5、翻页后如何给checkbox赋值呢?关键就在这里,datagrid重写了$.fn.datagrid.defaults.viewonAfterRender事件,因此在datagrid的view事件里绑定这个函数就OK了。onAfterRender事件是当easyui的元素渲染完毕后执行的事件,在这里会调用手写的 ischeckItem 函数来实现对checkbox的赋值!
  
下面为大家贴上实现的具体代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 $("#maingrid").datagrid({ 
idField: 'id',
view: fileview
});

var fileview = $.extend({}, $.fn.datagrid.defaults.view, { onAfterRender: function (target) { ischeckItem(); } });

var checkedItems = [];
function ischeckItem() {
for (var i = 0; i < checkedItems.length; i++) {
$('#maingrid').datagrid('selectRecord', checkedItems[i]); //根据id选中行
}
}

function findCheckedItem(ID) {
for (var i = 0; i < checkedItems.length; i++) {
if (checkedItems[i] == ID) return i;
}
return -1;
}

function addcheckItem() {
var row = $('#maingrid').datagrid('getChecked');
for (var i = 0; i < row.length; i++) {
if (findCheckedItem(row[i].id) == -1) {
checkedItems.push(row[i].id);
}
}
}
function removeAllItem(rows) {

for (var i = 0; i < rows.length; i++) {
var k = findCheckedItem(rows[i].id);
if (k != -1) {
checkedItems.splice(i, 1);
}
}
}
function removeSingleItem(rowIndex, rowData) {
var k = findCheckedItem(rowData.id);
if (k != -1) {
checkedItems.splice(k, 1);
}
}

下面是批量删除的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function destroyItems(items) {
var row = null;
if (items == "list") {
items = checkedItems.join(',');
row = $('#maingrid').datagrid('getSelections');
}
else {
row = items;
}
if (row != null) {
$.messager.confirm('Confirm', '您确定要删除此记录?', function (r) {
if (r) {
$.post(location.href, { id: items, action: "deletelist" }, function (result) {
if (result == "1") {
$('#maingrid').datagrid('reload');
} else {
$.messager.show({
title: 'Error',
msg: result
});
}
});
}
});
}
else { $.messager.alert('-警告-', '请选择至少一条记录才能进行删除', 'info'); }

}

一个小攻城师2014年的总结

今儿是2014的最后一天,我是不是要写点东西总结下自己呢?

2014年一路走过

对于一个北漂的人来说,唉,每年都TMD过的太快了,一线城市的生活就是这么快节奏,就是这么任性!还计划着今年要干什么干什么,却一晃就漂到年底了,猛的醒过来,“fuck,什么都没完成!于是有了下面一幅图的出现”

看完这个段子,大家是不是感觉趟枪了,o(∩_∩)o 哈哈,事实就是这个样子!


说点认真的吧,这年还是收获很多的。
工作上,掌握一些新的技术和一些编程理念,最重要的是自己由后台慢慢转变为一名前端攻城师,接触了angularjs前端框架,后端语言也由asp.net 转变成了 java,遇到问题更加冷静去思考去寻找解决问题的方案。总之呢,时间长了,会突然觉得所谓的大神,所谓的高手 不是他们的技术有多牛,不是他们的学历有多高,而是在工作中日积月累的解决问题的能力,慢慢培养出解决问题的思维方式和编程理念,当然我不否认在此基础之上需要夯实的基础知识!

在说说大部队吧,由开始的十几个人,由于各种原因,走了一批人,来了一批人,来不及感伤,来不及道别,只能快速融入新组建的团队中。然后嘻嘻嘻哈哈开始新产品的规划与开发。很幸运,大家相处很融洽和舒服,我们在朝着共同的目标奋斗着,希望有一天我们的产品能有越来越多的用户!

我呢,是一个不善言谈的人,在人际交际中,不喜欢阿谀奉承,不喜欢勾心斗角,不喜欢拍人马屁,喜欢较真,喜欢说大实话。说到这里,像我这种性格的人也许不适合在当今的社会中生存,更别说什么搞好层级关系,职位提升等等。但随着时间的流逝和自己意志力的流逝,自己总会被周遭所同化,你必须学会阿谀奉承、必须学会拍人马屁、必须学会掩饰自己,必须学会如何处理人际关系,我们必须扮演好在生活中、在工作中的角色,正如 《楚门的世界》 里所反应的,我们每个人都是生活中的演员!

查看更多

highchart 自定义事件插件

highchart 插件之自定义事件

下面是扩展插件的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
(function (HC) {
/*jshint expr:true, boss:true */
var UNDEFINED;
//reseting all events, fired by Highcharts
HC.Chart.prototype.callbacks.push(function (chart) {
var resetAxisEvents = chart.customEvent.resetAxisEvents,
series = chart.series,
serLen = series.length,
xAxis = chart.xAxis,
yAxis = chart.yAxis,
i = 0;

resetAxisEvents(xAxis, 'xAxis', chart);
resetAxisEvents(yAxis, 'yAxis', chart);

for (; i < serLen; i++) {
series[i].update({
customEvents: {
series: series[i].options.events,
point: series[i].options.point.events
},
events: {
click: null
},
point: {
events: {
click: null
}
}
},false);
}

chart.xAxis[0].isDirty = true;
chart.redraw();
});

//custom event body
var customEvent = HC.Chart.prototype.customEvent = function (obj, proto) {
customEvent.add = function (elem, events, obj) {
for (var key in events) {

(function (key) {
if (events.hasOwnProperty(key)) {
if(!elem[key] || elem[key] === UNDEFINED) {
HC.addEvent(elem.element, key, function (e) {
events[key].call(obj, e);
return false;
});
}

elem[key] = true;
}
})(key)

}
};

HC.Chart.prototype.customEvent.resetAxisEvents = function(axis, type, chart) {
var axisLength = axis.length,
userOptions = chart.userOptions,
i = 0,
j = 0,
redraw = false,
customEvents, plotBandsLength, plotLinesLength, plotLines, plotBands,cAxis;

for(;i<axisLength;i++) {

if(type === 'xAxis' && userOptions.xAxis !== UNDEFINED) {

cAxis = HC.splat(userOptions.xAxis);
plotLines = cAxis[i].plotLines;
plotBands = cAxis[i].plotBands;

} else if(type === 'yAxis' && userOptions.yAxis !== UNDEFINED) {

cAxis = HC.splat(userOptions.yAxis);
plotLines = cAxis[i].plotLines;
plotBands = cAxis[i].plotBands;
}

if(plotLines !== UNDEFINED) {
plotLinesLength = plotLines.length;

for(j=0;j<plotLinesLength;j++){
var t = plotLines[j].events;
if(t) {
plotLines[j].customEvents = t;
plotLines[j].events = null;
}
};

redraw = true;
}

if(plotBands !== UNDEFINED) {
plotBandsLength = plotBands.length;

for(j=0;j<plotBandsLength;j++) {
var t = plotBands[j].events;
if(t) {
plotBands[j].customEvents = t;
plotBands[j].events = null;
}
};

redraw = true;
}

if(redraw) {
chart.yAxis[i].update({
plotLines: plotLines,
plotBands: plotBands
},false);
}
};
};


HC.wrap(obj, proto, function (proceed) {
var events,
element,
eventsPoint,
elementPoint,
op;

//call default actions
proceed.apply(this, Array.prototype.slice.call(arguments, 1));

//switch on object
switch (proto) {
case 'addLabel':
events = this.axis.options.labels.events;
element = this.label;
break;
case 'setTitle':
events = this.options.title.events;
element = this.title;
break;
case 'drawDataLabels':
events = this.dataLabelsGroup ? this.options.dataLabels.events : null;
element = this.dataLabelsGroup ? this.dataLabelsGroup : null;
break;
case 'render':
if (this.axisTitle) {
events = this.options.title.events;
element = this.axisTitle;
}
if (this.options.value || this.options.from) {
events = this.options.customEvents;
element = this.svgElem;
}
break;
case 'drawPoints':
op = this.options;
events = op.customEvents ? op.customEvents.series : op,
element = this.group;
eventsPoint = op.customEvents ? op.customEvents.point : op.point.events;
elementPoint = this.points;
break;
case 'renderItem':
events = this.options.itemEvents;
element = this.group;
break;
}


if (events || eventsPoint) {

if (eventsPoint) {
var len = elementPoint.length
j = 0;

for (; j < len; j++) {
var elemPoint = elementPoint[j].graphic;

if (elementPoint[j].y && elemPoint !== UNDEFINED) {
customEvent.add(elemPoint, eventsPoint, elementPoint[j]);
}
}
}

customEvent.add(element, events, this);
}


});
};

//labels
customEvent(HC.Tick.prototype, 'addLabel');

//axis
//title
customEvent(HC.Axis.prototype, 'render');
//plotbands + plotlines
customEvent(HC.PlotLineOrBand.prototype, 'render');

//series events & point events
customEvent(HC.Series.prototype, 'drawPoints');
customEvent(HC.seriesTypes.column.prototype, 'drawPoints');
customEvent(HC.seriesTypes.pie.prototype, 'drawPoints');

//datalabels events
customEvent(HC.Series.prototype, 'drawDataLabels');
customEvent(HC.seriesTypes.column.prototype, 'drawDataLabels');
customEvent(HC.seriesTypes.pie.prototype, 'drawDataLabels');

//title events
customEvent(HC.Chart.prototype, 'setTitle');

//legend items
customEvent(HC.Legend.prototype, 'renderItem');

//bubble charts
if(HC.seriesTypes.bubble) {
customEvent(HC.seriesTypes.bubble.prototype, 'drawPoints');
customEvent(HC.seriesTypes.bubble.prototype, 'drawDataLabels');
}

})(Highcharts);

查看更多

highchart legend 可拖拽扩展

highchart 插件之legend 拖拽扩展

下面是扩展插件的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
(function (H) {
var addEvent = H.addEvent;

H.wrap(H.Chart.prototype, 'init', function (proceed) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));

var chart = this,
legend = chart.legend,
box = legend.box,
options = legend.options,
isDragging,
downX,
downY,
optionsX,
optionsY,
currentX,
currentY;
if (options.draggable) {
box.css({
cursor: 'move'
});
addEvent(box.element, 'mousedown', function (e) {
e = chart.pointer.normalize(e);
downX = e.chartX;
downY = e.chartY;
optionsX = options.x;
optionsY = options.y;
currentX = legend.group.attr('translateX');
currentY = legend.group.attr('translateY');
isDragging = true;
});
addEvent(chart.container, 'mousemove', function (e) {
if (isDragging) {
e = chart.pointer.normalize(e);
var draggedX = e.chartX - downX,
draggedY = e.chartY - downY;

options.x = optionsX + draggedX;
options.y = optionsY + draggedY;

// Do the move is we're inside the chart
if (currentX + draggedX > 0 && currentX + draggedX + legend.legendWidth < chart.chartWidth && currentY + draggedY > 0 && currentY + draggedY + legend.legendHeight < chart.chartHeight) {
legend.group.placed = false; // prevent animation
legend.group.align(H.extend({
width: legend.legendWidth,
height: legend.legendHeight
}, options), true, 'spacingBox');
}
if (chart.pointer.selectionMarker) {
chart.pointer.selectionMarker = chart.pointer.selectionMarker.destroy();
}

}
});
addEvent(document, 'mouseup', function () {
isDragging = false;
});
}
});
}(Highcharts));

前端初始化代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
$(function () {
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'line'
},
title: {
text: 'Highcharts Draggable Legend Demo'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
labels: {
zIndex: 6
}
},
yAxis: {
title: {
text: 'Temperature (°C)'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}],
labels: {
zIndex: 6
}
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y + '°C';
}
},
legend: {
layout: 'vertical',
backgroundColor: 'white',
align: 'right',
verticalAlign: 'top',
y: 165,
x: -220,
borderWidth: 1,
borderRadius: 5,

floating: true,
draggable: true,
zIndex: 20
},
series: [{
name: 'Tokyo',
data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
}, {
name: 'New York',
data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
}, {
name: 'Berlin',
data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
}, {
name: 'London',
data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
}]
});
});

效果图

demo在线预览