Chinaunix首页 | 论坛 | 博客
  • 博客访问: 569065
  • 博文数量: 109
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1987
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-15 22:39
个人简介

HT for Web 3D. HT for modern web and mobile app development. www.hightopo.com

文章分类

全部博文(109)

文章存档

2018年(28)

2017年(21)

2016年(10)

2015年(28)

2014年(19)

2013年(3)

我的朋友

分类: HTML5

2015-04-28 16:32:45

使用 HT for Web (以下简称 HT)开发有 Chart 需求的项目的时候,感觉很痛苦,HT 集成的 Chart 组件中,并不包含有坐标,在展现方面不是很直观,但是也不是没有解决方案,接下来我们就来聊聊具体的解决方案。

首先,第一种解决方案是,在定义 Chart 矢量的时候在 comps 中除了定义 Chart 外,再添加几个你自定义的绘制区域来绘制你想要的坐标轴,效果及 example 如下:


Chart 的定义代码见附录1(代码的定义太长),代码虽然长,但是代码的逻辑并不乱,各个模块间的矢量描述还是比较清晰的,具体可以参考 HT 的矢量手册,看到如此长的代码,我自己都没信心去维护它,维护这样的代码纯粹是体力活,而且复用性也不高,每一个不同的 Chart 都要类似如此地绘制,绘制一两个这样的图表感觉还好,绘制多了,真心会感觉很恶心,再这上面很浪费时间。

其次,第二种解决方案是,通过数据绑定来自定义绘制坐标轴。实现以上相同效果,其代码见附录2。可以明显看出其代码量会比第一种解决方案好很多,而且代码可以复用。在其他的图表中,可以将横轴和纵轴的文本内容设置到 data 的 attr 属性上,并在定义 chart 时使用上如下代码就可以实现坐标文本的效果:

点击(此处)折叠或打开

  1. ht.Default.setImage('chartName', {
  2.     width: Number,
  3.     height: Number,
  4.     comps: [
  5.         {
  6.             // define chart
  7.         },
  8.         {
  9.             type: 'xAxis',
  10.             rect: Array
  11.         },
  12.         {
  13.             type: 'yAxis',
  14.             rect: Array
  15.         }
  16.     ]
  17. });

在这里我已经通过 ht.Default.setCompType('typeName', function(g, rect, comp, data, view){}) 的方法定义了名字为 xAxis 和 yAxis 的 CompType,这两个 CompType 分别绘制了横轴和纵轴的坐标文本,代替了第一种方案制定多个 CompType 为 text 的写法,稍微优化了下代码,提高代码的可维护性。

但是,这样但使用方法总刚觉有些别扭,明明坐标轴是 Chart 的一部分,在定义 Chart 上却要硬生生地将图表和坐标部分分开,那如果用户还要在定义标题、坐标刻度、坐标说明等需求,那这个方案还是无法爽快的解决大部分通用的需求,需要定义许多 CompType 来渲染不同的需求,而且在使用上也不是那么爽快。接下来要说明的方案三,就是来解决使用上及维护上的问题。

最后,第三种解决方案是,和第二种解决方案差不多,都是通过 ht.Default.setCompType('typeName', function(g, rect, comp, data, view){}) 的方法来定义名字为 axisChart 的 CompType,不同的是,数据并不是设置到 data 中,而是在 ht.Default.setImage() 的 comps 中直接定义其相关属性。具体的配置属性说明及其具体的代码实现可以查看附件,使用方式很简单,在引入 ht.js 核心文件的前提下,引入附件的 axisChart.js 文件即可。

接下来来看下 axisChart 的具体使用及几个简单的例子:

例1:设计同一时刻不同小区之间的电流电压情况的柱状图柱状图:


代码如下:

点击(此处)折叠或打开

  1. ht.Default.setImage('c1', {
  2.     width: 600,
  3.     height: 400,
  4.     comps: [
  5.         {
  6.             type: 'axisChart',
  7.             rect: [0, 0, 600, 400],
  8.             yAxis: [
  9.                 {
  10.                     name: '单位:V',
  11.                     max: 270,
  12.                     min: 150,
  13.                     splitNumber: 10,
  14.                     axisTitle: {
  15.                         text: '电压',
  16.                         rotate: -90
  17.                     },
  18.                     axisLine: {
  19.                         arrow: true
  20.                     }
  21.                 },
  22.                 {
  23.                     position: 'right',
  24.                     name: '单位:I',
  25.                     max: 20,
  26.                     splitNumber: 20,
  27.                     axisTitle: {
  28.                         text: '电流',
  29.                         rotate: 90
  30.                     },
  31.                     axisLabel: {
  32.                         interval: 1
  33.                     },
  34.                     axisLine: {
  35.                         arrow: true
  36.                     }
  37.                 }
  38.             ],
  39.             xAxis: [
  40.                 {
  41.                     type: 'category',
  42.                     data: ['抚梅源', '藕花深处', '紫东花园', '紫金苑', '华府山水', '水云间', '瑞景新城'],
  43.                     axisTitle: {
  44.                         text: '小区名称'
  45.                     }
  46.                 }
  47.             ],
  48.             series: [
  49.                 {
  50.                     label: function(value){
  51.                         return value + ' V';
  52.                     },
  53.                     data: {
  54.                         values: [220, 210, 200, 209, 230, 215, 218],
  55.                         color: '#f90'
  56.                     }
  57.                 },
  58.                 {
  59.                     yAxisPosition: 'right',
  60.                     label: true,
  61.                     data: {
  62.                         values: [10, 4, 15, 9, 12, 18, 7],
  63.                         color: '#af0'
  64.                     }
  65.                 }
  66.             ]
  67.         }
  68.     ]
  69. });

