diff --git a/README.md b/README.md index f6f126a..1ea40a8 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,116 @@ -# wx-charts -微信小程序图表工具,charts for WeChat small app +# `重要通知:本项目已停止在github更新,转至码云平台` +# `重要通知:本项目已停止在github更新,转至码云平台` +# `重要通知:本项目已停止在github更新,转至码云平台` -基于canvas绘制,体积小巧 +# [码云平台开源地址](https://gitee.com/uCharts/uCharts) -**持续优化更新中,请保持关注~ 有任何问题欢迎在[Issues](https://github.com/xiaolin3303/wx-charts/issues)中讨论,[提出issue前请先阅读此须知](https://github.com/xiaolin3303/wx-charts/issues/67)** +# [uCharts官方网站](https://www.ucharts.cn) +- https://www.ucharts.cn -# 支持图表类型 -- 饼图 `pie` -- 圆环图 `ring` -- 线图 `line` -- 柱状图 `column` -- 区域图 `area` -- 雷达图 `radar` - -代码分析 [Here](https://segmentfault.com/a/1190000007649376) - -# 更新记录 - -- [ ] 动画性能优化 -- [x] 图表滚动的支持,感谢[@jxintang](https://github.com/jxintang) -- [x] [优化曲线绘制](https://github.com/xiaolin3303/wx-charts/issues/79) -- [x] 新增雷达图 2017-03-17 -- [x] 新增tooltip 2017-03-07 -- [x] 新增曲线的绘制 2017-03-06 -- [x] 新增更新数据、终止进行中的动画方法,渲染完成事件回调 2017-02-17 -- [x] 新增圆环图title, subtitle 2017-01-10 -- [x] x轴文案碰撞避让 2016-12-30 -- [x] add pie chart dataLabel 2016-12-19 -- [x] add animation 2016-12-05 -- [x] build with `rollup` 2016-12-02 -- [x] add legend 2016-11-29 +# [在线文档](http://doc.ucharts.cn) -# 如何使用 -1、直接引用编译好的文件 `dist/wxcharts.js` 或者 `dist/wxcharts-min.js` -2、自行编译 +## QQ交流群:371774600 +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/QQqrcode.png?raw=true) -``` -git clone https://github.com/xiaolin3303/wx-charts.git -npm install rollup -g -npm install -rollup -c 或者 rollup --config rollup.config.prod.js -``` -[实际项目中如何具体使用wx-charts](https://github.com/xiaolin3303/wx-charts/issues/28) 或者 访问[wx-charts-demo](https://github.com/xiaolin3303/wx-charts-demo)查看在微信开发工具中直接运行的例子 -# 参数说明 -[参数说明 - wxCharts使用文档](https://github.com/xiaolin3303/wx-charts/issues/56) +## 快速体验 -# 方法 & 事件 +一套代码编到7个平台,依次扫描二维码,亲自体验uCharts图表跨平台效果! -[方法 & 事件 - wxCharts使用说明](https://github.com/xiaolin3303/wx-charts/issues/57) +IOS因demo比较简单无法上架,请自行编译。 -# Example +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/qrcode.png?raw=true) -![pieChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/pie.png) -![ringChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/ring.png) -![lineChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/line.png) -![curveLineChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/4636c9d2fbbaaa7944ee48e02b3a595e77c099e5/example/curve-line.png) -![columnChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/column.png) -![areaChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/area.png) -![areaChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/radar.png) -![pieChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/pie.gif) -![ringChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/ring.gif) -![lineChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/line.gif) -![columnChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/column.gif) -![areaChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/area.gif) -![tooltip](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/tooltip.gif) -![scrollLineChart](https://raw.githubusercontent.com/xiaolin3303/wx-charts/master/example/scrollLine.gif) +## [更新记录](https://www.kancloud.cn/qiun/ucharts/content/%E6%9B%B4%E6%96%B0%E8%AE%B0%E5%BD%95.md) -更多内容请查看[Example - wxCharts使用说明](https://github.com/xiaolin3303/wx-charts/issues/58) -# 测试 -1. iPhone 6s, IOS 9.3.5 -2. 小米4, ANDORID 6.0.1 +## 支持图表类型 +- 饼图 `pie` +- 圆环图 `ring` +- 线图 `line`(直线、曲线) +- 柱状图 `column`(分组、堆叠、温度计) +- 区域图 `area`(直线、曲线) +- 雷达图 `radar` +- 圆弧进度图 `arcbar` +- 仪表盘 `gauge` +- K线图 `candle`(完善中) +- 条状图 `bar`(开发中) +- 混合图 `mix`(支持point、line直线曲线、column、area直线曲线) + + +## 插件特点 +- 改造后的插件可以跨端使用,支持H5、小程序(微信/支付宝/百度/头条)、APP,调用简单方便、性能及体验极佳。 +- 虽然没有Echarts及F2图表功能强大,但可以实现一套业务逻辑各端通用,并解决了支付宝小程序图表显示模糊等问题。 +- 支持单页面多图表,demo中单页10个图表,响应速度超快。 +- 支持入场动画及ToolTip动画效果。 +- 独特支持`横屏模式`感谢`masterLi`提供需求。 + +## 为何不用Echarts? +- 相比Echarts及F2的复杂的设置,本插件几乎等于傻瓜式的配置。 +- Echarts在跨端使用更复杂,本插件只需要简单的两个``标签轻松区别搞定,代码整洁易维护。 +- Echarts在IOS端图表显示错位,只能引用网页解决。 +- 本插件打包后的体积相比Echarts小很多很多,所以性能更好。 +- 如果您是uni-app初学者,那么强烈建议您使用uCharts,并且目前可以跨全端通用,减少工作量,增强一致性体验。 +- 图表样式均可自定义,懂js的都可以读懂插件源码,直接修改wxcharts.js源码即可。 +- 本插件经过大量测试,反复论证并加以改造而成,请各位放心使用。 + +## uni-app图表选型参考流程 + +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/xuanxing.png?raw=true) + +## 亲手教您如何改造uCharts,打造您的专属图表 +- 为何要改造uCharts? +- 并不是所有图表插件直接拿来就可以满足客户需求,如果您的UI设计师设计一个图表,如下图: + +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/example.gif?raw=true) + +- 您会发现这个图表即使在echarts里也不是很好实现,那么就需要我们自己动手去实现。下面就让我们一起来完成,本文旨在抛砖引玉,希望各位朋友能够更好的应用uCharts来完成您的项目,如果您有更好的设计,请提交您的PR到github[uCharts跨端图表](https://github.com/16cheng/uCharts),帮助更多朋友,感谢您的付出及贡献! + +## 图表示例 +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/stack.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/meter.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/mix.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/mix2.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/candle.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/yibiaopan.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/arcbar.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/column.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/column2.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/lineA.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/lineA-scroll.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/dashLine.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/area.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/pie.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/ring.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/radar.gif?raw=true) +![](https://github.com/16cheng/uCharts/blob/master/example/uni-app/static/lineB.gif?raw=true) + +## 常见问题 + +各位遇到问题请先参考以下问题,如果仍不能解决,请留言。 + +### 通用问题 +- 如果用在您的项目上图表不显示,请先运行demo页面,如果demo页面也无法显示,请查看全局样式是否定义了`canvas的样式`,如有请取消。 +- 如发现实例化图表后,`客户端卡死`的状况,请在实例化图表前(即调用`showColumn(canvasId,chartData)`前)检查传入图表数组(`chartData.categories`和`chartData.series`)是否为空,如果为空则不要实例化图表。后续将在源码中解决此问题。 +- 图表`背景颜色`问题,很多朋友设置图表背景颜色时候,只修改了view和canvas的css,忘记了修改实例化参数中的`background:'#FFFFFF'`,导致图表画板右侧有一道白条(这个是图表配置中的右边距),所以特修改了demo中的`柱状图`的背景颜色供大家参考。 + +### 支付宝、百度、头条问题 +- 在高分屏模式下,如果发现图表已显示,但位置不正确,请检查上级`view`容器的`样式`,为了解决高分屏canvas模糊问题,使用了css的`transform`,所以请修改上级样式使canvas容器缩放至相应位置。 +- 如果将canvas放在多级组件下,遇到ToolTip不显示或点击区域不正确,请在`touch`事件中增加以下代码解决。 +```javascript +//#ifdef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO +e.mp.currentTarget.offsetTop+=uni.upx2px(510); +//#endif +``` +> `uni.upx2px(510);`是canvas组件的上级组件的高度 -兼容性问题请在[Issue](https://github.com/xiaolin3303/wx-charts/issues)中提出 +### 组件问题 +- 很多小伙伴们自行把本插件做成组件来调用,做成组件需要注意,如果涉及到v-if切换显示图表组件,第二次可能会变空白,这里有两个建议: +1、建议用v-show替代v-if切换显示图表组件。 +2、建议参考demo,不要将canvas做到组件里使用,即直接写在主页面中。 +### 初步解决`组件内使用问题`,感谢`342805357@qq.com`提出组件问题解决方案,增加`opts.$this`参数,组件使用时实例化前请传递this。后续会增加组件使用示例,请关注。 -# 一些问题的说明汇总 -- [wx-charts自适应屏幕宽度的问题](https://github.com/xiaolin3303/wx-charts/issues/4) -- [项目中如何具体使用wxCharts](https://github.com/xiaolin3303/wx-charts/issues/28) +# `支付宝小程序IDE中不显示,但运行到真机是可以显示的,请真机测试。` diff --git a/dist/wxcharts.js b/dist/u-charts.js similarity index 53% rename from dist/wxcharts.js rename to dist/u-charts.js index e2fb996..30a2753 100644 --- a/dist/wxcharts.js +++ b/dist/u-charts.js @@ -1,10 +1,40 @@ /* - * charts for WeChat small app v1.0 - * - * https://github.com/xiaolin3303/wx-charts - * 2016-11-28 - * - * Designed and built with all the love of Web + * uCharts v1.6.9 + * uni-app平台高性能跨全端图表 + * 支持H5、APP、小程序(微信/支付宝/百度/头条) + * Designed by QIUN秋云 + * + * uCharts官方网站 + * https://www.uCharts.cn + * + * 开源地址: + * https://github.com/16cheng/uCharts + * 开源地址即将变更为: + * https://gitee.com/qiuyunkeji/uCharts + * 开源协议变更为Apache-2.0 + * + * uni-app插件市场地址: + * http://ext.dcloud.net.cn/plugin?id=271 + * + * 主要更新记录 + * 2019-04-01 + * 改造为兼容uni-app的uCharts + * 2019-04-14 + * 支持支付宝/百度/头条小程序实现跨全端 + * 2019-04-15 + * 支持横屏模式,新增rotate参数,默认flase + * 2019-04-16 + * 新增圆弧进度图,图表类型arcbar + * 2019-04-22 + * 修改图表拖拽功能跨端支持,增加拖拽时显示滚动条 + * 2019-04-28 + * 新增柱状图自定义颜色 + * 2019-05-01 + * 新增仪表盘图 + * 2019-05-14 + * 新增K线图 + * + * */ 'use strict'; @@ -17,12 +47,15 @@ var config = { legendHeight: 15, yAxisTitleWidth: 15, padding: 12, + pixelRatio:1,//适配H5高分屏 + rotate:false,//横屏模式 columePadding: 3, - fontSize: 10, - dataPointShape: ['diamond', 'circle', 'triangle', 'rect'], - colors: ['#7cb5ec', '#f7a35c', '#434348', '#90ed7d', '#f15c80', '#8085e9'], - pieChartLinePadding: 25, - pieChartTextPadding: 15, + fontSize: 13, + //dataPointShape: ['diamond', 'circle', 'triangle', 'rect'], + dataPointShape: ['circle', 'circle', 'circle', 'circle'],//仿F2图例样式改为圆点 + colors: ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d'], + pieChartLinePadding: 15, + pieChartTextPadding: 5, xAxisTextPadding: 3, titleColor: '#333333', titleFontSize: 20, @@ -31,9 +64,10 @@ var config = { toolTipPadding: 3, toolTipBackground: '#000000', toolTipOpacity: 0.7, - toolTipLineHeight: 14, + toolTipLineHeight: 20, radarGridCount: 3, - radarLabelTextMargin: 15 + radarLabelTextMargin: 15, + gaugeLabelTextMargin:15 }; // Object.assign polyfill @@ -95,6 +129,19 @@ var util = { } }; +// hex 转 rgba +function hexToRgb(hexValue, opc) { + var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + var hex = hexValue.replace(rgx, function (m, r, g, b) { + return r + r + g + g + b + b; + }); + var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + var r = parseInt(rgb[1], 16); + var g = parseInt(rgb[2], 16); + var b = parseInt(rgb[3], 16); + return 'rgba(' + r + ',' + g + ',' + b + ',' + opc + ')'; +} + function findRange(num, type, limit) { if (isNaN(num)) { throw new Error('[wxCharts] unvalid series data!'); @@ -260,6 +307,15 @@ function fillSeriesColor(series, config) { }); } +function fillSeriesType(series, opts) { + return series.map(function (item) { + if (!item.type) { + item.type = opts.type; + } + return item; + }); +} + function getDataRange(minData, maxData) { var limit = 0; var range = maxData - minData; @@ -285,9 +341,10 @@ function getDataRange(minData, maxData) { } function measureText(text) { - var fontSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10; + var fontSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : config.fontSize; // wx canvas 未实现measureText方法, 此处自行实现 + // 适配修改初始字体10px为其他大小的方法 text = String(text); var text = text.split(''); var width = 0; @@ -312,7 +369,7 @@ function measureText(text) { width += 10; } }); - return width * fontSize / 10; + return width * fontSize / 10 ; } function dataCombine(series) { @@ -321,6 +378,43 @@ function dataCombine(series) { }, []); } +function dataCombineStack(series) { + var sum = new Array(series[0].data.length); + for(var j = 0; j < sum.length; j++) { + sum[j] =0; + } + for(var i = 0; i < series.length; i++) { + for(var j = 0; j < sum.length; j++) { + sum[j] += series[i].data[j]; + } + } + return series.reduce(function (a, b) { + return (a.data ? a.data : a).concat(b.data).concat(sum); + }, []); +} + +function getTouches(touches, opts, e){ + let x,y; + if(touches.clientX){ + if(opts.rotate){//适配横屏 + y = opts.height-touches.clientX*opts.pixelRatio; + x = (touches.pageY-e.mp.currentTarget.offsetTop-(opts.height/opts.pixelRatio/2)*(opts.pixelRatio-1))*opts.pixelRatio; + }else{ + x = touches.clientX*opts.pixelRatio; + y = (touches.pageY-e.mp.currentTarget.offsetTop-(opts.height/opts.pixelRatio/2)*(opts.pixelRatio-1))*opts.pixelRatio; + } + }else{ + if(opts.rotate){//适配横屏 + y = opts.height-touches.x*opts.pixelRatio; + x = touches.y*opts.pixelRatio; + }else{ + x = touches.x*opts.pixelRatio; + y = touches.y*opts.pixelRatio; + } + } + return{x:x,y:y} +} + function getSeriesDataItem(series, index) { var data = []; series.forEach(function (item) { @@ -336,8 +430,6 @@ function getSeriesDataItem(series, index) { return data; } - - function getMaxTextListLength(list) { var lengthList = list.map(function (item) { return measureText(item); @@ -385,9 +477,71 @@ function getToolTipData(seriesData, calPoints, index, categories) { return { textList: textList, offset: offset }; } +function getCandleToolTipData(series,seriesData, calPoints, index, categories,extra) { + var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {}; + let upColor = extra.color.upFill; + let downColor = extra.color.downFill; + //颜色顺序为开盘,收盘,最低,最高 + let color=[upColor,upColor,downColor,upColor]; + var textList = []; + let text0={ + text: categories[index], + color: null + }; + textList.push(text0); + seriesData.map(function (item) { + //console.log(color) + if(index==0 && item.data[1]-item.data[0]<0){ + color[1]=downColor; + }else{ + if(item.data[0]series[index-1][1]){ + color[2]=upColor; + } + if(item.data[3] 4 && arguments[4] !== undefined ? arguments[4] : 0; - var currentIndex = -1; if (isInExactChartArea(currentPoints, opts, config)) { xAxisPoints.forEach(function (item, index) { @@ -493,9 +647,10 @@ function calLegendData(series, opts, config) { legendHeight: 0 }; } - var padding = 5; - var marginTop = 8; - var shapeWidth = 15; + //适配H5高分屏 + var padding = 5*opts.pixelRatio; + var marginTop = 8*opts.pixelRatio; + var shapeWidth = 15*opts.pixelRatio; var legendList = []; var widthCount = 0; var currentRow = []; @@ -535,14 +690,14 @@ function calCategoriesData(categories, opts, config) { var categoriesTextLenth = categories.map(function (item) { return measureText(item); }); - + var maxTextLength = Math.max.apply(this, categoriesTextLenth); - if (maxTextLength + 2 * config.xAxisTextPadding > eachSpacing) { + if (opts.xAxis.rotateLabel==true && maxTextLength + 2 * config.xAxisTextPadding > eachSpacing) { result.angle = 45 * Math.PI / 180; result.xAxisHeight = 2 * config.xAxisTextPadding + maxTextLength * Math.sin(result.angle); } - + return result; } @@ -594,6 +749,75 @@ function getPieDataPoints(series) { return series; } +function getArcbarDataPoints(series,arcbarOption) { + var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + if(process==1){ + process=0.999999; + } + series.forEach(function (item) { + item.data = item.data === null ? 0 : item.data; + let totalAngle; + if(arcbarOption.type=='default'){ + totalAngle=arcbarOption.startAngle-arcbarOption.endAngle+1; + }else{ + totalAngle=2; + } + item._proportion_ = totalAngle * item.data* process + arcbarOption.startAngle; + if (item._proportion_ >= 2) { + item._proportion_ = item._proportion_ % 2; + } + }); + return series; +} + +function getGaugeAxisPoints(categories,startAngle,endAngle) { + let totalAngle=startAngle-endAngle+1; + let tempStartAngle=startAngle; + for(let i=0 ; i= 2) { + categories[i]._endAngle_ = categories[i]._endAngle_ % 2; + } + tempStartAngle=categories[i]._endAngle_; + } + return categories; +} + +function getGaugeDataPoints(series,categories,gaugeOption) { + var process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1; + series.forEach(function (item) { + item.data = item.data === null ? 0 : item.data; + if(gaugeOption.pointer.color=='auto'){ + for(let i=0 ;i=gaugeOption.oldData){ + item._proportion_ = (item._endAngle_-item._oldAngle_)* process+gaugeOption.oldAngle; + }else{ + item._proportion_ =item._oldAngle_- (item._oldAngle_-item._endAngle_)* process; + } + if (item._proportion_ >= 2) { + item._proportion_ = item._proportion_ % 2; + } + }); + return series; +} + + function getPieTextMaxLength(series) { series = getPieDataPoints(series); var maxLength = 0; @@ -626,10 +850,47 @@ function fixColumeData(points, eachSpacing, columnLen, index, config, opts) { }); } +function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) { + return points.map(function (item) { + if (item === null) { + return null; + } + item.width = eachSpacing - 2 * config.columePadding; + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } else { + item.width = Math.min(item.width, 25); + } + if(index>0){ + item.width -= 2*border; + } + return item; + }); +} + +function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts,series) { + + return points.map(function (item,indexn) { + + if (item === null) { + return null; + } + item.width = eachSpacing - 2 * config.columePadding; + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } else { + item.width = Math.min(item.width, 25); + } + return item; + }); +} + function getXAxisPoints(categories, opts, config) { var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth; var spacingValid = opts.width - 2 * config.padding - yAxisTotalWidth; - var dataCount = opts.enableScroll ? Math.min(5, categories.length) : categories.length; + var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length; var eachSpacing = spacingValid / dataCount; var xAxisPoints = []; @@ -647,6 +908,32 @@ function getXAxisPoints(categories, opts, config) { return { xAxisPoints: xAxisPoints, startX: startX, endX: endX, eachSpacing: eachSpacing }; } +function getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) { + var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1; + + var points = []; + var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + data.forEach(function (item, index) { + if (item === null) { + points.push(null); + } else { + var cPoints = []; + item.forEach(function (items, indexs) { + var point = {}; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + var value = items.value || items; + var height = validHeight * (value - minRange) / (maxRange - minRange); + height *= process; + point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding; + cPoints.push(point); + }); + points.push(cPoints); + } + }); + + return points; +} + function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) { var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1; @@ -657,8 +944,10 @@ function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, points.push(null); } else { var point = {}; + point.color = item.color; point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); - var height = validHeight * (item - minRange) / (maxRange - minRange); + var value = item.value || item; + var height = validHeight * (value - minRange) / (maxRange - minRange); height *= process; point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding; points.push(point); @@ -668,16 +957,92 @@ function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, return points; } -function getYAxisTextList(series, opts, config) { - var data = dataCombine(series); +function getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,seriesIndex, stackSeries) { + var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1; + var points = []; + var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + + data.forEach(function (item, index) { + if (item === null) { + points.push(null); + } else { + var point = {}; + point.color = item.color; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + + if(seriesIndex>0){ + var value=0; + for(let i=0;i<=seriesIndex;i++){ + value+=stackSeries[i].data[index]; + } + var value0 = value-item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + var height0 = validHeight * (value0 - minRange) / (maxRange - minRange); + }else{ + var value = item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + var height0 = 0; + } + var heightc=height0; + height *= process; + heightc *= process; + point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding; + point.y0 = opts.height - config.xAxisHeight - config.legendHeight - Math.round(heightc) - config.padding; + points.push(point); + } + }); + + return points; +} + +function getYAxisTextList(series, opts, config ,stack) { + var data; + if(stack=='stack'){ + //data = dataCombine(series); + data = dataCombineStack(series); + }else{ + data = dataCombine(series); + } + + var sorted = []; // remove null from data data = data.filter(function (item) { - return item !== null; + //return item !== null; + if(typeof item === 'object' && item !== null) { + //判断是否为数组 + if(item.constructor == Array){ + return item !== null; + }else{ + return item.value !== null; + } + } else { + return item !== null; + } }); - var minData = Math.min.apply(this, data); - var maxData = Math.max.apply(this, data); + //var minData = Math.min.apply(this, data); + //var maxData = Math.max.apply(this, data); + data.map((item)=>{ + if(typeof item === 'object') { + if(item.constructor == Array){ + item.map((subitem)=>{ + sorted.push(subitem); + }) + }else{ + sorted.push(item.value); + } + } else { + sorted.push(item); + } + //typeof item === 'object' ? sorted.push(item.value) : sorted.push(item) + }) + var minData = 0; + var maxData = 0; + if(sorted.length>0){ + minData = Math.min.apply(this, sorted); + maxData = Math.max.apply(this, sorted); + } if (typeof opts.yAxis.min === 'number') { - minData = Math.min(opts.yAxis.min, minData); + minData = Math.min(opts.yAxis.min, minData); } if (typeof opts.yAxis.max === 'number') { maxData = Math.max(opts.yAxis.max, maxData); @@ -685,8 +1050,8 @@ function getYAxisTextList(series, opts, config) { // fix issue https://github.com/xiaolin3303/wx-charts/issues/9 if (minData === maxData) { - var rangeSpan = maxData || 1; - minData -= rangeSpan; + var rangeSpan = maxData || 10; + //minData -= rangeSpan; maxData += rangeSpan; } @@ -704,8 +1069,10 @@ function getYAxisTextList(series, opts, config) { } function calYAxisData(series, opts, config) { - - var ranges = getYAxisTextList(series, opts, config); + //堆叠图重算Y轴 + var columnstyle=assign({},opts.extra.column||{"type":""}); + + var ranges = getYAxisTextList(series, opts, config, columnstyle.type); var yAxisWidth = config.yAxisWidth; var rangesFormat = ranges.map(function (item) { item = util.toFixed(item, 2); @@ -720,12 +1087,11 @@ function calYAxisData(series, opts, config) { return { rangesFormat: rangesFormat, ranges: ranges, yAxisWidth: yAxisWidth }; } -function drawPointShape(points, color, shape, context) { +function drawPointShape(points, color, shape, context,opts) { context.beginPath(); context.setStrokeStyle("#ffffff"); - context.setLineWidth(1); + context.setLineWidth(1*opts.pixelRatio); context.setFillStyle(color); - if (shape === 'diamond') { points.forEach(function (item, index) { if (item !== null) { @@ -739,8 +1105,8 @@ function drawPointShape(points, color, shape, context) { } else if (shape === 'circle') { points.forEach(function (item, index) { if (item !== null) { - context.moveTo(item.x + 3.5, item.y); - context.arc(item.x, item.y, 4, 0, 2 * Math.PI, false); + context.moveTo(item.x + 3.5*opts.pixelRatio, item.y); + context.arc(item.x, item.y, 4*opts.pixelRatio, 0, 2 * Math.PI, false); } }); } else if (shape === 'rect') { @@ -760,6 +1126,8 @@ function drawPointShape(points, color, shape, context) { } }); } + + context.closePath(); context.fill(); context.stroke(); @@ -778,21 +1146,21 @@ function drawRingTitle(opts, config, context) { if (subtitle) { var textWidth = measureText(subtitle, subtitlefontSize); var startX = (opts.width - textWidth) / 2 + (opts.subtitle.offsetX || 0); - var startY = (opts.height - config.legendHeight + subtitlefontSize) / 2; + var startY = ((opts.height - config.legendHeight + subtitlefontSize) / 2 )+ (opts.subtitle.offsetY || 0); if (title) { - startY -= (titleHeight + margin) / 2; + startY -= (titleHeight + margin) / 2 ; } context.beginPath(); context.setFontSize(subtitlefontSize); context.setFillStyle(subtitleFontColor); context.fillText(subtitle, startX, startY); - context.stroke(); context.closePath(); + context.stroke(); } if (title) { var _textWidth = measureText(title, titlefontSize); var _startX = (opts.width - _textWidth) / 2 + (opts.title.offsetX || 0); - var _startY = (opts.height - config.legendHeight + titlefontSize) / 2; + var _startY = ((opts.height - config.legendHeight + titlefontSize) / 2 ) + (opts.title.offsetY || 0); if (subtitle) { _startY += (subtitleHeight + margin) / 2; } @@ -800,8 +1168,8 @@ function drawRingTitle(opts, config, context) { context.setFontSize(titlefontSize); context.setFillStyle(titleFontColor); context.fillText(title, _startX, _startY); - context.stroke(); context.closePath(); + context.stroke(); } } @@ -809,25 +1177,62 @@ function drawPointText(points, series, config, context) { // 绘制数据文案 var data = series.data; - context.beginPath(); - context.setFontSize(config.fontSize); - context.setFillStyle('#666666'); + points.forEach(function (item, index) { if (item !== null) { - var formatVal = series.format ? series.format(data[index]) : data[index]; + //var formatVal = series.format ? series.format(data[index]) : data[index]; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle('#666666'); + var value = data[index].value || data[index] + var formatVal = series.format ? series.format(value) : value; context.fillText(formatVal, item.x - measureText(formatVal) / 2, item.y - 2); + context.closePath(); + context.stroke(); } }); - context.closePath(); - context.stroke(); + +} + +function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) { + radius -= gaugeOption.width/2+config.gaugeLabelTextMargin; + + let totalAngle=gaugeOption.startAngle-gaugeOption.endAngle+1; + let splitAngle=totalAngle/gaugeOption.splitLine.splitNumber; + let totalNumber=gaugeOption.endNumber-gaugeOption.startNumber; + let splitNumber=totalNumber/gaugeOption.splitLine.splitNumber; + let nowAngle=gaugeOption.startAngle; + let nowNumber=gaugeOption.startNumber; + for(let i=0;i=2){ + nowAngle=nowAngle % 2; + } + nowNumber+=splitNumber; + } + } function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) { var radarOption = opts.extra.radar || {}; radius += config.radarLabelTextMargin; - context.beginPath(); - context.setFontSize(config.fontSize); - context.setFillStyle(radarOption.labelColor || '#666666'); + angleList.forEach(function (angle, index) { var pos = { x: radius * Math.cos(angle), @@ -841,10 +1246,14 @@ function drawRadarLabel(angleList, radius, centerPosition, opts, config, context } else if (pos.x < 0) { startX -= measureText(opts.categories[index] || ''); } + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(radarOption.labelColor || '#666666'); context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2); + context.closePath(); + context.stroke(); }); - context.stroke(); - context.closePath(); + } function drawPieText(series, opts, config, context, radius, center) { @@ -919,7 +1328,7 @@ function drawPieText(series, opts, config, context, radius, center) { var lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center); var lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center); var textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center); - context.setLineWidth(1); + context.setLineWidth(1*opts.pixelRatio); context.setFontSize(config.fontSize); context.beginPath(); context.setStrokeStyle(item.color); @@ -937,11 +1346,11 @@ function drawPieText(series, opts, config, context, radius, center) { context.closePath(); context.fill(); context.beginPath(); + context.setFontSize(config.fontSize); context.setFillStyle('#666666'); context.fillText(item.text, textStartX, textPosition.y + 3); context.closePath(); context.stroke(); - context.closePath(); }); } @@ -951,23 +1360,33 @@ function drawToolTipSplitLine(offsetX, opts, config, context) { var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; context.beginPath(); context.setStrokeStyle('#cccccc'); - context.setLineWidth(1); + context.setLineWidth(1*opts.pixelRatio); context.moveTo(offsetX, startY); context.lineTo(offsetX, endY); - context.stroke(); context.closePath(); + context.stroke(); +} + +function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) { + var startY = config.padding; + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + context.beginPath(); + context.setFillStyle(hexToRgb('#000000', 0.08)); + context.rect(offsetX-eachSpacing/2, startY, eachSpacing, endY-startY); + context.closePath(); + context.fill(); } function drawToolTip(textList, offset, opts, config, context) { - var legendWidth = 4; - var legendMarginRight = 5; - var arrowWidth = 8; + var legendWidth = 4*opts.pixelRatio; + var legendMarginRight = 5*opts.pixelRatio; + var arrowWidth = 8*opts.pixelRatio; var isOverRightBorder = false; offset = assign({ x: 0, y: 0 }, offset); - offset.y -= 8; + offset.y -= 8*opts.pixelRatio; var textWidth = textList.map(function (item) { return measureText(item.text); }); @@ -982,53 +1401,60 @@ function drawToolTip(textList, offset, opts, config, context) { // draw background rect context.beginPath(); - context.setFillStyle(opts.tooltip.option.background || config.toolTipBackground); - context.setGlobalAlpha(config.toolTipOpacity); + context.setFillStyle(hexToRgb(opts.tooltip.option.background || config.toolTipBackground, config.toolTipOpacity)); if (isOverRightBorder) { - context.moveTo(offset.x, offset.y + 10); - context.lineTo(offset.x - arrowWidth, offset.y + 10 - 5); - context.lineTo(offset.x - arrowWidth, offset.y + 10 + 5); - context.moveTo(offset.x, offset.y + 10); - context.fillRect(offset.x - toolTipWidth - arrowWidth, offset.y, toolTipWidth, toolTipHeight); + context.moveTo(offset.x, offset.y + 10*opts.pixelRatio); + context.lineTo(offset.x - arrowWidth, offset.y + 10*opts.pixelRatio - 5*opts.pixelRatio); + context.lineTo(offset.x - arrowWidth, offset.y); + context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y); + context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y+toolTipHeight); + context.lineTo(offset.x - arrowWidth, offset.y+toolTipHeight); + context.lineTo(offset.x - arrowWidth, offset.y + 10*opts.pixelRatio + 5*opts.pixelRatio); + context.lineTo(offset.x, offset.y + 10*opts.pixelRatio); } else { - context.moveTo(offset.x, offset.y + 10); - context.lineTo(offset.x + arrowWidth, offset.y + 10 - 5); - context.lineTo(offset.x + arrowWidth, offset.y + 10 + 5); - context.moveTo(offset.x, offset.y + 10); - context.fillRect(offset.x + arrowWidth, offset.y, toolTipWidth, toolTipHeight); + context.moveTo(offset.x, offset.y + 10*opts.pixelRatio); + context.lineTo(offset.x + arrowWidth, offset.y + 10*opts.pixelRatio - 5*opts.pixelRatio); + context.lineTo(offset.x + arrowWidth, offset.y); + context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y); + context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y+toolTipHeight); + context.lineTo(offset.x + arrowWidth, offset.y+toolTipHeight); + context.lineTo(offset.x + arrowWidth, offset.y + 10*opts.pixelRatio + 5*opts.pixelRatio); + context.lineTo(offset.x, offset.y + 10*opts.pixelRatio); } context.closePath(); context.fill(); - context.setGlobalAlpha(1); // draw legend textList.forEach(function (item, index) { - context.beginPath(); - context.setFillStyle(item.color); - var startX = offset.x + arrowWidth + 2 * config.toolTipPadding; - var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + config.toolTipPadding; - if (isOverRightBorder) { - startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding; - } - context.fillRect(startX, startY, legendWidth, config.fontSize); - context.closePath(); + if(item.color !== null){ + context.beginPath(); + context.setFillStyle(item.color); + var startX = offset.x + arrowWidth + 2 * config.toolTipPadding; + var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + config.toolTipPadding + 1; + if (isOverRightBorder) { + startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding; + } + context.fillRect(startX, startY, legendWidth, config.fontSize); + context.closePath(); + } }); // draw text list - context.beginPath(); - context.setFontSize(config.fontSize); - context.setFillStyle('#ffffff'); + textList.forEach(function (item, index) { var startX = offset.x + arrowWidth + 2 * config.toolTipPadding + legendWidth + legendMarginRight; if (isOverRightBorder) { startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding + +legendWidth + legendMarginRight; } var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + config.toolTipPadding; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle('#ffffff'); context.fillText(item.text, startX, startY + config.fontSize); + context.closePath(); + context.stroke(); }); - context.stroke(); - context.closePath(); } function drawYAxisTitle(title, opts, config, context) { @@ -1040,58 +1466,246 @@ function drawYAxisTitle(title, opts, config, context) { context.translate(0, opts.height); context.rotate(-90 * Math.PI / 180); context.fillText(title, startX, config.padding + 0.5 * config.fontSize); - context.stroke(); context.closePath(); + context.stroke(); context.restore(); } function drawColumnDataPoints(series, opts, config, context) { var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; - + var columnOption = opts.extra.column || {type:{},meter:{}}; + columnOption.type=columnOption.type==undefined? 'group':columnOption.type; + columnOption.meter=columnOption.meter||{} + columnOption.meter.border=columnOption.meter.border==undefined? 4:columnOption.meter.border; + columnOption.meter.fillColor=columnOption.meter.fillColor==undefined? '#FFFFFF':columnOption.meter.fillColor; var _calYAxisData = calYAxisData(series, opts, config), ranges = _calYAxisData.ranges; - + var _getXAxisPoints = getXAxisPoints(opts.categories, opts, config), xAxisPoints = _getXAxisPoints.xAxisPoints, eachSpacing = _getXAxisPoints.eachSpacing; var minRange = ranges.pop(); var maxRange = ranges.shift(); + var calPoints = []; + context.save(); if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { context.translate(opts._scrollDistance_, 0); } - + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing); + } + series.forEach(function (eachSeries, seriesIndex) { var data = eachSeries.data; - var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); - points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); - - // 绘制柱状数据图 - context.beginPath(); - context.setFillStyle(eachSeries.color); - points.forEach(function (item, index) { - if (item !== null) { - var startX = item.x - item.width / 2 + 1; - var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; - context.moveTo(startX, item.y); - context.rect(startX, item.y, item.width - 2, height); - } - }); - context.closePath(); - context.fill(); + switch (columnOption.type){ + case 'group': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + var tooltipPoints = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series,process); + calPoints.push(tooltipPoints); + points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + break; + case 'stack': + // 绘制堆叠数据图 + var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series,process); + calPoints.push(points); + points = fixColumeStackData(points, eachSpacing, series.length, seriesIndex, config, opts,series); + + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + var height0 = opts.height - item.y0 - config.padding - config.xAxisHeight - config.legendHeight; + if(seriesIndex>0){ + height -= height0; + } + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + break; + case 'meter': + // 绘制温度计数据图 + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + points = fixColumeMeterData(points, eachSpacing, series.length, seriesIndex, config, opts, columnOption.meter.border); + if(seriesIndex==0){ + points.forEach(function (item, index) { + if (item !== null) { + //画背景颜色 + context.beginPath(); + context.setFillStyle(columnOption.meter.fillColor); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + //画边框线 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(columnOption.meter.border*opts.pixelRatio); + context.moveTo(startX+columnOption.meter.border*0.5, item.y+height); + context.lineTo(startX+columnOption.meter.border*0.5, item.y+columnOption.meter.border*0.5); + context.lineTo(startX+item.width-columnOption.meter.border, item.y+columnOption.meter.border*0.5); + context.lineTo(startX+item.width-columnOption.meter.border, item.y+height); + context.stroke(); + } + }); + }else{ + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + } + break; + } }); + if (opts.dataLabel !== false && process === 1) { + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + switch (columnOption.type){ + case 'group': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); + drawPointText(points, eachSeries, config, context); + break; + case 'stack': + var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series,process); + drawPointText(points, eachSeries, config, context); + break; + case 'meter': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + break; + } + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + +function drawCandleDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var candleOption = opts.extra.candle || {color:{},average:{}}; + candleOption.color.upLine=candleOption.color.upLine? candleOption.color.upLine: '#f04864'; + candleOption.color.upFill=candleOption.color.upFill? candleOption.color.upFill: '#f04864'; + candleOption.color.downLine=candleOption.color.downLine? candleOption.color.downLine: '#2fc25b'; + candleOption.color.downFill=candleOption.color.downFill? candleOption.color.downFill: '#2fc25b'; + candleOption.average.show = candleOption.average.show===true? true : false; + candleOption.average.name = candleOption.average.name? candleOption.average.name : []; + candleOption.average.day = candleOption.average.day? candleOption.average.day : []; + candleOption.average.color = candleOption.average.color? candleOption.average.color : ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d']; + opts.extra.candle=candleOption; + + var _calYAxisData5 = calYAxisData(series, opts, config), + ranges = _calYAxisData5.ranges; + + var _getXAxisPoints5 = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints5.xAxisPoints, + eachSpacing = _getXAxisPoints5.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + series.forEach(function (eachSeries, seriesIndex) { var data = eachSeries.data; - var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); - points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); - if (opts.dataLabel !== false && process === 1) { - drawPointText(points, eachSeries, config, context); - } + var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + var splitPointList = splitPoints(points); + splitPointList=splitPointList[0]; + + splitPointList.forEach(function (points, index) { + context.beginPath(); + //如果上涨 + if(data[index][1]-data[index][0]>0){ + context.setStrokeStyle(candleOption.color.upLine); + context.setFillStyle(candleOption.color.upFill); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(points[3].x, points[3].y);//顶点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.lineTo(points[1].x-eachSpacing/4, points[1].y);//收盘左侧点 + context.lineTo(points[0].x-eachSpacing/4, points[0].y);//开盘左侧点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.lineTo(points[2].x, points[2].y);//底点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.lineTo(points[0].x+eachSpacing/4, points[0].y);//开盘右侧点 + context.lineTo(points[1].x+eachSpacing/4, points[1].y);//收盘右侧点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.moveTo(points[3].x, points[3].y);//顶点 + }else{ + context.setStrokeStyle(candleOption.color.downLine); + context.setFillStyle(candleOption.color.downFill); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(points[3].x, points[3].y);//顶点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.lineTo(points[0].x-eachSpacing/4, points[0].y);//开盘左侧点 + context.lineTo(points[1].x-eachSpacing/4, points[1].y);//收盘左侧点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.lineTo(points[2].x, points[2].y);//底点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.lineTo(points[1].x+eachSpacing/4, points[1].y);//收盘右侧点 + context.lineTo(points[0].x+eachSpacing/4, points[0].y);//开盘右侧点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.moveTo(points[3].x, points[3].y);//顶点 + } + context.closePath(); + context.fill(); + context.stroke(); + }); }); + context.restore(); + + //画均线 + if(candleOption.average.show){ + + } + return { xAxisPoints: xAxisPoints, + calPoints: calPoints, eachSpacing: eachSpacing }; } @@ -1119,7 +1733,8 @@ function drawAreaDataPoints(series, opts, config, context) { if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); } - + + series.forEach(function (eachSeries, seriesIndex) { var data = eachSeries.data; var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); @@ -1132,8 +1747,8 @@ function drawAreaDataPoints(series, opts, config, context) { context.beginPath(); context.setStrokeStyle(eachSeries.color); context.setFillStyle(eachSeries.color); - context.setGlobalAlpha(0.6); - context.setLineWidth(2); + context.setGlobalAlpha(0.2); + context.setLineWidth(2*opts.pixelRatio); if (points.length > 1) { var firstPoint = points[0]; var lastPoint = points[points.length - 1]; @@ -1168,12 +1783,43 @@ function drawAreaDataPoints(series, opts, config, context) { context.closePath(); context.fill(); context.setGlobalAlpha(1); + + + //画连线 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (opts.extra.lineStyle === 'curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); }); - + + //画点 if (opts.dataPointShape !== false) { var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; - drawPointShape(points, eachSeries.color, shape, context); + drawPointShape(points, eachSeries.color, shape, context,opts); } + }); if (opts.dataLabel !== false && process === 1) { series.forEach(function (eachSeries, seriesIndex) { @@ -1224,7 +1870,7 @@ function drawLineDataPoints(series, opts, config, context) { splitPointList.forEach(function (points, index) { context.beginPath(); context.setStrokeStyle(eachSeries.color); - context.setLineWidth(2); + context.setLineWidth(2*opts.pixelRatio); if (points.length === 1) { context.moveTo(points[0].x, points[0].y); context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); @@ -1252,7 +1898,7 @@ function drawLineDataPoints(series, opts, config, context) { if (opts.dataPointShape !== false) { var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; - drawPointShape(points, eachSeries.color, shape, context); + drawPointShape(points, eachSeries.color, shape, context,opts); } }); if (opts.dataLabel !== false && process === 1) { @@ -1272,6 +1918,185 @@ function drawLineDataPoints(series, opts, config, context) { }; } +function drawMixDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var _calYAxisData6 = calYAxisData(series, opts, config), + ranges = _calYAxisData6.ranges; + + var _getXAxisPoints6 = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints6.xAxisPoints, + eachSpacing = _getXAxisPoints6.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + var calPoints = []; + + var columnIndex=0; + var columnLength=0; + series.forEach(function (eachSeries, seriesIndex) { + if(eachSeries.type=='column'){ + columnLength+=1; + } + }); + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + + // 绘制柱状数据图 + if(eachSeries.type=='column'){ + points = fixColumeData(points, eachSpacing, columnLength , columnIndex, config, opts); + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + columnIndex+=1; + } + + //绘制区域图数据 + + if(eachSeries.type=='area'){ + var splitPointList = splitPoints(points); + splitPointList.forEach(function (points) { + // 绘制区域数据 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setFillStyle(eachSeries.color); + context.setGlobalAlpha(0.2); + context.setLineWidth(2*opts.pixelRatio); + if (points.length > 1) { + var firstPoint = points[0]; + var lastPoint = points[points.length - 1]; + context.moveTo(firstPoint.x, firstPoint.y); + if (eachSeries.style === 'curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.lineTo(lastPoint.x, endY); + context.lineTo(firstPoint.x, endY); + context.lineTo(firstPoint.x, firstPoint.y); + } else { + var item = points[0]; + context.moveTo(item.x - eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, endY); + context.lineTo(item.x - eachSpacing / 2, endY); + context.moveTo(item.x - eachSpacing / 2, item.y); + } + context.closePath(); + context.fill(); + context.setGlobalAlpha(1); + }); + } + + + + // 绘制折线数据图 + if(eachSeries.type=='line'){ + var splitPointList = splitPoints(points); + splitPointList.forEach(function (points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (eachSeries.style=='curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + } + + // 绘制点数据图 + if(eachSeries.type=='point'){ + var splitPointList = splitPoints(points); + splitPointList.forEach(function (points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + context.closePath(); + context.stroke(); + }); + } + + if (opts.dataPointShape !== false && eachSeries.type!=='column') { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context,opts); + } + }); + if (opts.dataLabel !== false && process === 1) { + var columnIndex=0; + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + if(eachSeries.type!=='column'){ + drawPointText(points, eachSeries, config, context); + }else{ + points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts); + drawPointText(points, eachSeries, config, context); + columnIndex+=1; + } + + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + function drawToolTipBridge(opts, config, context, process) { context.save(); if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { @@ -1284,6 +2109,11 @@ function drawToolTipBridge(opts, config, context, process) { } function drawXAxis(categories, opts, config, context) { + + if (opts.xAxis.disabled === true) { + return; + } + var _getXAxisPoints4 = getXAxisPoints(categories, opts, config), xAxisPoints = _getXAxisPoints4.xAxisPoints, startX = _getXAxisPoints4.startX, @@ -1291,22 +2121,56 @@ function drawXAxis(categories, opts, config, context) { eachSpacing = _getXAxisPoints4.eachSpacing; var startY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; - var endY = startY + config.xAxisLineHeight; - + var endY = config.padding; + + + //绘制滚动条 + if(opts.enableScroll && opts.xAxis.scrollShow){ + var scrollY=opts.height - config.padding - config.legendHeight + 4*opts.pixelRatio; + var scrollScreenWidth=endX-startX; + var scrollTotalWidth=eachSpacing*(xAxisPoints.length-1); + var scrollWidth=scrollScreenWidth*scrollScreenWidth/scrollTotalWidth; + var scrollLeft=0; + if (opts._scrollDistance_){ + scrollLeft=-opts._scrollDistance_*(scrollScreenWidth)/scrollTotalWidth; + } + context.beginPath(); + context.setLineCap('round'); + context.setLineWidth(6*opts.pixelRatio); + context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF"); + context.moveTo(startX, scrollY); + context.lineTo(endX, scrollY); + context.stroke(); + context.closePath(); + context.beginPath(); + context.setLineCap('round'); + context.setLineWidth(6*opts.pixelRatio); + context.setStrokeStyle(opts.xAxis.scrollColor ||"#A6A6A6"); + context.moveTo(startX+scrollLeft, scrollY); + context.lineTo(startX+scrollLeft+scrollWidth, scrollY); + context.stroke(); + context.closePath(); + } + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) { context.translate(opts._scrollDistance_, 0); } context.beginPath(); context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc"); - + context.setLineCap('butt'); + context.setLineWidth(1*opts.pixelRatio); + if(opts.xAxis.gridType=='dash'){ + context.setLineDash([opts.xAxis.dashLength]); + } if (opts.xAxis.disableGrid !== true) { if (opts.xAxis.type === 'calibration') { xAxisPoints.forEach(function (item, index) { if (index > 0) { context.moveTo(item - eachSpacing / 2, startY); - context.lineTo(item - eachSpacing / 2, startY + 4); + context.lineTo(item - eachSpacing / 2, startY + 4*opts.pixelRatio); } }); } else { @@ -1318,7 +2182,8 @@ function drawXAxis(categories, opts, config, context) { } context.closePath(); context.stroke(); - + context.setLineDash([]); + // 对X轴列表做抽稀处理 var validWidth = opts.width - 2 * config.padding - config.yAxisWidth - config.yAxisTitleWidth; var maxXAxisListLength = Math.min(categories.length, Math.ceil(validWidth / config.fontSize / 1.5)); @@ -1329,15 +2194,17 @@ function drawXAxis(categories, opts, config, context) { }); if (config._xAxisTextAngle_ === 0) { - context.beginPath(); - context.setFontSize(config.fontSize); - context.setFillStyle(opts.xAxis.fontColor || '#666666'); + categories.forEach(function (item, index) { var offset = eachSpacing / 2 - measureText(item) / 2; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.xAxis.fontColor || '#666666'); context.fillText(item, xAxisPoints[index] + offset, startY + config.fontSize + 5); + context.closePath(); + context.stroke(); }); - context.closePath(); - context.stroke(); + } else { categories.forEach(function (item, index) { context.save(); @@ -1361,30 +2228,50 @@ function drawXAxis(categories, opts, config, context) { } context.restore(); + } -function drawYAxisGrid(opts, config, context) { +function drawYAxisGrid(categories,opts, config, context) { + if (opts.yAxis.disableGrid === true) { + return; + } var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; var eachSpacing = Math.floor(spacingValid / config.yAxisSplit); var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth; var startX = config.padding + yAxisTotalWidth; - var endX = opts.width - config.padding; - + var _getXAxisPoints4 = getXAxisPoints(categories, opts, config), + xAxisPoints = _getXAxisPoints4.xAxisPoints, + xAxiseachSpacing = _getXAxisPoints4.eachSpacing; + var TotalWidth=xAxiseachSpacing*(xAxisPoints.length-1); + var endX = startX+TotalWidth; + var points = []; for (var i = 0; i < config.yAxisSplit; i++) { points.push(config.padding + eachSpacing * i); } points.push(config.padding + eachSpacing * config.yAxisSplit + 2); + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) { + context.translate(opts._scrollDistance_, 0); + } + + if(opts.yAxis.gridType=='dash'){ + context.setLineDash([opts.yAxis.dashLength]); + } context.beginPath(); context.setStrokeStyle(opts.yAxis.gridColor || "#cccccc"); - context.setLineWidth(1); + + context.setLineWidth(1*opts.pixelRatio); points.forEach(function (item, index) { context.moveTo(startX, item); context.lineTo(endX, item); }); context.closePath(); context.stroke(); + context.setLineDash([]); + + context.restore(); } function drawYAxis(series, opts, config, context) { @@ -1406,9 +2293,9 @@ function drawYAxis(series, opts, config, context) { // set YAxis background context.setFillStyle(opts.background || '#ffffff'); if (opts._scrollDistance_ < 0) { - context.fillRect(0, 0, startX, endY + config.xAxisHeight + 5); + context.fillRect(0, 0, startX, endY + config.xAxisHeight ); } - context.fillRect(endX, 0, opts.width, endY + config.xAxisHeight + 5); + context.fillRect(endX, 0, opts.width, endY + config.xAxisHeight ); var points = []; for (var i = 0; i <= config.yAxisSplit; i++) { @@ -1416,15 +2303,17 @@ function drawYAxis(series, opts, config, context) { } context.stroke(); - context.beginPath(); - context.setFontSize(config.fontSize); - context.setFillStyle(opts.yAxis.fontColor || '#666666'); + rangesFormat.forEach(function (item, index) { var pos = points[index] ? points[index] : endY; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.yAxis.fontColor || '#666666'); context.fillText(item, config.padding + config.yAxisTitleWidth, pos + config.fontSize / 2); + context.closePath(); + context.stroke(); }); - context.closePath(); - context.stroke(); + if (opts.yAxis.title) { drawYAxisTitle(opts.yAxis.title, opts, config, context); @@ -1443,9 +2332,9 @@ function drawLegend(series, opts, config, context) { var _calLegendData = calLegendData(series, opts, config), legendList = _calLegendData.legendList; - var padding = 5; - var marginTop = 8; - var shapeWidth = 15; + var padding = 5*opts.pixelRatio; + var marginTop = 10*opts.pixelRatio; + var shapeWidth = 15*opts.pixelRatio; legendList.forEach(function (itemList, listIndex) { var width = 0; itemList.forEach(function (item) { @@ -1460,49 +2349,71 @@ function drawLegend(series, opts, config, context) { switch (opts.type) { case 'line': context.beginPath(); - context.setLineWidth(1); + /* + context.setLineWidth(1*opts.pixelRatio); context.setStrokeStyle(item.color); context.moveTo(startX - 2, startY + 5); context.lineTo(startX + 17, startY + 5); context.stroke(); context.closePath(); context.beginPath(); - context.setLineWidth(1); - context.setStrokeStyle('#ffffff'); + */ + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); context.setFillStyle(item.color); - context.moveTo(startX + 7.5, startY + 5); - context.arc(startX + 7.5, startY + 5, 4, 0, 2 * Math.PI); + context.moveTo(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio); + context.arc(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio, 6*opts.pixelRatio, 0, 2 * Math.PI); context.fill(); context.stroke(); context.closePath(); break; case 'pie': + context.beginPath(); + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); + context.setFillStyle(item.color); + context.moveTo(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio); + context.arc(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio, 6*opts.pixelRatio, 0, 2 * Math.PI); + context.fill(); + context.stroke(); + context.closePath(); + break; case 'ring': context.beginPath(); + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); context.setFillStyle(item.color); - context.moveTo(startX + 7.5, startY + 5); - context.arc(startX + 7.5, startY + 5, 7, 0, 2 * Math.PI); - context.closePath(); + context.moveTo(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio); + context.arc(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio, 6*opts.pixelRatio, 0, 2 * Math.PI); context.fill(); + context.stroke(); + context.closePath(); break; + //圆弧进度图不显示图例 + case 'gauge': + break; + case 'arcbar': + break; default: context.beginPath(); context.setFillStyle(item.color); context.moveTo(startX, startY); - context.rect(startX, startY, 15, 10); + context.rect(startX, startY, 15*opts.pixelRatio, 10*opts.pixelRatio); context.closePath(); context.fill(); } startX += padding + shapeWidth; context.beginPath(); + context.setFontSize(config.fontSize); context.setFillStyle(opts.extra.legendTextColor || '#333333'); - context.fillText(item.name, startX, startY + 9); + context.fillText(item.name, startX, startY + 6*opts.pixelRatio+3*opts.pixelRatio); context.closePath(); context.stroke(); startX += measureText(item.name) + 2 * padding; }); }); } + function drawPieDataPoints(series, opts, config, context) { var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; @@ -1524,7 +2435,7 @@ function drawPieDataPoints(series, opts, config, context) { }); series.forEach(function (eachSeries) { context.beginPath(); - context.setLineWidth(2); + context.setLineWidth(2*opts.pixelRatio); context.setStrokeStyle('#ffffff'); context.setFillStyle(eachSeries.color); context.moveTo(centerPosition.x, centerPosition.y); @@ -1575,6 +2486,189 @@ function drawPieDataPoints(series, opts, config, context) { }; } +function drawArcbarDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var arcbarOption = opts.extra.arcbar || {}; + arcbarOption.startAngle=arcbarOption.startAngle? arcbarOption.startAngle: 0.75; + arcbarOption.endAngle=arcbarOption.endAngle? arcbarOption.endAngle : 0.25; + arcbarOption.type=arcbarOption.type? arcbarOption.type : 'default'; + + series = getArcbarDataPoints(series, arcbarOption, process); + var centerPosition = { + x: opts.width / 2, + y: (opts.height) / 2 + }; + var radius = Math.min(centerPosition.x , centerPosition.y); + + if (typeof arcbarOption.width === 'number' && arcbarOption.width > 0) { + arcbarOption.width=arcbarOption.width; + }else{ + arcbarOption.width=12*opts.pixelRatio; + } + radius -= config.padding+arcbarOption.width/2; + + //背景颜色 + context.setLineWidth(arcbarOption.width); // 设置圆环的宽度 + context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9'); // 设置圆环的颜色 + context.setLineCap('round'); // 设置圆环端点的形状 + context.beginPath(); //开始一个新的路径 + if(arcbarOption.type=='default'){ + context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * Math.PI, false); + }else{ + context.arc(centerPosition.x, centerPosition.y, radius, 0, 2 * Math.PI, false); + } + + context.stroke(); //对当前路径进行描边 + + + series.forEach(function (eachSeries) { + context.setLineWidth(arcbarOption.width); + context.setStrokeStyle(eachSeries.color); + context.setLineCap('round'); + context.beginPath(); + context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ * Math.PI, false); + context.stroke(); + + }); + drawRingTitle(opts, config, context); + return { + center: centerPosition, + radius: radius, + series: series + }; +} + +function drawGaugeDataPoints(categories,series, opts, config, context) { + var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1; + var gaugeOption = opts.extra.gauge || {}; + gaugeOption.startAngle=gaugeOption.startAngle? gaugeOption.startAngle: 0.75; + if(gaugeOption.oldAngle==undefined){ + gaugeOption.oldAngle=gaugeOption.startAngle; + } + if(gaugeOption.oldData==undefined){ + gaugeOption.oldData=0; + } + gaugeOption.endAngle=gaugeOption.endAngle? gaugeOption.endAngle : 0.25; + categories = getGaugeAxisPoints(categories,gaugeOption.startAngle,gaugeOption.endAngle); + var centerPosition = { + x: opts.width / 2, + y: (opts.height) / 2 + }; + var radius = Math.min(centerPosition.x , centerPosition.y); + if (typeof gaugeOption.width === 'number' && gaugeOption.width > 0) { + gaugeOption.width=gaugeOption.width; + }else{ + gaugeOption.width=15*opts.pixelRatio; + } + radius -= config.padding+gaugeOption.width/2; + var innerRadius = radius-gaugeOption.width; + + + + //画背景 + context.setLineWidth(gaugeOption.width); + context.setLineCap('butt'); + categories.forEach(function (eachCategories) { + context.beginPath(); + context.setStrokeStyle(eachCategories.color); + context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_ * Math.PI, eachCategories._endAngle_ * Math.PI, false); + context.stroke(); + }); + context.save(); + + //画刻度线 + let totalAngle=gaugeOption.startAngle-gaugeOption.endAngle+1; + gaugeOption.splitLine.fixRadius=gaugeOption.splitLine.fixRadius? gaugeOption.splitLine.fixRadius : 0; + gaugeOption.splitLine.splitNumber=gaugeOption.splitLine.splitNumber? gaugeOption.splitLine.splitNumber : 10; + gaugeOption.splitLine.width=gaugeOption.splitLine.width? gaugeOption.splitLine.width : 15*opts.pixelRatio ; + gaugeOption.splitLine.color=gaugeOption.splitLine.color? gaugeOption.splitLine.color : '#FFFFFF'; + gaugeOption.splitLine.childNumber=gaugeOption.splitLine.childNumber? gaugeOption.splitLine.childNumber : 5; + gaugeOption.splitLine.childWidth=gaugeOption.splitLine.childWidth? gaugeOption.splitLine.childWidth : 5*opts.pixelRatio; + + let splitAngle=totalAngle/gaugeOption.splitLine.splitNumber; + let childAngle=totalAngle/gaugeOption.splitLine.splitNumber/gaugeOption.splitLine.childNumber; + let startX=-radius-gaugeOption.width*0.5-gaugeOption.splitLine.fixRadius; + let endX=-radius-gaugeOption.width*0.5-gaugeOption.splitLine.fixRadius+gaugeOption.splitLine.width; + let childendX=-radius-gaugeOption.width*0.5-gaugeOption.splitLine.fixRadius+gaugeOption.splitLine.childWidth; + + context.translate(centerPosition.x, centerPosition.y); + context.rotate((gaugeOption.startAngle-1)* Math.PI); + + for(let i=0 ; i< gaugeOption.splitLine.splitNumber+1; i++){ + context.beginPath(); + context.setStrokeStyle(gaugeOption.splitLine.color); + context.setLineWidth(2*opts.pixelRatio); + context.moveTo(startX, 0); + context.lineTo(endX, 0); + context.stroke(); + context.rotate(splitAngle* Math.PI); + } + context.restore(); + + context.save(); + context.translate(centerPosition.x, centerPosition.y); + context.rotate((gaugeOption.startAngle-1)* Math.PI); + + for(let i=0 ; i< gaugeOption.splitLine.splitNumber*gaugeOption.splitLine.childNumber+1; i++){ + context.beginPath(); + context.setStrokeStyle(gaugeOption.splitLine.color); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(startX, 0); + context.lineTo(childendX, 0); + context.stroke(); + context.rotate(childAngle* Math.PI); + } + context.restore(); + + //画指针 + gaugeOption.pointer.width=gaugeOption.pointer.width? gaugeOption.pointer.width : 15*opts.pixelRatio; + if (gaugeOption.pointer.color == undefined || gaugeOption.pointer.color == 'auto') { + gaugeOption.pointer.color == 'auto'; + }else{ + gaugeOption.pointer.color == gaugeOption.pointer.color; + } + series = getGaugeDataPoints(series,categories,gaugeOption, process); + + series.forEach(function (eachSeries) { + context.save(); + context.translate(centerPosition.x, centerPosition.y); + context.rotate((eachSeries._proportion_-1)* Math.PI); + context.beginPath(); + context.setFillStyle(eachSeries.color); + context.moveTo(gaugeOption.pointer.width, 0); + context.lineTo(0,-gaugeOption.pointer.width/2); + context.lineTo(-innerRadius,0); + context.lineTo(0,gaugeOption.pointer.width/2); + context.lineTo(gaugeOption.pointer.width,0); + context.closePath(); + context.fill(); + context.beginPath(); + context.setFillStyle('#FFFFFF'); + context.arc(0, 0, gaugeOption.pointer.width/6, 0,2* Math.PI, false); + context.fill(); + context.restore(); + }); + + if (opts.dataLabel !== false) { + drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context); + } + + drawRingTitle(opts, config, context); + + if (process === 1 && opts.type === 'gauge') { + gaugeOption.oldAngle=series[0]._proportion_; + gaugeOption.oldData=series[0].data; + } + return { + center: centerPosition, + radius: radius, + innerRadius:innerRadius, + categories: categories, + totalAngle:totalAngle + }; +} + function drawRadarDataPoints(series, opts, config, context) { var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; @@ -1591,7 +2685,7 @@ function drawRadarDataPoints(series, opts, config, context) { // draw grid context.beginPath(); - context.setLineWidth(1); + context.setLineWidth(1*opts.pixelRatio); context.setStrokeStyle(radarOption.gridColor || "#cccccc"); coordinateAngle.forEach(function (angle) { var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition); @@ -1606,7 +2700,7 @@ function drawRadarDataPoints(series, opts, config, context) { var _loop = function _loop(i) { var startPos = {}; context.beginPath(); - context.setLineWidth(1); + context.setLineWidth(1*opts.pixelRatio); context.setStrokeStyle(radarOption.gridColor || "#cccccc"); coordinateAngle.forEach(function (angle, index) { var pos = convertCoordinateOrigin(radius / config.radarGridCount * i * Math.cos(angle), radius / config.radarGridCount * i * Math.sin(angle), centerPosition); @@ -1627,11 +2721,12 @@ function drawRadarDataPoints(series, opts, config, context) { } var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process); + radarDataPoints.forEach(function (eachSeries, seriesIndex) { // 绘制区域数据 context.beginPath(); context.setFillStyle(eachSeries.color); - context.setGlobalAlpha(0.6); + context.setGlobalAlpha(0.3); eachSeries.data.forEach(function (item, index) { if (index === 0) { context.moveTo(item.position.x, item.position.y); @@ -1648,7 +2743,7 @@ function drawRadarDataPoints(series, opts, config, context) { var points = eachSeries.data.map(function (item) { return item.position; }); - drawPointShape(points, eachSeries.color, shape, context); + drawPointShape(points, eachSeries.color, shape, context,opts); } }); // draw label text @@ -1695,9 +2790,11 @@ function Animation(opts) { var delay = 17; var createAnimationFrame = function createAnimationFrame() { + if (typeof requestAnimationFrame !== 'undefined') { - return requestAnimationFrame; + return requestAnimationFrame; } else if (typeof setTimeout !== 'undefined') { + return function (step, delay) { setTimeout(function () { var timeStamp = +new Date(); @@ -1705,6 +2802,7 @@ function Animation(opts) { }, delay); }; } else { + return function (step) { step(null); }; @@ -1712,7 +2810,9 @@ function Animation(opts) { }; var animationFrame = createAnimationFrame(); var startTimeStamp = null; + var _step = function step(timestamp) { + if (timestamp === null || this.isStop === true) { opts.onProcess && opts.onProcess(1); opts.onAnimationFinish && opts.onAnimationFinish(); @@ -1725,6 +2825,7 @@ function Animation(opts) { var process = (timestamp - startTimeStamp) / opts.duration; var timingFunction = Timing[opts.timing]; process = timingFunction(process); + opts.onProcess && opts.onProcess(process); animationFrame(_step, delay); } else { @@ -1733,7 +2834,6 @@ function Animation(opts) { } }; _step = _step.bind(this); - animationFrame(_step, delay); } @@ -1749,7 +2849,8 @@ function drawCharts(type, opts, config, context) { var series = opts.series; var categories = opts.categories; series = fillSeriesColor(series, config); - + series = fillSeriesType(series, opts); + var _calLegendData = calLegendData(series, opts, config), legendHeight = _calLegendData.legendHeight; @@ -1773,14 +2874,31 @@ function drawCharts(type, opts, config, context) { var duration = opts.animation ? 1000 : 0; this.animationInstance && this.animationInstance.stop(); + + //先清空画布,不然百度和支付宝ToolTip有重影 + context.clearRect(0, 0, opts.width, opts.height); + if(opts.rotate){ + //判断是否是百度和支付宝平台,需要赋值,不然每次都旋转 + if(opts.rotateLock!==true){ + context.translate(opts.height, 0); + context.rotate(90 * Math.PI / 180); + context.save(); + }else if(opts._rotate_!==true){ + context.translate(opts.height, 0); + context.rotate(90 * Math.PI / 180); + context.save(); + opts._rotate_=true; + } + } + switch (type) { case 'line': this.animationInstance = new Animation({ timing: 'easeIn', duration: duration, onProcess: function onProcess(process) { - drawYAxisGrid(opts, config, context); - + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); var _drawLineDataPoints = drawLineDataPoints(series, opts, config, context, process), xAxisPoints = _drawLineDataPoints.xAxisPoints, calPoints = _drawLineDataPoints.calPoints, @@ -1789,33 +2907,61 @@ function drawCharts(type, opts, config, context) { _this.chartData.xAxisPoints = xAxisPoints; _this.chartData.calPoints = calPoints; _this.chartData.eachSpacing = eachSpacing; - drawXAxis(categories, opts, config, context); drawLegend(opts.series, opts, config, context); drawYAxis(series, opts, config, context); drawToolTipBridge(opts, config, context, process); drawCanvas(opts, context); + }, onAnimationFinish: function onAnimationFinish() { _this.event.trigger('renderComplete'); } }); + break; + case 'mix': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawMixDataPoints = drawMixDataPoints(series, opts, config, context, process), + xAxisPoints = _drawMixDataPoints.xAxisPoints, + calPoints = _drawMixDataPoints.calPoints, + eachSpacing = _drawMixDataPoints.eachSpacing; + + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + + break; case 'column': - this.animationInstance = new Animation({ + this.animationInstance = new Animation({ timing: 'easeIn', duration: duration, onProcess: function onProcess(process) { - drawYAxisGrid(opts, config, context); - + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); var _drawColumnDataPoints = drawColumnDataPoints(series, opts, config, context, process), xAxisPoints = _drawColumnDataPoints.xAxisPoints, + calPoints = _drawColumnDataPoints.calPoints, eachSpacing = _drawColumnDataPoints.eachSpacing; - _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; _this.chartData.eachSpacing = eachSpacing; - drawXAxis(categories, opts, config, context); drawLegend(opts.series, opts, config, context); drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); drawCanvas(opts, context); }, onAnimationFinish: function onAnimationFinish() { @@ -1828,8 +2974,8 @@ function drawCharts(type, opts, config, context) { timing: 'easeIn', duration: duration, onProcess: function onProcess(process) { - drawYAxisGrid(opts, config, context); - + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); var _drawAreaDataPoints = drawAreaDataPoints(series, opts, config, context, process), xAxisPoints = _drawAreaDataPoints.xAxisPoints, calPoints = _drawAreaDataPoints.calPoints, @@ -1838,7 +2984,6 @@ function drawCharts(type, opts, config, context) { _this.chartData.xAxisPoints = xAxisPoints; _this.chartData.calPoints = calPoints; _this.chartData.eachSpacing = eachSpacing; - drawXAxis(categories, opts, config, context); drawLegend(opts.series, opts, config, context); drawYAxis(series, opts, config, context); drawToolTipBridge(opts, config, context, process); @@ -1855,7 +3000,7 @@ function drawCharts(type, opts, config, context) { timing: 'easeInOut', duration: duration, onProcess: function onProcess(process) { - _this.chartData.pieData = drawPieDataPoints(series, opts, config, context, process); + _this.chartData.pieData = drawPieDataPoints(series, opts, config, context, process); drawLegend(opts.series, opts, config, context); drawCanvas(opts, context); }, @@ -1869,7 +3014,7 @@ function drawCharts(type, opts, config, context) { timing: 'easeInOut', duration: duration, onProcess: function onProcess(process) { - _this.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process); + _this.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process); drawLegend(opts.series, opts, config, context); drawCanvas(opts, context); }, @@ -1878,6 +3023,57 @@ function drawCharts(type, opts, config, context) { } }); break; + case 'arcbar': + this.animationInstance = new Animation({ + timing: 'easeInOut', + duration: duration, + onProcess: function onProcess(process) { + _this.chartData.arcbarData = drawArcbarDataPoints(series, opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'gauge': + this.animationInstance = new Animation({ + timing: 'easeInOut', + duration: duration, + onProcess: function onProcess(process) { + _this.chartData.gaugeData = drawGaugeDataPoints(categories, series,opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'candle': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawCandleDataPoints = drawCandleDataPoints(series, opts, config, context, process), + xAxisPoints = _drawCandleDataPoints.xAxisPoints, + calPoints = _drawCandleDataPoints.calPoints, + eachSpacing = _drawCandleDataPoints.eachSpacing; + + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; } } @@ -1911,37 +3107,102 @@ Event.prototype.trigger = function () { }; var Charts = function Charts(opts) { + opts.fontSize=opts.fontSize ? opts.fontSize*opts.pixelRatio : 13*opts.pixelRatio; opts.title = opts.title || {}; opts.subtitle = opts.subtitle || {}; opts.yAxis = opts.yAxis || {}; + opts.yAxis.gridType=opts.yAxis.gridType? opts.yAxis.gridType : 'solid'; + opts.yAxis.dashLength=opts.yAxis.dashLength? opts.yAxis.dashLength : 4*opts.pixelRatio; opts.xAxis = opts.xAxis || {}; + opts.xAxis.rotateLabel = opts.xAxis.rotateLabel ? true : false; + opts.xAxis.type=opts.xAxis.type? opts.xAxis.type : 'calibration'; + opts.xAxis.gridType=opts.xAxis.gridType? opts.xAxis.gridType : 'solid'; + opts.xAxis.dashLength=opts.xAxis.dashLength? opts.xAxis.dashLength : 4*opts.pixelRatio; + opts.xAxis.itemCount = opts.xAxis.itemCount ? opts.xAxis.itemCount : 5; + opts.xAxis.scrollAlign = opts.xAxis.scrollAlign ? opts.xAxis.scrollAlign : 'left'; opts.extra = opts.extra || {}; opts.legend = opts.legend === false ? false : true; + opts.rotate = opts.rotate ? true : false; opts.animation = opts.animation === false ? false : true; var config$$1 = assign({}, config); config$$1.yAxisTitleWidth = opts.yAxis.disabled !== true && opts.yAxis.title ? config$$1.yAxisTitleWidth : 0; - config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : config$$1.pieChartLinePadding; - config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding; - + config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : config$$1.pieChartLinePadding*opts.pixelRatio; + config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding*opts.pixelRatio; + config$$1.yAxisSplit = opts.yAxis.splitNumber? opts.yAxis.splitNumber : config.yAxisSplit; + //屏幕旋转 + config$$1.rotate=opts.rotate; + if(opts.rotate){ + let tempWidth=opts.width; + let tempHeight=opts.height; + opts.width=tempHeight; + opts.height=tempWidth; + } + + //适配H5高分屏 + config$$1.yAxisWidth=config.yAxisWidth*opts.pixelRatio; + config$$1.xAxisHeight=config.xAxisHeight*opts.pixelRatio; + if(opts.enableScroll && opts.xAxis.scrollShow){ + config$$1.xAxisHeight+=4*opts.pixelRatio; + } + config$$1.xAxisLineHeight=config.xAxisLineHeight*opts.pixelRatio; + config$$1.legendHeight=config.legendHeight*opts.pixelRatio; + //config$$1.yAxisTitleWidth=config.yAxisTitleWidth*opts.pixelRatio; + config$$1.padding=config.padding*opts.pixelRatio; + config$$1.fontSize=opts.fontSize; + config$$1.titleFontSize=config.titleFontSize*opts.pixelRatio; + config$$1.subtitleFontSize=config.subtitleFontSize*opts.pixelRatio; + config$$1.toolTipPadding=config.toolTipPadding*opts.pixelRatio; + config$$1.toolTipLineHeight=config.toolTipLineHeight*opts.pixelRatio; + config$$1.columePadding=config.columePadding*opts.pixelRatio; + //config$$1.xAxisTextPadding=config.xAxisTextPadding*opts.pixelRatio; + + //向配置中传入当前pixelRatio及字体大小 + config.pixelRatio=opts.pixelRatio; + config.fontSize=opts.fontSize; + config.rotate=opts.rotate; + this.opts = opts; this.config = config$$1; - this.context = wx.createCanvasContext(opts.canvasId); + opts.$this = opts.$this? opts.$this : this; + this.context = uni.createCanvasContext(opts.canvasId, opts.$this); // store calcuated chart data // such as chart point coordinate this.chartData = {}; this.event = new Event(); + this.scrollOption = { currentOffset: 0, startTouchX: 0, distance: 0 }; - + + //计算右对齐偏移距离 + if(opts.enableScroll && opts.xAxis.scrollAlign=='right'){ + let _calYAxisData = calYAxisData(opts.series, opts, config$$1), + yAxisWidth = _calYAxisData.yAxisWidth; + config$$1.yAxisWidth = yAxisWidth; + let offsetLeft=0; + let _getXAxisPoints0 = getXAxisPoints(opts.categories, opts, config$$1), + xAxisPoints = _getXAxisPoints0.xAxisPoints, + startX = _getXAxisPoints0.startX, + endX = _getXAxisPoints0.endX, + eachSpacing = _getXAxisPoints0.eachSpacing; + let totalWidth=eachSpacing*(xAxisPoints.length-1); + let screenWidth=endX-startX; + offsetLeft=screenWidth-totalWidth; + this.scrollOption = { + currentOffset: offsetLeft, + startTouchX: offsetLeft, + distance: 0 + }; + opts._scrollDistance_= offsetLeft; + } + drawCharts.call(this, opts.type, opts, config$$1, this.context); }; Charts.prototype.updateData = function () { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - this.opts.series = data.series || this.opts.series; this.opts.categories = data.categories || this.opts.categories; @@ -1951,6 +3212,17 @@ Charts.prototype.updateData = function () { drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); }; +Charts.prototype.zoom = function () { + var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount; + if(this.opts.enableScroll!==true){ + console.log('请启用滚动条后使用!') + return; + } + this.opts.animation=false; + this.opts.xAxis.itemCount = val.itemCount; + drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); +}; + Charts.prototype.stopAnimation = function () { this.animationInstance && this.animationInstance.stop(); }; @@ -1960,18 +3232,15 @@ Charts.prototype.addEventListener = function (type, listener) { }; Charts.prototype.getCurrentDataIndex = function (e) { - var touches = e.touches && e.touches.length ? e.touches : e.changedTouches; - if (touches && touches.length) { - var _touches$ = touches[0], - x = _touches$.x, - y = _touches$.y; - + var touches= e.mp.changedTouches[0]; + if (touches) { + var _touches$= getTouches(touches, this.opts, e); if (this.opts.type === 'pie' || this.opts.type === 'ring') { - return findPieChartCurrentIndex({ x: x, y: y }, this.chartData.pieData); + return findPieChartCurrentIndex({ x: _touches$.x, y: _touches$.y }, this.chartData.pieData); } else if (this.opts.type === 'radar') { - return findRadarChartCurrentIndex({ x: x, y: y }, this.chartData.radarData, this.opts.categories.length); + return findRadarChartCurrentIndex({ x: _touches$.x, y: _touches$.y }, this.chartData.radarData, this.opts.categories.length); } else { - return findCurrentIndex({ x: x, y: y }, this.chartData.xAxisPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset)); + return findCurrentIndex({ x: _touches$.x, y: _touches$.y }, this.chartData.xAxisPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset)); } } return -1; @@ -1979,22 +3248,25 @@ Charts.prototype.getCurrentDataIndex = function (e) { Charts.prototype.showToolTip = function (e) { var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - if (this.opts.type === 'line' || this.opts.type === 'area') { + var touches= e.mp.changedTouches[0]; + var _touches$= getTouches(touches, this.opts, e); + + if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'mix' || this.opts.type === 'column') { var index = this.getCurrentDataIndex(e); var currentOffset = this.scrollOption.currentOffset; - + var opts = assign({}, this.opts, { _scrollDistance_: currentOffset, animation: false }); if (index > -1) { + var seriesData = getSeriesDataItem(this.opts.series, index); if (seriesData.length !== 0) { var _getToolTipData = getToolTipData(seriesData, this.chartData.calPoints, index, this.opts.categories, option), textList = _getToolTipData.textList, offset = _getToolTipData.offset; - + offset.y=_touches$.y; opts.tooltip = { textList: textList, offset: offset, @@ -2004,18 +3276,54 @@ Charts.prototype.showToolTip = function (e) { } drawCharts.call(this, opts.type, opts, this.config, this.context); } + if (this.opts.type === 'candle') { + + var index = this.getCurrentDataIndex(e); + var currentOffset = this.scrollOption.currentOffset; + + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + if (index > -1) { + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var _getToolTipData = getCandleToolTipData(this.opts.series[0].data,seriesData, this.chartData.calPoints, index, this.opts.categories, this.opts.extra.candle, option), + textList = _getToolTipData.textList, + offset = _getToolTipData.offset; + offset.y=_touches$.y; + opts.tooltip = { + textList: textList, + offset: offset, + option: option + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } }; Charts.prototype.scrollStart = function (e) { - if (e.touches[0] && this.opts.enableScroll === true) { - this.scrollOption.startTouchX = e.touches[0].x; + var touches= e.mp.changedTouches[0]; + if (touches && this.opts.enableScroll === true) { + if(touches.x){ + this.scrollOption.startTouchX = touches.x; + }else{ + this.scrollOption.startTouchX = touches.clientX; + } } }; Charts.prototype.scroll = function (e) { // TODO throtting... - if (e.touches[0] && this.opts.enableScroll === true) { - var _distance = e.touches[0].x - this.scrollOption.startTouchX; + var touches= e.mp.changedTouches[0]; + if (touches && this.opts.enableScroll === true) { + var _distance; + if(touches.x){ + _distance = touches.x - this.scrollOption.startTouchX; + }else{ + _distance = touches.clientX - this.scrollOption.startTouchX; + } var currentOffset = this.scrollOption.currentOffset; var validDistance = calValidDistance(currentOffset + _distance, this.chartData, this.config, this.opts); @@ -2025,7 +3333,6 @@ Charts.prototype.scroll = function (e) { _scrollDistance_: currentOffset + _distance, animation: false }); - drawCharts.call(this, opts.type, opts, this.config, this.context); } }; diff --git a/dist/wxcharts-min.js b/dist/wxcharts-min.js deleted file mode 100644 index 3adc841..0000000 --- a/dist/wxcharts-min.js +++ /dev/null @@ -1,10 +0,0 @@ -/* - * charts for WeChat small app v1.0 - * - * https://github.com/xiaolin3303/wx-charts - * 2016-11-28 - * - * Designed and built with all the love of Web - */ - -"use strict";function assign(t,e){if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var i=Object(t),a=1;a=0?r=0:Math.abs(t)>=o-n&&(r=n-o),r}function isInAngleRange(t,e,i){function a(t){for(;t<0;)t+=2*Math.PI;for(;t>2*Math.PI;)t-=2*Math.PI;return t}return t=a(t),e=a(e),i=a(i),e>i&&(i+=2*Math.PI,t=e&&t<=i}function calRotateTranslate(t,e,i){var a=t,n=i-e,o=a+(i-n-a)/Math.sqrt(2);return o*=-1,{transX:o,transY:(i-n)*(Math.sqrt(2)-1)-(i-n-a)/Math.sqrt(2)}}function createCurveControlPoints(t,e){function i(t,e){return!(!t[e-1]||!t[e+1])&&(t[e].y>=Math.max(t[e-1].y,t[e+1].y)||t[e].y<=Math.min(t[e-1].y,t[e+1].y))}var a=null,n=null,o=null,r=null;if(e<1?(a=t[0].x+.2*(t[1].x-t[0].x),n=t[0].y+.2*(t[1].y-t[0].y)):(a=t[e].x+.2*(t[e+1].x-t[e-1].x),n=t[e].y+.2*(t[e+1].y-t[e-1].y)),e>t.length-3){var s=t.length-1;o=t[s].x-.2*(t[s].x-t[s-1].x),r=t[s].y-.2*(t[s].y-t[s-1].y)}else o=t[e+1].x-.2*(t[e+2].x-t[e].x),r=t[e+1].y-.2*(t[e+2].y-t[e].y);return i(t,e+1)&&(r=t[e+1].y),i(t,e)&&(n=t[e].y),{ctrA:{x:a,y:n},ctrB:{x:o,y:r}}}function convertCoordinateOrigin(t,e,i){return{x:i.x+t,y:i.y-e}}function avoidCollision(t,e){if(e)for(;util.isCollision(t,e);)t.start.x>0?t.start.y--:t.start.x<0?t.start.y++:t.start.y>0?t.start.y++:t.start.y--;return t}function fillSeriesColor(t,e){var i=0;return t.map(function(t){return t.color||(t.color=e.colors[i],i=(i+1)%e.colors.length),t})}function getDataRange(t,e){var i=0,a=e-t;return i=a>=1e4?1e3:a>=1e3?100:a>=100?10:a>=10?5:a>=1?1:a>=.1?.1:.01,{minRange:findRange(t,"lower",i),maxRange:findRange(e,"upper",i)}}function measureText(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:10;t=String(t);var t=t.split(""),i=0;return t.forEach(function(t){/[a-zA-Z]/.test(t)?i+=7:/[0-9]/.test(t)?i+=5.5:/\./.test(t)?i+=2.7:/-/.test(t)?i+=3.25:/[\u4e00-\u9fa5]/.test(t)?i+=10:/\(|\)/.test(t)?i+=3.73:/\s/.test(t)?i+=2.5:/%/.test(t)?i+=8:i+=10}),i*e/10}function dataCombine(t){return t.reduce(function(t,e){return(t.data?t.data:t).concat(e.data)},[])}function getSeriesDataItem(t,e){var i=[];return t.forEach(function(t){if(null!==t.data[e]&&void 0!==t.data[e]){var a={};a.color=t.color,a.name=t.name,a.data=t.format?t.format(t.data[e]):t.data[e],i.push(a)}}),i}function getMaxTextListLength(t){var e=t.map(function(t){return measureText(t)});return Math.max.apply(null,e)}function getRadarCoordinateSeries(t){for(var e=2*Math.PI/t,i=[],a=0;a4&&void 0!==arguments[4]?arguments[4]:{},o=t.map(function(t){return{text:n.format?n.format(t,a[i]):t.name+": "+t.data,color:t.color}}),r=[],s={x:0,y:0};return e.forEach(function(t){void 0!==t[i]&&null!==t[i]&&r.push(t[i])}),r.forEach(function(t){s.x=Math.round(t.x),s.y+=t.y}),s.y/=r.length,{textList:o,offset:s}}function findCurrentIndex(t,e,i,a){var n=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,o=-1;return isInExactChartArea(t,i,a)&&e.forEach(function(e,i){t.x+n>e&&(o=i)}),o}function isInExactChartArea(t,e,i){return t.xi.padding+i.yAxisWidth+i.yAxisTitleWidth&&t.y>i.padding&&t.y2*Math.PI&&(t-=2*Math.PI),t},r=Math.atan2(e.center.y-t.y,t.x-e.center.x);r*=-1,r<0&&(r+=2*Math.PI);e.angleList.map(function(t){return t=o(-1*t)}).forEach(function(t,e){var i=o(t-a/2),s=o(t+a/2);s=i&&r<=s||r+2*Math.PI>=i&&r+2*Math.PI<=s)&&(n=e)})}return n}function findPieChartCurrentIndex(t,e){var i=-1;if(isInExactPieChartArea(t,e.center,e.radius)){var a=Math.atan2(e.center.y-t.y,t.x-e.center.x);a=-a;for(var n=0,o=e.series.length;ne.width?(a.push(o),n=i,o=[t]):(n+=i,o.push(t))}),o.length&&a.push(o),{legendList:a,legendHeight:a.length*(i.fontSize+8)+5}}function calCategoriesData(t,e,i){var a={angle:0,xAxisHeight:i.xAxisHeight},n=getXAxisPoints(t,e,i),o=n.eachSpacing,r=t.map(function(t){return measureText(t)}),s=Math.max.apply(this,r);return s+2*i.xAxisTextPadding>o&&(a.angle=45*Math.PI/180,a.xAxisHeight=2*i.xAxisTextPadding+s*Math.sin(a.angle)),a}function getRadarDataPoints(t,e,i,a,n){var o=arguments.length>5&&void 0!==arguments[5]?arguments[5]:1,r=n.extra.radar||{};r.max=r.max||0;var s=Math.max(r.max,Math.max.apply(null,dataCombine(a))),l=[];return a.forEach(function(a){var n={};n.color=a.color,n.data=[],a.data.forEach(function(a,r){var l={};l.angle=t[r],l.proportion=a/s,l.position=convertCoordinateOrigin(i*l.proportion*o*Math.cos(l.angle),i*l.proportion*o*Math.sin(l.angle),e),n.data.push(l)}),l.push(n)}),l}function getPieDataPoints(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:1,i=0,a=0;return t.forEach(function(t){t.data=null===t.data?0:t.data,i+=t.data}),t.forEach(function(t){t.data=null===t.data?0:t.data,t._proportion_=t.data/i*e}),t.forEach(function(t){t._start_=a,a+=2*t._proportion_*Math.PI}),t}function getPieTextMaxLength(t){t=getPieDataPoints(t);var e=0;return t.forEach(function(t){var i=t.format?t.format(+t._proportion_.toFixed(2)):util.toFixed(100*t._proportion_)+"%";e=Math.max(e,measureText(i))}),e}function fixColumeData(t,e,i,a,n,o){return t.map(function(t){return null===t?null:(t.width=(e-2*n.columePadding)/i,o.extra.column&&o.extra.column.width&&+o.extra.column.width>0?t.width=Math.min(t.width,+o.extra.column.width):t.width=Math.min(t.width,25),t.x+=(a+.5-i/2)*t.width,t)})}function getXAxisPoints(t,e,i){var a=i.yAxisWidth+i.yAxisTitleWidth,n=e.width-2*i.padding-a,o=e.enableScroll?Math.min(5,t.length):t.length,r=n/o,s=[],l=i.padding+a,h=e.width-i.padding;return t.forEach(function(t,e){s.push(l+e*r)}),!0===e.enableScroll?s.push(l+t.length*r):s.push(h),{xAxisPoints:s,startX:l,endX:h,eachSpacing:r}}function getDataPoints(t,e,i,a,n,o,r){var s=arguments.length>7&&void 0!==arguments[7]?arguments[7]:1,l=[],h=o.height-2*r.padding-r.xAxisHeight-r.legendHeight;return t.forEach(function(t,c){if(null===t)l.push(null);else{var d={};d.x=a[c]+Math.round(n/2);var x=h*(t-e)/(i-e);x*=s,d.y=o.height-r.xAxisHeight-r.legendHeight-Math.round(x)-r.padding,l.push(d)}}),l}function getYAxisTextList(t,e,i){var a=dataCombine(t);a=a.filter(function(t){return null!==t});var n=Math.min.apply(this,a),o=Math.max.apply(this,a);if("number"==typeof e.yAxis.min&&(n=Math.min(e.yAxis.min,n)),"number"==typeof e.yAxis.max&&(o=Math.max(e.yAxis.max,o)),n===o){var r=o||1;n-=r,o+=r}for(var s=getDataRange(n,o),l=s.minRange,h=s.maxRange,c=[],d=(h-l)/i.yAxisSplit,x=0;x<=i.yAxisSplit;x++)c.push(l+d*x);return c.reverse()}function calYAxisData(t,e,i){var a=getYAxisTextList(t,e,i),n=i.yAxisWidth,o=a.map(function(t){return t=util.toFixed(t,2),t=e.yAxis.format?e.yAxis.format(Number(t)):t,n=Math.max(n,measureText(t)+5),t});return!0===e.yAxis.disabled&&(n=0),{rangesFormat:o,ranges:a,yAxisWidth:n}}function drawPointShape(t,e,i,a){a.beginPath(),a.setStrokeStyle("#ffffff"),a.setLineWidth(1),a.setFillStyle(e),"diamond"===i?t.forEach(function(t,e){null!==t&&(a.moveTo(t.x,t.y-4.5),a.lineTo(t.x-4.5,t.y),a.lineTo(t.x,t.y+4.5),a.lineTo(t.x+4.5,t.y),a.lineTo(t.x,t.y-4.5))}):"circle"===i?t.forEach(function(t,e){null!==t&&(a.moveTo(t.x+3.5,t.y),a.arc(t.x,t.y,4,0,2*Math.PI,!1))}):"rect"===i?t.forEach(function(t,e){null!==t&&(a.moveTo(t.x-3.5,t.y-3.5),a.rect(t.x-3.5,t.y-3.5,7,7))}):"triangle"===i&&t.forEach(function(t,e){null!==t&&(a.moveTo(t.x,t.y-4.5),a.lineTo(t.x-4.5,t.y+4.5),a.lineTo(t.x+4.5,t.y+4.5),a.lineTo(t.x,t.y-4.5))}),a.closePath(),a.fill(),a.stroke()}function drawRingTitle(t,e,i){var a=t.title.fontSize||e.titleFontSize,n=t.subtitle.fontSize||e.subtitleFontSize,o=t.title.name||"",r=t.subtitle.name||"",s=t.title.color||e.titleColor,l=t.subtitle.color||e.subtitleColor,h=o?a:0,c=r?n:0;if(r){var d=measureText(r,n),x=(t.width-d)/2+(t.subtitle.offsetX||0),f=(t.height-e.legendHeight+n)/2;o&&(f-=(h+5)/2),i.beginPath(),i.setFontSize(n),i.setFillStyle(l),i.fillText(r,x,f),i.stroke(),i.closePath()}if(o){var u=measureText(o,a),g=(t.width-u)/2+(t.title.offsetX||0),p=(t.height-e.legendHeight+a)/2;r&&(p+=(c+5)/2),i.beginPath(),i.setFontSize(a),i.setFillStyle(s),i.fillText(o,g,p),i.stroke(),i.closePath()}}function drawPointText(t,e,i,a){var n=e.data;a.beginPath(),a.setFontSize(i.fontSize),a.setFillStyle("#666666"),t.forEach(function(t,i){if(null!==t){var o=e.format?e.format(n[i]):n[i];a.fillText(o,t.x-measureText(o)/2,t.y-2)}}),a.closePath(),a.stroke()}function drawRadarLabel(t,e,i,a,n,o){var r=a.extra.radar||{};e+=n.radarLabelTextMargin,o.beginPath(),o.setFontSize(n.fontSize),o.setFillStyle(r.labelColor||"#666666"),t.forEach(function(t,r){var s={x:e*Math.cos(t),y:e*Math.sin(t)},l=convertCoordinateOrigin(s.x,s.y,i),h=l.x,c=l.y;util.approximatelyEqual(s.x,0)?h-=measureText(a.categories[r]||"")/2:s.x<0&&(h-=measureText(a.categories[r]||"")),o.fillText(a.categories[r]||"",h,c+n.fontSize/2)}),o.stroke(),o.closePath()}function drawPieText(t,e,i,a,n,o){var r=n+i.pieChartLinePadding,s=[],l=null;t.map(function(t){return{arc:2*Math.PI-(t._start_+2*Math.PI*t._proportion_/2),text:t.format?t.format(+t._proportion_.toFixed(2)):util.toFixed(100*t._proportion_)+"%",color:t.color}}).forEach(function(t){var e=Math.cos(t.arc)*r,a=Math.sin(t.arc)*r,o=Math.cos(t.arc)*n,h=Math.sin(t.arc)*n,c=e>=0?e+i.pieChartTextPadding:e-i.pieChartTextPadding,d=a,x=measureText(t.text),f=d;l&&util.isSameXCoordinateArea(l.start,{x:c})&&(f=c>0?Math.min(d,l.start.y):e<0?Math.max(d,l.start.y):d>0?Math.max(d,l.start.y):Math.min(d,l.start.y)),c<0&&(c-=x);var u={lineStart:{x:o,y:h},lineEnd:{x:e,y:a},start:{x:c,y:f},width:x,height:i.fontSize,text:t.text,color:t.color};l=avoidCollision(u,l),s.push(l)}),s.forEach(function(t){var e=convertCoordinateOrigin(t.lineStart.x,t.lineStart.y,o),n=convertCoordinateOrigin(t.lineEnd.x,t.lineEnd.y,o),r=convertCoordinateOrigin(t.start.x,t.start.y,o);a.setLineWidth(1),a.setFontSize(i.fontSize),a.beginPath(),a.setStrokeStyle(t.color),a.setFillStyle(t.color),a.moveTo(e.x,e.y);var s=t.start.x<0?r.x+t.width:r.x,l=t.start.x<0?r.x-5:r.x+5;a.quadraticCurveTo(n.x,n.y,s,r.y),a.moveTo(e.x,e.y),a.stroke(),a.closePath(),a.beginPath(),a.moveTo(r.x+t.width,r.y),a.arc(s,r.y,2,0,2*Math.PI),a.closePath(),a.fill(),a.beginPath(),a.setFillStyle("#666666"),a.fillText(t.text,l,r.y+3),a.closePath(),a.stroke(),a.closePath()})}function drawToolTipSplitLine(t,e,i,a){var n=i.padding,o=e.height-i.padding-i.xAxisHeight-i.legendHeight;a.beginPath(),a.setStrokeStyle("#cccccc"),a.setLineWidth(1),a.moveTo(t,n),a.lineTo(t,o),a.stroke(),a.closePath()}function drawToolTip(t,e,i,a,n){var o=!1;e=assign({x:0,y:0},e),e.y-=8;var r=t.map(function(t){return measureText(t.text)}),s=9+4*a.toolTipPadding+Math.max.apply(null,r),l=2*a.toolTipPadding+t.length*a.toolTipLineHeight;e.x-Math.abs(i._scrollDistance_)+8+s>i.width&&(o=!0),n.beginPath(),n.setFillStyle(i.tooltip.option.background||a.toolTipBackground),n.setGlobalAlpha(a.toolTipOpacity),o?(n.moveTo(e.x,e.y+10),n.lineTo(e.x-8,e.y+10-5),n.lineTo(e.x-8,e.y+10+5),n.moveTo(e.x,e.y+10),n.fillRect(e.x-s-8,e.y,s,l)):(n.moveTo(e.x,e.y+10),n.lineTo(e.x+8,e.y+10-5),n.lineTo(e.x+8,e.y+10+5),n.moveTo(e.x,e.y+10),n.fillRect(e.x+8,e.y,s,l)),n.closePath(),n.fill(),n.setGlobalAlpha(1),t.forEach(function(t,i){n.beginPath(),n.setFillStyle(t.color);var r=e.x+8+2*a.toolTipPadding,l=e.y+(a.toolTipLineHeight-a.fontSize)/2+a.toolTipLineHeight*i+a.toolTipPadding;o&&(r=e.x-s-8+2*a.toolTipPadding),n.fillRect(r,l,4,a.fontSize),n.closePath()}),n.beginPath(),n.setFontSize(a.fontSize),n.setFillStyle("#ffffff"),t.forEach(function(t,i){var r=e.x+8+2*a.toolTipPadding+4+5;o&&(r=e.x-s-8+2*a.toolTipPadding+4+5);var l=e.y+(a.toolTipLineHeight-a.fontSize)/2+a.toolTipLineHeight*i+a.toolTipPadding;n.fillText(t.text,r,l+a.fontSize)}),n.stroke(),n.closePath()}function drawYAxisTitle(t,e,i,a){var n=i.xAxisHeight+(e.height-i.xAxisHeight-measureText(t))/2;a.save(),a.beginPath(),a.setFontSize(i.fontSize),a.setFillStyle(e.yAxis.titleFontColor||"#333333"),a.translate(0,e.height),a.rotate(-90*Math.PI/180),a.fillText(t,n,i.padding+.5*i.fontSize),a.stroke(),a.closePath(),a.restore()}function drawColumnDataPoints(t,e,i,a){var n=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,o=calYAxisData(t,e,i),r=o.ranges,s=getXAxisPoints(e.categories,e,i),l=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),d=r.shift();return a.save(),e._scrollDistance_&&0!==e._scrollDistance_&&!0===e.enableScroll&&a.translate(e._scrollDistance_,0),t.forEach(function(o,r){var s=o.data,x=getDataPoints(s,c,d,l,h,e,i,n);x=fixColumeData(x,h,t.length,r,i,e),a.beginPath(),a.setFillStyle(o.color),x.forEach(function(t,n){if(null!==t){var o=t.x-t.width/2+1,r=e.height-t.y-i.padding-i.xAxisHeight-i.legendHeight;a.moveTo(o,t.y),a.rect(o,t.y,t.width-2,r)}}),a.closePath(),a.fill()}),t.forEach(function(o,r){var s=o.data,x=getDataPoints(s,c,d,l,h,e,i,n);x=fixColumeData(x,h,t.length,r,i,e),!1!==e.dataLabel&&1===n&&drawPointText(x,o,i,a)}),a.restore(),{xAxisPoints:l,eachSpacing:h}}function drawAreaDataPoints(t,e,i,a){var n=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,o=calYAxisData(t,e,i),r=o.ranges,s=getXAxisPoints(e.categories,e,i),l=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),d=r.shift(),x=e.height-i.padding-i.xAxisHeight-i.legendHeight,f=[];return a.save(),e._scrollDistance_&&0!==e._scrollDistance_&&!0===e.enableScroll&&a.translate(e._scrollDistance_,0),e.tooltip&&e.tooltip.textList&&e.tooltip.textList.length&&1===n&&drawToolTipSplitLine(e.tooltip.offset.x,e,i,a),t.forEach(function(t,o){var r=t.data,s=getDataPoints(r,c,d,l,h,e,i,n);if(f.push(s),splitPoints(s).forEach(function(i){if(a.beginPath(),a.setStrokeStyle(t.color),a.setFillStyle(t.color),a.setGlobalAlpha(.6),a.setLineWidth(2),i.length>1){var n=i[0],o=i[i.length-1];a.moveTo(n.x,n.y),"curve"===e.extra.lineStyle?i.forEach(function(t,e){if(e>0){var n=createCurveControlPoints(i,e-1);a.bezierCurveTo(n.ctrA.x,n.ctrA.y,n.ctrB.x,n.ctrB.y,t.x,t.y)}}):i.forEach(function(t,e){e>0&&a.lineTo(t.x,t.y)}),a.lineTo(o.x,x),a.lineTo(n.x,x),a.lineTo(n.x,n.y)}else{var r=i[0];a.moveTo(r.x-h/2,r.y),a.lineTo(r.x+h/2,r.y),a.lineTo(r.x+h/2,x),a.lineTo(r.x-h/2,x),a.moveTo(r.x-h/2,r.y)}a.closePath(),a.fill(),a.setGlobalAlpha(1)}),!1!==e.dataPointShape){var u=i.dataPointShape[o%i.dataPointShape.length];drawPointShape(s,t.color,u,a)}}),!1!==e.dataLabel&&1===n&&t.forEach(function(t,o){drawPointText(getDataPoints(t.data,c,d,l,h,e,i,n),t,i,a)}),a.restore(),{xAxisPoints:l,calPoints:f,eachSpacing:h}}function drawLineDataPoints(t,e,i,a){var n=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,o=calYAxisData(t,e,i),r=o.ranges,s=getXAxisPoints(e.categories,e,i),l=s.xAxisPoints,h=s.eachSpacing,c=r.pop(),d=r.shift(),x=[];return a.save(),e._scrollDistance_&&0!==e._scrollDistance_&&!0===e.enableScroll&&a.translate(e._scrollDistance_,0),e.tooltip&&e.tooltip.textList&&e.tooltip.textList.length&&1===n&&drawToolTipSplitLine(e.tooltip.offset.x,e,i,a),t.forEach(function(t,o){var r=t.data,s=getDataPoints(r,c,d,l,h,e,i,n);if(x.push(s),splitPoints(s).forEach(function(i,n){a.beginPath(),a.setStrokeStyle(t.color),a.setLineWidth(2),1===i.length?(a.moveTo(i[0].x,i[0].y),a.arc(i[0].x,i[0].y,1,0,2*Math.PI)):(a.moveTo(i[0].x,i[0].y),"curve"===e.extra.lineStyle?i.forEach(function(t,e){if(e>0){var n=createCurveControlPoints(i,e-1);a.bezierCurveTo(n.ctrA.x,n.ctrA.y,n.ctrB.x,n.ctrB.y,t.x,t.y)}}):i.forEach(function(t,e){e>0&&a.lineTo(t.x,t.y)}),a.moveTo(i[0].x,i[0].y)),a.closePath(),a.stroke()}),!1!==e.dataPointShape){var f=i.dataPointShape[o%i.dataPointShape.length];drawPointShape(s,t.color,f,a)}}),!1!==e.dataLabel&&1===n&&t.forEach(function(t,o){drawPointText(getDataPoints(t.data,c,d,l,h,e,i,n),t,i,a)}),a.restore(),{xAxisPoints:l,calPoints:x,eachSpacing:h}}function drawToolTipBridge(t,e,i,a){i.save(),t._scrollDistance_&&0!==t._scrollDistance_&&!0===t.enableScroll&&i.translate(t._scrollDistance_,0),t.tooltip&&t.tooltip.textList&&t.tooltip.textList.length&&1===a&&drawToolTip(t.tooltip.textList,t.tooltip.offset,t,e,i),i.restore()}function drawXAxis(t,e,i,a){var n=getXAxisPoints(t,e,i),o=n.xAxisPoints,r=(n.startX,n.endX,n.eachSpacing),s=e.height-i.padding-i.xAxisHeight-i.legendHeight,l=s+i.xAxisLineHeight;a.save(),e._scrollDistance_&&0!==e._scrollDistance_&&a.translate(e._scrollDistance_,0),a.beginPath(),a.setStrokeStyle(e.xAxis.gridColor||"#cccccc"),!0!==e.xAxis.disableGrid&&("calibration"===e.xAxis.type?o.forEach(function(t,e){e>0&&(a.moveTo(t-r/2,s),a.lineTo(t-r/2,s+4))}):o.forEach(function(t,e){a.moveTo(t,s),a.lineTo(t,l)})),a.closePath(),a.stroke();var h=e.width-2*i.padding-i.yAxisWidth-i.yAxisTitleWidth,c=Math.min(t.length,Math.ceil(h/i.fontSize/1.5)),d=Math.ceil(t.length/c);t=t.map(function(t,e){return e%d!=0?"":t}),0===i._xAxisTextAngle_?(a.beginPath(),a.setFontSize(i.fontSize),a.setFillStyle(e.xAxis.fontColor||"#666666"),t.forEach(function(t,e){var n=r/2-measureText(t)/2;a.fillText(t,o[e]+n,s+i.fontSize+5)}),a.closePath(),a.stroke()):t.forEach(function(t,n){a.save(),a.beginPath(),a.setFontSize(i.fontSize),a.setFillStyle(e.xAxis.fontColor||"#666666");var l=measureText(t),h=r/2-l,c=calRotateTranslate(o[n]+r/2,s+i.fontSize/2+5,e.height),d=c.transX,x=c.transY;a.rotate(-1*i._xAxisTextAngle_),a.translate(d,x),a.fillText(t,o[n]+h,s+i.fontSize+5),a.closePath(),a.stroke(),a.restore()}),a.restore()}function drawYAxisGrid(t,e,i){for(var a=t.height-2*e.padding-e.xAxisHeight-e.legendHeight,n=Math.floor(a/e.yAxisSplit),o=e.yAxisWidth+e.yAxisTitleWidth,r=e.padding+o,s=t.width-e.padding,l=[],h=0;h4&&void 0!==arguments[4]?arguments[4]:1,o=e.extra.pie||{};t=getPieDataPoints(t,n);var r={x:e.width/2,y:(e.height-i.legendHeight)/2},s=Math.min(r.x-i.pieChartLinePadding-i.pieChartTextPadding-i._pieTextMaxLength_,r.y-i.pieChartLinePadding-i.pieChartTextPadding);if(e.dataLabel?s-=10:s-=2*i.padding,t=t.map(function(t){return t._start_+=(o.offsetAngle||0)*Math.PI/180,t}),t.forEach(function(t){a.beginPath(),a.setLineWidth(2),a.setStrokeStyle("#ffffff"),a.setFillStyle(t.color),a.moveTo(r.x,r.y),a.arc(r.x,r.y,s,t._start_,t._start_+2*t._proportion_*Math.PI),a.closePath(),a.fill(),!0!==e.disablePieStroke&&a.stroke()}),"ring"===e.type){var l=.6*s;"number"==typeof e.extra.ringWidth&&e.extra.ringWidth>0&&(l=Math.max(0,s-e.extra.ringWidth)),a.beginPath(),a.setFillStyle(e.background||"#ffffff"),a.moveTo(r.x,r.y),a.arc(r.x,r.y,l,0,2*Math.PI),a.closePath(),a.fill()}if(!1!==e.dataLabel&&1===n){for(var h=!1,c=0,d=t.length;c0){h=!0;break}h&&drawPieText(t,e,i,a,s,r)}return 1===n&&"ring"===e.type&&drawRingTitle(e,i,a),{center:r,radius:s,series:t}}function drawRadarDataPoints(t,e,i,a){var n=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,o=e.extra.radar||{},r=getRadarCoordinateSeries(e.categories.length),s={x:e.width/2,y:(e.height-i.legendHeight)/2},l=Math.min(s.x-(getMaxTextListLength(e.categories)+i.radarLabelTextMargin),s.y-i.radarLabelTextMargin);l-=i.padding,a.beginPath(),a.setLineWidth(1),a.setStrokeStyle(o.gridColor||"#cccccc"),r.forEach(function(t){var e=convertCoordinateOrigin(l*Math.cos(t),l*Math.sin(t),s);a.moveTo(s.x,s.y),a.lineTo(e.x,e.y)}),a.stroke(),a.closePath();for(var h=1;h<=i.radarGridCount;h++)!function(t){var e={};a.beginPath(),a.setLineWidth(1),a.setStrokeStyle(o.gridColor||"#cccccc"),r.forEach(function(n,o){var r=convertCoordinateOrigin(l/i.radarGridCount*t*Math.cos(n),l/i.radarGridCount*t*Math.sin(n),s);0===o?(e=r,a.moveTo(r.x,r.y)):a.lineTo(r.x,r.y)}),a.lineTo(e.x,e.y),a.stroke(),a.closePath()}(h);return getRadarDataPoints(r,s,l,t,e,n).forEach(function(t,n){if(a.beginPath(),a.setFillStyle(t.color),a.setGlobalAlpha(.6),t.data.forEach(function(t,e){0===e?a.moveTo(t.position.x,t.position.y):a.lineTo(t.position.x,t.position.y)}),a.closePath(),a.fill(),a.setGlobalAlpha(1),!1!==e.dataPointShape){var o=i.dataPointShape[n%i.dataPointShape.length];drawPointShape(t.data.map(function(t){return t.position}),t.color,o,a)}}),drawRadarLabel(r,l,s,e,i,a),{center:s,radius:l,angleList:r}}function drawCanvas(t,e){e.draw()}function Animation(t){this.isStop=!1,t.duration=void 0===t.duration?1e3:t.duration,t.timing=t.timing||"linear";var e=function(){return"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:"undefined"!=typeof setTimeout?function(t,e){setTimeout(function(){var e=+new Date;t(e)},e)}:function(t){t(null)}}(),i=null,a=function(n){if(null===n||!0===this.isStop)return t.onProcess&&t.onProcess(1),void(t.onAnimationFinish&&t.onAnimationFinish());if(null===i&&(i=n),n-it.end.x||e.end.xt.start.y||e.start.y0&&void 0!==arguments[0]?arguments[0]:{};this.opts.series=t.series||this.opts.series,this.opts.categories=t.categories||this.opts.categories,this.opts.title=assign({},this.opts.title,t.title||{}),this.opts.subtitle=assign({},this.opts.subtitle,t.subtitle||{}),drawCharts.call(this,this.opts.type,this.opts,this.config,this.context)},Charts.prototype.stopAnimation=function(){this.animationInstance&&this.animationInstance.stop()},Charts.prototype.addEventListener=function(t,e){this.event.addEventListener(t,e)},Charts.prototype.getCurrentDataIndex=function(t){var e=t.touches&&t.touches.length?t.touches:t.changedTouches;if(e&&e.length){var i=e[0],a=i.x,n=i.y;return"pie"===this.opts.type||"ring"===this.opts.type?findPieChartCurrentIndex({x:a,y:n},this.chartData.pieData):"radar"===this.opts.type?findRadarChartCurrentIndex({x:a,y:n},this.chartData.radarData,this.opts.categories.length):findCurrentIndex({x:a,y:n},this.chartData.xAxisPoints,this.opts,this.config,Math.abs(this.scrollOption.currentOffset))}return-1},Charts.prototype.showToolTip=function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("line"===this.opts.type||"area"===this.opts.type){var i=this.getCurrentDataIndex(t),a=this.scrollOption.currentOffset,n=assign({},this.opts,{_scrollDistance_:a,animation:!1});if(i>-1){var o=getSeriesDataItem(this.opts.series,i);if(0!==o.length){var r=getToolTipData(o,this.chartData.calPoints,i,this.opts.categories,e),s=r.textList,l=r.offset;n.tooltip={textList:s,offset:l,option:e}}}drawCharts.call(this,n.type,n,this.config,this.context)}},Charts.prototype.scrollStart=function(t){t.touches[0]&&!0===this.opts.enableScroll&&(this.scrollOption.startTouchX=t.touches[0].x)},Charts.prototype.scroll=function(t){if(t.touches[0]&&!0===this.opts.enableScroll){var e=t.touches[0].x-this.scrollOption.startTouchX,i=this.scrollOption.currentOffset,a=calValidDistance(i+e,this.chartData,this.config,this.opts);this.scrollOption.distance=e=a-i;var n=assign({},this.opts,{_scrollDistance_:i+e,animation:!1});drawCharts.call(this,n.type,n,this.config,this.context)}},Charts.prototype.scrollEnd=function(t){if(!0===this.opts.enableScroll){var e=this.scrollOption,i=e.currentOffset,a=e.distance;this.scrollOption.currentOffset=i+a,this.scrollOption.distance=0}},module.exports=Charts; diff --git a/example/area.gif b/example/area.gif deleted file mode 100644 index f13aa72..0000000 Binary files a/example/area.gif and /dev/null differ diff --git a/example/area.png b/example/area.png deleted file mode 100644 index 5e850c4..0000000 Binary files a/example/area.png and /dev/null differ diff --git a/example/column.gif b/example/column.gif deleted file mode 100644 index 4281c10..0000000 Binary files a/example/column.gif and /dev/null differ diff --git a/example/column.png b/example/column.png deleted file mode 100644 index 56bc077..0000000 Binary files a/example/column.png and /dev/null differ diff --git a/example/curve-line.png b/example/curve-line.png deleted file mode 100644 index 3beaf97..0000000 Binary files a/example/curve-line.png and /dev/null differ diff --git a/example/line.gif b/example/line.gif deleted file mode 100644 index a25d4fd..0000000 Binary files a/example/line.gif and /dev/null differ diff --git a/example/line.png b/example/line.png deleted file mode 100644 index 8e3aa4d..0000000 Binary files a/example/line.png and /dev/null differ diff --git a/example/pie.gif b/example/pie.gif deleted file mode 100644 index 179c1df..0000000 Binary files a/example/pie.gif and /dev/null differ diff --git a/example/pie.png b/example/pie.png deleted file mode 100644 index 2491e69..0000000 Binary files a/example/pie.png and /dev/null differ diff --git a/example/radar.png b/example/radar.png deleted file mode 100644 index 96bab54..0000000 Binary files a/example/radar.png and /dev/null differ diff --git a/example/ring.gif b/example/ring.gif deleted file mode 100644 index 1b310c2..0000000 Binary files a/example/ring.gif and /dev/null differ diff --git a/example/ring.png b/example/ring.png deleted file mode 100644 index 801328b..0000000 Binary files a/example/ring.png and /dev/null differ diff --git a/example/scrollLine.gif b/example/scrollLine.gif deleted file mode 100644 index 1f6ade4..0000000 Binary files a/example/scrollLine.gif and /dev/null differ diff --git a/example/tooltip.gif b/example/tooltip.gif deleted file mode 100644 index 51b83b3..0000000 Binary files a/example/tooltip.gif and /dev/null differ diff --git a/example/uni-app/App.vue b/example/uni-app/App.vue new file mode 100644 index 0000000..753e57e --- /dev/null +++ b/example/uni-app/App.vue @@ -0,0 +1,17 @@ + + + diff --git a/example/uni-app/components/u-charts/u-charts.js b/example/uni-app/components/u-charts/u-charts.js new file mode 100644 index 0000000..30a2753 --- /dev/null +++ b/example/uni-app/components/u-charts/u-charts.js @@ -0,0 +1,3351 @@ +/* + * uCharts v1.6.9 + * uni-app平台高性能跨全端图表 + * 支持H5、APP、小程序(微信/支付宝/百度/头条) + * Designed by QIUN秋云 + * + * uCharts官方网站 + * https://www.uCharts.cn + * + * 开源地址: + * https://github.com/16cheng/uCharts + * 开源地址即将变更为: + * https://gitee.com/qiuyunkeji/uCharts + * 开源协议变更为Apache-2.0 + * + * uni-app插件市场地址: + * http://ext.dcloud.net.cn/plugin?id=271 + * + * 主要更新记录 + * 2019-04-01 + * 改造为兼容uni-app的uCharts + * 2019-04-14 + * 支持支付宝/百度/头条小程序实现跨全端 + * 2019-04-15 + * 支持横屏模式,新增rotate参数,默认flase + * 2019-04-16 + * 新增圆弧进度图,图表类型arcbar + * 2019-04-22 + * 修改图表拖拽功能跨端支持,增加拖拽时显示滚动条 + * 2019-04-28 + * 新增柱状图自定义颜色 + * 2019-05-01 + * 新增仪表盘图 + * 2019-05-14 + * 新增K线图 + * + * + */ + +'use strict'; + +var config = { + yAxisWidth: 15, + yAxisSplit: 5, + xAxisHeight: 15, + xAxisLineHeight: 15, + legendHeight: 15, + yAxisTitleWidth: 15, + padding: 12, + pixelRatio:1,//适配H5高分屏 + rotate:false,//横屏模式 + columePadding: 3, + fontSize: 13, + //dataPointShape: ['diamond', 'circle', 'triangle', 'rect'], + dataPointShape: ['circle', 'circle', 'circle', 'circle'],//仿F2图例样式改为圆点 + colors: ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d'], + pieChartLinePadding: 15, + pieChartTextPadding: 5, + xAxisTextPadding: 3, + titleColor: '#333333', + titleFontSize: 20, + subtitleColor: '#999999', + subtitleFontSize: 15, + toolTipPadding: 3, + toolTipBackground: '#000000', + toolTipOpacity: 0.7, + toolTipLineHeight: 20, + radarGridCount: 3, + radarLabelTextMargin: 15, + gaugeLabelTextMargin:15 +}; + +// Object.assign polyfill +// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign +function assign(target, varArgs) { + if (target == null) { + // TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource != null) { + // Skip over if undefined or null + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; +} + +var util = { + toFixed: function toFixed(num, limit) { + limit = limit || 2; + if (this.isFloat(num)) { + num = num.toFixed(limit); + } + return num; + }, + isFloat: function isFloat(num) { + return num % 1 !== 0; + }, + approximatelyEqual: function approximatelyEqual(num1, num2) { + return Math.abs(num1 - num2) < 1e-10; + }, + isSameSign: function isSameSign(num1, num2) { + return Math.abs(num1) === num1 && Math.abs(num2) === num2 || Math.abs(num1) !== num1 && Math.abs(num2) !== num2; + }, + isSameXCoordinateArea: function isSameXCoordinateArea(p1, p2) { + return this.isSameSign(p1.x, p2.x); + }, + isCollision: function isCollision(obj1, obj2) { + obj1.end = {}; + obj1.end.x = obj1.start.x + obj1.width; + obj1.end.y = obj1.start.y - obj1.height; + obj2.end = {}; + obj2.end.x = obj2.start.x + obj2.width; + obj2.end.y = obj2.start.y - obj2.height; + var flag = obj2.start.x > obj1.end.x || obj2.end.x < obj1.start.x || obj2.end.y > obj1.start.y || obj2.start.y < obj1.end.y; + + return !flag; + } +}; + +// hex 转 rgba +function hexToRgb(hexValue, opc) { + var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + var hex = hexValue.replace(rgx, function (m, r, g, b) { + return r + r + g + g + b + b; + }); + var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + var r = parseInt(rgb[1], 16); + var g = parseInt(rgb[2], 16); + var b = parseInt(rgb[3], 16); + return 'rgba(' + r + ',' + g + ',' + b + ',' + opc + ')'; +} + +function findRange(num, type, limit) { + if (isNaN(num)) { + throw new Error('[wxCharts] unvalid series data!'); + } + limit = limit || 10; + type = type ? type : 'upper'; + var multiple = 1; + while (limit < 1) { + limit *= 10; + multiple *= 10; + } + if (type === 'upper') { + num = Math.ceil(num * multiple); + } else { + num = Math.floor(num * multiple); + } + while (num % limit !== 0) { + if (type === 'upper') { + num++; + } else { + num--; + } + } + + return num / multiple; +} + +function calValidDistance(distance, chartData, config, opts) { + + var dataChartAreaWidth = opts.width - config.padding - chartData.xAxisPoints[0]; + var dataChartWidth = chartData.eachSpacing * opts.categories.length; + var validDistance = distance; + if (distance >= 0) { + validDistance = 0; + } else if (Math.abs(distance) >= dataChartWidth - dataChartAreaWidth) { + validDistance = dataChartAreaWidth - dataChartWidth; + } + return validDistance; +} + +function isInAngleRange(angle, startAngle, endAngle) { + function adjust(angle) { + while (angle < 0) { + angle += 2 * Math.PI; + } + while (angle > 2 * Math.PI) { + angle -= 2 * Math.PI; + } + + return angle; + } + + angle = adjust(angle); + startAngle = adjust(startAngle); + endAngle = adjust(endAngle); + if (startAngle > endAngle) { + endAngle += 2 * Math.PI; + if (angle < startAngle) { + angle += 2 * Math.PI; + } + } + + return angle >= startAngle && angle <= endAngle; +} + +function calRotateTranslate(x, y, h) { + var xv = x; + var yv = h - y; + + var transX = xv + (h - yv - xv) / Math.sqrt(2); + transX *= -1; + + var transY = (h - yv) * (Math.sqrt(2) - 1) - (h - yv - xv) / Math.sqrt(2); + + return { + transX: transX, + transY: transY + }; +} + +function createCurveControlPoints(points, i) { + + function isNotMiddlePoint(points, i) { + if (points[i - 1] && points[i + 1]) { + return points[i].y >= Math.max(points[i - 1].y, points[i + 1].y) || points[i].y <= Math.min(points[i - 1].y, points[i + 1].y); + } else { + return false; + } + } + + var a = 0.2; + var b = 0.2; + var pAx = null; + var pAy = null; + var pBx = null; + var pBy = null; + if (i < 1) { + pAx = points[0].x + (points[1].x - points[0].x) * a; + pAy = points[0].y + (points[1].y - points[0].y) * a; + } else { + pAx = points[i].x + (points[i + 1].x - points[i - 1].x) * a; + pAy = points[i].y + (points[i + 1].y - points[i - 1].y) * a; + } + + if (i > points.length - 3) { + var last = points.length - 1; + pBx = points[last].x - (points[last].x - points[last - 1].x) * b; + pBy = points[last].y - (points[last].y - points[last - 1].y) * b; + } else { + pBx = points[i + 1].x - (points[i + 2].x - points[i].x) * b; + pBy = points[i + 1].y - (points[i + 2].y - points[i].y) * b; + } + + // fix issue https://github.com/xiaolin3303/wx-charts/issues/79 + if (isNotMiddlePoint(points, i + 1)) { + pBy = points[i + 1].y; + } + if (isNotMiddlePoint(points, i)) { + pAy = points[i].y; + } + + return { + ctrA: { x: pAx, y: pAy }, + ctrB: { x: pBx, y: pBy } + }; +} + +function convertCoordinateOrigin(x, y, center) { + return { + x: center.x + x, + y: center.y - y + }; +} + +function avoidCollision(obj, target) { + if (target) { + // is collision test + while (util.isCollision(obj, target)) { + if (obj.start.x > 0) { + obj.start.y--; + } else if (obj.start.x < 0) { + obj.start.y++; + } else { + if (obj.start.y > 0) { + obj.start.y++; + } else { + obj.start.y--; + } + } + } + } + return obj; +} + +function fillSeriesColor(series, config) { + var index = 0; + return series.map(function (item) { + if (!item.color) { + item.color = config.colors[index]; + index = (index + 1) % config.colors.length; + } + return item; + }); +} + +function fillSeriesType(series, opts) { + return series.map(function (item) { + if (!item.type) { + item.type = opts.type; + } + return item; + }); +} + +function getDataRange(minData, maxData) { + var limit = 0; + var range = maxData - minData; + if (range >= 10000) { + limit = 1000; + } else if (range >= 1000) { + limit = 100; + } else if (range >= 100) { + limit = 10; + } else if (range >= 10) { + limit = 5; + } else if (range >= 1) { + limit = 1; + } else if (range >= 0.1) { + limit = 0.1; + } else { + limit = 0.01; + } + return { + minRange: findRange(minData, 'lower', limit), + maxRange: findRange(maxData, 'upper', limit) + }; +} + +function measureText(text) { + var fontSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : config.fontSize; + + // wx canvas 未实现measureText方法, 此处自行实现 + // 适配修改初始字体10px为其他大小的方法 + text = String(text); + var text = text.split(''); + var width = 0; + text.forEach(function (item) { + if (/[a-zA-Z]/.test(item)) { + width += 7; + } else if (/[0-9]/.test(item)) { + width += 5.5; + } else if (/\./.test(item)) { + width += 2.7; + } else if (/-/.test(item)) { + width += 3.25; + } else if (/[\u4e00-\u9fa5]/.test(item)) { + width += 10; + } else if (/\(|\)/.test(item)) { + width += 3.73; + } else if (/\s/.test(item)) { + width += 2.5; + } else if (/%/.test(item)) { + width += 8; + } else { + width += 10; + } + }); + return width * fontSize / 10 ; +} + +function dataCombine(series) { + return series.reduce(function (a, b) { + return (a.data ? a.data : a).concat(b.data); + }, []); +} + +function dataCombineStack(series) { + var sum = new Array(series[0].data.length); + for(var j = 0; j < sum.length; j++) { + sum[j] =0; + } + for(var i = 0; i < series.length; i++) { + for(var j = 0; j < sum.length; j++) { + sum[j] += series[i].data[j]; + } + } + return series.reduce(function (a, b) { + return (a.data ? a.data : a).concat(b.data).concat(sum); + }, []); +} + +function getTouches(touches, opts, e){ + let x,y; + if(touches.clientX){ + if(opts.rotate){//适配横屏 + y = opts.height-touches.clientX*opts.pixelRatio; + x = (touches.pageY-e.mp.currentTarget.offsetTop-(opts.height/opts.pixelRatio/2)*(opts.pixelRatio-1))*opts.pixelRatio; + }else{ + x = touches.clientX*opts.pixelRatio; + y = (touches.pageY-e.mp.currentTarget.offsetTop-(opts.height/opts.pixelRatio/2)*(opts.pixelRatio-1))*opts.pixelRatio; + } + }else{ + if(opts.rotate){//适配横屏 + y = opts.height-touches.x*opts.pixelRatio; + x = touches.y*opts.pixelRatio; + }else{ + x = touches.x*opts.pixelRatio; + y = touches.y*opts.pixelRatio; + } + } + return{x:x,y:y} +} + +function getSeriesDataItem(series, index) { + var data = []; + series.forEach(function (item) { + if (item.data[index] !== null && typeof item.data[index] !== 'undefined') { + var seriesItem = {}; + seriesItem.color = item.color; + seriesItem.name = item.name; + seriesItem.data = item.format ? item.format(item.data[index]) : item.data[index]; + data.push(seriesItem); + } + }); + + return data; +} + +function getMaxTextListLength(list) { + var lengthList = list.map(function (item) { + return measureText(item); + }); + return Math.max.apply(null, lengthList); +} + +function getRadarCoordinateSeries(length) { + var eachAngle = 2 * Math.PI / length; + var CoordinateSeries = []; + for (var i = 0; i < length; i++) { + CoordinateSeries.push(eachAngle * i); + } + + return CoordinateSeries.map(function (item) { + return -1 * item + Math.PI / 2; + }); +} + +function getToolTipData(seriesData, calPoints, index, categories) { + var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; + + var textList = seriesData.map(function (item) { + return { + text: option.format ? option.format(item, categories[index]) : item.name + ': ' + item.data, + color: item.color + }; + }); + var validCalPoints = []; + var offset = { + x: 0, + y: 0 + }; + calPoints.forEach(function (points) { + if (typeof points[index] !== 'undefined' && points[index] !== null) { + validCalPoints.push(points[index]); + } + }); + validCalPoints.forEach(function (item) { + offset.x = Math.round(item.x); + offset.y += item.y; + }); + + offset.y /= validCalPoints.length; + return { textList: textList, offset: offset }; +} + +function getCandleToolTipData(series,seriesData, calPoints, index, categories,extra) { + var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {}; + let upColor = extra.color.upFill; + let downColor = extra.color.downFill; + //颜色顺序为开盘,收盘,最低,最高 + let color=[upColor,upColor,downColor,upColor]; + var textList = []; + let text0={ + text: categories[index], + color: null + }; + textList.push(text0); + seriesData.map(function (item) { + //console.log(color) + if(index==0 && item.data[1]-item.data[0]<0){ + color[1]=downColor; + }else{ + if(item.data[0]series[index-1][1]){ + color[2]=upColor; + } + if(item.data[3] 4 && arguments[4] !== undefined ? arguments[4] : 0; + var currentIndex = -1; + if (isInExactChartArea(currentPoints, opts, config)) { + xAxisPoints.forEach(function (item, index) { + if (currentPoints.x + offset > item) { + currentIndex = index; + } + }); + } + + return currentIndex; +} + +function isInExactChartArea(currentPoints, opts, config) { + return currentPoints.x < opts.width - config.padding && currentPoints.x > config.padding + config.yAxisWidth + config.yAxisTitleWidth && currentPoints.y > config.padding && currentPoints.y < opts.height - config.legendHeight - config.xAxisHeight - config.padding; +} + +function findRadarChartCurrentIndex(currentPoints, radarData, count) { + var eachAngleArea = 2 * Math.PI / count; + var currentIndex = -1; + if (isInExactPieChartArea(currentPoints, radarData.center, radarData.radius)) { + var fixAngle = function fixAngle(angle) { + if (angle < 0) { + angle += 2 * Math.PI; + } + if (angle > 2 * Math.PI) { + angle -= 2 * Math.PI; + } + return angle; + }; + + var angle = Math.atan2(radarData.center.y - currentPoints.y, currentPoints.x - radarData.center.x); + angle = -1 * angle; + if (angle < 0) { + angle += 2 * Math.PI; + } + + var angleList = radarData.angleList.map(function (item) { + item = fixAngle(-1 * item); + + return item; + }); + + angleList.forEach(function (item, index) { + var rangeStart = fixAngle(item - eachAngleArea / 2); + var rangeEnd = fixAngle(item + eachAngleArea / 2); + if (rangeEnd < rangeStart) { + rangeEnd += 2 * Math.PI; + } + if (angle >= rangeStart && angle <= rangeEnd || angle + 2 * Math.PI >= rangeStart && angle + 2 * Math.PI <= rangeEnd) { + currentIndex = index; + } + }); + } + + return currentIndex; +} + +function findPieChartCurrentIndex(currentPoints, pieData) { + var currentIndex = -1; + if (isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) { + var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x); + angle = -angle; + for (var i = 0, len = pieData.series.length; i < len; i++) { + var item = pieData.series[i]; + if (isInAngleRange(angle, item._start_, item._start_ + item._proportion_ * 2 * Math.PI)) { + currentIndex = i; + break; + } + } + } + + return currentIndex; +} + +function isInExactPieChartArea(currentPoints, center, radius) { + return Math.pow(currentPoints.x - center.x, 2) + Math.pow(currentPoints.y - center.y, 2) <= Math.pow(radius, 2); +} + +function splitPoints(points) { + var newPoints = []; + var items = []; + points.forEach(function (item, index) { + if (item !== null) { + items.push(item); + } else { + if (items.length) { + newPoints.push(items); + } + items = []; + } + }); + if (items.length) { + newPoints.push(items); + } + + return newPoints; +} + +function calLegendData(series, opts, config) { + if (opts.legend === false) { + return { + legendList: [], + legendHeight: 0 + }; + } + //适配H5高分屏 + var padding = 5*opts.pixelRatio; + var marginTop = 8*opts.pixelRatio; + var shapeWidth = 15*opts.pixelRatio; + var legendList = []; + var widthCount = 0; + var currentRow = []; + series.forEach(function (item) { + var itemWidth = 3 * padding + shapeWidth + measureText(item.name || 'undefined'); + if (widthCount + itemWidth > opts.width) { + legendList.push(currentRow); + widthCount = itemWidth; + currentRow = [item]; + } else { + widthCount += itemWidth; + currentRow.push(item); + } + }); + if (currentRow.length) { + legendList.push(currentRow); + } + + return { + legendList: legendList, + legendHeight: legendList.length * (config.fontSize + marginTop) + padding + }; +} + +function calCategoriesData(categories, opts, config) { + var result = { + angle: 0, + xAxisHeight: config.xAxisHeight + }; + + var _getXAxisPoints = getXAxisPoints(categories, opts, config), + eachSpacing = _getXAxisPoints.eachSpacing; + + // get max length of categories text + + + var categoriesTextLenth = categories.map(function (item) { + return measureText(item); + }); + + var maxTextLength = Math.max.apply(this, categoriesTextLenth); + + if (opts.xAxis.rotateLabel==true && maxTextLength + 2 * config.xAxisTextPadding > eachSpacing) { + result.angle = 45 * Math.PI / 180; + result.xAxisHeight = 2 * config.xAxisTextPadding + maxTextLength * Math.sin(result.angle); + } + + return result; +} + +function getRadarDataPoints(angleList, center, radius, series, opts) { + var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1; + + var radarOption = opts.extra.radar || {}; + radarOption.max = radarOption.max || 0; + var maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series))); + + var data = []; + series.forEach(function (each) { + var listItem = {}; + listItem.color = each.color; + listItem.data = []; + each.data.forEach(function (item, index) { + var tmp = {}; + tmp.angle = angleList[index]; + + tmp.proportion = item / maxData; + tmp.position = convertCoordinateOrigin(radius * tmp.proportion * process * Math.cos(tmp.angle), radius * tmp.proportion * process * Math.sin(tmp.angle), center); + listItem.data.push(tmp); + }); + + data.push(listItem); + }); + + return data; +} + +function getPieDataPoints(series) { + var process = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + + var count = 0; + var _start_ = 0; + series.forEach(function (item) { + item.data = item.data === null ? 0 : item.data; + count += item.data; + }); + series.forEach(function (item) { + item.data = item.data === null ? 0 : item.data; + item._proportion_ = item.data / count * process; + }); + series.forEach(function (item) { + item._start_ = _start_; + _start_ += 2 * item._proportion_ * Math.PI; + }); + + return series; +} + +function getArcbarDataPoints(series,arcbarOption) { + var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + if(process==1){ + process=0.999999; + } + series.forEach(function (item) { + item.data = item.data === null ? 0 : item.data; + let totalAngle; + if(arcbarOption.type=='default'){ + totalAngle=arcbarOption.startAngle-arcbarOption.endAngle+1; + }else{ + totalAngle=2; + } + item._proportion_ = totalAngle * item.data* process + arcbarOption.startAngle; + if (item._proportion_ >= 2) { + item._proportion_ = item._proportion_ % 2; + } + }); + return series; +} + +function getGaugeAxisPoints(categories,startAngle,endAngle) { + let totalAngle=startAngle-endAngle+1; + let tempStartAngle=startAngle; + for(let i=0 ; i= 2) { + categories[i]._endAngle_ = categories[i]._endAngle_ % 2; + } + tempStartAngle=categories[i]._endAngle_; + } + return categories; +} + +function getGaugeDataPoints(series,categories,gaugeOption) { + var process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1; + series.forEach(function (item) { + item.data = item.data === null ? 0 : item.data; + if(gaugeOption.pointer.color=='auto'){ + for(let i=0 ;i=gaugeOption.oldData){ + item._proportion_ = (item._endAngle_-item._oldAngle_)* process+gaugeOption.oldAngle; + }else{ + item._proportion_ =item._oldAngle_- (item._oldAngle_-item._endAngle_)* process; + } + if (item._proportion_ >= 2) { + item._proportion_ = item._proportion_ % 2; + } + }); + return series; +} + + +function getPieTextMaxLength(series) { + series = getPieDataPoints(series); + var maxLength = 0; + series.forEach(function (item) { + var text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%'; + maxLength = Math.max(maxLength, measureText(text)); + }); + + return maxLength; +} + +function fixColumeData(points, eachSpacing, columnLen, index, config, opts) { + return points.map(function (item) { + if (item === null) { + return null; + } + item.width = (eachSpacing - 2 * config.columePadding) / columnLen; + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + // customer column width + item.width = Math.min(item.width, +opts.extra.column.width); + } else { + // default width should less tran 25px + // don't ask me why, I don't know + item.width = Math.min(item.width, 25); + } + item.x += (index + 0.5 - columnLen / 2) * item.width; + + return item; + }); +} + +function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) { + return points.map(function (item) { + if (item === null) { + return null; + } + item.width = eachSpacing - 2 * config.columePadding; + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } else { + item.width = Math.min(item.width, 25); + } + if(index>0){ + item.width -= 2*border; + } + return item; + }); +} + +function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts,series) { + + return points.map(function (item,indexn) { + + if (item === null) { + return null; + } + item.width = eachSpacing - 2 * config.columePadding; + + if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) { + item.width = Math.min(item.width, +opts.extra.column.width); + } else { + item.width = Math.min(item.width, 25); + } + return item; + }); +} + +function getXAxisPoints(categories, opts, config) { + var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth; + var spacingValid = opts.width - 2 * config.padding - yAxisTotalWidth; + var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length; + var eachSpacing = spacingValid / dataCount; + + var xAxisPoints = []; + var startX = config.padding + yAxisTotalWidth; + var endX = opts.width - config.padding; + categories.forEach(function (item, index) { + xAxisPoints.push(startX + index * eachSpacing); + }); + if (opts.enableScroll === true) { + xAxisPoints.push(startX + categories.length * eachSpacing); + } else { + xAxisPoints.push(endX); + } + + return { xAxisPoints: xAxisPoints, startX: startX, endX: endX, eachSpacing: eachSpacing }; +} + +function getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) { + var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1; + + var points = []; + var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + data.forEach(function (item, index) { + if (item === null) { + points.push(null); + } else { + var cPoints = []; + item.forEach(function (items, indexs) { + var point = {}; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + var value = items.value || items; + var height = validHeight * (value - minRange) / (maxRange - minRange); + height *= process; + point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding; + cPoints.push(point); + }); + points.push(cPoints); + } + }); + + return points; +} + +function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) { + var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1; + + var points = []; + var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + data.forEach(function (item, index) { + if (item === null) { + points.push(null); + } else { + var point = {}; + point.color = item.color; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + var value = item.value || item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + height *= process; + point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding; + points.push(point); + } + }); + + return points; +} + +function getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,seriesIndex, stackSeries) { + var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1; + var points = []; + var validHeight = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + + data.forEach(function (item, index) { + if (item === null) { + points.push(null); + } else { + var point = {}; + point.color = item.color; + point.x = xAxisPoints[index] + Math.round(eachSpacing / 2); + + if(seriesIndex>0){ + var value=0; + for(let i=0;i<=seriesIndex;i++){ + value+=stackSeries[i].data[index]; + } + var value0 = value-item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + var height0 = validHeight * (value0 - minRange) / (maxRange - minRange); + }else{ + var value = item; + var height = validHeight * (value - minRange) / (maxRange - minRange); + var height0 = 0; + } + var heightc=height0; + height *= process; + heightc *= process; + point.y = opts.height - config.xAxisHeight - config.legendHeight - Math.round(height) - config.padding; + point.y0 = opts.height - config.xAxisHeight - config.legendHeight - Math.round(heightc) - config.padding; + points.push(point); + } + }); + + return points; +} + +function getYAxisTextList(series, opts, config ,stack) { + var data; + if(stack=='stack'){ + //data = dataCombine(series); + data = dataCombineStack(series); + }else{ + data = dataCombine(series); + } + + var sorted = []; + // remove null from data + data = data.filter(function (item) { + //return item !== null; + if(typeof item === 'object' && item !== null) { + //判断是否为数组 + if(item.constructor == Array){ + return item !== null; + }else{ + return item.value !== null; + } + } else { + return item !== null; + } + }); + //var minData = Math.min.apply(this, data); + //var maxData = Math.max.apply(this, data); + data.map((item)=>{ + if(typeof item === 'object') { + if(item.constructor == Array){ + item.map((subitem)=>{ + sorted.push(subitem); + }) + }else{ + sorted.push(item.value); + } + } else { + sorted.push(item); + } + //typeof item === 'object' ? sorted.push(item.value) : sorted.push(item) + }) + var minData = 0; + var maxData = 0; + if(sorted.length>0){ + minData = Math.min.apply(this, sorted); + maxData = Math.max.apply(this, sorted); + } + if (typeof opts.yAxis.min === 'number') { + minData = Math.min(opts.yAxis.min, minData); + } + if (typeof opts.yAxis.max === 'number') { + maxData = Math.max(opts.yAxis.max, maxData); + } + + // fix issue https://github.com/xiaolin3303/wx-charts/issues/9 + if (minData === maxData) { + var rangeSpan = maxData || 10; + //minData -= rangeSpan; + maxData += rangeSpan; + } + + var dataRange = getDataRange(minData, maxData); + var minRange = dataRange.minRange; + var maxRange = dataRange.maxRange; + + var range = []; + var eachRange = (maxRange - minRange) / config.yAxisSplit; + + for (var i = 0; i <= config.yAxisSplit; i++) { + range.push(minRange + eachRange * i); + } + return range.reverse(); +} + +function calYAxisData(series, opts, config) { + //堆叠图重算Y轴 + var columnstyle=assign({},opts.extra.column||{"type":""}); + + var ranges = getYAxisTextList(series, opts, config, columnstyle.type); + var yAxisWidth = config.yAxisWidth; + var rangesFormat = ranges.map(function (item) { + item = util.toFixed(item, 2); + item = opts.yAxis.format ? opts.yAxis.format(Number(item)) : item; + yAxisWidth = Math.max(yAxisWidth, measureText(item) + 5); + return item; + }); + if (opts.yAxis.disabled === true) { + yAxisWidth = 0; + } + + return { rangesFormat: rangesFormat, ranges: ranges, yAxisWidth: yAxisWidth }; +} + +function drawPointShape(points, color, shape, context,opts) { + context.beginPath(); + context.setStrokeStyle("#ffffff"); + context.setLineWidth(1*opts.pixelRatio); + context.setFillStyle(color); + if (shape === 'diamond') { + points.forEach(function (item, index) { + if (item !== null) { + context.moveTo(item.x, item.y - 4.5); + context.lineTo(item.x - 4.5, item.y); + context.lineTo(item.x, item.y + 4.5); + context.lineTo(item.x + 4.5, item.y); + context.lineTo(item.x, item.y - 4.5); + } + }); + } else if (shape === 'circle') { + points.forEach(function (item, index) { + if (item !== null) { + context.moveTo(item.x + 3.5*opts.pixelRatio, item.y); + context.arc(item.x, item.y, 4*opts.pixelRatio, 0, 2 * Math.PI, false); + } + }); + } else if (shape === 'rect') { + points.forEach(function (item, index) { + if (item !== null) { + context.moveTo(item.x - 3.5, item.y - 3.5); + context.rect(item.x - 3.5, item.y - 3.5, 7, 7); + } + }); + } else if (shape === 'triangle') { + points.forEach(function (item, index) { + if (item !== null) { + context.moveTo(item.x, item.y - 4.5); + context.lineTo(item.x - 4.5, item.y + 4.5); + context.lineTo(item.x + 4.5, item.y + 4.5); + context.lineTo(item.x, item.y - 4.5); + } + }); + } + + + context.closePath(); + context.fill(); + context.stroke(); +} + +function drawRingTitle(opts, config, context) { + var titlefontSize = opts.title.fontSize || config.titleFontSize; + var subtitlefontSize = opts.subtitle.fontSize || config.subtitleFontSize; + var title = opts.title.name || ''; + var subtitle = opts.subtitle.name || ''; + var titleFontColor = opts.title.color || config.titleColor; + var subtitleFontColor = opts.subtitle.color || config.subtitleColor; + var titleHeight = title ? titlefontSize : 0; + var subtitleHeight = subtitle ? subtitlefontSize : 0; + var margin = 5; + if (subtitle) { + var textWidth = measureText(subtitle, subtitlefontSize); + var startX = (opts.width - textWidth) / 2 + (opts.subtitle.offsetX || 0); + var startY = ((opts.height - config.legendHeight + subtitlefontSize) / 2 )+ (opts.subtitle.offsetY || 0); + if (title) { + startY -= (titleHeight + margin) / 2 ; + } + context.beginPath(); + context.setFontSize(subtitlefontSize); + context.setFillStyle(subtitleFontColor); + context.fillText(subtitle, startX, startY); + context.closePath(); + context.stroke(); + } + if (title) { + var _textWidth = measureText(title, titlefontSize); + var _startX = (opts.width - _textWidth) / 2 + (opts.title.offsetX || 0); + var _startY = ((opts.height - config.legendHeight + titlefontSize) / 2 ) + (opts.title.offsetY || 0); + if (subtitle) { + _startY += (subtitleHeight + margin) / 2; + } + context.beginPath(); + context.setFontSize(titlefontSize); + context.setFillStyle(titleFontColor); + context.fillText(title, _startX, _startY); + context.closePath(); + context.stroke(); + } +} + +function drawPointText(points, series, config, context) { + // 绘制数据文案 + var data = series.data; + + + points.forEach(function (item, index) { + if (item !== null) { + //var formatVal = series.format ? series.format(data[index]) : data[index]; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle('#666666'); + var value = data[index].value || data[index] + var formatVal = series.format ? series.format(value) : value; + context.fillText(formatVal, item.x - measureText(formatVal) / 2, item.y - 2); + context.closePath(); + context.stroke(); + } + }); + +} + +function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) { + radius -= gaugeOption.width/2+config.gaugeLabelTextMargin; + + let totalAngle=gaugeOption.startAngle-gaugeOption.endAngle+1; + let splitAngle=totalAngle/gaugeOption.splitLine.splitNumber; + let totalNumber=gaugeOption.endNumber-gaugeOption.startNumber; + let splitNumber=totalNumber/gaugeOption.splitLine.splitNumber; + let nowAngle=gaugeOption.startAngle; + let nowNumber=gaugeOption.startNumber; + for(let i=0;i=2){ + nowAngle=nowAngle % 2; + } + nowNumber+=splitNumber; + } + +} + +function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) { + var radarOption = opts.extra.radar || {}; + radius += config.radarLabelTextMargin; + + angleList.forEach(function (angle, index) { + var pos = { + x: radius * Math.cos(angle), + y: radius * Math.sin(angle) + }; + var posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition); + var startX = posRelativeCanvas.x; + var startY = posRelativeCanvas.y; + if (util.approximatelyEqual(pos.x, 0)) { + startX -= measureText(opts.categories[index] || '') / 2; + } else if (pos.x < 0) { + startX -= measureText(opts.categories[index] || ''); + } + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(radarOption.labelColor || '#666666'); + context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2); + context.closePath(); + context.stroke(); + }); + +} + +function drawPieText(series, opts, config, context, radius, center) { + var lineRadius = radius + config.pieChartLinePadding; + var textObjectCollection = []; + var lastTextObject = null; + + var seriesConvert = series.map(function (item) { + var arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._proportion_ / 2); + var text = item.format ? item.format(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%'; + var color = item.color; + return { arc: arc, text: text, color: color }; + }); + seriesConvert.forEach(function (item) { + // line end + var orginX1 = Math.cos(item.arc) * lineRadius; + var orginY1 = Math.sin(item.arc) * lineRadius; + + // line start + var orginX2 = Math.cos(item.arc) * radius; + var orginY2 = Math.sin(item.arc) * radius; + + // text start + var orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding; + var orginY3 = orginY1; + + var textWidth = measureText(item.text); + var startY = orginY3; + + if (lastTextObject && util.isSameXCoordinateArea(lastTextObject.start, { x: orginX3 })) { + if (orginX3 > 0) { + startY = Math.min(orginY3, lastTextObject.start.y); + } else if (orginX1 < 0) { + startY = Math.max(orginY3, lastTextObject.start.y); + } else { + if (orginY3 > 0) { + startY = Math.max(orginY3, lastTextObject.start.y); + } else { + startY = Math.min(orginY3, lastTextObject.start.y); + } + } + } + + if (orginX3 < 0) { + orginX3 -= textWidth; + } + + var textObject = { + lineStart: { + x: orginX2, + y: orginY2 + }, + lineEnd: { + x: orginX1, + y: orginY1 + }, + start: { + x: orginX3, + y: startY + }, + width: textWidth, + height: config.fontSize, + text: item.text, + color: item.color + }; + + lastTextObject = avoidCollision(textObject, lastTextObject); + textObjectCollection.push(lastTextObject); + }); + + textObjectCollection.forEach(function (item) { + var lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center); + var lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center); + var textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center); + context.setLineWidth(1*opts.pixelRatio); + context.setFontSize(config.fontSize); + context.beginPath(); + context.setStrokeStyle(item.color); + context.setFillStyle(item.color); + context.moveTo(lineStartPoistion.x, lineStartPoistion.y); + var curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x; + var textStartX = item.start.x < 0 ? textPosition.x - 5 : textPosition.x + 5; + context.quadraticCurveTo(lineEndPoistion.x, lineEndPoistion.y, curveStartX, textPosition.y); + context.moveTo(lineStartPoistion.x, lineStartPoistion.y); + context.stroke(); + context.closePath(); + context.beginPath(); + context.moveTo(textPosition.x + item.width, textPosition.y); + context.arc(curveStartX, textPosition.y, 2, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle('#666666'); + context.fillText(item.text, textStartX, textPosition.y + 3); + context.closePath(); + context.stroke(); + context.closePath(); + }); +} + +function drawToolTipSplitLine(offsetX, opts, config, context) { + var startY = config.padding; + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + context.beginPath(); + context.setStrokeStyle('#cccccc'); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(offsetX, startY); + context.lineTo(offsetX, endY); + context.closePath(); + context.stroke(); +} + +function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) { + var startY = config.padding; + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + context.beginPath(); + context.setFillStyle(hexToRgb('#000000', 0.08)); + context.rect(offsetX-eachSpacing/2, startY, eachSpacing, endY-startY); + context.closePath(); + context.fill(); +} + +function drawToolTip(textList, offset, opts, config, context) { + var legendWidth = 4*opts.pixelRatio; + var legendMarginRight = 5*opts.pixelRatio; + var arrowWidth = 8*opts.pixelRatio; + var isOverRightBorder = false; + offset = assign({ + x: 0, + y: 0 + }, offset); + offset.y -= 8*opts.pixelRatio; + var textWidth = textList.map(function (item) { + return measureText(item.text); + }); + + var toolTipWidth = legendWidth + legendMarginRight + 4 * config.toolTipPadding + Math.max.apply(null, textWidth); + var toolTipHeight = 2 * config.toolTipPadding + textList.length * config.toolTipLineHeight; + + // if beyond the right border + if (offset.x - Math.abs(opts._scrollDistance_) + arrowWidth + toolTipWidth > opts.width) { + isOverRightBorder = true; + } + + // draw background rect + context.beginPath(); + context.setFillStyle(hexToRgb(opts.tooltip.option.background || config.toolTipBackground, config.toolTipOpacity)); + if (isOverRightBorder) { + context.moveTo(offset.x, offset.y + 10*opts.pixelRatio); + context.lineTo(offset.x - arrowWidth, offset.y + 10*opts.pixelRatio - 5*opts.pixelRatio); + context.lineTo(offset.x - arrowWidth, offset.y); + context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y); + context.lineTo(offset.x - arrowWidth - Math.round(toolTipWidth), offset.y+toolTipHeight); + context.lineTo(offset.x - arrowWidth, offset.y+toolTipHeight); + context.lineTo(offset.x - arrowWidth, offset.y + 10*opts.pixelRatio + 5*opts.pixelRatio); + context.lineTo(offset.x, offset.y + 10*opts.pixelRatio); + } else { + context.moveTo(offset.x, offset.y + 10*opts.pixelRatio); + context.lineTo(offset.x + arrowWidth, offset.y + 10*opts.pixelRatio - 5*opts.pixelRatio); + context.lineTo(offset.x + arrowWidth, offset.y); + context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y); + context.lineTo(offset.x + arrowWidth + Math.round(toolTipWidth), offset.y+toolTipHeight); + context.lineTo(offset.x + arrowWidth, offset.y+toolTipHeight); + context.lineTo(offset.x + arrowWidth, offset.y + 10*opts.pixelRatio + 5*opts.pixelRatio); + context.lineTo(offset.x, offset.y + 10*opts.pixelRatio); + } + + context.closePath(); + context.fill(); + + // draw legend + textList.forEach(function (item, index) { + if(item.color !== null){ + context.beginPath(); + context.setFillStyle(item.color); + var startX = offset.x + arrowWidth + 2 * config.toolTipPadding; + var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + config.toolTipPadding + 1; + if (isOverRightBorder) { + startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding; + } + context.fillRect(startX, startY, legendWidth, config.fontSize); + context.closePath(); + } + }); + + // draw text list + + textList.forEach(function (item, index) { + var startX = offset.x + arrowWidth + 2 * config.toolTipPadding + legendWidth + legendMarginRight; + if (isOverRightBorder) { + startX = offset.x - toolTipWidth - arrowWidth + 2 * config.toolTipPadding + +legendWidth + legendMarginRight; + } + var startY = offset.y + (config.toolTipLineHeight - config.fontSize) / 2 + config.toolTipLineHeight * index + config.toolTipPadding; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle('#ffffff'); + context.fillText(item.text, startX, startY + config.fontSize); + context.closePath(); + context.stroke(); + }); +} + +function drawYAxisTitle(title, opts, config, context) { + var startX = config.xAxisHeight + (opts.height - config.xAxisHeight - measureText(title)) / 2; + context.save(); + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.yAxis.titleFontColor || '#333333'); + context.translate(0, opts.height); + context.rotate(-90 * Math.PI / 180); + context.fillText(title, startX, config.padding + 0.5 * config.fontSize); + context.closePath(); + context.stroke(); + context.restore(); +} + +function drawColumnDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var columnOption = opts.extra.column || {type:{},meter:{}}; + columnOption.type=columnOption.type==undefined? 'group':columnOption.type; + columnOption.meter=columnOption.meter||{} + columnOption.meter.border=columnOption.meter.border==undefined? 4:columnOption.meter.border; + columnOption.meter.fillColor=columnOption.meter.fillColor==undefined? '#FFFFFF':columnOption.meter.fillColor; + var _calYAxisData = calYAxisData(series, opts, config), + ranges = _calYAxisData.ranges; + + var _getXAxisPoints = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints.xAxisPoints, + eachSpacing = _getXAxisPoints.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing); + } + + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + switch (columnOption.type){ + case 'group': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + var tooltipPoints = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series,process); + calPoints.push(tooltipPoints); + points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + break; + case 'stack': + // 绘制堆叠数据图 + var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series,process); + calPoints.push(points); + points = fixColumeStackData(points, eachSpacing, series.length, seriesIndex, config, opts,series); + + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + var height0 = opts.height - item.y0 - config.padding - config.xAxisHeight - config.legendHeight; + if(seriesIndex>0){ + height -= height0; + } + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + break; + case 'meter': + // 绘制温度计数据图 + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + points = fixColumeMeterData(points, eachSpacing, series.length, seriesIndex, config, opts, columnOption.meter.border); + if(seriesIndex==0){ + points.forEach(function (item, index) { + if (item !== null) { + //画背景颜色 + context.beginPath(); + context.setFillStyle(columnOption.meter.fillColor); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + //画边框线 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(columnOption.meter.border*opts.pixelRatio); + context.moveTo(startX+columnOption.meter.border*0.5, item.y+height); + context.lineTo(startX+columnOption.meter.border*0.5, item.y+columnOption.meter.border*0.5); + context.lineTo(startX+item.width-columnOption.meter.border, item.y+columnOption.meter.border*0.5); + context.lineTo(startX+item.width-columnOption.meter.border, item.y+height); + context.stroke(); + } + }); + }else{ + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + } + break; + } + }); + if (opts.dataLabel !== false && process === 1) { + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + switch (columnOption.type){ + case 'group': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts); + drawPointText(points, eachSeries, config, context); + break; + case 'stack': + var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series,process); + drawPointText(points, eachSeries, config, context); + break; + case 'meter': + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + break; + } + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + +function drawCandleDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + var candleOption = opts.extra.candle || {color:{},average:{}}; + candleOption.color.upLine=candleOption.color.upLine? candleOption.color.upLine: '#f04864'; + candleOption.color.upFill=candleOption.color.upFill? candleOption.color.upFill: '#f04864'; + candleOption.color.downLine=candleOption.color.downLine? candleOption.color.downLine: '#2fc25b'; + candleOption.color.downFill=candleOption.color.downFill? candleOption.color.downFill: '#2fc25b'; + candleOption.average.show = candleOption.average.show===true? true : false; + candleOption.average.name = candleOption.average.name? candleOption.average.name : []; + candleOption.average.day = candleOption.average.day? candleOption.average.day : []; + candleOption.average.color = candleOption.average.color? candleOption.average.color : ['#1890ff', '#2fc25b', '#facc14', '#f04864', '#8543e0', '#90ed7d']; + opts.extra.candle=candleOption; + + var _calYAxisData5 = calYAxisData(series, opts, config), + ranges = _calYAxisData5.ranges; + + var _getXAxisPoints5 = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints5.xAxisPoints, + eachSpacing = _getXAxisPoints5.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + var splitPointList = splitPoints(points); + splitPointList=splitPointList[0]; + + splitPointList.forEach(function (points, index) { + context.beginPath(); + //如果上涨 + if(data[index][1]-data[index][0]>0){ + context.setStrokeStyle(candleOption.color.upLine); + context.setFillStyle(candleOption.color.upFill); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(points[3].x, points[3].y);//顶点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.lineTo(points[1].x-eachSpacing/4, points[1].y);//收盘左侧点 + context.lineTo(points[0].x-eachSpacing/4, points[0].y);//开盘左侧点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.lineTo(points[2].x, points[2].y);//底点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.lineTo(points[0].x+eachSpacing/4, points[0].y);//开盘右侧点 + context.lineTo(points[1].x+eachSpacing/4, points[1].y);//收盘右侧点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.moveTo(points[3].x, points[3].y);//顶点 + }else{ + context.setStrokeStyle(candleOption.color.downLine); + context.setFillStyle(candleOption.color.downFill); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(points[3].x, points[3].y);//顶点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.lineTo(points[0].x-eachSpacing/4, points[0].y);//开盘左侧点 + context.lineTo(points[1].x-eachSpacing/4, points[1].y);//收盘左侧点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.lineTo(points[2].x, points[2].y);//底点 + context.lineTo(points[1].x, points[1].y);//收盘中间点 + context.lineTo(points[1].x+eachSpacing/4, points[1].y);//收盘右侧点 + context.lineTo(points[0].x+eachSpacing/4, points[0].y);//开盘右侧点 + context.lineTo(points[0].x, points[0].y);//开盘中间点 + context.moveTo(points[3].x, points[3].y);//顶点 + } + context.closePath(); + context.fill(); + context.stroke(); + }); + }); + + context.restore(); + + //画均线 + if(candleOption.average.show){ + + } + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + +function drawAreaDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var _calYAxisData2 = calYAxisData(series, opts, config), + ranges = _calYAxisData2.ranges; + + var _getXAxisPoints2 = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints2.xAxisPoints, + eachSpacing = _getXAxisPoints2.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + var calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + + + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + + var splitPointList = splitPoints(points); + + splitPointList.forEach(function (points) { + // 绘制区域数据 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setFillStyle(eachSeries.color); + context.setGlobalAlpha(0.2); + context.setLineWidth(2*opts.pixelRatio); + if (points.length > 1) { + var firstPoint = points[0]; + var lastPoint = points[points.length - 1]; + + context.moveTo(firstPoint.x, firstPoint.y); + if (opts.extra.lineStyle === 'curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + + context.lineTo(lastPoint.x, endY); + context.lineTo(firstPoint.x, endY); + context.lineTo(firstPoint.x, firstPoint.y); + } else { + var item = points[0]; + context.moveTo(item.x - eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, endY); + context.lineTo(item.x - eachSpacing / 2, endY); + context.moveTo(item.x - eachSpacing / 2, item.y); + } + context.closePath(); + context.fill(); + context.setGlobalAlpha(1); + + + //画连线 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (opts.extra.lineStyle === 'curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + + //画点 + if (opts.dataPointShape !== false) { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context,opts); + } + + }); + if (opts.dataLabel !== false && process === 1) { + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + +function drawLineDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var _calYAxisData3 = calYAxisData(series, opts, config), + ranges = _calYAxisData3.ranges; + + var _getXAxisPoints3 = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints3.xAxisPoints, + eachSpacing = _getXAxisPoints3.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var calPoints = []; + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + var splitPointList = splitPoints(points); + + splitPointList.forEach(function (points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (opts.extra.lineStyle === 'curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + + if (opts.dataPointShape !== false) { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context,opts); + } + }); + if (opts.dataLabel !== false && process === 1) { + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + drawPointText(points, eachSeries, config, context); + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + +function drawMixDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var _calYAxisData6 = calYAxisData(series, opts, config), + ranges = _calYAxisData6.ranges; + + var _getXAxisPoints6 = getXAxisPoints(opts.categories, opts, config), + xAxisPoints = _getXAxisPoints6.xAxisPoints, + eachSpacing = _getXAxisPoints6.eachSpacing; + + var minRange = ranges.pop(); + var maxRange = ranges.shift(); + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + var calPoints = []; + + var columnIndex=0; + var columnLength=0; + series.forEach(function (eachSeries, seriesIndex) { + if(eachSeries.type=='column'){ + columnLength+=1; + } + }); + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context); + } + + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + calPoints.push(points); + + // 绘制柱状数据图 + if(eachSeries.type=='column'){ + points = fixColumeData(points, eachSpacing, columnLength , columnIndex, config, opts); + points.forEach(function (item, index) { + if (item !== null) { + context.beginPath(); + context.setFillStyle(item.color || eachSeries.color); + var startX = item.x - item.width / 2 + 1; + var height = opts.height - item.y - config.padding - config.xAxisHeight - config.legendHeight; + context.moveTo(startX, item.y); + context.rect(startX, item.y, item.width - 2, height); + context.closePath(); + context.fill(); + } + }); + columnIndex+=1; + } + + //绘制区域图数据 + + if(eachSeries.type=='area'){ + var splitPointList = splitPoints(points); + splitPointList.forEach(function (points) { + // 绘制区域数据 + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setFillStyle(eachSeries.color); + context.setGlobalAlpha(0.2); + context.setLineWidth(2*opts.pixelRatio); + if (points.length > 1) { + var firstPoint = points[0]; + var lastPoint = points[points.length - 1]; + context.moveTo(firstPoint.x, firstPoint.y); + if (eachSeries.style === 'curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.lineTo(lastPoint.x, endY); + context.lineTo(firstPoint.x, endY); + context.lineTo(firstPoint.x, firstPoint.y); + } else { + var item = points[0]; + context.moveTo(item.x - eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, item.y); + context.lineTo(item.x + eachSpacing / 2, endY); + context.lineTo(item.x - eachSpacing / 2, endY); + context.moveTo(item.x - eachSpacing / 2, item.y); + } + context.closePath(); + context.fill(); + context.setGlobalAlpha(1); + }); + } + + + + // 绘制折线数据图 + if(eachSeries.type=='line'){ + var splitPointList = splitPoints(points); + splitPointList.forEach(function (points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + if (points.length === 1) { + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + } else { + context.moveTo(points[0].x, points[0].y); + if (eachSeries.style=='curve') { + points.forEach(function (item, index) { + if (index > 0) { + var ctrlPoint = createCurveControlPoints(points, index - 1); + context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y); + } + }); + } else { + points.forEach(function (item, index) { + if (index > 0) { + context.lineTo(item.x, item.y); + } + }); + } + context.moveTo(points[0].x, points[0].y); + } + context.closePath(); + context.stroke(); + }); + } + + // 绘制点数据图 + if(eachSeries.type=='point'){ + var splitPointList = splitPoints(points); + splitPointList.forEach(function (points, index) { + context.beginPath(); + context.setStrokeStyle(eachSeries.color); + context.setLineWidth(2*opts.pixelRatio); + context.moveTo(points[0].x, points[0].y); + context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI); + context.closePath(); + context.stroke(); + }); + } + + if (opts.dataPointShape !== false && eachSeries.type!=='column') { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + drawPointShape(points, eachSeries.color, shape, context,opts); + } + }); + if (opts.dataLabel !== false && process === 1) { + var columnIndex=0; + series.forEach(function (eachSeries, seriesIndex) { + var data = eachSeries.data; + var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process); + if(eachSeries.type!=='column'){ + drawPointText(points, eachSeries, config, context); + }else{ + points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts); + drawPointText(points, eachSeries, config, context); + columnIndex+=1; + } + + }); + } + + context.restore(); + + return { + xAxisPoints: xAxisPoints, + calPoints: calPoints, + eachSpacing: eachSpacing + }; +} + +function drawToolTipBridge(opts, config, context, process) { + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) { + context.translate(opts._scrollDistance_, 0); + } + if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) { + drawToolTip(opts.tooltip.textList, opts.tooltip.offset, opts, config, context); + } + context.restore(); +} + +function drawXAxis(categories, opts, config, context) { + + if (opts.xAxis.disabled === true) { + return; + } + + var _getXAxisPoints4 = getXAxisPoints(categories, opts, config), + xAxisPoints = _getXAxisPoints4.xAxisPoints, + startX = _getXAxisPoints4.startX, + endX = _getXAxisPoints4.endX, + eachSpacing = _getXAxisPoints4.eachSpacing; + + var startY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + var endY = config.padding; + + + //绘制滚动条 + if(opts.enableScroll && opts.xAxis.scrollShow){ + var scrollY=opts.height - config.padding - config.legendHeight + 4*opts.pixelRatio; + var scrollScreenWidth=endX-startX; + var scrollTotalWidth=eachSpacing*(xAxisPoints.length-1); + var scrollWidth=scrollScreenWidth*scrollScreenWidth/scrollTotalWidth; + var scrollLeft=0; + if (opts._scrollDistance_){ + scrollLeft=-opts._scrollDistance_*(scrollScreenWidth)/scrollTotalWidth; + } + context.beginPath(); + context.setLineCap('round'); + context.setLineWidth(6*opts.pixelRatio); + context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF"); + context.moveTo(startX, scrollY); + context.lineTo(endX, scrollY); + context.stroke(); + context.closePath(); + context.beginPath(); + context.setLineCap('round'); + context.setLineWidth(6*opts.pixelRatio); + context.setStrokeStyle(opts.xAxis.scrollColor ||"#A6A6A6"); + context.moveTo(startX+scrollLeft, scrollY); + context.lineTo(startX+scrollLeft+scrollWidth, scrollY); + context.stroke(); + context.closePath(); + } + + context.save(); + + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) { + context.translate(opts._scrollDistance_, 0); + } + + context.beginPath(); + context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc"); + context.setLineCap('butt'); + context.setLineWidth(1*opts.pixelRatio); + if(opts.xAxis.gridType=='dash'){ + context.setLineDash([opts.xAxis.dashLength]); + } + if (opts.xAxis.disableGrid !== true) { + if (opts.xAxis.type === 'calibration') { + xAxisPoints.forEach(function (item, index) { + if (index > 0) { + context.moveTo(item - eachSpacing / 2, startY); + context.lineTo(item - eachSpacing / 2, startY + 4*opts.pixelRatio); + } + }); + } else { + xAxisPoints.forEach(function (item, index) { + context.moveTo(item, startY); + context.lineTo(item, endY); + }); + } + } + context.closePath(); + context.stroke(); + context.setLineDash([]); + + // 对X轴列表做抽稀处理 + var validWidth = opts.width - 2 * config.padding - config.yAxisWidth - config.yAxisTitleWidth; + var maxXAxisListLength = Math.min(categories.length, Math.ceil(validWidth / config.fontSize / 1.5)); + var ratio = Math.ceil(categories.length / maxXAxisListLength); + + categories = categories.map(function (item, index) { + return index % ratio !== 0 ? '' : item; + }); + + if (config._xAxisTextAngle_ === 0) { + + categories.forEach(function (item, index) { + var offset = eachSpacing / 2 - measureText(item) / 2; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.xAxis.fontColor || '#666666'); + context.fillText(item, xAxisPoints[index] + offset, startY + config.fontSize + 5); + context.closePath(); + context.stroke(); + }); + + } else { + categories.forEach(function (item, index) { + context.save(); + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.xAxis.fontColor || '#666666'); + var textWidth = measureText(item); + var offset = eachSpacing / 2 - textWidth; + + var _calRotateTranslate = calRotateTranslate(xAxisPoints[index] + eachSpacing / 2, startY + config.fontSize / 2 + 5, opts.height), + transX = _calRotateTranslate.transX, + transY = _calRotateTranslate.transY; + + context.rotate(-1 * config._xAxisTextAngle_); + context.translate(transX, transY); + context.fillText(item, xAxisPoints[index] + offset, startY + config.fontSize + 5); + context.closePath(); + context.stroke(); + context.restore(); + }); + } + + context.restore(); + +} + +function drawYAxisGrid(categories,opts, config, context) { + if (opts.yAxis.disableGrid === true) { + return; + } + var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + var eachSpacing = Math.floor(spacingValid / config.yAxisSplit); + var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth; + var startX = config.padding + yAxisTotalWidth; + var _getXAxisPoints4 = getXAxisPoints(categories, opts, config), + xAxisPoints = _getXAxisPoints4.xAxisPoints, + xAxiseachSpacing = _getXAxisPoints4.eachSpacing; + var TotalWidth=xAxiseachSpacing*(xAxisPoints.length-1); + var endX = startX+TotalWidth; + + var points = []; + for (var i = 0; i < config.yAxisSplit; i++) { + points.push(config.padding + eachSpacing * i); + } + points.push(config.padding + eachSpacing * config.yAxisSplit + 2); + + context.save(); + if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) { + context.translate(opts._scrollDistance_, 0); + } + + if(opts.yAxis.gridType=='dash'){ + context.setLineDash([opts.yAxis.dashLength]); + } + context.beginPath(); + context.setStrokeStyle(opts.yAxis.gridColor || "#cccccc"); + + context.setLineWidth(1*opts.pixelRatio); + points.forEach(function (item, index) { + context.moveTo(startX, item); + context.lineTo(endX, item); + }); + context.closePath(); + context.stroke(); + context.setLineDash([]); + + context.restore(); +} + +function drawYAxis(series, opts, config, context) { + if (opts.yAxis.disabled === true) { + return; + } + + var _calYAxisData4 = calYAxisData(series, opts, config), + rangesFormat = _calYAxisData4.rangesFormat; + + var yAxisTotalWidth = config.yAxisWidth + config.yAxisTitleWidth; + + var spacingValid = opts.height - 2 * config.padding - config.xAxisHeight - config.legendHeight; + var eachSpacing = Math.floor(spacingValid / config.yAxisSplit); + var startX = config.padding + yAxisTotalWidth; + var endX = opts.width - config.padding; + var endY = opts.height - config.padding - config.xAxisHeight - config.legendHeight; + + // set YAxis background + context.setFillStyle(opts.background || '#ffffff'); + if (opts._scrollDistance_ < 0) { + context.fillRect(0, 0, startX, endY + config.xAxisHeight ); + } + context.fillRect(endX, 0, opts.width, endY + config.xAxisHeight ); + + var points = []; + for (var i = 0; i <= config.yAxisSplit; i++) { + points.push(config.padding + eachSpacing * i); + } + + context.stroke(); + + rangesFormat.forEach(function (item, index) { + var pos = points[index] ? points[index] : endY; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.yAxis.fontColor || '#666666'); + context.fillText(item, config.padding + config.yAxisTitleWidth, pos + config.fontSize / 2); + context.closePath(); + context.stroke(); + }); + + + if (opts.yAxis.title) { + drawYAxisTitle(opts.yAxis.title, opts, config, context); + } +} + +function drawLegend(series, opts, config, context) { + if (!opts.legend) { + return; + } + // each legend shape width 15px + // the spacing between shape and text in each legend is the `padding` + // each legend spacing is the `padding` + // legend margin top `config.padding` + + var _calLegendData = calLegendData(series, opts, config), + legendList = _calLegendData.legendList; + + var padding = 5*opts.pixelRatio; + var marginTop = 10*opts.pixelRatio; + var shapeWidth = 15*opts.pixelRatio; + legendList.forEach(function (itemList, listIndex) { + var width = 0; + itemList.forEach(function (item) { + item.name = item.name || 'undefined'; + width += 3 * padding + measureText(item.name) + shapeWidth; + }); + var startX = (opts.width - width) / 2 + padding; + var startY = opts.height - config.padding - config.legendHeight + listIndex * (config.fontSize + marginTop) + padding + marginTop; + + context.setFontSize(config.fontSize); + itemList.forEach(function (item) { + switch (opts.type) { + case 'line': + context.beginPath(); + /* + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); + context.moveTo(startX - 2, startY + 5); + context.lineTo(startX + 17, startY + 5); + context.stroke(); + context.closePath(); + context.beginPath(); + */ + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); + context.setFillStyle(item.color); + context.moveTo(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio); + context.arc(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio, 6*opts.pixelRatio, 0, 2 * Math.PI); + context.fill(); + context.stroke(); + context.closePath(); + break; + case 'pie': + context.beginPath(); + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); + context.setFillStyle(item.color); + context.moveTo(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio); + context.arc(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio, 6*opts.pixelRatio, 0, 2 * Math.PI); + context.fill(); + context.stroke(); + context.closePath(); + break; + case 'ring': + context.beginPath(); + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(item.color); + context.setFillStyle(item.color); + context.moveTo(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio); + context.arc(startX + 7.5*opts.pixelRatio, startY + 5*opts.pixelRatio, 6*opts.pixelRatio, 0, 2 * Math.PI); + context.fill(); + context.stroke(); + context.closePath(); + break; + //圆弧进度图不显示图例 + case 'gauge': + break; + case 'arcbar': + break; + default: + context.beginPath(); + context.setFillStyle(item.color); + context.moveTo(startX, startY); + context.rect(startX, startY, 15*opts.pixelRatio, 10*opts.pixelRatio); + context.closePath(); + context.fill(); + } + startX += padding + shapeWidth; + context.beginPath(); + context.setFontSize(config.fontSize); + context.setFillStyle(opts.extra.legendTextColor || '#333333'); + context.fillText(item.name, startX, startY + 6*opts.pixelRatio+3*opts.pixelRatio); + context.closePath(); + context.stroke(); + startX += measureText(item.name) + 2 * padding; + }); + }); +} + +function drawPieDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var pieOption = opts.extra.pie || {}; + series = getPieDataPoints(series, process); + var centerPosition = { + x: opts.width / 2, + y: (opts.height - config.legendHeight) / 2 + }; + var radius = Math.min(centerPosition.x - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, centerPosition.y - config.pieChartLinePadding - config.pieChartTextPadding); + if (opts.dataLabel) { + radius -= 10; + } else { + radius -= 2 * config.padding; + } + series = series.map(function (eachSeries) { + eachSeries._start_ += (pieOption.offsetAngle || 0) * Math.PI / 180; + return eachSeries; + }); + series.forEach(function (eachSeries) { + context.beginPath(); + context.setLineWidth(2*opts.pixelRatio); + context.setStrokeStyle('#ffffff'); + context.setFillStyle(eachSeries.color); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, radius, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI); + context.closePath(); + context.fill(); + if (opts.disablePieStroke !== true) { + context.stroke(); + } + }); + + if (opts.type === 'ring') { + var innerPieWidth = radius * 0.6; + if (typeof opts.extra.ringWidth === 'number' && opts.extra.ringWidth > 0) { + innerPieWidth = Math.max(0, radius - opts.extra.ringWidth); + } + context.beginPath(); + context.setFillStyle(opts.background || '#ffffff'); + context.moveTo(centerPosition.x, centerPosition.y); + context.arc(centerPosition.x, centerPosition.y, innerPieWidth, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + } + + if (opts.dataLabel !== false && process === 1) { + // fix https://github.com/xiaolin3303/wx-charts/issues/132 + var valid = false; + for (var i = 0, len = series.length; i < len; i++) { + if (series[i].data > 0) { + valid = true; + break; + } + } + + if (valid) { + drawPieText(series, opts, config, context, radius, centerPosition); + } + } + + if (process === 1 && opts.type === 'ring') { + drawRingTitle(opts, config, context); + } + + return { + center: centerPosition, + radius: radius, + series: series + }; +} + +function drawArcbarDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var arcbarOption = opts.extra.arcbar || {}; + arcbarOption.startAngle=arcbarOption.startAngle? arcbarOption.startAngle: 0.75; + arcbarOption.endAngle=arcbarOption.endAngle? arcbarOption.endAngle : 0.25; + arcbarOption.type=arcbarOption.type? arcbarOption.type : 'default'; + + series = getArcbarDataPoints(series, arcbarOption, process); + var centerPosition = { + x: opts.width / 2, + y: (opts.height) / 2 + }; + var radius = Math.min(centerPosition.x , centerPosition.y); + + if (typeof arcbarOption.width === 'number' && arcbarOption.width > 0) { + arcbarOption.width=arcbarOption.width; + }else{ + arcbarOption.width=12*opts.pixelRatio; + } + radius -= config.padding+arcbarOption.width/2; + + //背景颜色 + context.setLineWidth(arcbarOption.width); // 设置圆环的宽度 + context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9'); // 设置圆环的颜色 + context.setLineCap('round'); // 设置圆环端点的形状 + context.beginPath(); //开始一个新的路径 + if(arcbarOption.type=='default'){ + context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * Math.PI, false); + }else{ + context.arc(centerPosition.x, centerPosition.y, radius, 0, 2 * Math.PI, false); + } + + context.stroke(); //对当前路径进行描边 + + + series.forEach(function (eachSeries) { + context.setLineWidth(arcbarOption.width); + context.setStrokeStyle(eachSeries.color); + context.setLineCap('round'); + context.beginPath(); + context.arc(centerPosition.x, centerPosition.y, radius, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ * Math.PI, false); + context.stroke(); + + }); + drawRingTitle(opts, config, context); + return { + center: centerPosition, + radius: radius, + series: series + }; +} + +function drawGaugeDataPoints(categories,series, opts, config, context) { + var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1; + var gaugeOption = opts.extra.gauge || {}; + gaugeOption.startAngle=gaugeOption.startAngle? gaugeOption.startAngle: 0.75; + if(gaugeOption.oldAngle==undefined){ + gaugeOption.oldAngle=gaugeOption.startAngle; + } + if(gaugeOption.oldData==undefined){ + gaugeOption.oldData=0; + } + gaugeOption.endAngle=gaugeOption.endAngle? gaugeOption.endAngle : 0.25; + categories = getGaugeAxisPoints(categories,gaugeOption.startAngle,gaugeOption.endAngle); + var centerPosition = { + x: opts.width / 2, + y: (opts.height) / 2 + }; + var radius = Math.min(centerPosition.x , centerPosition.y); + if (typeof gaugeOption.width === 'number' && gaugeOption.width > 0) { + gaugeOption.width=gaugeOption.width; + }else{ + gaugeOption.width=15*opts.pixelRatio; + } + radius -= config.padding+gaugeOption.width/2; + var innerRadius = radius-gaugeOption.width; + + + + //画背景 + context.setLineWidth(gaugeOption.width); + context.setLineCap('butt'); + categories.forEach(function (eachCategories) { + context.beginPath(); + context.setStrokeStyle(eachCategories.color); + context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_ * Math.PI, eachCategories._endAngle_ * Math.PI, false); + context.stroke(); + }); + context.save(); + + //画刻度线 + let totalAngle=gaugeOption.startAngle-gaugeOption.endAngle+1; + gaugeOption.splitLine.fixRadius=gaugeOption.splitLine.fixRadius? gaugeOption.splitLine.fixRadius : 0; + gaugeOption.splitLine.splitNumber=gaugeOption.splitLine.splitNumber? gaugeOption.splitLine.splitNumber : 10; + gaugeOption.splitLine.width=gaugeOption.splitLine.width? gaugeOption.splitLine.width : 15*opts.pixelRatio ; + gaugeOption.splitLine.color=gaugeOption.splitLine.color? gaugeOption.splitLine.color : '#FFFFFF'; + gaugeOption.splitLine.childNumber=gaugeOption.splitLine.childNumber? gaugeOption.splitLine.childNumber : 5; + gaugeOption.splitLine.childWidth=gaugeOption.splitLine.childWidth? gaugeOption.splitLine.childWidth : 5*opts.pixelRatio; + + let splitAngle=totalAngle/gaugeOption.splitLine.splitNumber; + let childAngle=totalAngle/gaugeOption.splitLine.splitNumber/gaugeOption.splitLine.childNumber; + let startX=-radius-gaugeOption.width*0.5-gaugeOption.splitLine.fixRadius; + let endX=-radius-gaugeOption.width*0.5-gaugeOption.splitLine.fixRadius+gaugeOption.splitLine.width; + let childendX=-radius-gaugeOption.width*0.5-gaugeOption.splitLine.fixRadius+gaugeOption.splitLine.childWidth; + + context.translate(centerPosition.x, centerPosition.y); + context.rotate((gaugeOption.startAngle-1)* Math.PI); + + for(let i=0 ; i< gaugeOption.splitLine.splitNumber+1; i++){ + context.beginPath(); + context.setStrokeStyle(gaugeOption.splitLine.color); + context.setLineWidth(2*opts.pixelRatio); + context.moveTo(startX, 0); + context.lineTo(endX, 0); + context.stroke(); + context.rotate(splitAngle* Math.PI); + } + context.restore(); + + context.save(); + context.translate(centerPosition.x, centerPosition.y); + context.rotate((gaugeOption.startAngle-1)* Math.PI); + + for(let i=0 ; i< gaugeOption.splitLine.splitNumber*gaugeOption.splitLine.childNumber+1; i++){ + context.beginPath(); + context.setStrokeStyle(gaugeOption.splitLine.color); + context.setLineWidth(1*opts.pixelRatio); + context.moveTo(startX, 0); + context.lineTo(childendX, 0); + context.stroke(); + context.rotate(childAngle* Math.PI); + } + context.restore(); + + //画指针 + gaugeOption.pointer.width=gaugeOption.pointer.width? gaugeOption.pointer.width : 15*opts.pixelRatio; + if (gaugeOption.pointer.color == undefined || gaugeOption.pointer.color == 'auto') { + gaugeOption.pointer.color == 'auto'; + }else{ + gaugeOption.pointer.color == gaugeOption.pointer.color; + } + series = getGaugeDataPoints(series,categories,gaugeOption, process); + + series.forEach(function (eachSeries) { + context.save(); + context.translate(centerPosition.x, centerPosition.y); + context.rotate((eachSeries._proportion_-1)* Math.PI); + context.beginPath(); + context.setFillStyle(eachSeries.color); + context.moveTo(gaugeOption.pointer.width, 0); + context.lineTo(0,-gaugeOption.pointer.width/2); + context.lineTo(-innerRadius,0); + context.lineTo(0,gaugeOption.pointer.width/2); + context.lineTo(gaugeOption.pointer.width,0); + context.closePath(); + context.fill(); + context.beginPath(); + context.setFillStyle('#FFFFFF'); + context.arc(0, 0, gaugeOption.pointer.width/6, 0,2* Math.PI, false); + context.fill(); + context.restore(); + }); + + if (opts.dataLabel !== false) { + drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context); + } + + drawRingTitle(opts, config, context); + + if (process === 1 && opts.type === 'gauge') { + gaugeOption.oldAngle=series[0]._proportion_; + gaugeOption.oldData=series[0].data; + } + return { + center: centerPosition, + radius: radius, + innerRadius:innerRadius, + categories: categories, + totalAngle:totalAngle + }; +} + +function drawRadarDataPoints(series, opts, config, context) { + var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1; + + var radarOption = opts.extra.radar || {}; + var coordinateAngle = getRadarCoordinateSeries(opts.categories.length); + var centerPosition = { + x: opts.width / 2, + y: (opts.height - config.legendHeight) / 2 + }; + + var radius = Math.min(centerPosition.x - (getMaxTextListLength(opts.categories) + config.radarLabelTextMargin), centerPosition.y - config.radarLabelTextMargin); + + radius -= config.padding; + + // draw grid + context.beginPath(); + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(radarOption.gridColor || "#cccccc"); + coordinateAngle.forEach(function (angle) { + var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition); + context.moveTo(centerPosition.x, centerPosition.y); + context.lineTo(pos.x, pos.y); + }); + context.stroke(); + context.closePath(); + + // draw split line grid + + var _loop = function _loop(i) { + var startPos = {}; + context.beginPath(); + context.setLineWidth(1*opts.pixelRatio); + context.setStrokeStyle(radarOption.gridColor || "#cccccc"); + coordinateAngle.forEach(function (angle, index) { + var pos = convertCoordinateOrigin(radius / config.radarGridCount * i * Math.cos(angle), radius / config.radarGridCount * i * Math.sin(angle), centerPosition); + if (index === 0) { + startPos = pos; + context.moveTo(pos.x, pos.y); + } else { + context.lineTo(pos.x, pos.y); + } + }); + context.lineTo(startPos.x, startPos.y); + context.stroke(); + context.closePath(); + }; + + for (var i = 1; i <= config.radarGridCount; i++) { + _loop(i); + } + + var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process); + + radarDataPoints.forEach(function (eachSeries, seriesIndex) { + // 绘制区域数据 + context.beginPath(); + context.setFillStyle(eachSeries.color); + context.setGlobalAlpha(0.3); + eachSeries.data.forEach(function (item, index) { + if (index === 0) { + context.moveTo(item.position.x, item.position.y); + } else { + context.lineTo(item.position.x, item.position.y); + } + }); + context.closePath(); + context.fill(); + context.setGlobalAlpha(1); + + if (opts.dataPointShape !== false) { + var shape = config.dataPointShape[seriesIndex % config.dataPointShape.length]; + var points = eachSeries.data.map(function (item) { + return item.position; + }); + drawPointShape(points, eachSeries.color, shape, context,opts); + } + }); + // draw label text + drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context); + + return { + center: centerPosition, + radius: radius, + angleList: coordinateAngle + }; +} + +function drawCanvas(opts, context) { + context.draw(); +} + +var Timing = { + easeIn: function easeIn(pos) { + return Math.pow(pos, 3); + }, + + easeOut: function easeOut(pos) { + return Math.pow(pos - 1, 3) + 1; + }, + + easeInOut: function easeInOut(pos) { + if ((pos /= 0.5) < 1) { + return 0.5 * Math.pow(pos, 3); + } else { + return 0.5 * (Math.pow(pos - 2, 3) + 2); + } + }, + + linear: function linear(pos) { + return pos; + } +}; + +function Animation(opts) { + this.isStop = false; + opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration; + opts.timing = opts.timing || 'linear'; + + var delay = 17; + + var createAnimationFrame = function createAnimationFrame() { + + if (typeof requestAnimationFrame !== 'undefined') { + return requestAnimationFrame; + } else if (typeof setTimeout !== 'undefined') { + + return function (step, delay) { + setTimeout(function () { + var timeStamp = +new Date(); + step(timeStamp); + }, delay); + }; + } else { + + return function (step) { + step(null); + }; + } + }; + var animationFrame = createAnimationFrame(); + var startTimeStamp = null; + + var _step = function step(timestamp) { + + if (timestamp === null || this.isStop === true) { + opts.onProcess && opts.onProcess(1); + opts.onAnimationFinish && opts.onAnimationFinish(); + return; + } + if (startTimeStamp === null) { + startTimeStamp = timestamp; + } + if (timestamp - startTimeStamp < opts.duration) { + var process = (timestamp - startTimeStamp) / opts.duration; + var timingFunction = Timing[opts.timing]; + process = timingFunction(process); + + opts.onProcess && opts.onProcess(process); + animationFrame(_step, delay); + } else { + opts.onProcess && opts.onProcess(1); + opts.onAnimationFinish && opts.onAnimationFinish(); + } + }; + _step = _step.bind(this); + animationFrame(_step, delay); +} + +// stop animation immediately +// and tigger onAnimationFinish +Animation.prototype.stop = function () { + this.isStop = true; +}; + +function drawCharts(type, opts, config, context) { + var _this = this; + + var series = opts.series; + var categories = opts.categories; + series = fillSeriesColor(series, config); + series = fillSeriesType(series, opts); + + var _calLegendData = calLegendData(series, opts, config), + legendHeight = _calLegendData.legendHeight; + + config.legendHeight = legendHeight; + + var _calYAxisData = calYAxisData(series, opts, config), + yAxisWidth = _calYAxisData.yAxisWidth; + + config.yAxisWidth = yAxisWidth; + if (categories && categories.length) { + var _calCategoriesData = calCategoriesData(categories, opts, config), + xAxisHeight = _calCategoriesData.xAxisHeight, + angle = _calCategoriesData.angle; + + config.xAxisHeight = xAxisHeight; + config._xAxisTextAngle_ = angle; + } + if (type === 'pie' || type === 'ring') { + config._pieTextMaxLength_ = opts.dataLabel === false ? 0 : getPieTextMaxLength(series); + } + + var duration = opts.animation ? 1000 : 0; + this.animationInstance && this.animationInstance.stop(); + + //先清空画布,不然百度和支付宝ToolTip有重影 + context.clearRect(0, 0, opts.width, opts.height); + if(opts.rotate){ + //判断是否是百度和支付宝平台,需要赋值,不然每次都旋转 + if(opts.rotateLock!==true){ + context.translate(opts.height, 0); + context.rotate(90 * Math.PI / 180); + context.save(); + }else if(opts._rotate_!==true){ + context.translate(opts.height, 0); + context.rotate(90 * Math.PI / 180); + context.save(); + opts._rotate_=true; + } + } + + switch (type) { + case 'line': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawLineDataPoints = drawLineDataPoints(series, opts, config, context, process), + xAxisPoints = _drawLineDataPoints.xAxisPoints, + calPoints = _drawLineDataPoints.calPoints, + eachSpacing = _drawLineDataPoints.eachSpacing; + + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + + break; + case 'mix': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawMixDataPoints = drawMixDataPoints(series, opts, config, context, process), + xAxisPoints = _drawMixDataPoints.xAxisPoints, + calPoints = _drawMixDataPoints.calPoints, + eachSpacing = _drawMixDataPoints.eachSpacing; + + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + + break; + case 'column': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawColumnDataPoints = drawColumnDataPoints(series, opts, config, context, process), + xAxisPoints = _drawColumnDataPoints.xAxisPoints, + calPoints = _drawColumnDataPoints.calPoints, + eachSpacing = _drawColumnDataPoints.eachSpacing; + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'area': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawAreaDataPoints = drawAreaDataPoints(series, opts, config, context, process), + xAxisPoints = _drawAreaDataPoints.xAxisPoints, + calPoints = _drawAreaDataPoints.calPoints, + eachSpacing = _drawAreaDataPoints.eachSpacing; + + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'ring': + case 'pie': + this.animationInstance = new Animation({ + timing: 'easeInOut', + duration: duration, + onProcess: function onProcess(process) { + _this.chartData.pieData = drawPieDataPoints(series, opts, config, context, process); + drawLegend(opts.series, opts, config, context); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'radar': + this.animationInstance = new Animation({ + timing: 'easeInOut', + duration: duration, + onProcess: function onProcess(process) { + _this.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process); + drawLegend(opts.series, opts, config, context); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'arcbar': + this.animationInstance = new Animation({ + timing: 'easeInOut', + duration: duration, + onProcess: function onProcess(process) { + _this.chartData.arcbarData = drawArcbarDataPoints(series, opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'gauge': + this.animationInstance = new Animation({ + timing: 'easeInOut', + duration: duration, + onProcess: function onProcess(process) { + _this.chartData.gaugeData = drawGaugeDataPoints(categories, series,opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + case 'candle': + this.animationInstance = new Animation({ + timing: 'easeIn', + duration: duration, + onProcess: function onProcess(process) { + drawYAxisGrid(categories,opts, config, context); + drawXAxis(categories, opts, config, context); + var _drawCandleDataPoints = drawCandleDataPoints(series, opts, config, context, process), + xAxisPoints = _drawCandleDataPoints.xAxisPoints, + calPoints = _drawCandleDataPoints.calPoints, + eachSpacing = _drawCandleDataPoints.eachSpacing; + + _this.chartData.xAxisPoints = xAxisPoints; + _this.chartData.calPoints = calPoints; + _this.chartData.eachSpacing = eachSpacing; + drawLegend(opts.series, opts, config, context); + drawYAxis(series, opts, config, context); + drawToolTipBridge(opts, config, context, process); + drawCanvas(opts, context); + }, + onAnimationFinish: function onAnimationFinish() { + _this.event.trigger('renderComplete'); + } + }); + break; + } +} + +// simple event implement + +function Event() { + this.events = {}; +} + +Event.prototype.addEventListener = function (type, listener) { + this.events[type] = this.events[type] || []; + this.events[type].push(listener); +}; + +Event.prototype.trigger = function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var type = args[0]; + var params = args.slice(1); + if (!!this.events[type]) { + this.events[type].forEach(function (listener) { + try { + listener.apply(null, params); + } catch (e) { + console.error(e); + } + }); + } +}; + +var Charts = function Charts(opts) { + opts.fontSize=opts.fontSize ? opts.fontSize*opts.pixelRatio : 13*opts.pixelRatio; + opts.title = opts.title || {}; + opts.subtitle = opts.subtitle || {}; + opts.yAxis = opts.yAxis || {}; + opts.yAxis.gridType=opts.yAxis.gridType? opts.yAxis.gridType : 'solid'; + opts.yAxis.dashLength=opts.yAxis.dashLength? opts.yAxis.dashLength : 4*opts.pixelRatio; + opts.xAxis = opts.xAxis || {}; + opts.xAxis.rotateLabel = opts.xAxis.rotateLabel ? true : false; + opts.xAxis.type=opts.xAxis.type? opts.xAxis.type : 'calibration'; + opts.xAxis.gridType=opts.xAxis.gridType? opts.xAxis.gridType : 'solid'; + opts.xAxis.dashLength=opts.xAxis.dashLength? opts.xAxis.dashLength : 4*opts.pixelRatio; + opts.xAxis.itemCount = opts.xAxis.itemCount ? opts.xAxis.itemCount : 5; + opts.xAxis.scrollAlign = opts.xAxis.scrollAlign ? opts.xAxis.scrollAlign : 'left'; + opts.extra = opts.extra || {}; + opts.legend = opts.legend === false ? false : true; + opts.rotate = opts.rotate ? true : false; + opts.animation = opts.animation === false ? false : true; + var config$$1 = assign({}, config); + config$$1.yAxisTitleWidth = opts.yAxis.disabled !== true && opts.yAxis.title ? config$$1.yAxisTitleWidth : 0; + config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : config$$1.pieChartLinePadding*opts.pixelRatio; + config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding*opts.pixelRatio; + config$$1.yAxisSplit = opts.yAxis.splitNumber? opts.yAxis.splitNumber : config.yAxisSplit; + //屏幕旋转 + config$$1.rotate=opts.rotate; + if(opts.rotate){ + let tempWidth=opts.width; + let tempHeight=opts.height; + opts.width=tempHeight; + opts.height=tempWidth; + } + + //适配H5高分屏 + config$$1.yAxisWidth=config.yAxisWidth*opts.pixelRatio; + config$$1.xAxisHeight=config.xAxisHeight*opts.pixelRatio; + if(opts.enableScroll && opts.xAxis.scrollShow){ + config$$1.xAxisHeight+=4*opts.pixelRatio; + } + config$$1.xAxisLineHeight=config.xAxisLineHeight*opts.pixelRatio; + config$$1.legendHeight=config.legendHeight*opts.pixelRatio; + //config$$1.yAxisTitleWidth=config.yAxisTitleWidth*opts.pixelRatio; + config$$1.padding=config.padding*opts.pixelRatio; + config$$1.fontSize=opts.fontSize; + config$$1.titleFontSize=config.titleFontSize*opts.pixelRatio; + config$$1.subtitleFontSize=config.subtitleFontSize*opts.pixelRatio; + config$$1.toolTipPadding=config.toolTipPadding*opts.pixelRatio; + config$$1.toolTipLineHeight=config.toolTipLineHeight*opts.pixelRatio; + config$$1.columePadding=config.columePadding*opts.pixelRatio; + //config$$1.xAxisTextPadding=config.xAxisTextPadding*opts.pixelRatio; + + //向配置中传入当前pixelRatio及字体大小 + config.pixelRatio=opts.pixelRatio; + config.fontSize=opts.fontSize; + config.rotate=opts.rotate; + + this.opts = opts; + this.config = config$$1; + opts.$this = opts.$this? opts.$this : this; + this.context = uni.createCanvasContext(opts.canvasId, opts.$this); + // store calcuated chart data + // such as chart point coordinate + this.chartData = {}; + this.event = new Event(); + + this.scrollOption = { + currentOffset: 0, + startTouchX: 0, + distance: 0 + }; + + //计算右对齐偏移距离 + if(opts.enableScroll && opts.xAxis.scrollAlign=='right'){ + let _calYAxisData = calYAxisData(opts.series, opts, config$$1), + yAxisWidth = _calYAxisData.yAxisWidth; + config$$1.yAxisWidth = yAxisWidth; + let offsetLeft=0; + let _getXAxisPoints0 = getXAxisPoints(opts.categories, opts, config$$1), + xAxisPoints = _getXAxisPoints0.xAxisPoints, + startX = _getXAxisPoints0.startX, + endX = _getXAxisPoints0.endX, + eachSpacing = _getXAxisPoints0.eachSpacing; + let totalWidth=eachSpacing*(xAxisPoints.length-1); + let screenWidth=endX-startX; + offsetLeft=screenWidth-totalWidth; + this.scrollOption = { + currentOffset: offsetLeft, + startTouchX: offsetLeft, + distance: 0 + }; + opts._scrollDistance_= offsetLeft; + } + + drawCharts.call(this, opts.type, opts, config$$1, this.context); +}; + +Charts.prototype.updateData = function () { + var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + this.opts.series = data.series || this.opts.series; + this.opts.categories = data.categories || this.opts.categories; + + this.opts.title = assign({}, this.opts.title, data.title || {}); + this.opts.subtitle = assign({}, this.opts.subtitle, data.subtitle || {}); + + drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); +}; + +Charts.prototype.zoom = function () { + var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount; + if(this.opts.enableScroll!==true){ + console.log('请启用滚动条后使用!') + return; + } + this.opts.animation=false; + this.opts.xAxis.itemCount = val.itemCount; + drawCharts.call(this, this.opts.type, this.opts, this.config, this.context); +}; + +Charts.prototype.stopAnimation = function () { + this.animationInstance && this.animationInstance.stop(); +}; + +Charts.prototype.addEventListener = function (type, listener) { + this.event.addEventListener(type, listener); +}; + +Charts.prototype.getCurrentDataIndex = function (e) { + var touches= e.mp.changedTouches[0]; + if (touches) { + var _touches$= getTouches(touches, this.opts, e); + if (this.opts.type === 'pie' || this.opts.type === 'ring') { + return findPieChartCurrentIndex({ x: _touches$.x, y: _touches$.y }, this.chartData.pieData); + } else if (this.opts.type === 'radar') { + return findRadarChartCurrentIndex({ x: _touches$.x, y: _touches$.y }, this.chartData.radarData, this.opts.categories.length); + } else { + return findCurrentIndex({ x: _touches$.x, y: _touches$.y }, this.chartData.xAxisPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset)); + } + } + return -1; +}; + +Charts.prototype.showToolTip = function (e) { + var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + var touches= e.mp.changedTouches[0]; + var _touches$= getTouches(touches, this.opts, e); + + if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'mix' || this.opts.type === 'column') { + var index = this.getCurrentDataIndex(e); + var currentOffset = this.scrollOption.currentOffset; + + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + if (index > -1) { + + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var _getToolTipData = getToolTipData(seriesData, this.chartData.calPoints, index, this.opts.categories, option), + textList = _getToolTipData.textList, + offset = _getToolTipData.offset; + offset.y=_touches$.y; + opts.tooltip = { + textList: textList, + offset: offset, + option: option + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } + if (this.opts.type === 'candle') { + + var index = this.getCurrentDataIndex(e); + var currentOffset = this.scrollOption.currentOffset; + + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset, + animation: false + }); + if (index > -1) { + var seriesData = getSeriesDataItem(this.opts.series, index); + if (seriesData.length !== 0) { + var _getToolTipData = getCandleToolTipData(this.opts.series[0].data,seriesData, this.chartData.calPoints, index, this.opts.categories, this.opts.extra.candle, option), + textList = _getToolTipData.textList, + offset = _getToolTipData.offset; + offset.y=_touches$.y; + opts.tooltip = { + textList: textList, + offset: offset, + option: option + }; + } + } + drawCharts.call(this, opts.type, opts, this.config, this.context); + } +}; + +Charts.prototype.scrollStart = function (e) { + var touches= e.mp.changedTouches[0]; + if (touches && this.opts.enableScroll === true) { + if(touches.x){ + this.scrollOption.startTouchX = touches.x; + }else{ + this.scrollOption.startTouchX = touches.clientX; + } + } +}; + +Charts.prototype.scroll = function (e) { + // TODO throtting... + var touches= e.mp.changedTouches[0]; + if (touches && this.opts.enableScroll === true) { + var _distance; + if(touches.x){ + _distance = touches.x - this.scrollOption.startTouchX; + }else{ + _distance = touches.clientX - this.scrollOption.startTouchX; + } + var currentOffset = this.scrollOption.currentOffset; + + var validDistance = calValidDistance(currentOffset + _distance, this.chartData, this.config, this.opts); + + this.scrollOption.distance = _distance = validDistance - currentOffset; + var opts = assign({}, this.opts, { + _scrollDistance_: currentOffset + _distance, + animation: false + }); + drawCharts.call(this, opts.type, opts, this.config, this.context); + } +}; + +Charts.prototype.scrollEnd = function (e) { + if (this.opts.enableScroll === true) { + var _scrollOption = this.scrollOption, + currentOffset = _scrollOption.currentOffset, + distance = _scrollOption.distance; + + this.scrollOption.currentOffset = currentOffset + distance; + this.scrollOption.distance = 0; + } +}; + +module.exports = Charts; diff --git a/example/uni-app/main.js b/example/uni-app/main.js new file mode 100644 index 0000000..6abef22 --- /dev/null +++ b/example/uni-app/main.js @@ -0,0 +1,11 @@ +import Vue from 'vue' +import App from './App' + +Vue.config.productionTip = false + +App.mpType = 'app' + +const app = new Vue({ + ...App +}) +app.$mount() diff --git a/example/uni-app/manifest.json b/example/uni-app/manifest.json new file mode 100644 index 0000000..81f285c --- /dev/null +++ b/example/uni-app/manifest.json @@ -0,0 +1,61 @@ +{ + "name" : "wx-charts", + "appid" : "__UNI__B3AB472", + "description": "", + "versionName": "1.0.0", + "versionCode": "100", + "transformPx": false, + "app-plus": { /* 5+App特有相关 */ + "splashscreen": { + "alwaysShowBeforeRender": true, + "waiting": true, + "autoclose": true, + "delay": 0 + }, + "modules": { /* 模块配置 */ + + }, + "distribute": { /* 应用发布信息 */ + "android": { /* android打包配置 */ + "permissions": ["", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ] + }, + "ios": { /* ios打包配置 */ + + }, + "sdkConfigs": { /* SDK配置 */ + + } + } + }, + "quickapp": { /* 快应用特有相关 */ + + }, + "mp-weixin": { /* 小程序特有相关 */ + "appid": "", + "setting": { + "urlCheck": true + } + } +} diff --git a/example/uni-app/pages.json b/example/uni-app/pages.json new file mode 100644 index 0000000..39de4ec --- /dev/null +++ b/example/uni-app/pages.json @@ -0,0 +1,20 @@ +{ + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages + { + "path": "pages/ucharts-demo/ucharts-demo", + "style": { + "navigationBarTitleText": "uCharts跨端图表", + "navigationBarTextStyle":"black" + } + } + ], + "globalStyle": { + "navigationBarTextStyle": "black", + "navigationBarTitleText": "uCharts跨端图表", + "navigationBarBackgroundColor": "#F8F8F8", + "backgroundColor": "#F8F8F8", + "mp-alipay" : { + "titleBarColor" : "#FFFFFF" + } + } +} diff --git a/example/uni-app/pages/ucharts-demo/column/column.vue b/example/uni-app/pages/ucharts-demo/column/column.vue new file mode 100644 index 0000000..d7e4824 --- /dev/null +++ b/example/uni-app/pages/ucharts-demo/column/column.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/example/uni-app/pages/ucharts-demo/column/meter.vue b/example/uni-app/pages/ucharts-demo/column/meter.vue new file mode 100644 index 0000000..e243bdc --- /dev/null +++ b/example/uni-app/pages/ucharts-demo/column/meter.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/example/uni-app/pages/ucharts-demo/column/stack.vue b/example/uni-app/pages/ucharts-demo/column/stack.vue new file mode 100644 index 0000000..1295edf --- /dev/null +++ b/example/uni-app/pages/ucharts-demo/column/stack.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/example/uni-app/pages/ucharts-demo/index.vue b/example/uni-app/pages/ucharts-demo/index.vue new file mode 100644 index 0000000..c2a54d3 --- /dev/null +++ b/example/uni-app/pages/ucharts-demo/index.vue @@ -0,0 +1,955 @@ + + + + + diff --git a/example/uni-app/pages/ucharts-demo/mix/mix.vue b/example/uni-app/pages/ucharts-demo/mix/mix.vue new file mode 100644 index 0000000..6c521cd --- /dev/null +++ b/example/uni-app/pages/ucharts-demo/mix/mix.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/example/uni-app/static/QQqrcode.png b/example/uni-app/static/QQqrcode.png new file mode 100644 index 0000000..a778159 Binary files /dev/null and b/example/uni-app/static/QQqrcode.png differ diff --git a/example/uni-app/static/arcbar.gif b/example/uni-app/static/arcbar.gif new file mode 100644 index 0000000..23a2cd0 Binary files /dev/null and b/example/uni-app/static/arcbar.gif differ diff --git a/example/uni-app/static/area.gif b/example/uni-app/static/area.gif new file mode 100644 index 0000000..a3fb511 Binary files /dev/null and b/example/uni-app/static/area.gif differ diff --git a/example/uni-app/static/area.png b/example/uni-app/static/area.png new file mode 100644 index 0000000..077a464 Binary files /dev/null and b/example/uni-app/static/area.png differ diff --git a/example/uni-app/static/candle.gif b/example/uni-app/static/candle.gif new file mode 100644 index 0000000..05a6a68 Binary files /dev/null and b/example/uni-app/static/candle.gif differ diff --git a/example/uni-app/static/column.gif b/example/uni-app/static/column.gif new file mode 100644 index 0000000..491f076 Binary files /dev/null and b/example/uni-app/static/column.gif differ diff --git a/example/uni-app/static/column.png b/example/uni-app/static/column.png new file mode 100644 index 0000000..a47ec26 Binary files /dev/null and b/example/uni-app/static/column.png differ diff --git a/example/uni-app/static/column2.gif b/example/uni-app/static/column2.gif new file mode 100644 index 0000000..3c915b4 Binary files /dev/null and b/example/uni-app/static/column2.gif differ diff --git a/example/uni-app/static/dashLine.gif b/example/uni-app/static/dashLine.gif new file mode 100644 index 0000000..57f6337 Binary files /dev/null and b/example/uni-app/static/dashLine.gif differ diff --git a/example/uni-app/static/demo.png b/example/uni-app/static/demo.png new file mode 100644 index 0000000..2a0b2a6 Binary files /dev/null and b/example/uni-app/static/demo.png differ diff --git a/example/uni-app/static/dianxin.jpg b/example/uni-app/static/dianxin.jpg new file mode 100644 index 0000000..3828422 Binary files /dev/null and b/example/uni-app/static/dianxin.jpg differ diff --git a/example/uni-app/static/example.gif b/example/uni-app/static/example.gif new file mode 100644 index 0000000..a9a87bf Binary files /dev/null and b/example/uni-app/static/example.gif differ diff --git a/example/uni-app/static/gauge.gif b/example/uni-app/static/gauge.gif new file mode 100644 index 0000000..932c826 Binary files /dev/null and b/example/uni-app/static/gauge.gif differ diff --git a/example/uni-app/static/lineA-scroll.gif b/example/uni-app/static/lineA-scroll.gif new file mode 100644 index 0000000..15ec5d1 Binary files /dev/null and b/example/uni-app/static/lineA-scroll.gif differ diff --git a/example/uni-app/static/lineA.gif b/example/uni-app/static/lineA.gif new file mode 100644 index 0000000..f8e4ac1 Binary files /dev/null and b/example/uni-app/static/lineA.gif differ diff --git a/example/uni-app/static/lineA.png b/example/uni-app/static/lineA.png new file mode 100644 index 0000000..e66bdcc Binary files /dev/null and b/example/uni-app/static/lineA.png differ diff --git a/example/uni-app/static/lineB.gif b/example/uni-app/static/lineB.gif new file mode 100644 index 0000000..e69f552 Binary files /dev/null and b/example/uni-app/static/lineB.gif differ diff --git a/example/uni-app/static/lineB.png b/example/uni-app/static/lineB.png new file mode 100644 index 0000000..ab7207e Binary files /dev/null and b/example/uni-app/static/lineB.png differ diff --git a/example/uni-app/static/logo.png b/example/uni-app/static/logo.png new file mode 100644 index 0000000..b5771e2 Binary files /dev/null and b/example/uni-app/static/logo.png differ diff --git a/example/uni-app/static/meter.gif b/example/uni-app/static/meter.gif new file mode 100644 index 0000000..8775320 Binary files /dev/null and b/example/uni-app/static/meter.gif differ diff --git a/example/uni-app/static/mix.gif b/example/uni-app/static/mix.gif new file mode 100644 index 0000000..0978efb Binary files /dev/null and b/example/uni-app/static/mix.gif differ diff --git a/example/uni-app/static/mix2.gif b/example/uni-app/static/mix2.gif new file mode 100644 index 0000000..5229a4f Binary files /dev/null and b/example/uni-app/static/mix2.gif differ diff --git a/example/uni-app/static/pie.gif b/example/uni-app/static/pie.gif new file mode 100644 index 0000000..c29081c Binary files /dev/null and b/example/uni-app/static/pie.gif differ diff --git a/example/uni-app/static/pie.png b/example/uni-app/static/pie.png new file mode 100644 index 0000000..34a84ea Binary files /dev/null and b/example/uni-app/static/pie.png differ diff --git a/example/uni-app/static/qrcode.gif b/example/uni-app/static/qrcode.gif new file mode 100644 index 0000000..21d321e Binary files /dev/null and b/example/uni-app/static/qrcode.gif differ diff --git a/example/uni-app/static/qrcode.png b/example/uni-app/static/qrcode.png new file mode 100644 index 0000000..a9dbf60 Binary files /dev/null and b/example/uni-app/static/qrcode.png differ diff --git a/example/uni-app/static/radar.gif b/example/uni-app/static/radar.gif new file mode 100644 index 0000000..888c9f2 Binary files /dev/null and b/example/uni-app/static/radar.gif differ diff --git a/example/uni-app/static/radar.png b/example/uni-app/static/radar.png new file mode 100644 index 0000000..4467b8e Binary files /dev/null and b/example/uni-app/static/radar.png differ diff --git a/example/uni-app/static/ring.gif b/example/uni-app/static/ring.gif new file mode 100644 index 0000000..71a01cf Binary files /dev/null and b/example/uni-app/static/ring.gif differ diff --git a/example/uni-app/static/ring.png b/example/uni-app/static/ring.png new file mode 100644 index 0000000..d015a71 Binary files /dev/null and b/example/uni-app/static/ring.png differ diff --git a/example/uni-app/static/stack.gif b/example/uni-app/static/stack.gif new file mode 100644 index 0000000..d673747 Binary files /dev/null and b/example/uni-app/static/stack.gif differ diff --git a/example/uni-app/static/tuozhuai.gif b/example/uni-app/static/tuozhuai.gif new file mode 100644 index 0000000..d2b9153 Binary files /dev/null and b/example/uni-app/static/tuozhuai.gif differ diff --git a/example/uni-app/static/xuanxing.png b/example/uni-app/static/xuanxing.png new file mode 100644 index 0000000..ac137e2 Binary files /dev/null and b/example/uni-app/static/xuanxing.png differ diff --git a/example/uni-app/static/yibiaopan.gif b/example/uni-app/static/yibiaopan.gif new file mode 100644 index 0000000..81b4f3b Binary files /dev/null and b/example/uni-app/static/yibiaopan.gif differ diff --git a/example/uni-app/uni.scss b/example/uni-app/uni.scss new file mode 100644 index 0000000..f0f426c --- /dev/null +++ b/example/uni-app/uni.scss @@ -0,0 +1,76 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:24upx; +$uni-font-size-base:28upx; +$uni-font-size-lg:32upx; + +/* 图片尺寸 */ +$uni-img-size-sm:40upx; +$uni-img-size-base:52upx; +$uni-img-size-lg:80upx; + +/* Border Radius */ +$uni-border-radius-sm: 4upx; +$uni-border-radius-base: 6upx; +$uni-border-radius-lg: 12upx; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 10px; +$uni-spacing-row-base: 20upx; +$uni-spacing-row-lg: 30upx; + +/* 垂直间距 */ +$uni-spacing-col-sm: 8upx; +$uni-spacing-col-base: 16upx; +$uni-spacing-col-lg: 24upx; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:40upx; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:36upx; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:30upx; \ No newline at end of file