例2: 不同时刻,不同小区的电压情况的折线图:


代码如下:

点击(此处)折叠或打开

  1. ht.Default.setImage('c2', {
  2.     width: 600,
  3.     height: 400,
  4.     comps: [
  5.         {
  6.             type: 'axisChart',
  7.             rect: [0, 0, 600, 400],
  8.             yAxis: [
  9.                 {
  10.                     name: '单位:V',
  11.                     max: 240,
  12.                     min: 190,
  13.                     splitNumber: 10,
  14.                     axisTitle: {
  15.                         text: '电压',
  16.                         rotate: -90
  17.                     },
  18.                     axisLine: {
  19.                         arrow: true
  20.                     }
  21.                 }
  22.             ],
  23.             xAxis: [
  24.                 {
  25.                     type: 'time',
  26.                     min: new Date(2015, 0, 1),
  27.                     max: new Date(2015, 0, 2),
  28.                     splitNumber: 25,
  29.                     axisTitle: {
  30.                         text: '时间'
  31.                     },
  32.                     axisLabel: {
  33.                         interval: 2,
  34.                         formatter: function(value, index, min, max){
  35.                             return value.format('dd-hh');
  36.                         }
  37.                     },
  38.                     axisLine: {
  39.                         arrow: true
  40.                     }
  41.                 }
  42.             ],
  43.             series: [
  44.                 {
  45.                     type: 'line',
  46.                     data: {
  47.                         values: [220, 210, 200, 209, 230, 215, 218, 220, 210, 200, 209, 230, 215, 218, 209, 230, 215, 218, 220, 210, 200, 209, 230, 215, 218],
  48.                         color: '#f90'
  49.                     }
  50.                 },
  51.                 {
  52.                     type: 'line',
  53.                     data: {
  54.                         values: [225, 209, 208, 206, 205, 221, 213, 224, 218, 224, 205, 208, 216, 220, 208, 210, 219, 219, 210, 209, 219, 207, 222, 222, 215],
  55.                         color: '#7d0'
  56.                     }
  57.                 },
  58.                 {
  59.                     type: 'line',
  60.                     linePoint: true,
  61.                     line3d: true,
  62.                     data: {
  63.                         values: [211, 216, 215, 205, 206, 206, 223, 217, 217, 215, 212, 221, 219, 222, 205, 208, 205, 218, 223, 222, 207, 215, 215, 222, 223],
  64.                         color: '#ab0'
  65.                     }
  66.                 }
  67.             ]
  68.         }
  69.     ]
  70. });

最后,还有一点要说明,axisChart 的代码并不是那么的无懈可击,我个人觉得代码设计上还是有些欠缺,所有的代码总共有差不多 1000 行,我觉得太臃肿了,在设计上自己也感觉不是那么的友好,等想修改的时候发现已经投入太多时间了,还有好多事情等待着我我去学习、去探讨,所以也就线这样吧,等有空了再重构一番,但是我相信在功能上还是能够满足大部分的需求,在设计上,或者是实现的方法上,还是在使用过程中发现的 bug,还望大家能够不吝赐教。

附录1

点击(此处)折叠或打开

  1. ht.Default.setImage('chart', {
  2.     width: 650,
  3.     height: 380,
  4.     comps: [
  5.         // column chart
  6.         {
  7.             type: 'columnChart',
  8.             rect: [10, 60, 630, 260],
  9.             label: true,
  10.             labelColor: '#20284C',
  11.             labelFont: '8px Arial',
  12.             series: [
  13.                 {
  14.                     color: '#20284C',
  15.                     values: [471, 482, 567, 525, 590, 637, 780, 679, 848]
  16.                 },
  17.                 {
  18.                     color: '#303F74',
  19.                     values: [275, 290, 361, 328, 346, 341, 440, 423, 505]
  20.                 },
  21.                 {
  22.                     color: '#7E93CD',
  23.                     values: [82, 104, 115, 118, 135, 154, 198, 197, 247]
  24.                 },
  25.                 {
  26.                     color: '#A9B6DB',
  27.                     values: [65, 78, 87, 87, 113, 130, 167, 159, 213]
  28.                 }
  29.             ]
  30.         },
  31.         // 竖线
  32.         {
  33.             type: 'rect',
  34.             rect: [15, 60, 1, 260],
  35.             background: '#566CB0'
  36.         },
  37.         {
  38.             type: 'shape',
  39.             rect: [5.5, 30, 20, 30],
  40.             borderWidth: 1,
  41.             borderColor: '#566CB0',
  42.             points: [0, 20 / 3 * 2, 20 / 2, 0, 20, 20 / 3 * 2, 20 / 2, 0, 20 / 2, 30],
  43.             segments: [1, 2, 2, 1, 2]
  44.         },
  45.         // 坐标文本
  46.         {
  47.             type: 'text',
  48.             rect: [0, 320 - 26 * 10 - 8, 15, 16],
  49.             align: 'right',
  50.             text: Math.round(84.8 * 10)
  51.         },
  52.         {
  53.             type: 'text',
  54.             rect: [0, 320 - 26 * 9 - 8, 15, 16],
  55.             align: 'right',
  56.             text: Math.round(84.8 * 9)
  57.         },
  58.         {
  59.             type: 'text',
  60.             rect: [0, 320 - 26 * 8 - 8, 15, 16],
  61.             align: 'right',
  62.             text: Math.round(84.8 * 8)
  63.         },
  64.         {
  65.             type: 'text',
  66.             rect: [0, 320 - 26 * 7 - 8, 15, 16],
  67.             align: 'right',
  68.             text: Math.round(84.8 * 7)
  69.         },
  70.         {
  71.             type: 'text',
  72.             rect: [0, 320 - 26 * 6 - 8, 15, 16],
  73.             align: 'right',
  74.             text: Math.round(84.8 * 6)
  75.         },
  76.         {
  77.             type: 'text',
  78.             rect: [0, 320 - 26 * 5 - 8, 15, 16],
  79.             align: 'right',
  80.             text: Math.round(84.8 * 5)
  81.         },
  82.         {
  83.             type: 'text',
  84.             rect: [0, 320 - 26 * 4 - 8, 15, 16],
  85.             align: 'right',
  86.             text: Math.round(84.8 * 4)
  87.         },
  88.         {
  89.             type: 'text',
  90.             rect: [0, 320 - 26 * 3 - 8, 15, 16],
  91.             align: 'right',
  92.             text: Math.round(84.8 * 3)
  93.         },
  94.         {
  95.             type: 'text',
  96.             rect: [0, 320 - 26 * 2 - 8, 15, 16],
  97.             align: 'right',
  98.             text: Math.round(84.8 * 2)
  99.         },
  100.         {
  101.             type: 'text',
  102.             rect: [0, 320 - 26 * 1 - 8, 15, 16],
  103.             align: 'right',
  104.             text: Math.round(84.8 * 1)
  105.         },
  106.         {
  107.             type: 'text',
  108.             rect: [0, 320 - 8, 15, 16],
  109.             align: 'right',
  110.             text: 0
  111.         },
  112.         // Q
  113.         {
  114.             type: 'text',
  115.             rect: [55, 322, 0, 16],
  116.             align: 'center',
  117.             text: 'Q2\'11'
  118.         },
  119.         {
  120.             type: 'text',
  121.             rect: [124, 322, 0, 16],
  122.             align: 'center',
  123.             text: 'Q3\'11'
  124.         },
  125.         {
  126.             type: 'text',
  127.             rect: [191, 322, 0, 16],
  128.             align: 'center',
  129.             text: 'Q4\'11'
  130.         },
  131.         {
  132.             type: 'text',
  133.             rect: [259, 322, 0, 16],
  134.             align: 'center',
  135.             text: 'Q1\'12'
  136.         },
  137.         {
  138.             type: 'text',
  139.             rect: [327, 322, 0, 16],
  140.             align: 'center',
  141.             text: 'Q2\'12'
  142.         },
  143.         {
  144.             type: 'text',
  145.             rect: [394, 322, 0, 16],
  146.             align: 'center',
  147.             text: 'Q3\'12'
  148.         },
  149.         {
  150.             type: 'text',
  151.             rect: [462, 322, 0, 16],
  152.             align: 'center',
  153.             text: 'Q4\'12'
  154.         },
  155.         {
  156.             type: 'text',
  157.             rect: [529, 322, 0, 16],
  158.             align: 'center',
  159.             text: 'Q1\'13'
  160.         },
  161.         {
  162.             type: 'text',
  163.             rect: [596, 322, 0, 16],
  164.             align: 'center',
  165.             text: 'Q2\'13'
  166.         },
  167.         // line
  168.         {
  169.             type: 'rect',
  170.             rect: [15, 320, 620, 1],
  171.             background: '#566CB0'
  172.         },
  173.         {
  174.             type: 'shape',
  175.             rect: [635, 310.5, 30, 20],
  176.             borderWidth: 1,
  177.             borderColor: '#566CB0',
  178.             points: [20 / 3 * 2, 0, 30, 20 / 2, 20 / 3 * 2, 20, 30, 20 / 2, 0, 20 / 2],
  179.             segments: [1, 2, 2, 1, 2]
  180.         }
  181.     ]
  182. });

附录2

点击(此处)折叠或打开

  1. ht.Default.setCompType('yAxis', function(g, rect, comp, data, view) {
  2.     var labels = data.a('yLabels'),
  3.             len = labels.length,
  4.             x = rect.x,
  5.             y = rect.y,
  6.             w = rect.width,
  7.             h = rect.height,
  8.             dh = h / (len - 1);
  9.     g.save();
  10.     g.font = '12px arial, sans-serif';
  11.     g.fillStyle = 'black';
  12.     g.textAlign = 'right';
  13.     for(var i = 0; i < len; i++){
  14.         g.fillText(labels[i], x, y);
  15.         y += dh;
  16.     }
  17.     g.restore();
  18. });

  19. ht.Default.setCompType('xAxis', function(g, rect, comp, data, view) {
  20.     var labels = data.a('xLabels'),
  21.             len = labels.length,
  22.             x = rect.x,
  23.             y = rect.y,
  24.             w = rect.width,
  25.             h = rect.height,
  26.             dw = w / (len * 3 + 1),
  27.             dw3 = 3 * dw;
  28.     x += dw * 2;
  29.     g.save();
  30.     g.font = '12px arial, sans-serif';
  31.     g.fillStyle = 'black';
  32.     g.textAlign = 'center';
  33.     for(var i = 0; i < len; i++){
  34.         g.fillText(labels[i], x, y);
  35.         x += dw3;
  36.     }
  37.     g.restore();
  38. });

  39. ht.Default.setImage('chart1', {
  40.     width: 650,
  41.     height: 380,
  42.     comps: [
  43.         // column chart
  44.         {
  45.             type: 'columnChart',
  46.             rect: [10, 60, 630, 260],
  47.             label: true,
  48.             labelColor: '#20284C',
  49.             labelFont: '8px Arial',
  50.             series: [
  51.                 {
  52.                     color: '#20284C',
  53.                     values: [471, 482, 567, 525, 590, 637, 780, 679, 848]
  54.                 },
  55.                 {
  56.                     color: '#303F74',
  57.                     values: [275, 290, 361, 328, 346, 341, 440, 423, 505]
  58.                 },
  59.                 {
  60.                     color: '#7E93CD',
  61.                     values: [82, 104, 115, 118, 135, 154, 198, 197, 247]
  62.                 },
  63.                 {
  64.                     color: '#A9B6DB',
  65.                     values: [65, 78, 87, 87, 113, 130, 167, 159, 213]
  66.                 }
  67.             ]
  68.         },
  69.         // 竖线
  70.         {
  71.             type: 'rect',
  72.             rect: [15, 60, 1, 260],
  73.             background: '#566CB0'
  74.         },
  75.         // 向上的箭头
  76.         {
  77.             type: 'shape',
  78.             rect: [5.5, 30, 20, 30],
  79.             borderWidth: 1,
  80.             borderColor: '#566CB0',
  81.             points: [0, 20 / 3 * 2, 20 / 2, 0, 20, 20 / 3 * 2, 20 / 2, 0, 20 / 2, 30],
  82.             segments: [1, 2, 2, 1, 2]
  83.         },
  84.         // 坐标文本
  85.         {
  86.             type: 'yAxis',
  87.             rect: [12, 60, 15, 260]
  88.         },
  89.         // Q
  90.         {
  91.             type: 'xAxis',
  92.             rect: [10, 330, 630, 16]
  93.         },
  94.         // line
  95.         {
  96.             type: 'rect',
  97.             rect: [15, 320, 620, 1],
  98.             background: '#566CB0'
  99.         },
  100.         // 向右的箭头
  101.         {
  102.             type: 'shape',
  103.             rect: [635, 310.5, 30, 20],
  104.             borderWidth: 1,
  105.             borderColor: '#566CB0',
  106.             points: [20 / 3 * 2, 0, 30, 20 / 2, 20 / 3 * 2, 20, 30, 20 / 2, 0, 20 / 2],
  107.             segments: [1, 2, 2, 1, 2]
  108.         }
  109.     ]
  110. });
阅读(1715) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册