소스 검색

uview plus 工具广场ui

hjr 7 달 전
부모
커밋
7dcf86c561
100개의 변경된 파일21150개의 추가작업 그리고 30개의 파일을 삭제
  1. 9 0
      App.vue
  2. 32 0
      components/horizontal-rule/debounce.js
  3. 235 0
      components/horizontal-rule/horizontal-rule.vue
  4. 217 0
      components/horizontal-rule/vertical-rule.vue
  5. 66 0
      components/our-loading/loaders/bounce.vue
  6. 61 0
      components/our-loading/loaders/double-bounce.vue
  7. 69 0
      components/our-loading/loaders/double-cube.vue
  8. 70 0
      components/our-loading/loaders/double-dot.vue
  9. 147 0
      components/our-loading/loaders/loop.vue
  10. 46 0
      components/our-loading/loaders/rotate-plane.vue
  11. 47 0
      components/our-loading/loaders/scale-out.vue
  12. 76 0
      components/our-loading/loaders/shrink-rect.vue
  13. 129 0
      components/our-loading/our-loading.vue
  14. 42 0
      components/xiaoran-circle/xiaoran-circle.css
  15. 226 0
      components/xiaoran-circle/xiaoran-circle.vue
  16. 1 0
      index.html
  17. 1 1
      pages.json
  18. 144 0
      pages/scaleDemo/index.vue
  19. 48 2
      pages/tools/jingXuanBiZhi.vue
  20. 71 2
      pages/tools/quWeiCePing.vue
  21. 34 3
      pages/tools/shengBoChuChen.vue
  22. 14 2
      pages/tools/shouJiCeJu.vue
  23. 147 2
      pages/tools/shouJiQingLi.vue
  24. 33 2
      pages/tools/wangLuoXinXi.vue
  25. 155 3
      pages/tools/wifiGuanLi.vue
  26. 43 2
      pages/tools/yangShengKeTang.vue
  27. 72 7
      pages/tools/yiJianShengDian.vue
  28. 5 2
      pages/tools/yunDongJiBu.vue
  29. 5 2
      pages/tools/ziTiDaXiao.vue
  30. 124 0
      pages/xiaoran-circle/xiaoran-circle.vue
  31. 320 0
      uni_modules/qiun-data-charts/changelog.md
  32. 1618 0
      uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue
  33. 42 0
      uni_modules/qiun-data-charts/components/qiun-error/qiun-error.vue
  34. 162 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading1.vue
  35. 170 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading2.vue
  36. 173 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading3.vue
  37. 222 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading4.vue
  38. 229 0
      uni_modules/qiun-data-charts/components/qiun-loading/loading5.vue
  39. 36 0
      uni_modules/qiun-data-charts/components/qiun-loading/qiun-loading.vue
  40. 422 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js
  41. 606 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js
  42. 5 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md
  43. 7706 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js
  44. 17 0
      uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js
  45. 201 0
      uni_modules/qiun-data-charts/license.md
  46. 80 0
      uni_modules/qiun-data-charts/package.json
  47. 84 0
      uni_modules/qiun-data-charts/readme.md
  48. 22 0
      uni_modules/qiun-data-charts/static/app-plus/echarts.min.js
  49. 22 0
      uni_modules/qiun-data-charts/static/h5/echarts.min.js
  50. 6 0
      uni_modules/uni-wifi/changelog.md
  51. 122 0
      uni_modules/uni-wifi/package.json
  52. 145 0
      uni_modules/uni-wifi/readme.md
  53. 3 0
      uni_modules/uni-wifi/utssdk/app-android/config.json
  54. 802 0
      uni_modules/uni-wifi/utssdk/app-android/index.uts
  55. 8 0
      uni_modules/uni-wifi/utssdk/app-ios/Info.plist
  56. 8 0
      uni_modules/uni-wifi/utssdk/app-ios/UTS.entitlements
  57. 9 0
      uni_modules/uni-wifi/utssdk/app-ios/config.json
  58. 268 0
      uni_modules/uni-wifi/utssdk/app-ios/index.uts
  59. 388 0
      uni_modules/uni-wifi/utssdk/index.d.ts
  60. 424 0
      uni_modules/uni-wifi/utssdk/interface.uts
  61. 35 0
      uni_modules/uni-wifi/utssdk/uni.autotest.js
  62. 59 0
      uni_modules/uni-wifi/utssdk/unierror.uts
  63. 21 0
      uni_modules/uview-plus/LICENSE
  64. 74 0
      uni_modules/uview-plus/README.md
  65. 912 0
      uni_modules/uview-plus/changelog.md
  66. 85 0
      uni_modules/uview-plus/components/u--form/u--form.vue
  67. 50 0
      uni_modules/uview-plus/components/u--image/u--image.vue
  68. 74 0
      uni_modules/uview-plus/components/u--input/u--input.vue
  69. 45 0
      uni_modules/uview-plus/components/u--text/u--text.vue
  70. 47 0
      uni_modules/uview-plus/components/u--textarea/u--textarea.vue
  71. 109 0
      uni_modules/uview-plus/components/u-action-sheet-data/u-action-sheet-data.vue
  72. 26 0
      uni_modules/uview-plus/components/u-action-sheet/actionSheet.js
  73. 62 0
      uni_modules/uview-plus/components/u-action-sheet/props.js
  74. 282 0
      uni_modules/uview-plus/components/u-action-sheet/u-action-sheet.vue
  75. 28 0
      uni_modules/uview-plus/components/u-album/album.js
  76. 86 0
      uni_modules/uview-plus/components/u-album/props.js
  77. 300 0
      uni_modules/uview-plus/components/u-album/u-album.vue
  78. 22 0
      uni_modules/uview-plus/components/u-alert/alert.js
  79. 46 0
      uni_modules/uview-plus/components/u-alert/props.js
  80. 250 0
      uni_modules/uview-plus/components/u-alert/u-alert.vue
  81. 23 0
      uni_modules/uview-plus/components/u-avatar-group/avatarGroup.js
  82. 54 0
      uni_modules/uview-plus/components/u-avatar-group/props.js
  83. 109 0
      uni_modules/uview-plus/components/u-avatar-group/u-avatar-group.vue
  84. 28 0
      uni_modules/uview-plus/components/u-avatar/avatar.js
  85. 81 0
      uni_modules/uview-plus/components/u-avatar/props.js
  86. 61 0
      uni_modules/uview-plus/components/u-avatar/u-avatar.vue
  87. 27 0
      uni_modules/uview-plus/components/u-back-top/backtop.js
  88. 56 0
      uni_modules/uview-plus/components/u-back-top/props.js
  89. 132 0
      uni_modules/uview-plus/components/u-back-top/u-back-top.vue
  90. 27 0
      uni_modules/uview-plus/components/u-badge/badge.js
  91. 79 0
      uni_modules/uview-plus/components/u-badge/props.js
  92. 176 0
      uni_modules/uview-plus/components/u-badge/u-badge.vue
  93. 27 0
      uni_modules/uview-plus/components/u-box/props.js
  94. 91 0
      uni_modules/uview-plus/components/u-box/u-box.vue
  95. 43 0
      uni_modules/uview-plus/components/u-button/button.js
  96. 46 0
      uni_modules/uview-plus/components/u-button/nvue.scss
  97. 159 0
      uni_modules/uview-plus/components/u-button/props.js
  98. 503 0
      uni_modules/uview-plus/components/u-button/u-button.vue
  99. 81 0
      uni_modules/uview-plus/components/u-button/vue.scss
  100. 45 0
      uni_modules/uview-plus/components/u-calendar/calendar.js

+ 9 - 0
App.vue

@@ -17,4 +17,13 @@
 	@import url("static/css/fui.css");
 	@import url("static/css/flex.css");
 	@import url("static/css/uflex.css");
+	.btn_s{
+		height: 68rpx;
+		line-height: 68rpx;
+		border-radius: 60rpx;
+		text-align: center;
+		color: #fff;
+		background: linear-gradient(90deg, #03fedf, #2ed9fb);
+		cursor: pointer;
+	}
 </style>

+ 32 - 0
components/horizontal-rule/debounce.js

@@ -0,0 +1,32 @@
+let timeout = null;
+
+/**
+ * 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
+ * 
+ * @param {Function} func 要执行的回调函数 
+ * @param {Number} wait 延时的时间
+ * @param {Boolean} immediate 是否立即执行 
+ * @return null
+ */
+
+function debounce(func, wait = 300, immediate=false) {
+	
+	// 清除定时器
+	if (timeout !== null) clearTimeout(timeout);
+	
+	if (immediate) {
+		// 立即执行,此类情况一般用不到
+		var callNow = !timeout;
+		timeout = setTimeout(function() {
+			timeout = null;
+		}, wait);
+		if (callNow) typeof func === 'function' && func();
+	} else {
+		// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
+		timeout = setTimeout(function() {
+			typeof func === 'function' && func();
+		}, wait);
+	}
+}
+
+export default debounce

+ 235 - 0
components/horizontal-rule/horizontal-rule.vue

@@ -0,0 +1,235 @@
+<template>
+	<view>
+		<view class="dividing-rule">
+			<!-- 标记 -->
+			<view class="flex-center" style="top: 1px;">
+				<view class="triangl-down"></view>
+			</view>
+			<view class="flex-center" style="top: 7px;">
+				<view class="markLine"></view>
+			</view>
+			<scroll-view scroll-x scroll-with-animation :scroll-left="scrollLeft" :show-scrollbar="false"
+				@scroll="scroll" style="border-top:1px solid #ccc;padding-top: 3px;padding-bottom: 10px;">
+				<view :style="{width: totalWidth + 'px'}">
+					<view style="width: 100%;"
+						:style="{paddingLeft: initPosition + 'px', paddingRight: initPosition+1 + 'px'}">
+						<!-- 刻度线 -->
+						<view style="display: flex;">
+							<view v-for="(item,index) in options" :key="index" :class="item.type"
+								:style="{minWidth: lineWidth - 1 + 'px'}">
+							</view>
+						</view>
+						<!-- 刻度值 -->
+						<view style="display: flex;margin-top: 6px;">
+							<view v-for="(item,index) in options" :key="index" :style="{minWidth: lineWidth + 'px'}"
+								:class="[selectIndex == index ? 'line-label' : '']">
+								<text style="margin-left: -5px;">{{item.val}}</text>
+							</view>
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import debounce from './debounce.js'
+
+	export default {
+		name: "horizontal-rule",
+		props: {
+			min: { // 最小值
+				type: Number,
+				default: 0,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			},
+			max: { // 最大值
+				type: Number,
+				default: 100,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			},
+			value: { // 初始值
+				type: Number,
+				default: 50,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			},
+			multiple: { // 倍数 只支持10的倍数; multiple = 1 表示每个刻度的值等于1;multiple = 10 表示每个刻度的值等于0.1
+				type: [Number],
+				default: 1
+			},
+			lineWidth: { // 每个刻度之间的宽度
+				type: Number,
+				default: 6,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			}
+		},
+		data() {
+			return {
+				options: [], // 刻度线
+				selectIndex: -1,
+				scrollLeft: 0, //初始位置
+				initPosition: '', // 最小刻度尺的位置
+				totalWidth: '100%', // 尺子总宽度
+				currentVal: '0', // 当前值
+			};
+		},
+		watch: {
+			value: function(val, oldVal) {
+				this.init()
+			}
+		},
+		mounted() {
+			var left = 0;
+			// 获取页面元素
+			let view = uni.createSelectorQuery().in(this).select('.dividing-rule');
+			view.boundingClientRect(data => {
+				left = data.left
+				console.log('获取页面元素', data)
+			}).exec()
+			// 获取指针位置
+			let middleLine = uni.createSelectorQuery().in(this).select('.markLine');
+			middleLine.boundingClientRect(data => {
+				console.log('获取指针位置', data)
+				this.initPosition = data.left - left
+				this.init()
+			}).exec()
+		},
+		methods: {
+			// 初始化刻度尺
+			init: function() {
+				// 最大值不能小于最小值
+				if (this.min >= this.max) return
+				this.options = []
+				let index = this.min
+				let length = this.max * this.multiple
+				for (let i = this.min * this.multiple; i <= length; i++) {
+					let type = ''
+					if (i % 5 == 0) {
+						type = 'line-md'
+						if (i % 10 == 0) {
+							type = 'line-lg'
+						}
+					} else {
+						type = 'line-sm'
+					}
+					// 每 10 格 显示一个刻度值
+					let val = ''
+					if (i % 10 == 0) {
+						val = i / this.multiple
+					}
+					this.options.push({
+						type: type,
+						val: val
+					})
+
+				}
+				console.log('总刻度', JSON.parse(JSON.stringify(this.options)))
+				// 总宽度 = 总格子 * 每个格子的宽度
+				this.totalWidth = ((this.max - this.min) * this.multiple) * this.lineWidth
+				// 初始位置
+				setTimeout(() => {
+					// 初始值必须在min 与 max 之间
+					if (this.value < this.min) {
+						this.scrollLeft = 0
+					} else if (this.value > this.max) {
+						this.scrollLeft = this.totalWidth
+					} else {
+						this.scrollLeft = (this.value - this.min) * this.multiple * this.lineWidth
+					}
+					this.currentVal = this.value
+					this.selectIndex = this.options.findIndex((item, index) => this.value == item.val)
+					console.log('初始位置---------------》', this.scrollLeft)
+					this.$emit('change', this.currentVal)
+				}, 40)
+			},
+			// 监听滚动事件
+			scroll: function(e) {
+				var result = ((this.max - this.min) / this.totalWidth * e.detail.scrollLeft) + this.min
+				this.currentVal = result 
+				this.$emit('change', this.currentVal)
+				// 处理滑在两个刻度之间,自动靠近最近一个刻度
+				debounce(() => {
+					var num = Math.round(result * this.multiple)/this.multiple
+					this.scrollLeft = (num - this.min) * this.multiple * this.lineWidth
+					this.selectIndex = this.options.findIndex((item, index) => num == item.val)
+				}, 500)
+			}
+		}
+
+	}
+</script>
+
+<style>
+	.dividing-rule {
+		position: relative;
+	}
+
+	.flex-center {
+		display: flex;
+		flex-direction: row;
+		justify-content: center;
+		width: 100%;
+		position: absolute;
+		z-index: 1000;
+	}
+
+	.triangl-down {
+		width: 0;
+		height: 0;
+		border-top: 12px solid #3F86FF;
+		border-left: 6px solid transparent;
+		border-right: 6px solid transparent;
+		border-radius: 2px;
+	}
+
+	.markLine {
+		width: 2px;
+		height: 20px;
+		z-index: 1;
+		margin-top: -4px;
+		background: #3F86FF;
+	}
+
+	.bg-red {
+		background: red;
+	}
+
+	.bg-blue {
+		background: blue;
+	}
+
+	.line {
+		display: flex;
+		border-top: 1px solid lightgray;
+		padding-top: 6px;
+		padding-bottom: 6px;
+	}
+
+	.line-lg {
+		height: 15px;
+		border-left: 1px solid #979797;
+	}
+
+	.line-md {
+		height: 10px;
+		border-left: 1px solid #e8e8e8;
+	}
+
+	.line-sm {
+		height: 5px;
+		border-left: 1px solid #e8e8e8;
+	}
+
+	.line-label {
+		color: #3F86FF;
+	}
+</style>

+ 217 - 0
components/horizontal-rule/vertical-rule.vue

@@ -0,0 +1,217 @@
+<template>
+	<view>
+		<view class="flex justify-start align-items">
+			<!-- <scroll-view :scroll-y="true" :scroll-with-animation="true" :scroll-top="scrollTop" :show-scrollbar="false"
+				:style="{height: height + 'px'}" @scroll="scroll" style="width: auto;"> -->
+			<scroll-view :scroll-with-animation="true" :scroll-top="scrollTop" :show-scrollbar="false"
+				:style="{height: '96vh'}" @scroll="scroll" style="width: auto;">
+				<view class="flex" >
+					<!-- :style="{paddingTop: height/2 + 'px', paddingBottom: height/2 - lineWidth + 'px'}" -->
+					<!-- 数值 -->
+					<view>
+						<!-- :class="index%2==0 ? 'bg-red' : 'bg-blue'" -->
+						<view v-for="(item,index) in options" :key="index" :style="{height: 4.95 +'px'}"
+							style="width: 20px;position: relative;">
+							<view style="margin-top: 0rpx;position: absolute;font-size: 24rpx;" :class="selectIndex == index ? 'line-label' : ''">{{item.val}}</view>
+						</view>
+					</view>
+					<!-- 刻度线 -->
+					<view class="line" style="border-right: 2px solid #000;">
+						<view v-for="(item,index) in options" :key="index" :style="{height: lineWidth - 1 + 'px'}"
+							:class="item.type">
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+			<!-- 标记 -->
+			<!-- <view class="flex align-items mark">
+				<view class="markLine"></view>
+				<view class="triangl-left"></view>
+			</view> -->
+		</view>
+	</view>
+</template>
+
+<script>
+	import debounce from './debounce.js'
+	export default {
+		name: "vertical-rule",
+		props: {
+			height: {
+				type: Number,
+				default: 200
+			},
+			min: { // 最小值
+				type: Number,
+				default: 0,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			},
+			max: { // 最大值
+				type: Number,
+				default: 150,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			},
+			value: { // 初始值
+				type: Number,
+				default: 50,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			},
+			multiple: { // 倍数 只支持10的倍数; multiple = 1 表示每个刻度的值等于1;multiple = 10 表示每个刻度的值等于0.1
+				type: [Number],
+				default: 10
+			},
+			lineWidth: { // 每个刻度之间的宽度
+				type: Number,
+				default: 6,
+				validator: function(val) {
+					return parseFloat(val) >= 0
+				}
+			}
+		},
+		data() {
+			return {
+				options: [], // 刻度线
+				selectIndex: -1,
+				scrollTop: 0, //初始位置
+				currentVal: '0', // 当前值
+				totalHeight: 0,
+			};
+		},
+		mounted() {
+			this.init()
+		},
+		methods: {
+			// 初始化刻度尺
+			init: function() {
+				// 最大值不能小于最小值
+				if (this.min >= this.max) return
+				this.options = []
+				let index = this.min
+				let length = this.max * this.multiple
+				for (let i = this.min * this.multiple; i <= length; i++) {
+					let type = ''
+					if (i % 5 == 0) {
+						type = 'line-md'
+						if (i % 10 == 0) {
+							type = 'line-lg'
+						}
+					} else {
+						type = 'line-sm'
+					}
+					// 每 10 格 显示一个刻度值
+					let val = ''
+					if (i % 10 == 0) {
+						val = i / this.multiple
+					}
+					this.options.push({
+						type: type,
+						val: val
+					})
+
+				}
+				// 总高度 = 总格子 * 每个格子的高度
+				this.totalHeight = ((this.max - this.min) * this.multiple) * this.lineWidth
+				console.log('总高度 = 总格子 * 每个格子的高度', this.totalHeight)
+				// 初始位置
+				setTimeout(() => {
+					// 初始值必须在min 与 max 之间
+					if (this.value < this.min) {
+						this.scrollTop = 0
+					} else if (this.value > this.max) {
+						this.scrollTop = this.heigh
+					} else {
+						this.scrollTop = (this.value - this.min) * this.multiple * this.lineWidth
+					}
+					this.currentVal = this.value
+					this.selectIndex = this.options.findIndex((item, index) => this.value == item.val)
+					this.$emit('change', this.currentVal)
+				}, 40)
+			},
+			scroll: function(e) {
+				var result = ((this.max - this.min) / this.totalHeight * e.detail.scrollTop) + this.min
+				this.currentVal = result 
+				this.$emit('change', this.currentVal)
+				// 处理滑在两个刻度之间,自动靠近最近一个刻度
+				debounce(() => {
+					var num = Math.round(result * this.multiple)/this.multiple
+					this.scrollTop = (num - this.min) * this.multiple * this.lineWidth
+					this.selectIndex = this.options.findIndex((item, index) => num == item.val)
+				}, 500)
+			}
+		}
+	}
+</script>
+
+<style>
+	.flex {
+		display: flex;
+	}
+
+	.justify-start {
+		justify-content: flex-start;
+	}
+
+	.align-items {
+		align-items: center;
+	}
+
+	.mark {
+		z-index: 100;
+		margin-left: -30px;
+	}
+
+	.markLine {
+		width: 23px;
+		height: 2px;
+		background: #3F86FF;
+	}
+
+	.triangl-left {
+		width: 0;
+		height: 0;
+		border-right: 12px solid #3F86FF;
+		border-top: 6px solid transparent;
+		border-bottom: 6px solid transparent;
+		border-radius: 2px;
+		margin-left: -5px;
+	}
+
+	.bg-red {
+		background: red;
+	}
+
+	.bg-blue {
+		background: blue;
+	}
+
+	.line {
+		display: flex;
+		flex-direction: column;
+		align-items: flex-end;
+	}
+
+	.line-lg {
+		width: 50px;
+		border-top: 2px solid #000;
+	}
+
+	.line-md {
+		width: 40px;
+		border-top: 2px solid #000;
+	}
+
+	.line-sm {
+		width: 20px;
+		border-top: 2px solid #000;
+	}
+
+	.line-label {
+		/* color: #3F86FF; */
+	}
+</style>

+ 66 - 0
components/our-loading/loaders/bounce.vue

@@ -0,0 +1,66 @@
+<template>
+  <view>
+    <view class="spinner-inside" :style="{
+      width: size + 110 + 'px',
+    }">
+      <view :style="{ backgroundColor:color }" class="bounce1"></view>
+      <view :style="{ backgroundColor:color }" class="bounce2"></view>
+      <view :style="{ backgroundColor:color }" class="bounce3"></view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'bounce',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+  text-align: center;
+}
+ 
+.spinner-inside > view {
+  width: 30px;
+  height: 30px;
+ 
+  border-radius: 100%;
+  display: inline-block;
+  -webkit-animation: bouncedelay 1.4s infinite ease-in-out;
+  animation: bouncedelay 1.4s infinite ease-in-out;
+  /* Prevent first frame from flickering when animation starts */
+  -webkit-animation-fill-mode: both;
+  animation-fill-mode: both;
+}
+ 
+.spinner-inside .bounce1 {
+  -webkit-animation-delay: -0.32s;
+  animation-delay: -0.32s;
+}
+ 
+.spinner-inside .bounce2 {
+  -webkit-animation-delay: -0.16s;
+  animation-delay: -0.16s;
+}
+ 
+@-webkit-keyframes bouncedelay {
+  0%, 80%, 100% { -webkit-transform: scale(0.0) }
+  40% { -webkit-transform: scale(1.0) }
+}
+ 
+@keyframes bouncedelay {
+  0%, 80%, 100% {
+    transform: scale(0.0);
+    -webkit-transform: scale(0.0);
+  } 40% {
+    transform: scale(1.0);
+    -webkit-transform: scale(1.0);
+  }
+}
+</style>

+ 61 - 0
components/our-loading/loaders/double-bounce.vue

@@ -0,0 +1,61 @@
+<template>
+  <view>
+    <view class="spinner-inside" :style="{
+      width: size+20+'px',
+      height: size+20+'px'
+    }">
+      <view :style="{ backgroundColor:color }" class="double-bounce1"></view>
+      <view :style="{ backgroundColor:color }" class="double-bounce2"></view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'doubleBounce',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+  position: relative;
+}
+ 
+.double-bounce1, .double-bounce2 {
+  width: 100%;
+  height: 100%;
+  border-radius: 50%;
+  opacity: 0.6;
+  position: absolute;
+  top: 0;
+  left: 0;
+   
+  -webkit-animation: bounce 2.0s infinite ease-in-out;
+  animation: bounce 2.0s infinite ease-in-out;
+}
+ 
+.double-bounce2 {
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}
+ 
+@-webkit-keyframes bounce {
+  0%, 100% { -webkit-transform: scale(0.0) }
+  50% { -webkit-transform: scale(1.0) }
+}
+ 
+@keyframes bounce {
+  0%, 100% {
+    transform: scale(0.0);
+    -webkit-transform: scale(0.0);
+  } 50% {
+    transform: scale(1.0);
+    -webkit-transform: scale(1.0);
+  }
+}
+</style>

+ 69 - 0
components/our-loading/loaders/double-cube.vue

@@ -0,0 +1,69 @@
+<template>
+  <view>
+    <view class="spinner-inside" :style="{
+      width: size+'px',
+      height: size+'px'
+    }">
+      <view :style="{ backgroundColor:color,width:size-10+'px',height:size-10+'px'}" class="cube1"></view>
+      <view :style="{ backgroundColor:color,width:size-10+'px',height:size-10+'px'}" class="cube2"></view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'doubleCube',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 50% auto;
+  position: relative;
+  transform: translate(-50%, -50%);
+}
+ 
+.cube1, .cube2 {
+  position: absolute;
+  top: 0;
+  left: 0;
+   
+  -webkit-animation: cubemove 1.8s infinite ease-in-out;
+  animation: cubemove 1.8s infinite ease-in-out;
+}
+ 
+.cube2 {
+  -webkit-animation-delay: -0.9s;
+  animation-delay: -0.9s;
+}
+ 
+@-webkit-keyframes cubemove {
+  25% { -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5) }
+  50% { -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg) }
+  75% { -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5) }
+  100% { -webkit-transform: rotate(-360deg) }
+}
+ 
+@keyframes cubemove {
+  25% {
+    transform: translateX(42px) rotate(-90deg) scale(0.5);
+    -webkit-transform: translateX(42px) rotate(-90deg) scale(0.5);
+  } 50% {
+    transform: translateX(42px) translateY(42px) rotate(-179deg);
+    -webkit-transform: translateX(42px) translateY(42px) rotate(-179deg);
+  } 50.1% {
+    transform: translateX(42px) translateY(42px) rotate(-180deg);
+    -webkit-transform: translateX(42px) translateY(42px) rotate(-180deg);
+  } 75% {
+    transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);
+    -webkit-transform: translateX(0px) translateY(42px) rotate(-270deg) scale(0.5);
+  } 100% {
+    transform: rotate(-360deg);
+    -webkit-transform: rotate(-360deg);
+  }
+}
+</style>

+ 70 - 0
components/our-loading/loaders/double-dot.vue

@@ -0,0 +1,70 @@
+<template>
+  <view>
+    <view class="spinner-inside" :style="{
+      width: size+40+'px',
+      height: size+40+'px'
+    }">
+      <view :style="{ backgroundColor:color }" class="dot1"></view>
+      <view :style="{ backgroundColor:color }" class="dot2"></view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'doubleDot',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+  position: relative;
+  text-align: center;
+   
+  -webkit-animation: rotate 2.0s infinite linear;
+  animation: rotate 2.0s infinite linear;
+}
+ 
+.dot1, .dot2 {
+  width: 60%;
+  height: 60%;
+  display: inline-block;
+  position: absolute;
+  top: 0;
+  background-color: #67CF22;
+  border-radius: 100%;
+   
+  -webkit-animation: bounce 2.0s infinite ease-in-out;
+  animation: bounce 2.0s infinite ease-in-out;
+}
+ 
+.dot2 {
+  top: auto;
+  bottom: 0px;
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}
+ 
+@-webkit-keyframes rotate { 100% { -webkit-transform: rotate(360deg) }}
+@keyframes rotate { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg) }}
+ 
+@-webkit-keyframes bounce {
+  0%, 100% { -webkit-transform: scale(0.0) }
+  50% { -webkit-transform: scale(1.0) }
+}
+ 
+@keyframes bounce {
+  0%, 100% {
+    transform: scale(0.0);
+    -webkit-transform: scale(0.0);
+  } 50% {
+    transform: scale(1.0);
+    -webkit-transform: scale(1.0);
+  }
+}
+</style>

+ 147 - 0
components/our-loading/loaders/loop.vue

@@ -0,0 +1,147 @@
+<template>
+  <view>
+   <view class="spinner-inside" :style="{
+      width: size+'px',
+      height: size+'px'
+    }">
+      <view class="spinner-inside-container container1">
+        <view :style="{ backgroundColor:color }" class="circle1"></view>
+        <view :style="{ backgroundColor:color }" class="circle2"></view>
+        <view :style="{ backgroundColor:color }" class="circle3"></view>
+        <view :style="{ backgroundColor:color }" class="circle4"></view>
+      </view>
+      <view class="spinner-inside-container container2">
+        <view :style="{ backgroundColor:color }" class="circle1"></view>
+        <view :style="{ backgroundColor:color }" class="circle2"></view>
+        <view :style="{ backgroundColor:color }" class="circle3"></view>
+        <view :style="{ backgroundColor:color }" class="circle4"></view>
+      </view>
+      <view class="spinner-inside-container container3">
+        <view :style="{ backgroundColor:color }" class="circle1"></view>
+        <view :style="{ backgroundColor:color }" class="circle2"></view>
+        <view :style="{ backgroundColor:color }" class="circle3"></view>
+        <view :style="{ backgroundColor:color }" class="circle4"></view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'loop',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+  position: relative;
+}
+ 
+.container1 > view, .container2 > view, .container3 > view {
+  width: 12px;
+  height: 12px;
+ 
+  border-radius: 100%;
+  position: absolute;
+  -webkit-animation: bouncedelay 1.2s infinite ease-in-out;
+  animation: bouncedelay 1.2s infinite ease-in-out;
+  -webkit-animation-fill-mode: both;
+  animation-fill-mode: both;
+}
+ 
+.spinner-inside .spinner-inside-container {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+}
+ 
+.container2 {
+  -webkit-transform: rotateZ(45deg);
+  transform: rotateZ(45deg);
+}
+ 
+.container3 {
+  -webkit-transform: rotateZ(90deg);
+  transform: rotateZ(90deg);
+}
+ 
+.circle1 { top: 0; left: 0; }
+.circle2 { top: 0; right: 0; }
+.circle3 { right: 0; bottom: 0; }
+.circle4 { left: 0; bottom: 0; }
+ 
+.container2 .circle1 {
+  -webkit-animation-delay: -1.1s;
+  animation-delay: -1.1s;
+}
+ 
+.container3 .circle1 {
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}
+ 
+.container1 .circle2 {
+  -webkit-animation-delay: -0.9s;
+  animation-delay: -0.9s;
+}
+ 
+.container2 .circle2 {
+  -webkit-animation-delay: -0.8s;
+  animation-delay: -0.8s;
+}
+ 
+.container3 .circle2 {
+  -webkit-animation-delay: -0.7s;
+  animation-delay: -0.7s;
+}
+ 
+.container1 .circle3 {
+  -webkit-animation-delay: -0.6s;
+  animation-delay: -0.6s;
+}
+ 
+.container2 .circle3 {
+  -webkit-animation-delay: -0.5s;
+  animation-delay: -0.5s;
+}
+ 
+.container3 .circle3 {
+  -webkit-animation-delay: -0.4s;
+  animation-delay: -0.4s;
+}
+ 
+.container1 .circle4 {
+  -webkit-animation-delay: -0.3s;
+  animation-delay: -0.3s;
+}
+ 
+.container2 .circle4 {
+  -webkit-animation-delay: -0.2s;
+  animation-delay: -0.2s;
+}
+ 
+.container3 .circle4 {
+  -webkit-animation-delay: -0.1s;
+  animation-delay: -0.1s;
+}
+ 
+@-webkit-keyframes bouncedelay {
+  0%, 80%, 100% { -webkit-transform: scale(0.0) }
+  40% { -webkit-transform: scale(1.0) }
+}
+ 
+@keyframes bouncedelay {
+  0%, 80%, 100% {
+    transform: scale(0.0);
+    -webkit-transform: scale(0.0);
+  } 40% {
+    transform: scale(1.0);
+    -webkit-transform: scale(1.0);
+  }
+}
+</style>

+ 46 - 0
components/our-loading/loaders/rotate-plane.vue

@@ -0,0 +1,46 @@
+<template>
+  <view>
+    <view :style="{
+      backgroundColor: color,
+      width: size+20+'px',
+      height: size+20+'px' }" class="spinner-inside"></view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'rotatePlane',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+ 
+  -webkit-animation: rotateplane 1.2s infinite ease-in-out;
+  animation: rotateplane 1.2s infinite ease-in-out;
+}
+ 
+@-webkit-keyframes rotateplane {
+  0% { -webkit-transform: perspective(120px) }
+  50% { -webkit-transform: perspective(120px) rotateY(180deg) }
+  100% { -webkit-transform: perspective(120px) rotateY(180deg)  rotateX(180deg) }
+}
+ 
+@keyframes rotateplane {
+  0% {
+    transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+    -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)
+  } 50% {
+    transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+    -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)
+  } 100% {
+    transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+    -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+  }
+}
+</style>

+ 47 - 0
components/our-loading/loaders/scale-out.vue

@@ -0,0 +1,47 @@
+<template>
+  <view>
+    <view :style="{
+      backgroundColor: color,
+      width: size+40+'px',
+      height: size+40+'px' }" class="spinner-inside"></view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'scaleOut',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+ 
+  border-radius: 100%; 
+  -webkit-animation: scaleout 1.0s infinite ease-in-out;
+  animation: scaleout 1.0s infinite ease-in-out;
+}
+ 
+@-webkit-keyframes scaleout {
+  0% { -webkit-transform: scale(0.0) }
+  100% {
+    -webkit-transform: scale(1.0);
+    opacity: 0;
+  }
+}
+ 
+@keyframes scaleout {
+  0% {
+    transform: scale(0.0);
+    -webkit-transform: scale(0.0);
+  } 100% {
+    transform: scale(1.0);
+    -webkit-transform: scale(1.0);
+    opacity: 0;
+  }
+}
+</style>

+ 76 - 0
components/our-loading/loaders/shrink-rect.vue

@@ -0,0 +1,76 @@
+<template>
+  <view>
+    <view class="spinner-inside" :style="{
+      width: size+20+'px',
+      height: size+20+'px'
+    }">
+      <view :style="{ backgroundColor:color }" class="rect1"></view>
+      <view :style="{ backgroundColor:color }" class="rect2"></view>
+      <view :style="{ backgroundColor:color }" class="rect3"></view>
+      <view :style="{ backgroundColor:color }" class="rect4"></view>
+      <view :style="{ backgroundColor:color }" class="rect5"></view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'shrinkRect',
+  props: {
+    color: String,
+    size: Number
+  }
+}
+</script>
+
+<style scoped>
+.spinner-inside {
+  margin: 25px auto;
+  text-align: center;
+  font-size: 10px;
+}
+
+.spinner-inside > view {
+  height: 100%;
+  width: 12%;
+	margin: 0 2px;
+  display: inline-block;
+  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
+  animation: stretchdelay 1.2s infinite ease-in-out;
+}
+ 
+.spinner-inside .rect2 {
+  -webkit-animation-delay: -1.1s;
+  animation-delay: -1.1s;
+}
+ 
+.spinner-inside .rect3 {
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}
+ 
+.spinner-inside .rect4 {
+  -webkit-animation-delay: -0.9s;
+  animation-delay: -0.9s;
+}
+ 
+.spinner-inside .rect5 {
+  -webkit-animation-delay: -0.8s;
+  animation-delay: -0.8s;
+}
+ 
+@-webkit-keyframes stretchdelay {
+  0%, 40%, 100% { -webkit-transform: scaleY(0.4) } 
+  20% { -webkit-transform: scaleY(1.0) }
+}
+ 
+@keyframes stretchdelay {
+  0%, 40%, 100% {
+    transform: scaleY(0.4);
+    -webkit-transform: scaleY(0.4);
+  }  20% {
+    transform: scaleY(1.0);
+    -webkit-transform: scaleY(1.0);
+  }
+}
+</style>

+ 129 - 0
components/our-loading/our-loading.vue

@@ -0,0 +1,129 @@
+<template>
+	<!-- #ifdef H5 -->
+	<transition name="fade">
+	<!-- #endif -->
+		<view class="mask" v-show="isActive" :class="{ 'full-screen': isFullScreen }" :style="{ backgroundColor }">
+			<view class="spinner" :style="{ transform:`translate(-50%, -${translateY}%)`}">
+				<slot>
+					<!--  ==========在这里改成选择的那一个========== -->
+					<shrinkRect :color="color" :size="size" />
+					<!--  ==========在这里改成选择的那一个========== -->
+				</slot>
+				<view v-if="text.length" :style="{ color:textColor }">
+					{{ text }}
+				</view>
+			</view>
+		</view>
+	<!-- #ifdef H5 -->
+	</transition>
+	<!-- #endif -->
+</template>
+
+<script>
+	// ==========在这里选一个你要的其他去掉也行==========
+	// import loop from './loaders/loop.vue'
+	// import bounce from './loaders/bounce.vue'
+	// import doubleBounce from './loaders/double-bounce.vue'
+	// import doubleCube from './loaders/double-cube.vue'
+	// import doubleDot from './loaders/double-dot.vue'
+	// import rotatePlane from './loaders/rotate-plane.vue'
+	// import scaleOut from './loaders/scale-out.vue'
+	import shrinkRect from './loaders/shrink-rect.vue'
+	// ==========在这里选一个你要的其他去掉也行==========
+
+	export default {
+		name: 'ourLoading',
+		components: {
+			// ==========在这里选择一个==========
+			// loop,
+			// bounce,
+			// doubleBounce,
+			// doubleCube,
+			// doubleDot,
+			// rotatePlane,
+			// scaleOut,
+			shrinkRect
+			// ==========在这里选择一个==========
+		},
+		props: {
+			active: Boolean,
+			translateY: {
+				type: Number,
+				default: 150
+			},
+			text: {
+				type: String,
+				default: ''
+			},
+			color: {
+				type: String,
+				default: '#333'
+			},
+			textColor: {
+				type: String,
+				default: '#333'
+			},
+			isFullScreen: {
+				type: Boolean,
+				default: false
+			},
+			backgroundColor: {
+				type: String,
+				default: 'rgba(255, 255, 255, .9)'
+			},
+			size: {
+				type: Number,
+				default: 40
+			}
+		},
+		data() {
+			return {
+				isActive: this.active || false
+			}
+		},
+		watch: {
+			active(value) {
+				this.isActive = value
+			}
+		}
+	}
+</script>
+
+<style scoped>
+	.mask {
+		position: absolute;
+		left: 0;
+		right: 0;
+		top: 0;
+		bottom: 0;
+		z-index: 3000;
+		transition: opacity .3s linear;
+	}
+
+	.full-screen {
+		position: fixed;
+		top: 0;
+		right: 0;
+		bottom: 0;
+		left: 0;
+	}
+
+	.spinner {
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		text-align: center;
+	}
+
+	/* #ifdef H5 */
+	.fade-enter-active,
+	.fade-leave-active {
+		transition: opacity .3s;
+	}
+
+	.fade-enter,
+	.fade-leave-to {
+		opacity: 0;
+	}
+	/* #endif */
+</style>

+ 42 - 0
components/xiaoran-circle/xiaoran-circle.css

@@ -0,0 +1,42 @@
+.circle_box {
+	position: relative;
+}
+.slot {
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+.CanvasBox {
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	top: 0px;
+	left: 0px;
+	
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 226 - 0
components/xiaoran-circle/xiaoran-circle.vue

@@ -0,0 +1,226 @@
+<template>
+	<view
+		:style="{
+			width: circleSize.width,
+			height: circleSize.height
+		}"
+		class="circle_box"
+	>
+		<view class="canvas">
+			<slot name="canvas"></slot>
+		</view>
+		<view class="slot">
+			<slot></slot>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "iCircle",
+		props: {
+			percent: {
+				// 百分比
+				type: Number,
+				default: 0
+			},
+			prefix: {
+				// 多个圆环情况下的前缀
+				type: String,
+				default: ""
+			},
+			size: {
+				// 图表的宽度和高度,单位 upx
+				type: Number,
+				default: 120
+			},
+			strokeWidth: {
+				// 进度环的线宽,单位 upx
+				type: Number,
+				default: 10
+			},
+			strokeColor: {
+				// 进度环的颜色 16进制
+				type: String,
+				default: "#2d8cf0"
+			},
+			trailWidth: {
+				// 进度环背景的线宽,单位 upx
+				type: Number,
+				default: 12
+			},
+			trailColor: {
+				// 进度环背景的颜色
+				type: String,
+				default: "#eaeef2"
+			},
+			BgId: {
+				// BgId
+				type: String,
+				required: true
+			},
+			InId: {
+				// InId
+				type: String,
+				required: true
+			},
+			dashboard: {
+				// 仪表盘
+				type: Boolean,
+				default: false
+			},
+			start: {
+				// 仪表盘起始角度
+				type: Number,
+				default: 27
+			}
+		},
+		data() {
+			return {
+				selfPercent: 0,
+				type: "add",
+				T: null
+			}
+		},
+		computed: {
+			UniSize() {
+				// 转换为upx
+				return uni.upx2px(this.size);
+			},
+			circleSize() {
+				return {
+					width: `${this.UniSize}px`,
+					height: `${this.UniSize}px`
+				};
+			},
+			center_x() {
+				return this.UniSize / 2;
+			},
+			center_y() {
+				return this.UniSize / 2;
+			},
+			rad() {
+				return Math.PI*2/100;
+			},
+			lineWidth() {
+				return uni.upx2px(this.trailWidth);
+			},
+			BgWidth() {
+				return uni.upx2px(this.strokeWidth);
+			},
+			radius() {
+				return this.center_x - this.BgWidth - Math.abs(this.BgWidth - this.lineWidth);
+			},
+			startDeg() {
+				return Math.PI * (1 - this.start/180);
+			},
+			countDeg() {
+				return this.start * 2 + 180;
+			},
+			fillDegArr() {
+				let start, end;
+				if (this.dashboard) {
+					start = this.startDeg;
+					end = Math.PI*this.selfPercent/100*this.countDeg/180 + this.startDeg;
+				} else {
+					start = -Math.PI/2;
+					end = -Math.PI/2 + this.selfPercent * this.rad;
+				}
+				return {start, end};
+			},
+			bgDegArr() {
+				let start, end;
+				if (this.dashboard) {
+					start = this.startDeg;
+					end = Math.PI*this.countDeg/180 + this.startDeg;
+				} else {
+					start = 0;
+					end = Math.PI * 2;
+				}
+				return {start, end};
+			}
+		},
+		methods: {
+			Init() {
+				this.backgroundCircle();
+				this.requestAnimationFrame();
+			},
+			requestAnimationFrame() {
+				if (this.type == "add") {
+					if (this.selfPercent >= this.percent) {
+						clearTimeout(this.T);
+						return;
+					}
+					this.selfPercent++;
+					if (this.selfPercent >= 100) {
+						this.selfPercent = 100;
+					}
+				} else {
+					if (this.selfPercent <= this.percent) {
+						clearTimeout(this.T);
+						return;
+					}
+					this.selfPercent--;
+					if (this.selfPercent <= 0) {
+						this.selfPercent = 0;
+					}
+				}
+				this.foregroundCircle();
+				this.T = setTimeout(this.requestAnimationFrame, 5);
+			},
+			backgroundCircle() {
+				const context = uni.createCanvasContext(this.BgId);
+				// 绘制背景圆环
+				const rad = Math.PI*2/100;
+				context.save();
+				// 开始路径绘制
+				context.beginPath();
+				context.setLineWidth(this.lineWidth); //设置线宽
+				context.setLineCap("round");
+				context.setStrokeStyle(this.trailColor);
+				//用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)
+				// context.arc(this.center_x, this.center_y, this.radius, 0, Math.PI * 2, false);
+				context.arc(this.center_x, this.center_y, this.radius , this.bgDegArr.start, this.bgDegArr.end, false);
+				context.stroke();
+				// 结束绘制路径
+				context.closePath();
+				// 恢复之前保存的绘图上下文。
+				context.restore();
+				// 绘制
+				context.draw()
+			},
+			foregroundCircle(){
+				const context = uni.createCanvasContext(this.InId);
+                context.save();
+                context.setStrokeStyle(this.strokeColor);
+				context.setLineWidth(this.BgWidth); //设置线宽
+				context.setLineCap("round");
+                context.beginPath();
+				context.arc(this.center_x, this.center_y, this.radius , this.fillDegArr.start, this.fillDegArr.end, false);
+                context.stroke();
+                context.closePath();
+                context.restore();
+				context.draw();
+            }
+		},
+		mounted() {
+			this.Init();
+		},
+		onReady() {
+		},
+		watch: {
+			percent(newV, oldV) {
+				if (newV > oldV) {
+					this.type = "add";
+				} else {
+					this.type = "reduce";
+				}
+				this.Init();
+			}
+		}
+	};
+</script>
+
+<style>
+	@import url("./xiaoran-circle.css");
+</style>

+ 1 - 0
index.html

@@ -9,6 +9,7 @@
         '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
         (coverSupport ? ', viewport-fit=cover' : '') + '" />')
     </script>
+	 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
     <title></title>
     <!--preload-links-->
     <!--app-context-->

+ 1 - 1
pages.json

@@ -116,5 +116,5 @@
 	      "pagePath": "pages/my/index"
 	    }
 	  ]
-	},
+	}
 }

+ 144 - 0
pages/scaleDemo/index.vue

@@ -0,0 +1,144 @@
+
+<template>
+  <div class="content">
+    <div>
+      <view class='scale-title'>横向没有小数点</view>
+      <view class='scale-value'>{{horizontaNoPointVal}}</view>
+      <vue-scale :min="10"
+                 :max="50"
+                 :int="true"
+                 :single="10"
+                 :h="80"
+                 :active="36"
+                 :styles="styles"
+                 @value="horizontaNoPointMethods"/>
+    </div>
+    <div>
+      <view class='scale-title'>横向有小数点</view>
+      <view class='scale-value'>{{horizontaPointVal}}</view>
+      <vue-scale :min="10"
+                 :max="50"
+                 :int="false"
+                 :single="10"
+                 :h="80"
+                 :active="36.1"
+                 :styles="styles"
+                 @value="horizontaPointMethods"/>
+    </div>
+    <div>
+      <view class='scale-title'>竖向没有小数点</view>
+      <view class='scale-container'>
+        <view class='scale-value'>{{verticalNoPointVal}}</view>
+        <view class='scale-view'>
+          <vue-scale :min="10"
+                     :max="100"
+                     direction="vertical"
+                     :int="true"
+                     :single="10"
+                     :h="80"
+                     :active="36"
+                     :styles="styles"
+                     @value="verticalNoPointMethods"/>
+        </view>
+      </view>
+    </div>
+    <div>
+      <view class='scale-title'>竖向有小数点</view>
+      <view class='scale-container'>
+        <view class='scale-value'>{{verticalPointVal}}</view>
+        <view class='scale-view'>
+          <vue-scale
+            :min="10"
+            :max="50"
+            :int="false"
+            :single="10"
+            :h="40"
+            :active="36.1"
+            :styles="styles"
+            direction="vertical"
+            @value="verticalPointMethods"/>
+        </view>
+      </view>
+    </div>
+  </div>
+</template>
+
+<script>
+import vueScale from '@/components/sapling-vue-scale/sapling-vue-scale.vue';
+export default {
+  name: 'scaleDemo',
+  components: {
+    vueScale,
+  },
+  data() {
+    return {
+      weight: 11,
+      height: 180,
+      styles: {
+        line: '#dbdbdb',
+        bginner: '#fbfbfb',
+        bgoutside: '#ffffff',
+        font: '#404040',
+        fontColor: '#404040',
+        fontSize: 16,
+      },
+      horizontaPointVal: '',
+      horizontaNoPointVal: '',
+      verticalPointVal: '',
+      verticalNoPointVal: '',
+    };
+  },
+  mounted() {
+  },
+  methods: {
+    // 横向滚动有小数点
+    horizontaPointMethods(msg) {
+      this.horizontaPointVal = msg;
+    },
+    // 横向滚动没有小数点
+    horizontaNoPointMethods(msg) {
+      this.horizontaNoPointVal = msg;
+    },
+    // 竖向滚动有小数点
+    verticalPointMethods(msg) {
+      this.verticalPointVal = msg;
+    },
+    // 竖向滚动没有小数点
+    verticalNoPointMethods(msg) {
+      this.verticalNoPointVal = msg;
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+  .content {
+    display: flex;
+    flex-direction: column;
+    padding: 0 30rpx 30rpx 30rpx;
+    box-sizing: border-box;
+    background: #fff;
+  }
+  .container {
+    padding: 0 40rpx;
+  }
+  .scale-value{
+    text-align: center;
+    color: #6643e7;
+  }
+  .scale-title{
+    margin-top: 50rpx;
+  }
+  .scale-container{
+    display: flex;
+  }
+  .scale-container .scale-value{
+    flex: 1;
+    line-height: 600rpx;
+  }
+  .scale-view{
+    width: 200rpx;
+    height: 600rpx;
+    flex: 1;
+  }
+</style>

+ 48 - 2
pages/tools/jingXuanBiZhi.vue

@@ -1,14 +1,60 @@
 <template>
 	<view class="content">
-		
+		<view class="flex scroll-x ai_end mgt-20" style="gap: 50rpx;">
+			<view class="text-28 text-999 cursor" :class="active == tab.id?'active':''"
+			 v-for="(tab,index) in category" @click="chooseTab(tab)">
+				{{ tab.name }}
+			</view>
+		</view>
+		<view class="flex mgt-40">
+			<view class="w-220 h-120 flex ai_center jc_center bg-white radio-20 mgr-20">
+				流行壁纸
+			</view>
+			<view class="w-220 h-120 flex ai_center jc_center bg-white radio-20">
+				最新壁纸
+			</view>
+		</view>
+		<view class="imgs mgt-40 flex fw_wrap" style="gap: 14rpx;">
+			<image class="w-220 h-280 radio-16" mode="aspectFill"
+			v-for="img in category[active-1].list" :src="img">
+				
+			</image>
+		</view>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+const category = ref([
+	{ name:'风景',list:[
+		'https://img2.baidu.com/it/u=643390968,3821598343&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800',
+		'https://img2.baidu.com/it/u=1207164141,4244022854&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500',
+		'https://img2.baidu.com/it/u=2122730436,3330551883&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500',
+		'https://img2.baidu.com/it/u=1934414271,796431517&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800'
+	],id:1 },
+	{ name:'设计',list:[],id:2 },
+	{ name:'物语',list:[],id:3 },
+	{ name:'城市',list:[],id:4 },
+])
+const active = ref(1)
+const chooseTab = (tab) =>{
+	active.value = tab.id
+}
+onMounted(()=>{
+	
+})
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		padding: 28rpx;
+		background: linear-gradient(to bottom, #a9d4ff, #cce6ff);
+	}
+	.active{
+		color: #000;
+		font-weight: 500;
+		font-size: 30rpx;
+	}
 </style>

+ 71 - 2
pages/tools/quWeiCePing.vue

@@ -1,14 +1,83 @@
 <template>
 	<view class="content">
-		
+		<view class="pdy-60 pdx-28 mgt-100 radio-20 bg-white w border-0_1 box">
+				<view class="title mgb-50" >
+					{{ curIndex + 1 }}、{{ QList[curIndex].title }}
+				</view>
+				<view class="Aitem flex" v-for="(a,key) in QList[curIndex].Alist" 
+				@click="chooseA(key)" :class="chooseList[curIndex] == key ?'active':''">
+					<view class="">{{ key }}、</view>
+					<view class="">{{ a }}</view>
+				</view>
+				<view class="next_btn cursor" @click="nextFn">{{ curIndex == QList.length - 1 ? '提交' : '下一题'}}</view>
+		</view>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+const QList = ref([
+	{ title:'你更喜欢哪种社交场合1?',Alist:{'A':'大型会所1','B':'小型会所','C':'与几位亲朋密友聚会','D':'独自一人'} },
+	{ title:'你更喜欢哪种社交场合2?',Alist:{'A':'大型会所2','B':'小型会所','C':'与几位亲朋密友聚会','D':'独自一人'} },
+	{ title:'你更喜欢哪种社交场合3?',Alist:{'A':'大型会所3','B':'小型会所','C':'与几位亲朋密友聚会','D':'独自一人'} },
+	{ title:'你更喜欢哪种社交场合4?',Alist:{'A':'大型会所4','B':'小型会所','C':'与几位亲朋密友聚会','D':'独自一人'} },
+	{ title:'你更喜欢哪种社交场合5?',Alist:{'A':'大型会所5','B':'小型会所','C':'与几位亲朋密友聚会','D':'独自一人'} }
+]) 
+const curIndex = ref(0)
+const curChoose = ref(null)
+const chooseList = ref([]) // 选择的数组 AABCD
+const chooseA = (key) =>{
+	chooseList.value[curIndex.value] = key
+}
+const nextFn = ()=>{
+	if(curIndex.value < QList.value.length - 1){
+		curIndex.value += 1
+	}else{
+		// 完成答题
+		uni.showToast({
+			title:'提交成功!',
+		})
+	}
+	
+}
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		padding: 28rpx;
+		background: linear-gradient(to bottom, #a9d4ff, #cce6ff);
+	}
+	.box{
+		height: 75vh;
+		border: 1rpx solid #000;
+		position: relative;
+		.Aitem{
+			border: 1rpx solid #000;
+			height: 80rpx;
+			line-height: 80rpx;
+			border-radius: 22rpx;
+			margin-bottom: 20rpx;
+			padding: 0 20rpx;
+			cursor: pointer;
+		}
+		.next_btn{
+			width: 320rpx;
+			height: 60rpx;
+			line-height: 60rpx;
+			text-align: center;
+			color: #fff;
+			background-color: #399bfc;
+			border-radius: 20rpx;
+			border: 1px solid #000;
+			transform: translate(50%);
+			position: absolute;
+			bottom: 60rpx;
+		}
+		.active{
+			border: 1px solid #399bfc;
+			color: #399bfc;
+		}
+	}
 </style>

+ 34 - 3
pages/tools/shengBoChuChen.vue

@@ -1,14 +1,45 @@
 <template>
-	<view class="content">
-		
+	<view class="content p-rel pdt-100">
+		<view class="p-rel h-200 flex ai_center fd_c">
+			<ourLoading active translateY="50" background-color="transparent" color="#ea9f8a" />
+		</view>
+		<view class="p-rel flex ai_center fd_c">
+			<view class="text-62 mgt-10">{{ statusNum }}%</view>
+			<view class="text-36 text-500 mgy-30">正在声波初尘中...</view>
+			<view class="text-24 text-555 mgb-80">手机音量调到最大,可以获得最后的除尘效果</view>
+			<view class="btn_s w-300" @click="handleClick">{{ open? '除尘结束':'开始除尘' }}</view>
+		</view>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+import ourLoading from '@/components/our-loading/our-loading.vue'
+const open = ref(false)
+const statusNum = ref(0)
+var timer = null
+const handleClick = () =>{
+	if(open.value) return
+	open.value = !open.value
+	if(open.value){
+		timer = setInterval(() => {
+			if(statusNum.value < 100){
+				let num = Math.ceil(Math.random()*3) 
+				statusNum.value += statusNum.value + num > 100 ? 1 : num
+			}else{
+				clearInterval(timer)
+			}
+		}, 30)
+	}else{
+		statusNum.value = 0
+	}
+}
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		background: linear-gradient(to bottom, #a9d4ff, #cce6ff);
+	}
 </style>

+ 14 - 2
pages/tools/shouJiCeJu.vue

@@ -1,14 +1,26 @@
 <template>
 	<view class="content">
-		
+		<vertical-rule style="position: absolute;right: 10rpx;" min="0" max="150" height="600" @change="change"></vertical-rule>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+import verticalRule from '@/components/horizontal-rule/vertical-rule.vue'
+const dfVal = ref(0)
+const change = (e)=>{
+	dfVal.value = Math.round(e)
+}
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		padding: 28rpx;
+		background: linear-gradient(to bottom, #a9d4ff, #cce6ff);
+	}
+	.calliper{
+		transform: translate(90deg);
+	}
 </style>

+ 147 - 2
pages/tools/shouJiQingLi.vue

@@ -1,14 +1,159 @@
 <template>
 	<view class="content">
-		
+		<view class="flex w ai_center jc_center fd_c mgt-20">
+			<!-- <qiun-data-charts
+				  style="width: 360rpx;height: 360rpx;"
+			      type="arcbar"
+			      :opts="opts"
+			      :chartData="chartData"
+			    /> -->
+			<iCircle
+				:percent="percent"
+				:size="350"
+				stroke-color="#44ebd9"
+				BgId="BgId1"
+				InId="InId1"
+				trailWidth="30"
+				strokeWidth="30"
+				trailColor="#d0effd"
+			>
+				<text  style="font-size:48rpx; color: #333;font-weight: bold;">{{ percent }}%</text>
+				<view slot="canvas">
+					<canvas
+						class="CanvasBox strokeCanvas"
+						canvas-id="BgId1"
+					></canvas>
+					<canvas
+						class="CanvasBox trailCanvas"
+						canvas-id="InId1"
+					></canvas>
+				</view>
+			</iCircle>
+			<view class="text-24 mgt-20">发现大量垃圾</view>
+			<view class="text-888 text-22 mgt-20">占用大量手机内存,急需清理</view>
+			<view class="mgt-50 clean_btn cursor" @click="sureClean">
+				{{ status?'正在清理中':'立即清理' }}
+			</view>
+		</view>
+		<view class="w bg-white h-320 mgt-80 radio-30 pd-20">
+			<view v-for="(i,key) in info" class="bg-eee h-80 radio-20 mgb-20 flex jc_between pdx-20 pdy-20">
+				<view>
+					<i v-if="key == '剩余内存'" style="color: #42aa87;" class="fas fa-rocket"></i>
+					<i v-else-if="key == '总计内存'" style="color: #42aa87;" class="fas fa-file"></i>
+					<i v-else-if="key == '已使用'" style="color: #42aa87;" class="fas fa-pie-chart"></i>
+					&nbsp; {{ key }}
+				</view>
+				<view class="" style="color: #42aa87;">
+					{{ i }}GB
+				</view>
+			</view>
+		</view>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+import iCircle from '@/components/xiaoran-circle/xiaoran-circle.vue';
+onMounted(()=>{
+	getServerData();
+})
+const info = ref({
+	'剩余内存':20.99,
+	'总计内存': 50.12,
+	'已使用':29.13,
+})
+const percent = ref(0)
+const status = ref(false)
+var timer = null
+const sureClean = ()=>{
+	if(status.value) return
+	status.value = !status.value
+	if(status.value){
+		timer = setInterval(() => {
+			if(percent.value < 100){
+				let num = Math.ceil(Math.random()*3) 
+				percent.value += percent.value + num > 100 ? 1 : num
+			}else{
+				clearInterval(timer)
+				percent.value = 0
+				status.value = false
+			}
+		}, 200)
+	}else{
+		percent.value = 0
+	}
+}
+const chartData = ref({
+	
+})
+const opts = ref({
+	 color: ["#1890FF","#91CB74","#FAC858","#EE6666","#73C0DE","#3CA272","#FC8452","#9A60B4","#ea7ccc"],
+	padding: undefined,
+	title: {
+	  name: "80%",
+	  fontSize: 35,
+	  color: "#000"
+	},
+	subtitle: {
+	  name: "",
+	  fontSize: 25,
+	  color: "#666666"
+	},
+	extra: {
+	  arcbar: {
+		type: "circle",
+		width: 14,
+		backgroundColor: "#cfeffc",
+		startAngle: 1.5,
+		endAngle: 0.25,
+		gap: 2
+	  }
+	},
+	background:'rgba(0,0,0,1)',
+})
+const getServerData = () => {
+      //模拟从服务器获取数据时的延时
+      setTimeout(() => {
+        //模拟服务器返回数据,如果数据格式和标准格式不同,需自行按下面的格式拼接
+        let res = {
+            series: [
+              {
+                name: "",
+                color: "#3ceedc",
+                data: 0.8
+              }
+            ]
+          };
+        chartData.value = JSON.parse(JSON.stringify(res));
+      }, 50);
+    }
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		padding: 28rpx;
+		background: linear-gradient(to bottom, #a5eed0, #dcefaf);
+		.clean_btn{
+			width: 400rpx;
+			text-align: center;
+			background: #fff;
+			height: 80rpx;
+			line-height: 80rpx;
+			color: #42aa87;
+			border-radius: 40rpx;
+			border: 1rpx solid;
+		}
+	}
+	.CanvasBox {
+	    width: 100%;
+	    height: 100%;
+	    position: absolute;
+	    top: 0px;
+	    left: 0px;
+	    display: flex;
+	    justify-content: center;
+	    align-items: center;
+	}
 </style>

+ 33 - 2
pages/tools/wangLuoXinXi.vue

@@ -1,14 +1,45 @@
 <template>
 	<view class="content">
-		
+		<view class="box">
+			<view class="">当前连接:YThuwai</view>
+			
+		</view>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+const list = ref([
+	
+])
+onMounted(()=>{
+	// uni.getConnectedWifi({
+	// 	success:(res)=>{
+	// 		console.log('res',res)
+	// 	}
+	// })
+	// uni.getWifiList({
+	// 	success:(res)=>{
+	// 		console.log('res',res)
+	// 	},
+	// 	fail: (err) => {
+	// 		console.log('err',err)
+	// 	}
+	// })
+})
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		padding: 28rpx;
+		background: linear-gradient(to bottom, #a9d4ff, #cce6ff);
+	}
+	.box{
+		background-color: #fff;
+		border-radius: 30rpx;
+		height: 95vh;
+		padding: 30rpx 28rpx;
+	}
 </style>

+ 155 - 3
pages/tools/wifiGuanLi.vue

@@ -1,14 +1,166 @@
 <template>
-	<view class="content">
-		
+	<view class="content p-rel">
+		<view class="box">
+			<view class="mgb-10">当前连接:YThuwai</view>
+			<view class="listbox">
+				<view class="flex jc_between pdy-30 border-bottom" v-for="wifi in list">
+					<view class="flex">
+						<i class="fas fa-wifi"></i> &nbsp;
+						{{ wifi.SSID }}
+					</view>
+					<view @click="connectedWifi(wifi)" :class="wifi.status ?'c_btn':'btn'">
+						{{ wifi.status? '已连接': '连接' }}
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+	<view class="ADBox">
+		横幅广告
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+const list = ref([
+	{
+	  "SSID": "YThuwai",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:true,
+	},
+	{
+	  "SSID": "YtZhe",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:false,
+	},
+	{
+	  "SSID": "DIRECT-GQDESKTOP2E4TVT1-msPR",
+	  "BSSID": "YY:YY:YY:YY:YY:YY",
+	  status:false,
+	},
+	{
+	  "SSID": "4-426",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:false,
+	},
+	{
+	  "SSID": "Tech_xxx",
+	  "BSSID": "YY:YY:YY:YY:YY:YY",
+	  status:false,
+	},
+	{
+	  "SSID": "88888888-pZ",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:false,
+	},
+	{
+	  "SSID": "ChinaNet-bG62",
+	  "BSSID": "YY:YY:YY:YY:YY:YY",
+	  status:false,
+	},
+	{
+	  "SSID": "GF-1",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:false,
+	},
+	{
+	  "SSID": "GAIF",
+	  "BSSID": "YY:YY:YY:YY:YY:YY",
+	  status:false,
+	},
+	{
+	  "SSID": "boss",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:false,
+	},
+	{
+	  "SSID": "ChinaNet-LJmh",
+	  "BSSID": "YY:YY:YY:YY:YY:YY",
+	  status:false,
+	},
+	{
+	  "SSID": "Home_WiFi",
+	  "BSSID": "XX:XX:XX:XX:XX:XX",
+	  status:false,
+	},
+	{
+	  "SSID": "Office_WiFi",
+	  "BSSID": "YY:YY:YY:YY:YY:YY",
+	  status:false,
+	}
+])
+onMounted(()=>{
+	// uni.getConnectedWifi({
+	// 	success:(res)=>{
+	// 		console.log('res',res)
+	// 	}
+	// })
+	// uni.getWifiList({
+	// 	success:(res)=>{
+	// 		console.log('res',res.wifiList)
+	// 	},
+	// 	fail: (err) => {
+	// 		console.log('err',err)
+	// 	}
+	// })
+})
+const connectedWifi = (wifi)=>{
+	uni.showToast({
+		title:`已连接`
+	})
+	list.value.map(item=>{ return item.status = false })
+	wifi.status = true
+}
 </script>
 
 <style lang="scss" scoped>
-	
+	.content{
+		height: 100vh;
+		padding: 28rpx;
+		background: linear-gradient(to bottom, #a9d4ff, #cce6ff);
+	}
+	.box{
+		background-color: #fff;
+		border-radius: 30rpx;
+		height: 95vh;
+		padding: 30rpx 28rpx;
+		.listbox{
+			max-height: 85vh;
+			overflow-y: scroll;
+			.c_btn{
+				background-color: #399bfc;
+				color: #fff;
+				font-size: 22rpx;
+				line-height: 48rpx;
+				border-radius: 30rpx;
+				cursor: pointer;
+				width: 120rpx;
+				height: 48rpx;
+				text-align: center;
+			}
+			.btn{
+				width: 120rpx;
+				height: 48rpx;
+				line-height: 48rpx;
+				text-align: center;
+				background-color: #fff;
+				color: #399bfc;
+				border: 1rpx solid #399bfc;
+				font-size: 22rpx;
+				border-radius: 30rpx;
+				cursor: pointer;
+			}
+		}
+	}
+	.ADBox{
+		position: fixed;
+		bottom: 0;
+		height: 120rpx;
+		width: 100%;
+		background-color: #fff;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
 </style>

+ 43 - 2
pages/tools/yangShengKeTang.vue

@@ -1,14 +1,55 @@
 <template>
 	<view class="content">
-		
+		<swiper class="swiper" circular :indicator-dots="true"
+		 indicator-color="#fff" indicator-active-color="#58b3df" 
+		 :autoplay="false" :interval="2000" :duration="2000">
+			<swiper-item v-for="img in imgList">
+				<image :src="img" class="swiper-item"></image>
+			</swiper-item>
+		</swiper>
 	</view>
 </template>
 
 <script setup>
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
+const imgList = ref([
+	'http://gips3.baidu.com/it/u=764883555,2569275522&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280',
+	'http://gips3.baidu.com/it/u=764883555,2569275522&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280',
+	'http://gips3.baidu.com/it/u=764883555,2569275522&fm=3028&app=3028&f=JPEG&fmt=auto?w=960&h=1280',
+	'https://img2.baidu.com/it/u=4214113141,2036563917&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=889',
+	'https://img0.baidu.com/it/u=3803731919,348987985&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=996',
+	
+])
 </script>
 
 <style lang="scss" scoped>
-	
+	.uni-margin-wrap {
+			width: 690rpx;
+			width: 100%;
+		}
+		.swiper {
+			height: 100vh;
+		}
+		.swiper-item {
+			display: block;
+			height: 100vh;
+			width: 100%;
+		}
+		.swiper-list {
+			margin-top: 40rpx;
+			margin-bottom: 0;
+		}
+		.uni-common-mt {
+			margin-top: 60rpx;
+			position: relative;
+		}
+		.info {
+			position: absolute;
+			right: 20rpx;
+		}
+		.uni-padding-wrap {
+			width: 550rpx;
+			padding: 0 100rpx;
+		}
 </style>

+ 72 - 7
pages/tools/yiJianShengDian.vue

@@ -11,13 +11,17 @@
 				预计可用3小时0分钟
 			</view>
 			<view class="btn cursor" @click="savePower">
-				立即省电 ▶
+				立即省电 <text style="transform: scale(0.7);"></text>
 			</view>
 		</view>
 		<view class="box2">
 			<view class="title">能耗分析</view>
 			<view class="statistics">
-				
+				 <qiun-data-charts 
+				      type="column"
+				      :opts="opts"
+				      :chartData="chartData"
+				    />
 			</view>
 		</view>
 	</view>
@@ -27,6 +31,62 @@
 import { ref, onMounted } from "vue";
 import { onShow } from "@dcloudio/uni-app";
 const powerNum = ref(90)
+const chartData = ref({})
+onShow(()=>{
+	getServerData();
+	// uni.vibrateLong({
+	// 	success: function () {
+	// 		console.log('success');
+	// 	}
+	// });
+})
+const opts = ref({
+	color: ["#2ff8e8","#2fe3f4"],
+	  padding: [15,15,0,5],
+	  enableScroll: false,
+	  dataLabel:false,
+	  legend: {},
+	  xAxis: {
+	    disableGrid: true,
+	  },
+	  yAxis: {
+		disabled:true,
+	    data: [
+	      {
+	        min: 0
+	      }
+	    ]
+	  },
+	  extra: {
+	    column: {
+	      type: "group",
+	      width: 20,
+	      activeBgColor: "#000000",
+	      activeBgOpacity: 0.08,
+	      linearType: "custom",
+	      seriesGap: 30,
+	      linearOpacity: 0.5,
+	      barBorderCircle: true,
+	      customColor: []
+	    }
+	  }
+})
+const getServerData = ()=>{
+	 //模拟从服务器获取数据时的延时
+	      setTimeout(() => {
+	        //模拟服务器返回数据,如果数据格式和标准格式不同,需自行按下面的格式拼接
+	        let res = {
+	            categories: ["待机","上网","导航","影片","音乐","打电话",'游戏'],
+	            series: [
+	              {
+	                name: "目标值",
+	                data: [35,36,31,33,13,34,10]
+	              }
+	            ]
+	          };
+	        chartData.value = JSON.parse(JSON.stringify(res));
+	      }, 50);
+}
 uni.getBatteryInfo({
   success: (res) => {
 	  powerNum.value = res.level
@@ -37,11 +97,11 @@ uni.getBatteryInfo({
 })
 // 立即省电
 const savePower = ()=>{
-	
+	uni.showToast({
+		title:'开启省电',
+		icon:'none',
+	})
 }
-// onShow(()=>{
-	
-// })
 </script>
 
 <style lang="scss" scoped>
@@ -73,8 +133,13 @@ const savePower = ()=>{
 		.box2{
 			background-color: rgba(255,255,255,.6);
 			margin-top: 40rpx;
-			height: 500rpx;
+			height: 600rpx;
 			border-radius: 30rpx;
+			padding: 50rpx 30rpx 20rpx;
+			.statistics{
+				margin-top: 20rpx;
+				// height: 200rpx;
+			}
 		}
 	}
 </style>

+ 5 - 2
pages/tools/yunDongJiBu.vue

@@ -1,6 +1,6 @@
 <template>
 	<view class="content">
-		
+		<image src="../../static/image/index_banner.jpg"></image>
 	</view>
 </template>
 
@@ -10,5 +10,8 @@ import { onShow } from "@dcloudio/uni-app";
 </script>
 
 <style lang="scss" scoped>
-	
+	image{
+		height: 100vh;
+		width: 100%;
+	}
 </style>

+ 5 - 2
pages/tools/ziTiDaXiao.vue

@@ -1,6 +1,6 @@
 <template>
 	<view class="content">
-		
+		<image src="../../static/image/index_banner.jpg"></image>
 	</view>
 </template>
 
@@ -10,5 +10,8 @@ import { onShow } from "@dcloudio/uni-app";
 </script>
 
 <style lang="scss" scoped>
-	
+	image{
+		height: 100vh;
+		width: 100%;
+	}
 </style>

+ 124 - 0
pages/xiaoran-circle/xiaoran-circle.vue

@@ -0,0 +1,124 @@
+<template>
+	<view class="box">
+		<view class="view_box">
+			<iCircle
+				:percent="percent"
+				:size="200"
+				:stroke-color="color"
+				:dashboard="true"
+				BgId="BgId1"
+				InId="InId1"
+			>
+				<icon v-if="percent == 100" type="success" size="60" color="#5cb85c" />
+				<text v-else style="font-size:24px; color: #FFFFFF;">{{ percent }}%</text>
+				<view slot="canvas">
+					<canvas
+						class="CanvasBox strokeCanvas"
+						canvas-id="BgId1"
+					></canvas>
+					<canvas
+						class="CanvasBox trailCanvas"
+						canvas-id="InId1"
+					></canvas>
+				</view>
+			</iCircle>
+			<iCircle
+				:percent="percent"
+				:size="200"
+				:stroke-color="color"
+				BgId="BgId"
+				InId="InId"
+			>
+				<icon v-if="percent == 100" type="success" size="60" color="#5cb85c" />
+				<text v-else style="font-size:24px; color: #FFFFFF;">{{ percent }}%</text>
+				<view slot="canvas">
+					<canvas
+						class="CanvasBox strokeCanvas"
+						canvas-id="BgId"
+					></canvas>
+					<canvas
+						class="CanvasBox trailCanvas"
+						canvas-id="InId"
+					></canvas>
+				</view>
+			</iCircle>
+		</view>
+		<view class="button_box">
+			<button type="primary" class="button_item" @click="add">+</button>
+			<button type="primary" class="button_item" @click="minus">-</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	import iCircle from '@/components/xiaoran-circle/xiaoran-circle.vue';
+	export default {
+		components: {
+			iCircle
+		},
+		data() {
+			return {
+				percent: 50
+			}
+		},
+		computed: {
+			color() {
+				let color = '#2db7f5';
+				if (this.percent == 100) {
+					color = '#5cb85c';
+				}
+				return color;
+			}
+		},
+		methods: {
+			add() {
+				if (this.percent >= 100) {
+					return false;
+				}
+				this.percent += 10;
+			},
+			minus() {
+				if (this.percent <= 0) {
+					return false;
+				}
+				this.percent -= 10;
+			}
+		}
+	}
+</script>
+
+<style>
+	.box {
+		/* margin-top: var(--status-bar-height); */
+		flex: 1;
+	}
+	.view_box {
+		width: 100%;
+		background: #000000;
+		display: flex;
+		align-items: center;
		justify-content: center;
+	}
+	.button_box {
+		display: flex;
+		flex-direction: column;
+		align-items: stretch;
+		justify-content: flex-start;
+		padding: 0 30upx;
+	}
+	.button_item {
+		width: 100%;
+		margin-top: 30upx;
+	}
+	
+	.CanvasBox {
+		width: 100%;
+		height: 100%;
+		position: absolute;
+		top: 0px;
+		left: 0px;
+		
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+</style>

+ 320 - 0
uni_modules/qiun-data-charts/changelog.md

@@ -0,0 +1,320 @@
+## 2.5.0-20230101(2023-01-01)
+- 秋云图表组件 修改条件编译顺序,确保uniapp的cli方式的项目依赖不完整时可以正常显示
+- 秋云图表组件 恢复props属性directory的使用,以修复vue3项目中,开启echarts后,echarts目录识别错误的bug
+- uCharts.js 修复区域图、混合图只有一个数据时图表显示不正确的bug
+- uCharts.js 修复折线图、区域图中时间轴类别图表tooltip指示点显示不正确的bug
+- uCharts.js 修复x轴使用labelCount时,并且boundaryGap = 'justify' 并且关闭Y轴显示的时候,最后一个坐标值不显示的bug
+- uCharts.js 修复折线图只有一组数据时 ios16 渲染颜色不正确的bug
+- uCharts.js 修复玫瑰图半径显示不正确的bug
+- uCharts.js 柱状图、山峰图增加正负图功能,y轴网格如果需要显示0轴则由 min max 及 splitNumber 确定,后续版本优化自动显示0轴
+- uCharts.js 柱状图column增加 opts.extra.column.labelPosition,数据标签位置,有效值为 outside外部, insideTop内顶部, center内中间, bottom内底部
+- uCharts.js 雷达图radar增加 opts.extra.radar.labelShow,否显示各项标识文案是,默认true
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.boxPadding,提示窗边框填充距离,默认3px
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.fontSize,提示窗字体大小配置,默认13px
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.lineHeight,提示窗文字行高,默认20px
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShow,是否显示左侧图例,默认true
+- uCharts.js 提示窗tooltip增加 opts.extra.tooltip.legendShape,图例形状,图例标识样式,有效值为 auto自动跟随图例, diamond◆, circle●, triangle▲, square■, rect▬, line-
+- uCharts.js 标记线markLine增加 opts.extra.markLine.labelFontSize,字体大小配置,默认13px
+- uCharts.js 标记线markLine增加 opts.extra.markLine.labelPadding,标签边框内填充距离,默认6px
+- uCharts.js 折线图line增加 opts.extra.line.linearType,渐变色类型,可选值 none关闭渐变色,custom 自定义渐变色。使用自定义渐变色时请赋值serie.linearColor作为颜色值
+- uCharts.js 折线图line增加 serie.linearColor,渐变色数组,格式为2维数组[起始位置,颜色值],例如[[0,'#0EE2F8'],[0.3,'#2BDCA8'],[0.6,'#1890FF'],[1,'#9A60B4']]
+- uCharts.js 折线图line增加 opts.extra.line.onShadow,是否开启折线阴影,开启后请赋值serie.setShadow阴影设置
+- uCharts.js 折线图line增加 serie.setShadow,阴影配置,格式为4位数组:[offsetX,offsetY,blur,color]
+- uCharts.js 折线图line增加 opts.extra.line.animation,动画效果方向,可选值为vertical 垂直动画效果,horizontal 水平动画效果
+- uCharts.js X轴xAxis增加 opts.xAxis.lineHeight,X轴字体行高,默认20px
+- uCharts.js X轴xAxis增加 opts.xAxis.marginTop,X轴文字距离轴线的距离,默认0px
+- uCharts.js X轴xAxis增加 opts.xAxis.title,当前X轴标题
+- uCharts.js X轴xAxis增加 opts.xAxis.titleFontSize,标题字体大小,默认13px
+- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetY,标题纵向偏移距离,负数为向上偏移,正数向下偏移
+- uCharts.js X轴xAxis增加 opts.xAxis.titleOffsetX,标题横向偏移距离,负数为向左偏移,正数向右偏移
+- uCharts.js X轴xAxis增加 opts.xAxis.titleFontColor,标题字体颜色,默认#666666
+
+## 报错TypeError: Cannot read properties of undefined (reading 'length')
+- 如果是uni-modules版本组件,请先登录HBuilderX账号;
+- 在HBuilderX中的manifest.json,点击重新获取uniapp的appid,或者删除appid重新粘贴,重新运行;
+- 如果是cli项目请使用码云上的非uniCloud版本组件;
+- 或者添加uniCloud的依赖;
+- 或者使用原生uCharts;
+## 2.4.5-20221130(2022-11-30)
+- uCharts.js 优化tooltip当文字很多变为左侧显示时,如果画布仍显显示不下,提示框错位置变为以左侧0位置起画
+- uCharts.js 折线图修复特殊情况下只有单点数据,并改变线宽后点变为圆形的bug
+- uCharts.js 修复Y轴disabled启用后无效并报错的bug
+- uCharts.js 修复仪表盘起始结束角度特殊情况下显示不正确的bug
+- uCharts.js 雷达图新增参数 opts.extra.radar.radius , 自定义雷达图半径
+- uCharts.js 折线图、区域图增加tooltip指示点,opts.extra.line.activeType/opts.extra.area.activeType,可选值"none"不启用激活指示点,"hollow"空心点模式,"solid"实心点模式
+## 2.4.4-20221102(2022-11-02)
+- 秋云图表组件 修复使用echarts时reload、reshow无法调用重新渲染的bug,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/40)
+- 秋云图表组件 修复使用echarts时,初始化时宽高不正确的bug,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/42)
+- 秋云图表组件 修复uniapp的h5使用history模式时,无法加载echarts的bug
+- 秋云图表组件 小程序端@complete、@scrollLeft、@scrollRight、@getTouchStart、@getTouchMove、@getTouchEnd事件增加opts参数传出,方便一些特殊需求的交互获取数据。
+
+- uCharts.js 修复calTooltipYAxisData方法内formatter格式化方法未与y轴方法同步的问题,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/43)
+- uCharts.js 地图新增参数opts.series[i].fillOpacity,以透明度方式来设置颜色过度效果,[详见码云PR](https://gitee.com/uCharts/uCharts/pulls/38)
+- uCharts.js 地图新增参数opts.extra.map.active,是否启用点击激活变色
+- uCharts.js 地图新增参数opts.extra.map.activeTextColor,是否启用点击激活变色
+- uCharts.js 地图新增渲染完成事件renderComplete
+- uCharts.js 漏斗图修复当部分数据相同时tooltip提示窗点击错误的bug
+- uCharts.js 漏斗图新增参数series.data[i].centerText 居中标签文案
+- uCharts.js 漏斗图新增参数series.data[i].centerTextSize 居中标签文案字体大小,默认opts.fontSize
+- uCharts.js 漏斗图新增参数series.data[i].centerTextColor 居中标签文案字体颜色,默认#FFFFFF
+- uCharts.js 漏斗图新增参数opts.extra.funnel.minSize 最小值的最小宽度,默认0
+- uCharts.js 进度条新增参数opts.extra.arcbar.direction,动画方向,可选值为cw顺时针、ccw逆时针
+- uCharts.js 混合图新增参数opts.extra.mix.line.width,折线的宽度,默认2
+- uCharts.js 修复tooltip开启horizentalLine水平横线标注时,图表显示错位的bug
+- uCharts.js 优化tooltip当文字很多变为左侧显示时,如果画布仍显显示不下,提示框错位置变为以左侧0位置起画
+- uCharts.js 修复开启滚动条后X轴文字超出绘图区域后的隐藏逻辑
+- uCharts.js 柱状图、条状图修复堆叠模式不能通过{value,color}赋值单个柱子颜色的问题
+- uCharts.js 气泡图修复不识别series.textSize和series.textColor的bug
+
+## 报错TypeError: Cannot read properties of undefined (reading 'length')
+1. 如果是uni-modules版本组件,请先登录HBuilderX账号;
+2. 在HBuilderX中的manifest.json,点击重新获取uniapp的appid,或者删除appid重新粘贴,重新运行;
+3. 如果是cli项目请使用码云上的非uniCloud版本组件;
+4. 或者添加uniCloud的依赖;
+5. 或者使用原生uCharts;
+## 2.4.3-20220505(2022-05-05)
+- 秋云图表组件 修复开启canvas2d后将series赋值为空数组显示加载图标时,再次赋值后画布闪动的bug
+- 秋云图表组件 修复升级hbx最新版后ECharts的highlight方法报错的bug
+- uCharts.js 雷达图新增参数opts.extra.radar.gridEval,数据点位网格抽希,默认1
+- uCharts.js 雷达图新增参数opts.extra.radar.axisLabel,	是否显示刻度点值,默认false
+- uCharts.js 雷达图新增参数opts.extra.radar.axisLabelTofix,刻度点值小数位数,默认0
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointShow,是否显示末端刻度圆点,默认false
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointRadius,刻度圆点的半径,默认3
+- uCharts.js 雷达图新增参数opts.extra.radar.labelPointColor,刻度圆点的颜色,默认#cccccc
+- uCharts.js 雷达图新增参数opts.extra.radar.linearType,渐变色类型,可选值"none"关闭渐变,"custom"开启渐变
+- uCharts.js 雷达图新增参数opts.extra.radar.customColor,自定义渐变颜色,数组类型对应series的数组长度以匹配不同series颜色的不同配色方案,例如["#FA7D8D", "#EB88E2"]
+- uCharts.js 雷达图优化支持series.textColor、series.textSize属性
+- uCharts.js 柱状图中温度计式图标,优化支持全圆角类型,修复边框有缝隙的bug,详见官网【演示】中的温度计图表
+- uCharts.js 柱状图新增参数opts.extra.column.activeWidth,当前点击柱状图的背景宽度,默认一个单元格单位
+- uCharts.js 混合图增加opts.extra.mix.area.gradient 区域图是否开启渐变色
+- uCharts.js 混合图增加opts.extra.mix.area.opacity 区域图透明度,默认0.2
+- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelText,自定义标签文字,避免formatter格式化的繁琐,详见官网【演示】中的饼图
+- uCharts.js 饼图、圆环图、玫瑰图、漏斗图,增加opts.series[0].data[i].labelShow,自定义是否显示某一个指示标签,避免因饼图类别太多导致标签重复或者居多导致图形变形的问题,详见官网【演示】中的饼图
+- uCharts.js 增加opts.series[i].legendText/opts.series[0].data[i].legendText(与series.name同级)自定义图例显示文字的方法
+- uCharts.js 优化X轴、Y轴formatter格式化方法增加形参,统一为fromatter:function(value,index,opts){}
+- uCharts.js 修复横屏模式下无法使用双指缩放方法的bug
+- uCharts.js 修复当只有一条数据或者多条数据值相等的时候Y轴自动计算的最大值错误的bug
+- 【官网模板】增加外部自定义图例与图表交互的例子,[点击跳转](https://www.ucharts.cn/v2/#/layout/info?id=2)
+
+## 注意:非unimodules 版本如因更新 hbx 至 3.4.7 导致报错如下,请到码云更新非 unimodules 版本组件,[点击跳转](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6)
+> Error in callback for immediate watcher "uchartsOpts": "SyntaxError: Unexpected token u in JSON at position 0"
+## 2.4.2-20220421(2022-04-21)
+- 秋云图表组件 修复HBX升级3.4.6.20220420版本后echarts报错的问题
+## 2.4.2-20220420(2022-04-20)
+## 重要!此版本uCharts新增了很多功能,修复了诸多已知问题
+- 秋云图表组件 新增onzoom开启双指缩放功能(仅uCharts),前提需要直角坐标系类图表类型,并且ontouch为true、opts.enableScroll为true,详见实例项目K线图
+- 秋云图表组件 新增optsWatch是否监听opts变化,关闭optsWatch后,动态修改opts不会触发图表重绘
+- 秋云图表组件 修复开启canvas2d功能后,动态更新数据后画布闪动的bug
+- 秋云图表组件 去除directory属性,改为自动获取echarts.min.js路径(升级不受影响)
+- 秋云图表组件 增加getImage()方法及@getImage事件,通过ref调用getImage()方法获,触发@getImage事件获取当前画布的base64图片文件流。
+- 秋云图表组件 支付宝、字节跳动、飞书、快手小程序支持开启canvas2d同层渲染设置。
+- 秋云图表组件 新增加【非uniCloud】版本组件,避免有些不需要uniCloud的使用组件发布至小程序需要提交隐私声明问题,请到码云[【非uniCloud版本】](https://gitee.com/uCharts/uCharts/tree/master/uni-app/uCharts-%E7%BB%84%E4%BB%B6),或npm[【非uniCloud版本】](https://www.npmjs.com/package/@qiun/uni-ucharts)下载使用。
+- uCharts.js 新增dobuleZoom双指缩放功能
+- uCharts.js 新增山峰图type="mount",数据格式为饼图类格式,不需要传入categories,具体详见新版官网在线演示
+- uCharts.js 修复折线图当数据中存在null时tooltip报错的bug
+- uCharts.js 修复饼图类当画布比较小时自动计算的半径是负数报错的bug
+- uCharts.js 统一各图表类型的series.formatter格式化方法的形参为(val, index, series, opts),方便格式化时有更多参数可用
+- uCharts.js 标记线功能增加labelText自定义显示文字,增加labelAlign标签显示位置(左侧或右侧),增加标签显示位置微调labelOffsetX、labelOffsetY
+- uCharts.js 修复条状图当数值很小时开启圆角后样式错误的bug
+- uCharts.js 修复X轴开启disabled后,X轴仍占用空间的bug
+- uCharts.js 修复X轴开启滚动条并且开启rotateLabel后,X轴文字与滚动条重叠的bug
+- uCharts.js 增加X轴rotateAngle文字旋转自定义角度,取值范围(-90至90)
+- uCharts.js 修复地图文字标签层级显示不正确的bug
+- uCharts.js 修复饼图、圆环图、玫瑰图当数据全部为0的时候不显示数据标签的bug
+- uCharts.js 修复当opts.padding上边距为0时,Y轴顶部刻度标签位置不正确的bug
+
+## 另外我们还开发了各大原生小程序组件,已发布至码云和npm
+[https://gitee.com/uCharts/uCharts](https://gitee.com/uCharts/uCharts)
+[https://www.npmjs.com/~qiun](https://www.npmjs.com/~qiun)
+
+## 对于原生uCharts文档我们已上线新版官方网站,详情点击下面链接进入官网
+[https://www.uCharts.cn/v2/](https://www.ucharts.cn/v2/)
+## 2.3.7-20220122(2022-01-22)
+## 重要!使用vue3编译,请使用cli模式并升级至最新依赖,HbuilderX编译需要使用3.3.8以上版本
+- uCharts.js 修复uni-app平台组件模式使用vue3编译到小程序报错的bug。
+## 2.3.7-20220118(2022-01-18)
+## 注意,使用vue3的前提是需要3.3.8.20220114-alpha版本的HBuilder!
+## 2.3.67-20220118(2022-01-18)
+- 秋云图表组件 组件初步支持vue3,全端编译会有些问题,具体详见下面修改:
+1. 小程序端运行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new uni_modules_qiunDataCharts_js_sdk_uCharts_uCharts.uCharts,将.uCharts去掉。
+2. 小程序端发行时,在uni_modules文件夹的qiun-data-charts.js中搜索 new e.uCharts,将.uCharts去掉,变为 new e。
+3. 如果觉得上述步骤比较麻烦,如果您的项目只编译到小程序端,可以修改u-charts.js最后一行导出方式,将 export default uCharts;变更为 export default { uCharts: uCharts }; 这样变更后,H5和App端的renderjs会有问题,请开发者自行选择。(此问题非组件问题,请等待DC官方修复Vue3的小程序端)
+## 2.3.6-20220111(2022-01-11)
+- 秋云图表组件 修改组件 props 属性中的 background 默认值为 rgba(0,0,0,0)
+## 2.3.6-20211201(2021-12-01)
+- uCharts.js 修复bar条状图开启圆角模式时,值很小时圆角渲染错误的bug
+## 2.3.5-20211014(2021-10-15)
+- uCharts.js 增加vue3的编译支持(仅原生uCharts,qiun-data-charts组件后续会支持,请关注更新)
+## 2.3.4-20211012(2021-10-12)
+- 秋云图表组件 修复 mac os x 系统 mouseover 事件丢失的 bug
+## 2.3.3-20210706(2021-07-06)
+- uCharts.js 增加雷达图开启数据点值(opts.dataLabel)的显示
+## 2.3.2-20210627(2021-06-27)
+- 秋云图表组件 修复tooltipCustom个别情况下传值不正确报错TypeError: Cannot read property 'name' of undefined的bug
+## 2.3.1-20210616(2021-06-16)
+- uCharts.js 修复圆角柱状图使用4角圆角时,当数值过大时不正确的bug
+## 2.3.0-20210612(2021-06-12)
+- uCharts.js 【重要】uCharts增加nvue兼容,可在nvue项目中使用gcanvas组件渲染uCharts,[详见码云uCharts-demo-nvue](https://gitee.com/uCharts/uCharts)
+- 秋云图表组件 增加tapLegend属性,是否开启图例点击交互事件
+- 秋云图表组件 getIndex事件中增加返回uCharts实例中的opts参数,以便在页面中调用参数
+- 示例项目 pages/other/other.vue增加app端自定义tooltip的方法,详见showOptsTooltip方法
+## 2.2.1-20210603(2021-06-03)
+- uCharts.js 修复饼图、圆环图、玫瑰图,当起始角度不为0时,tooltip位置不准确的bug
+- uCharts.js 增加温度计式柱状图开启顶部半圆形的配置
+## 2.2.0-20210529(2021-05-29)
+- uCharts.js 增加条状图type="bar"
+- 示例项目 pages/ucharts/ucharts.vue增加条状图的demo
+## 2.1.7-20210524(2021-05-24)
+- uCharts.js 修复大数据量模式下曲线图不平滑的bug
+## 2.1.6-20210523(2021-05-23)
+- 秋云图表组件 修复小程序端开启滚动条更新数据后滚动条位置不符合预期的bug
+## 2.1.5-2021051702(2021-05-17)
+- uCharts.js 修复自定义Y轴min和max值为0时不能正确显示的bug
+## 2.1.5-20210517(2021-05-17)
+- uCharts.js 修复Y轴自定义min和max时,未按指定的最大值最小值显示坐标轴刻度的bug
+## 2.1.4-20210516(2021-05-16)
+- 秋云图表组件 优化onWindowResize防抖方法
+- 秋云图表组件 修复APP端uCharts更新数据时,清空series显示loading图标后再显示图表,图表抖动的bug
+- uCharts.js 修复开启canvas2d后,x轴、y轴、series自定义字体大小未按比例缩放的bug
+- 示例项目 修复format-e.vue拼写错误导致app端使用uCharts渲染图表
+## 2.1.3-20210513(2021-05-13)
+- 秋云图表组件 修改uCharts变更chartData数据为updateData方法,支持带滚动条的数据动态打点
+- 秋云图表组件 增加onWindowResize防抖方法 fix by ど誓言,如尘般染指流年づ 
+- 秋云图表组件 H5或者APP变更chartData数据显示loading图表时,原数据闪现的bug
+- 秋云图表组件 props增加errorReload禁用错误点击重新加载的方法
+- uCharts.js 增加tooltip显示category(x轴对应点位)标题的功能,opts.extra.tooltip.showCategory,默认为false
+- uCharts.js 修复mix混合图只有柱状图时,tooltip的分割线显示位置不正确的bug
+- uCharts.js 修复开启滚动条,图表在拖动中动态打点,滚动条位置不正确的bug
+- uCharts.js 修复饼图类数据格式为echarts数据格式,series为空数组报错的bug
+- 示例项目 修改uCharts.js更新到v2.1.2版本后,@getIndex方法获取索引值变更为e.currentIndex.index
+- 示例项目 pages/updata/updata.vue增加滚动条拖动更新(数据动态打点)的demo
+- 示例项目 pages/other/other.vue增加errorReload禁用错误点击重新加载的demo
+## 2.1.2-20210509(2021-05-09)
+秋云图表组件 修复APP端初始化时就传入chartData或lacaldata不显示图表的bug
+## 2.1.1-20210509(2021-05-09)
+- 秋云图表组件 变更ECharts的eopts配置在renderjs内执行,支持在config-echarts.js配置文件内写function配置。
+- 秋云图表组件 修复APP端报错Prop being mutated: "onmouse"错误的bug。
+- 秋云图表组件 修复APP端报错Error: Not Found:Page[6][-1,27] at view.umd.min.js:1的bug。
+## 2.1.0-20210507(2021-05-07)
+- 秋云图表组件 修复初始化时就有数据或者数据更新的时候loading加载动画闪动的bug
+- uCharts.js 修复x轴format方法categories为字符串类型时返回NaN的bug
+- uCharts.js 修复series.textColor、legend.fontColor未执行全局默认颜色的bug
+## 2.1.0-20210506(2021-05-06)
+- 秋云图表组件 修复极个别情况下报错item.properties undefined的bug
+- 秋云图表组件 修复极个别情况下关闭加载动画reshow不起作用,无法显示图表的bug
+- 示例项目 pages/ucharts/ucharts.vue 增加时间轴折线图(type="tline")、时间轴区域图(type="tarea")、散点图(type="scatter")、气泡图demo(type="bubble")、倒三角形漏斗图(opts.extra.funnel.type="triangle")、金字塔形漏斗图(opts.extra.funnel.type="pyramid")
+- 示例项目 pages/format-u/format-u.vue 增加X轴format格式化示例
+- uCharts.js 升级至v2.1.0版本
+- uCharts.js 修复 玫瑰图面积模式点击tooltip位置不正确的bug
+- uCharts.js 修复 玫瑰图点击图例,只剩一个类别显示空白的bug
+- uCharts.js 修复 饼图类图点击图例,其他图表tooltip位置某些情况下不准的bug
+- uCharts.js 修复 x轴为矢量轴(时间轴)情况下,点击tooltip位置不正确的bug
+- uCharts.js 修复 词云图获取点击索引偶尔不准的bug
+- uCharts.js 增加 直角坐标系图表X轴format格式化方法(原生uCharts.js用法请使用formatter)
+- uCharts.js 增加 漏斗图扩展配置,倒三角形(opts.extra.funnel.type="triangle"),金字塔形(opts.extra.funnel.type="pyramid")
+- uCharts.js 增加 散点图(opts.type="scatter")、气泡图(opts.type="bubble")
+- 后期计划 完善散点图、气泡图,增加markPoints标记点,增加横向条状图。
+## 2.0.0-20210502(2021-05-02)
+- uCharts.js 修复词云图获取点击索引不正确的bug
+## 2.0.0-20210501(2021-05-01)
+- 秋云图表组件 修复QQ小程序、百度小程序在关闭动画效果情况下,v-for循环使用图表,显示不正确的bug
+## 2.0.0-20210426(2021-04-26)
+- 秋云图表组件 修复QQ小程序不支持canvas2d的bug
+- 秋云图表组件 修复钉钉小程序某些情况点击坐标计算错误的bug
+- uCharts.js 增加 extra.column.categoryGap 参数,柱状图类每个category点位(X轴点)柱子组之间的间距
+- uCharts.js 增加 yAxis.data[i].titleOffsetY 参数,标题纵向偏移距离,负数为向上偏移,正数向下偏移
+- uCharts.js 增加 yAxis.data[i].titleOffsetX 参数,标题横向偏移距离,负数为向左偏移,正数向右偏移
+- uCharts.js 增加 extra.gauge.labelOffset 参数,仪表盘标签文字径向便宜距离,默认13px
+## 2.0.0-20210422-2(2021-04-22)
+秋云图表组件 修复 formatterAssign 未判断 args[key] == null 的情况导致栈溢出的 bug
+## 2.0.0-20210422(2021-04-22)
+- 秋云图表组件 修复H5、APP、支付宝小程序、微信小程序canvas2d模式下横屏模式的bug
+## 2.0.0-20210421(2021-04-21)
+- uCharts.js 修复多行图例的情况下,图例在上方或者下方时,图例float为左侧或者右侧时,第二行及以后的图例对齐方式不正确的bug
+## 2.0.0-20210420(2021-04-20)
+- 秋云图表组件 修复微信小程序开启canvas2d模式后,windows版微信小程序不支持canvas2d模式的bug
+- 秋云图表组件 修改非uni_modules版本为v2.0版本qiun-data-charts组件
+## 2.0.0-20210419(2021-04-19)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
+## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
+## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
+## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font> 
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- uCharts.js 修复混合图中柱状图单独设置颜色不生效的bug
+- uCharts.js 修复多Y轴单独设置fontSize时,开启canvas2d后,未对应放大字体的bug
+## 2.0.0-20210418(2021-04-18)
+- 秋云图表组件 增加directory配置,修复H5端history模式下如果发布到二级目录无法正确加载echarts.min.js的bug
+## 2.0.0-20210416(2021-04-16)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
+## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
+## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
+## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font> 
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- 秋云图表组件 修复APP端某些情况下报错`Not Found Page`的bug,fix by 高级bug开发技术员
+- 示例项目 修复APP端v-for循环某些情况下报错`Not Found Page`的bug,fix by 高级bug开发技术员
+- uCharts.js 修复非直角坐标系tooltip提示窗右侧超出未变换方向显示的bug
+## 2.0.0-20210415(2021-04-15)
+- 秋云图表组件 修复H5端发布到二级目录下echarts无法加载的bug
+- 秋云图表组件 修复某些情况下echarts.off('finished')移除监听事件报错的bug
+## 2.0.0-20210414(2021-04-14)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX,如仍不好用,请重启电脑;
+## 如果是cli项目,请尝试清理node_modules,重新install,还不行就删除项目,再重新install。
+## 此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## 其他图表不显示问题详见[常见问题选项卡](https://demo.ucharts.cn)
+## <font color=#FF0000> 新手请先完整阅读帮助文档及常见问题3遍,右侧蓝色按钮示例项目请看2遍! </font> 
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在项目中的应用参见 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- 秋云图表组件 修复H5端在cli项目下ECharts引用地址错误的bug
+- 示例项目 增加ECharts的formatter用法的示例(详见示例项目format-e.vue)
+- uCharts.js 增加圆环图中心背景色的配置extra.ring.centerColor
+- uCharts.js 修复微信小程序安卓端柱状图开启透明色后显示不正确的bug
+## 2.0.0-20210413(2021-04-13)
+- 秋云图表组件 修复百度小程序多个图表真机未能正确获取根元素dom尺寸的bug
+- 秋云图表组件 修复百度小程序横屏模式方向不正确的bug
+- 秋云图表组件 修改ontouch时,@getTouchStart@getTouchMove@getTouchEnd的触发条件
+- uCharts.js 修复饼图类数据格式series属性不生效的bug
+- uCharts.js 增加时序区域图 详见示例项目中ucharts.vue
+## 2.0.0-20210412-2(2021-04-12)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册&lt;qiun-data-charts&gt;组件,请重启HBuilderX。如仍不好用,请重启电脑,此问题已于DCloud官方确认,HBuilderX下个版本会修复。
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- 秋云图表组件 修复uCharts在APP端横屏模式下不能正确渲染的bug
+- 示例项目 增加ECharts柱状图渐变色、圆角柱状图、横向柱状图(条状图)的示例
+## 2.0.0-20210412(2021-04-12)
+- 秋云图表组件 修复created中判断echarts导致APP端无法识别,改回mounted中判断echarts初始化
+- uCharts.js 修复2d模式下series.textOffset未乘像素比的bug
+## 2.0.0-20210411(2021-04-11)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧绿色【使用HBuilderX导入插件】即可使用,示例项目请点击右侧蓝色按钮【使用HBuilderX导入示例项目】。
+## 初次使用如果提示未注册<qiun-data-charts>组件,请重启HBuilderX,并清空小程序开发者工具缓存。
+## [DEMO演示及在线生成工具(v2.0文档)https://demo.ucharts.cn](https://demo.ucharts.cn)
+## [图表组件在uniCloudAdmin中的应用 UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- uCharts.js 折线图区域图增加connectNulls断点续连的功能,详见示例项目中ucharts.vue
+- 秋云图表组件 变更初始化方法为created,变更type2d默认值为true,优化2d模式下组件初始化后dom获取不到的bug
+- 秋云图表组件 修复左右布局时,右侧图表点击坐标错误的bug,修复tooltip柱状图自定义颜色显示object的bug
+## 2.0.0-20210410(2021-04-10)
+- 修复左右布局时,右侧图表点击坐标错误的bug,修复柱状图自定义颜色tooltip显示object的bug
+- 增加标记线及柱状图自定义颜色的demo
+## 2.0.0-20210409(2021-04-08)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧【使用HBuilderX导入插件】即可体验,DEMO演示及在线生成工具(v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
+## 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+- uCharts.js 修复钉钉小程序百度小程序measureText不准确的bug,修复2d模式下饼图类activeRadius为按比例放大的bug
+- 修复组件在支付宝小程序端点击位置不准确的bug
+## 2.0.0-20210408(2021-04-07)
+- 修复组件在支付宝小程序端不能显示的bug(目前支付宝小程不能点击交互,后续修复)
+- uCharts.js 修复高分屏下柱状图类,圆弧进度条 自定义宽度不能按比例放大的bug
+## 2.0.0-20210407(2021-04-06)
+## v1.0版本已停更,建议转uni_modules版本组件方式调用,点击右侧【使用HBuilderX导入插件】即可体验,DEMO演示及在线生成工具(v2.0文档)[https://demo.ucharts.cn](https://demo.ucharts.cn)
+## 增加 通过tofix和unit快速格式化y轴的demo add by `howcode`
+## 增加 图表组件在uniCloudAdmin中的应用 [UReport数据报表](https://ext.dcloud.net.cn/plugin?id=4651) 
+## 2.0.0-20210406(2021-04-05)
+# 秋云图表组件+uCharts v2.0版本同步上线,使用方法详见https://demo.ucharts.cn帮助页
+## 2.0.0(2021-04-05)
+# 秋云图表组件+uCharts v2.0版本同步上线,使用方法详见https://demo.ucharts.cn帮助页

+ 1618 - 0
uni_modules/qiun-data-charts/components/qiun-data-charts/qiun-data-charts.vue

@@ -0,0 +1,1618 @@
+<!-- 
+ * qiun-data-charts 秋云高性能跨全端图表组件
+ * Copyright (c) 2021 QIUN® 秋云 https://www.ucharts.cn All rights reserved.
+ * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+ * 复制使用请保留本段注释,感谢支持开源!
+ * 为方便更多开发者使用,如有更好的建议请提交码云 Pull Requests !
+ *
+ * uCharts®官方网站
+ * https://www.uCharts.cn
+ * 
+ * 开源地址:
+ * https://gitee.com/uCharts/uCharts
+ * 
+ * uni-app插件市场地址:
+ * http://ext.dcloud.net.cn/plugin?id=271
+ * 
+ -->
+<template>
+  <view class="chartsview" :id="'ChartBoxId'+cid">
+    <view v-if="mixinDatacomLoading">
+      <!-- 自定义加载状态,请改这里 -->
+      <qiun-loading :loadingType="loadingType" />
+    </view>
+    <view v-if="mixinDatacomErrorMessage && errorShow" @tap="reloading">
+      <!-- 自定义错误提示,请改这里 -->
+      <qiun-error :errorMessage="errorMessage" />
+    </view>
+    <!-- APP和H5采用renderjs渲染图表 -->
+    <!-- #ifdef APP-VUE || H5 -->
+    <block v-if="echarts">
+      <view
+        :style="{ background: background }"
+        style="width: 100%;height: 100%;"
+        :data-directory="directory"
+        :id="'EC'+cid" 
+        :prop="echartsOpts" 
+        :change:prop="rdcharts.ecinit" 
+        :resize="echartsResize"
+        :change:resize="rdcharts.ecresize"
+        v-show="showchart"
+      />
+    </block>
+    <block v-else>
+      <view
+        v-on:tap="rdcharts.tap"
+        v-on:mousemove="rdcharts.mouseMove"
+        v-on:mousedown="rdcharts.mouseDown"
+        v-on:mouseup="rdcharts.mouseUp"
+        v-on:touchstart="rdcharts.touchStart"
+        v-on:touchmove="rdcharts.touchMove"
+        v-on:touchend="rdcharts.touchEnd"
+        :id="'UC'+cid"
+        :prop="uchartsOpts"
+        :change:prop="rdcharts.ucinit"
+      >
+        <canvas
+          :id="cid"
+          :canvasId="cid"
+          :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+          :disable-scroll="disableScroll"
+          @error="_error"
+          v-show="showchart"
+        />
+      </view>
+    </block>
+    <!-- #endif -->
+    <!-- 支付宝小程序 -->
+    <!-- #ifdef MP-ALIPAY -->
+    <block v-if="ontouch">
+      <canvas
+        :id="cid"
+        :canvasId="cid"
+        :width="cWidth * pixel"
+        :height="cHeight * pixel"
+        :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+        :disable-scroll="disScroll"
+        @tap="_tap"
+        @touchstart="_touchStart"
+        @touchmove="_touchMove"
+        @touchend="_touchEnd"
+        @error="_error"
+        v-show="showchart"
+      />
+    </block>
+    <block v-if="!ontouch">
+      <canvas
+        :id="cid"
+        :canvasId="cid"
+        :width="cWidth * pixel"
+        :height="cHeight * pixel"
+        :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+        :disable-scroll="disScroll"
+        @tap="_tap"
+        @error="_error"
+        v-show="showchart"
+      />
+    </block>
+    <!-- #endif -->
+    <!-- 其他小程序通过vue渲染图表 -->
+    <!-- #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO || MP-KUAISHOU || MP-LARK || MP-JD || MP-360 -->
+    <block v-if="type2d">
+      <view v-if="ontouch" @tap="_tap">
+        <canvas
+          :id="cid"
+          :canvasId="cid"
+          :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+          type="2d"
+          :disable-scroll="disScroll"
+          @touchstart="_touchStart"
+          @touchmove="_touchMove"
+          @touchend="_touchEnd"
+          @error="_error"
+          v-show="showchart"
+        />
+      </view>
+      <view v-if="!ontouch" @tap="_tap">
+        <canvas
+          :id="cid"
+          :canvasId="cid"
+          :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+          type="2d"
+          :disable-scroll="disScroll"
+          @error="_error"
+          v-show="showchart"
+        />
+      </view>
+    </block>
+    <block v-if="!type2d">
+      <view v-if="ontouch" @tap="_tap">
+        <canvas
+          :id="cid"
+          :canvasId="cid"
+          :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+          @touchstart="_touchStart"
+          @touchmove="_touchMove"
+          @touchend="_touchEnd"
+          :disable-scroll="disScroll"
+          @error="_error"
+          v-if="showchart"
+        />
+      </view>
+      <view v-if="!ontouch" >
+        <canvas
+          :id="cid"
+          :canvasId="cid"
+          :style="{ width: cWidth + 'px', height: cHeight + 'px', background: background }"
+          :disable-scroll="disScroll"
+          @tap="_tap"
+          @error="_error"
+          v-if="showchart"
+        />
+      </view>
+    </block>
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+import uCharts from '../../js_sdk/u-charts/u-charts.js';
+import cfu from '../../js_sdk/u-charts/config-ucharts.js';
+// #ifdef APP-VUE || H5
+import cfe from '../../js_sdk/u-charts/config-echarts.js';
+// #endif
+
+function deepCloneAssign(origin = {}, ...args) {
+  for (let i in args) {
+    for (let key in args[i]) {
+      if (args[i].hasOwnProperty(key)) {
+        origin[key] = args[i][key] && typeof args[i][key] === 'object' ? deepCloneAssign(Array.isArray(args[i][key]) ? [] : {}, origin[key], args[i][key]) : args[i][key];
+      }
+    }
+  }
+  return origin;
+}
+
+function formatterAssign(args,formatter) {
+  for (let key in args) {
+    if(args.hasOwnProperty(key) && args[key] !== null && typeof args[key] === 'object'){
+      formatterAssign(args[key],formatter)
+    }else if(key === 'format' && typeof args[key] === 'string'){
+      args['formatter'] = formatter[args[key]] ? formatter[args[key]] : undefined;
+    }
+  }
+  return args;
+}
+
+// 时间转换函数,为了匹配uniClinetDB读取出的时间与categories不同
+function getFormatDate(date) {
+	var seperator = "-";
+	var year = date.getFullYear();
+	var month = date.getMonth() + 1;
+	var strDate = date.getDate();
+	if (month >= 1 && month <= 9) {
+			month = "0" + month;
+	}
+	if (strDate >= 0 && strDate <= 9) {
+			strDate = "0" + strDate;
+	}
+	var currentdate = year + seperator + month + seperator + strDate;
+	return currentdate;
+}
+
+var lastMoveTime = null;
+/**
+ * 防抖
+ *
+ * @param { Function } fn 要执行的方法
+ * @param { Number } wait  防抖多少毫秒
+ *
+ * 在 vue 中使用(注意:不能使用箭头函数,否则this指向不对,并且不能再次封装如:
+ * move(){  // 错误调用方式
+ *   debounce(function () {
+ *   console.log(this.title);
+ * }, 1000)});
+ * 应该直接使用:// 正确调用方式
+ * move: debounce(function () {
+ *   console.log(this.title);
+ * }, 1000)
+ */
+function debounce(fn, wait) {
+  let timer = false;
+  return function() {
+    clearTimeout(timer);
+    timer && clearTimeout(timer);
+    timer = setTimeout(() => {
+      timer = false;
+      fn.apply(this, arguments); // 把参数传进去
+    }, wait);
+  };
+}
+
+export default {
+  name: 'qiun-data-charts',
+  mixins: [uniCloud.mixinDatacom],
+  props: {
+    type: {
+      type: String,
+      default: null
+    },
+    canvasId: {
+      type: String,
+      default: 'uchartsid'
+    },
+    canvas2d: {
+      type: Boolean,
+      default: false
+    },
+    background: {
+      type: String,
+      default: 'rgba(0,0,0,0)'
+    },
+    animation: {
+      type: Boolean,
+      default: true
+    },
+    chartData: {
+      type: Object,
+      default() {
+        return {
+          categories: [],
+          series: []
+        };
+      }
+    },
+    opts: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    eopts: {
+      type: Object,
+      default() {
+        return {};
+      }
+    },
+    loadingType: {
+      type: Number,
+      default: 2
+    },
+    errorShow: {
+      type: Boolean,
+      default: true
+    },
+    errorReload: {
+      type: Boolean,
+      default: true
+    },
+    errorMessage: {
+      type: String,
+      default: null
+    },
+    inScrollView: {
+      type: Boolean,
+      default: false
+    },
+    reshow: {
+      type: Boolean,
+      default: false
+    },
+    reload: {
+      type: Boolean,
+      default: false
+    },
+    disableScroll: {
+      type: Boolean,
+      default: false
+    },
+    optsWatch: {
+      type: Boolean,
+      default: true
+    },
+    onzoom: {
+      type: Boolean,
+      default: false
+    },
+    ontap: {
+      type: Boolean,
+      default: true
+    },
+    ontouch: {
+      type: Boolean,
+      default: false
+    },
+    onmouse: {
+      type: Boolean,
+      default: true
+    },
+    onmovetip: {
+      type: Boolean,
+      default: false
+    },
+    echartsH5: {
+      type: Boolean,
+      default: false
+    },
+    echartsApp: {
+      type: Boolean,
+      default: false
+    },
+    tooltipShow: {
+      type: Boolean,
+      default: true
+    },
+    tooltipFormat: {
+      type: String,
+      default: undefined
+    },
+    tooltipCustom: {
+      type: Object,
+      default: undefined
+    },
+    startDate: {
+      type: String,
+      default: undefined
+    },
+    endDate: {
+      type: String,
+      default: undefined
+    },
+    textEnum: {
+      type: Array,
+      default () {
+        return []
+      }
+    },
+    groupEnum: {
+      type: Array,
+      default () {
+        return []
+      }
+    },
+    pageScrollTop: {
+      type: Number,
+      default: 0
+    },
+    directory: {
+      type: String,
+      default: '/'
+    },
+    tapLegend: {
+      type: Boolean,
+      default: true
+    },
+    menus: {
+      type: Array,
+      default () {
+        return []
+      }
+    }
+  },
+  data() {
+    return {
+      cid: 'uchartsid',
+      inWx: false,
+      inAli: false,
+      inTt: false,
+      inBd: false,
+      inH5: false,
+      inApp: false,
+      inWin: false,
+      type2d: true,
+      disScroll: false,
+      openmouse: false,
+      pixel: 1,
+      cWidth: 375,
+      cHeight: 250,
+      showchart: false,
+      echarts: false,
+      echartsResize:{
+        state:false
+      },
+      uchartsOpts: {},
+      echartsOpts: {},
+      drawData:{},
+      lastDrawTime:null,
+    };
+  },
+  created(){
+    this.cid = this.canvasId
+    if (this.canvasId == 'uchartsid' || this.canvasId == '') {
+      let t = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
+      let len = t.length
+      let id = ''
+      for (let i = 0; i < 32; i++) {
+        id += t.charAt(Math.floor(Math.random() * len))
+      }
+      this.cid = id
+    }
+    const systemInfo = uni.getSystemInfoSync()
+    if(systemInfo.platform === 'windows' || systemInfo.platform === 'mac'){
+      this.inWin = true;
+    }
+    // #ifdef MP-WEIXIN
+    this.inWx = true;
+    if (this.canvas2d === false || systemInfo.platform === 'windows' || systemInfo.platform === 'mac') {
+      this.type2d = false;
+    }else{
+      this.type2d = true;
+      this.pixel = systemInfo.pixelRatio;
+    }
+    // #endif
+    //非微信小程序端强制关闭canvas2d模式
+    // #ifndef MP-WEIXIN
+    this.type2d = false;
+    // #endif
+    // #ifdef  MP-TOUTIAO || MP-LARK || MP-ALIPAY
+    this.type2d = this.canvas2d;
+    // #endif
+    // #ifdef MP-ALIPAY
+    this.inAli = true;
+    this.pixel = systemInfo.pixelRatio;
+    // #endif
+    // #ifdef MP-BAIDU
+    this.inBd = true;
+    // #endif
+    // #ifdef MP-TOUTIAO
+    this.inTt = true;
+    // #endif
+    this.disScroll = this.disableScroll;
+  },
+  mounted() {
+    // #ifdef APP-VUE
+    this.inApp = true;
+    if (this.echartsApp === true) {
+      this.echarts = true;
+      this.openmouse = false;
+    }
+    // #endif
+    // #ifdef APP-NVUE
+    this.inApp = true;
+    this.mixinDatacomLoading = false
+    this.mixinDatacomErrorMessage = "暂不支持NVUE"
+    // #endif
+    // #ifdef H5
+    this.inH5 = true;
+    if(this.inWin === true){
+      this.openmouse = this.onmouse;
+    }
+    if (this.echartsH5 === true) {
+      this.echarts = true;
+    }
+    // #endif
+    this.$nextTick(()=>{
+      this.beforeInit();
+    })
+    // #ifndef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO || APP-VUE
+    const time = this.inH5 ? 500 : 200;
+    const _this = this;
+    uni.onWindowResize(
+      debounce(function(res) {
+        if (_this.mixinDatacomLoading == true) {
+          return;
+        }
+        let errmsg = _this.mixinDatacomErrorMessage;
+        if (errmsg !== null && errmsg !== 'null' && errmsg !== '') {
+          return;
+        }
+        if (_this.echarts) {
+          _this.echartsResize.state = !_this.echartsResize.state;
+        } else {
+          _this.resizeHandler();
+        }
+      }, time)
+    );
+    // #endif
+  },
+  destroyed(){
+    if(this.echarts === true){
+      delete cfe.option[this.cid]
+      delete cfe.instance[this.cid]
+    }else{
+      delete cfu.option[this.cid]
+      delete cfu.instance[this.cid]
+    }
+    // #ifndef MP-ALIPAY || MP-BAIDU || MP-TOUTIAO
+    uni.offWindowResize(()=>{})
+    // #endif
+  },
+  watch: {
+    chartDataProps: {
+      handler(val, oldval) {
+        if (typeof val === 'object') {
+          if (JSON.stringify(val) !== JSON.stringify(oldval)) {
+            this._clearChart();
+            if (val.series && val.series.length > 0) {
+              this.beforeInit();
+            }else{
+              this.mixinDatacomLoading = true;
+              this.showchart = false;
+              this.mixinDatacomErrorMessage = null;
+            }
+          }
+        } else {
+          this.mixinDatacomLoading = false;
+          this._clearChart();
+          this.showchart = false;
+          this.mixinDatacomErrorMessage = '参数错误:chartData数据类型错误';
+        }
+      },
+      immediate: false,
+      deep: true
+    },
+    localdata:{
+      handler(val, oldval) {
+        if (JSON.stringify(val) !== JSON.stringify(oldval)) {
+          if (val.length > 0) {
+            this.beforeInit();
+          }else{
+            this.mixinDatacomLoading = true;
+            this._clearChart();
+            this.showchart = false;
+            this.mixinDatacomErrorMessage = null;
+          }
+        }
+      },
+      immediate: false,
+      deep: true
+    },
+    optsProps: {
+      handler(val, oldval) {
+        if (typeof val === 'object') {
+          if (JSON.stringify(val) !== JSON.stringify(oldval) && this.echarts === false && this.optsWatch == true) {
+            this.checkData(this.drawData);
+          }
+        } else {
+          this.mixinDatacomLoading = false;
+          this._clearChart();
+          this.showchart = false;
+          this.mixinDatacomErrorMessage = '参数错误:opts数据类型错误';
+        }
+      },
+      immediate: false,
+      deep: true
+    },
+    eoptsProps: {
+      handler(val, oldval) {
+        if (typeof val === 'object') {
+          if (JSON.stringify(val) !== JSON.stringify(oldval) && this.echarts === true) {
+            this.checkData(this.drawData);
+          }
+        } else {
+          this.mixinDatacomLoading = false;
+          this.showchart = false;
+          this.mixinDatacomErrorMessage = '参数错误:eopts数据类型错误';
+        }
+      },
+      immediate: false,
+      deep: true
+    },
+    reshow(val, oldval) {
+      if (val === true && this.mixinDatacomLoading === false) {
+        setTimeout(() => {
+          this.mixinDatacomErrorMessage = null;
+          this.echartsResize.state = !this.echartsResize.state;
+          this.checkData(this.drawData);
+        }, 200);
+      }
+    },
+    reload(val, oldval) {
+      if (val === true) {
+        this.showchart = false;
+        this.mixinDatacomErrorMessage = null;
+        this.reloading();
+      }
+    },
+    mixinDatacomErrorMessage(val, oldval) {
+      if (val) {
+        this.emitMsg({name: 'error', params: {type:"error", errorShow: this.errorShow, msg: val, id: this.cid}});
+        if(this.errorShow){
+          console.log('[秋云图表组件]' + val);
+        }
+      }
+    },
+    errorMessage(val, oldval) {
+      if (val && this.errorShow && val !== null && val !== 'null' && val !== '') {
+        this.showchart = false;
+        this.mixinDatacomLoading = false;
+        this.mixinDatacomErrorMessage = val;
+      } else {
+        this.showchart = false;
+        this.mixinDatacomErrorMessage = null;
+        this.reloading();
+      }
+    }
+  },
+  computed: {
+    optsProps() {
+      return JSON.parse(JSON.stringify(this.opts));
+    },
+    eoptsProps() {
+      return JSON.parse(JSON.stringify(this.eopts));
+    },
+    chartDataProps() {
+      return JSON.parse(JSON.stringify(this.chartData));
+    },
+  },
+  methods: {
+    beforeInit(){
+      this.mixinDatacomErrorMessage = null;
+      if (typeof this.chartData === 'object' && this.chartData != null && this.chartData.series !== undefined && this.chartData.series.length > 0) {
+        //拷贝一下chartData,为了opts变更后统一数据来源
+        this.drawData = deepCloneAssign({}, this.chartData);
+        this.mixinDatacomLoading = false;
+        this.showchart = true;
+        this.checkData(this.chartData);
+      }else if(this.localdata.length>0){
+        this.mixinDatacomLoading = false;
+        this.showchart = true;
+        this.localdataInit(this.localdata);
+      }else if(this.collection !== ''){
+        this.mixinDatacomLoading = false;
+        this.getCloudData();
+      }else{
+        this.mixinDatacomLoading = true;
+      }
+    },
+    localdataInit(resdata){
+      //替换enum类型为正确的描述
+      if(this.groupEnum.length>0){
+        for (let i = 0; i < resdata.length; i++) {
+          for (let j = 0; j < this.groupEnum.length; j++) {
+            if(resdata[i].group === this.groupEnum[j].value){
+              resdata[i].group = this.groupEnum[j].text
+            }
+          }
+        }
+      }
+      if(this.textEnum.length>0){
+        for (let i = 0; i < resdata.length; i++) {
+          for (let j = 0; j < this.textEnum.length; j++) {
+            if(resdata[i].text === this.textEnum[j].value){
+              resdata[i].text = this.textEnum[j].text
+            }
+          }
+        }
+      }
+      let needCategories = false;
+      let tmpData = {categories:[], series:[]}
+      let tmpcategories = []
+      let tmpseries = [];
+      //拼接categories
+      if(this.echarts === true){
+        needCategories = cfe.categories.includes(this.type)
+      }else{
+        needCategories = cfu.categories.includes(this.type)
+      }
+      if(needCategories === true){
+        //如果props中的chartData带有categories,则优先使用chartData的categories
+        if(this.chartData && this.chartData.categories && this.chartData.categories.length>0){
+          tmpcategories = this.chartData.categories
+        }else{
+          //如果是日期类型的数据,不管是本地数据还是云数据,都按起止日期自动拼接categories
+          if(this.startDate && this.endDate){
+            let idate = new Date(this.startDate)
+            let edate = new Date(this.endDate)
+            while (idate <= edate) {
+            	tmpcategories.push(getFormatDate(idate))
+            	idate = idate.setDate(idate.getDate() + 1)
+            	idate = new Date(idate)
+            }
+          //否则从结果中去重并拼接categories
+          }else{
+            let tempckey = {};
+            resdata.map(function(item, index) {
+              if (item.text != undefined && !tempckey[item.text]) {
+                tmpcategories.push(item.text)
+                tempckey[item.text] = true
+              }
+            });
+          }
+        }
+        tmpData.categories = tmpcategories
+      }
+      //拼接series
+      let tempskey = {};
+      resdata.map(function(item, index) {
+        if (item.group != undefined && !tempskey[item.group]) {
+          tmpseries.push({ name: item.group, data: [] });
+          tempskey[item.group] = true;
+        }
+      });
+      //如果没有获取到分组名称(可能是带categories的数据,也可能是不带的饼图类)
+      if (tmpseries.length == 0) {
+        tmpseries = [{ name: '默认分组', data: [] }];
+        //如果是需要categories的图表类型
+        if(needCategories === true){
+          for (let j = 0; j < tmpcategories.length; j++) {
+            let seriesdata = 0;
+            for (let i = 0; i < resdata.length; i++) {
+              if (resdata[i].text == tmpcategories[j]) {
+                seriesdata = resdata[i].value;
+              }
+            }
+            tmpseries[0].data.push(seriesdata);
+          }
+        //如果是饼图类的图表类型
+        }else{
+          for (let i = 0; i < resdata.length; i++) {
+            tmpseries[0].data.push({"name": resdata[i].text,"value": resdata[i].value});
+          }
+        }
+      //如果有分组名
+      } else {
+        for (let k = 0; k < tmpseries.length; k++) {
+          //如果有categories
+          if (tmpcategories.length > 0) {
+            for (let j = 0; j < tmpcategories.length; j++) {
+              let seriesdata = 0;
+              for (let i = 0; i < resdata.length; i++) {
+                if (tmpseries[k].name == resdata[i].group && resdata[i].text == tmpcategories[j]) {
+                  seriesdata = resdata[i].value;
+                }
+              }
+              tmpseries[k].data.push(seriesdata);
+            }
+          //如果传了group而没有传text,即没有categories(正常情况下这种数据是不符合数据要求规范的)
+          } else {
+            for (let i = 0; i < resdata.length; i++) {
+              if (tmpseries[k].name == resdata[i].group) {
+                tmpseries[k].data.push(resdata[i].value);
+              }
+            }
+          }
+        }
+      }
+      tmpData.series = tmpseries
+      //拷贝一下chartData,为了opts变更后统一数据来源
+      this.drawData = deepCloneAssign({}, tmpData);
+      this.checkData(tmpData)
+    },
+    reloading() {
+      if(this.errorReload === false){
+        return;
+      }
+      this.showchart = false;
+      this.mixinDatacomErrorMessage = null;
+      if (this.collection !== '') {
+        this.mixinDatacomLoading = false;
+        this.onMixinDatacomPropsChange(true);
+      } else {
+        this.beforeInit();
+      }
+    },
+    checkData(anyData) {
+      let cid = this.cid
+      //复位opts或eopts
+      if(this.echarts === true){
+        cfe.option[cid] = deepCloneAssign({}, this.eopts);
+        cfe.option[cid].id = cid;
+        cfe.option[cid].type = this.type;
+      }else{
+        if (this.type && cfu.type.includes(this.type)) {
+          cfu.option[cid] = deepCloneAssign({}, cfu[this.type], this.opts);
+          cfu.option[cid].canvasId = cid;
+        } else {
+          this.mixinDatacomLoading = false;
+          this.showchart = false;
+          this.mixinDatacomErrorMessage = '参数错误:props参数中type类型不正确';
+        }
+      }
+      //挂载categories和series
+      let newData = deepCloneAssign({}, anyData);
+      if (newData.series !== undefined && newData.series.length > 0) {
+        this.mixinDatacomErrorMessage = null;
+        if (this.echarts === true) {
+          cfe.option[cid].chartData = newData;
+          this.$nextTick(()=>{
+            this.init()
+          })
+        }else{
+          cfu.option[cid].categories = newData.categories;
+          cfu.option[cid].series = newData.series;
+          this.$nextTick(()=>{
+            this.init()
+          })
+        }
+      }
+    },
+    resizeHandler() {
+      //渲染防抖
+      let currTime = Date.now();
+      let lastDrawTime = this.lastDrawTime?this.lastDrawTime:currTime-3000;
+      let duration = currTime - lastDrawTime;
+      if (duration < 1000) return;
+      let chartdom = uni
+        .createSelectorQuery()
+        // #ifndef MP-ALIPAY
+        .in(this)
+        // #endif
+        .select('#ChartBoxId'+this.cid)
+        .boundingClientRect(data => {
+          this.showchart = true;
+          if (data.width > 0 && data.height > 0) {
+            if (data.width !== this.cWidth || data.height !== this.cHeight) {
+              this.checkData(this.drawData)
+            }
+          }
+        })
+        .exec();
+    },
+    getCloudData() {
+      if (this.mixinDatacomLoading == true) {
+        return;
+      }
+      this.mixinDatacomLoading = true;
+      this.mixinDatacomGet()
+        .then(res => {
+          this.mixinDatacomResData = res.result.data;
+          this.localdataInit(this.mixinDatacomResData);
+        })
+        .catch(err => {
+          this.mixinDatacomLoading = false;
+          this.showchart = false;
+          this.mixinDatacomErrorMessage = '请求错误:' + err;
+        });
+    },
+    onMixinDatacomPropsChange(needReset, changed) {
+      if (needReset == true && this.collection !== '') {
+        this.showchart = false;
+        this.mixinDatacomErrorMessage = null;
+        this._clearChart();
+        this.getCloudData();
+      }
+    },
+    _clearChart() {
+      let cid = this.cid
+      if (this.echarts !== true && cfu.option[cid] && cfu.option[cid].context) {
+        const ctx = cfu.option[cid].context;
+        if(typeof ctx === "object" && !!!cfu.option[cid].update){
+          ctx.clearRect(0, 0, this.cWidth*this.pixel, this.cHeight*this.pixel);
+          ctx.draw();
+        }
+      }
+    },
+    init() {
+      let cid = this.cid
+      let chartdom = uni
+        .createSelectorQuery()
+        // #ifndef MP-ALIPAY
+        .in(this)
+        // #endif
+        .select('#ChartBoxId'+cid)
+        .boundingClientRect(data => {
+          if (data.width > 0 && data.height > 0) {
+            this.mixinDatacomLoading = false;
+            this.showchart = true;
+            this.lastDrawTime = Date.now();
+            this.cWidth = data.width;
+            this.cHeight = data.height;
+            if(this.echarts !== true){
+              cfu.option[cid].background = this.background == 'rgba(0,0,0,0)' ? '#FFFFFF' : this.background;
+              cfu.option[cid].canvas2d = this.type2d;
+              cfu.option[cid].pixelRatio = this.pixel;
+              cfu.option[cid].animation = this.animation;
+              cfu.option[cid].width = data.width * this.pixel;
+              cfu.option[cid].height = data.height * this.pixel;
+              cfu.option[cid].onzoom = this.onzoom;
+              cfu.option[cid].ontap = this.ontap;
+              cfu.option[cid].ontouch = this.ontouch;
+              cfu.option[cid].onmouse = this.openmouse;
+              cfu.option[cid].onmovetip = this.onmovetip;
+              cfu.option[cid].tooltipShow = this.tooltipShow;
+              cfu.option[cid].tooltipFormat = this.tooltipFormat;
+              cfu.option[cid].tooltipCustom = this.tooltipCustom;
+              cfu.option[cid].inScrollView = this.inScrollView;
+              cfu.option[cid].lastDrawTime = this.lastDrawTime;
+              cfu.option[cid].tapLegend = this.tapLegend;
+            }
+            //如果是H5或者App端,采用renderjs渲染图表
+            if (this.inH5 || this.inApp) {
+              if (this.echarts == true) {
+                cfe.option[cid].ontap = this.ontap;
+                cfe.option[cid].onmouse = this.openmouse;
+                cfe.option[cid].tooltipShow = this.tooltipShow;
+                cfe.option[cid].tooltipFormat = this.tooltipFormat;
+                cfe.option[cid].tooltipCustom = this.tooltipCustom;
+                cfe.option[cid].lastDrawTime = this.lastDrawTime;
+                this.echartsOpts = deepCloneAssign({}, cfe.option[cid]);
+              } else {
+                cfu.option[cid].rotateLock = cfu.option[cid].rotate;
+                this.uchartsOpts = deepCloneAssign({}, cfu.option[cid]);
+              }
+            //如果是小程序端,采用uCharts渲染
+            } else {
+              cfu.option[cid] = formatterAssign(cfu.option[cid],cfu.formatter)
+              this.mixinDatacomErrorMessage = null;
+              this.mixinDatacomLoading = false;
+              this.showchart = true;
+              this.$nextTick(()=>{
+                if (this.type2d === true) {
+                  const query = uni.createSelectorQuery().in(this)
+                  query
+                    .select('#' + cid)
+                    .fields({ node: true, size: true })
+                    .exec(res => {
+                      if (res[0]) {
+                        const canvas = res[0].node;
+                        const ctx = canvas.getContext('2d');
+                        cfu.option[cid].context = ctx;
+                        cfu.option[cid].rotateLock = cfu.option[cid].rotate;
+                        if(cfu.instance[cid] && cfu.option[cid] && cfu.option[cid].update === true){
+                          this._updataUChart(cid)
+                        }else{
+                          canvas.width = data.width * this.pixel;
+                          canvas.height = data.height * this.pixel;
+                          canvas._width = data.width * this.pixel;
+                          canvas._height = data.height * this.pixel;
+                          setTimeout(()=>{
+                            cfu.option[cid].context.restore();
+                            cfu.option[cid].context.save();
+                            this._newChart(cid)
+                          },100)
+                        }
+                      } else {
+                        this.showchart = false;
+                        this.mixinDatacomErrorMessage = '参数错误:开启2d模式后,未获取到dom节点,canvas-id:' + cid;
+                      }
+                    });
+                } else {
+                  if(this.inAli){
+                    cfu.option[cid].rotateLock = cfu.option[cid].rotate;
+                  }
+                  cfu.option[cid].context = uni.createCanvasContext(cid, this);
+                  if(cfu.instance[cid] && cfu.option[cid] && cfu.option[cid].update === true){
+                    this._updataUChart(cid)
+                  }else{
+                    setTimeout(()=>{
+                      cfu.option[cid].context.restore();
+                      cfu.option[cid].context.save();
+                      this._newChart(cid)
+                    },100)
+                  }
+                }
+              })
+            }
+          } else {
+            this.mixinDatacomLoading = false;
+            this.showchart = false;
+            if (this.reshow == true) {
+              this.mixinDatacomErrorMessage = '布局错误:未获取到父元素宽高尺寸!canvas-id:' + cid;
+            }
+          }
+        })
+        .exec();
+    },
+    saveImage(){
+    	uni.canvasToTempFilePath({
+    	  canvasId: this.cid,
+    	  success: res=>{
+    	    //#ifdef H5
+    			var a = document.createElement("a");
+    			a.href = res.tempFilePath;
+    			a.download = this.cid;
+    			a.target = '_blank'
+    			a.click();
+    	    //#endif
+    	    //#ifndef H5
+    	      uni.saveImageToPhotosAlbum({
+              filePath: res.tempFilePath,
+              success: function () {
+                uni.showToast({
+                  title: '保存成功',
+                  duration: 2000
+                });
+              }
+    	      });
+    	    //#endif
+    	  } 
+    	},this);
+    },
+    getImage(){
+      if(this.type2d == false){
+        uni.canvasToTempFilePath({
+          canvasId: this.cid,
+          success: res=>{
+            this.emitMsg({name: 'getImage', params: {type:"getImage", base64: res.tempFilePath}});
+          }
+        },this);
+      }else{
+        const query = uni.createSelectorQuery().in(this)
+        query
+          .select('#' + this.cid)
+          .fields({ node: true, size: true })
+          .exec(res => {
+            if (res[0]) {
+              const canvas = res[0].node;
+              this.emitMsg({name: 'getImage', params: {type:"getImage", base64: canvas.toDataURL('image/png')}});
+            }
+          });
+      }
+    },
+    // #ifndef APP-VUE || H5
+    _newChart(cid) {
+      if (this.mixinDatacomLoading == true) {
+        return;
+      }
+      this.showchart = true;
+      cfu.instance[cid] = new uCharts(cfu.option[cid]);
+      cfu.instance[cid].addEventListener('renderComplete', () => {
+        this.emitMsg({name: 'complete', params: {type:"complete", complete: true, id: cid, opts: cfu.instance[cid].opts}});
+        cfu.instance[cid].delEventListener('renderComplete')
+      });
+      cfu.instance[cid].addEventListener('scrollLeft', () => {
+        this.emitMsg({name: 'scrollLeft', params: {type:"scrollLeft", scrollLeft: true, id: cid, opts: cfu.instance[cid].opts}});
+      });
+      cfu.instance[cid].addEventListener('scrollRight', () => {
+        this.emitMsg({name: 'scrollRight', params: {type:"scrollRight", scrollRight: true, id: cid, opts: cfu.instance[cid].opts}});
+      });
+    },
+    _updataUChart(cid) {
+      cfu.instance[cid].updateData(cfu.option[cid])
+    },
+    _tooltipDefault(item, category, index, opts) {
+      if (category) {
+        let data = item.data
+        if(typeof item.data === "object"){
+          data = item.data.value
+        }
+        return category + ' ' + item.name + ':' + data;
+      } else {
+        if (item.properties && item.properties.name) {
+          return item.properties.name;
+        } else {
+          return item.name + ':' + item.data;
+        }
+      }
+    },
+    _showTooltip(e) {
+      let cid = this.cid
+      let tc = cfu.option[cid].tooltipCustom
+      if (tc && tc !== undefined && tc !== null) {
+        let offset = undefined;
+        if (tc.x >= 0 && tc.y >= 0) {
+          offset = { x: tc.x, y: tc.y + 10 };
+        }
+        cfu.instance[cid].showToolTip(e, {
+          index: tc.index,
+          offset: offset,
+          textList: tc.textList,
+          formatter: (item, category, index, opts) => {
+            if (typeof cfu.option[cid].tooltipFormat === 'string' && cfu.formatter[cfu.option[cid].tooltipFormat]) {
+              return cfu.formatter[cfu.option[cid].tooltipFormat](item, category, index, opts);
+            } else {
+              return this._tooltipDefault(item, category, index, opts);
+            }
+          }
+        });
+      } else {
+        cfu.instance[cid].showToolTip(e, {
+          formatter: (item, category, index, opts) => {
+            if (typeof cfu.option[cid].tooltipFormat === 'string' && cfu.formatter[cfu.option[cid].tooltipFormat]) {
+              return cfu.formatter[cfu.option[cid].tooltipFormat](item, category, index, opts);
+            } else {
+              return this._tooltipDefault(item, category, index, opts);
+            }
+          }
+        });
+      }
+    },
+    _tap(e,move) {
+      let cid = this.cid
+      let currentIndex = null;
+      let legendIndex = null;
+      if (this.inScrollView === true || this.inAli) {
+        let chartdom = uni
+          .createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this)
+          .select('#ChartBoxId'+cid)
+          // #endif
+          // #ifdef MP-ALIPAY
+          .select('#'+this.cid)
+          // #endif
+          .boundingClientRect(data => {
+            e.changedTouches=[];
+            if (this.inAli) {
+              e.changedTouches.unshift({ x: e.detail.clientX - data.left, y: e.detail.clientY - data.top});
+            }else{
+              e.changedTouches.unshift({ x: e.detail.x - data.left, y: e.detail.y - data.top - this.pageScrollTop});
+            }
+            if(move){
+              if (this.tooltipShow === true) {
+                this._showTooltip(e);
+              }
+            }else{
+              currentIndex = cfu.instance[cid].getCurrentDataIndex(e);
+              legendIndex = cfu.instance[cid].getLegendDataIndex(e);
+              if(this.tapLegend === true){
+                cfu.instance[cid].touchLegend(e);
+              }
+              if (this.tooltipShow === true) {
+                this._showTooltip(e);
+              }
+              this.emitMsg({name: 'getIndex', params: { type:"getIndex", event:{ x: e.detail.x - data.left, y: e.detail.y - data.top }, currentIndex: currentIndex, legendIndex: legendIndex, id: cid, opts: cfu.instance[cid].opts}});
+            }
+          })
+          .exec();
+      } else {
+        if(move){
+          if (this.tooltipShow === true) {
+            this._showTooltip(e);
+          }
+        }else{
+          e.changedTouches=[];
+          e.changedTouches.unshift({ x: e.detail.x - e.currentTarget.offsetLeft, y: e.detail.y - e.currentTarget.offsetTop });
+          currentIndex = cfu.instance[cid].getCurrentDataIndex(e);
+          legendIndex = cfu.instance[cid].getLegendDataIndex(e);
+          if(this.tapLegend === true){
+            cfu.instance[cid].touchLegend(e);
+          }
+          if (this.tooltipShow === true) {
+            this._showTooltip(e);
+          }
+          this.emitMsg({name: 'getIndex', params: {type:"getIndex", event:{ x: e.detail.x, y: e.detail.y - e.currentTarget.offsetTop }, currentIndex: currentIndex, legendIndex: legendIndex, id: cid, opts: cfu.instance[cid].opts}});
+        }
+      }
+    },
+    _touchStart(e) {
+      let cid = this.cid
+      lastMoveTime=Date.now();
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 1){
+        cfu.instance[cid].scrollStart(e);
+      }
+      this.emitMsg({name:'getTouchStart', params:{type:"touchStart", event:e.changedTouches[0], id:cid, opts: cfu.instance[cid].opts}});
+    },
+    _touchMove(e) {
+      let cid = this.cid
+      let currMoveTime = Date.now();
+      let duration = currMoveTime - lastMoveTime;
+      let touchMoveLimit = cfu.option[cid].touchMoveLimit || 24;
+      if (duration < Math.floor(1000 / touchMoveLimit)) return;//每秒60帧
+      lastMoveTime = currMoveTime;
+      if(cfu.option[cid].enableScroll === true && e.changedTouches.length == 1){
+        cfu.instance[cid].scroll(e);
+      }
+      if(this.ontap === true && cfu.option[cid].enableScroll === false && this.onmovetip === true){
+        this._tap(e,true)
+      }
+      if(this.ontouch === true && cfu.option[cid].enableScroll === true && this.onzoom === true && e.changedTouches.length == 2){
+        cfu.instance[cid].dobuleZoom(e);
+      }
+      this.emitMsg({name: 'getTouchMove', params: {type:"touchMove", event:e.changedTouches[0], id: cid, opts: cfu.instance[cid].opts}});
+    },
+    _touchEnd(e) {
+      let cid = this.cid
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 0){
+        cfu.instance[cid].scrollEnd(e);
+      }
+      this.emitMsg({name:'getTouchEnd', params:{type:"touchEnd", event:e.changedTouches[0], id:cid, opts: cfu.instance[cid].opts}});
+      if(this.ontap === true && cfu.option[cid].enableScroll === false && this.onmovetip === true){
+        this._tap(e,true)
+      }
+    },
+    // #endif
+    _error(e) {
+      this.mixinDatacomErrorMessage = e.detail.errMsg;
+    },
+    emitMsg(msg) {
+      this.$emit(msg.name, msg.params);
+    },
+    getRenderType() {
+      //防止如果开启echarts且父元素为v-if的情况renderjs监听不到prop变化的问题
+      if(this.echarts===true && this.mixinDatacomLoading===false){
+        this.beforeInit()
+      }
+    },
+    toJSON(){
+      return this
+    }
+  }
+};
+</script>
+
+<!-- #ifdef APP-VUE || H5 -->
+<script module="rdcharts" lang="renderjs">
+import uChartsRD from '../../js_sdk/u-charts/u-charts.js';
+import cfu from '../../js_sdk/u-charts/config-ucharts.js';
+import cfe from '../../js_sdk/u-charts/config-echarts.js';
+
+var that = {};
+var rootdom = null;
+
+function rddeepCloneAssign(origin = {}, ...args) {
+  for (let i in args) {
+    for (let key in args[i]) {
+      if (args[i].hasOwnProperty(key)) {
+        origin[key] = args[i][key] && typeof args[i][key] === 'object' ? rddeepCloneAssign(Array.isArray(args[i][key]) ? [] : {}, origin[key], args[i][key]) : args[i][key];
+      }
+    }
+  }
+  return origin;
+}
+
+function rdformatterAssign(args,formatter) {
+  for (let key in args) {
+    if(args.hasOwnProperty(key) && args[key] !== null && typeof args[key] === 'object'){
+      rdformatterAssign(args[key],formatter)
+    }else if(key === 'format' && typeof args[key] === 'string'){
+      args['formatter'] = formatter[args[key]] ? formatter[args[key]] : undefined;
+    }
+  }
+  return args;
+}
+
+export default {
+  data() {
+    return {
+      rid:null
+    }
+  },
+  mounted() {
+    rootdom = {top:0,left:0}
+    // #ifdef H5
+    let dm = document.querySelectorAll('uni-main')[0]
+    if(dm === undefined){
+      dm = document.querySelectorAll('uni-page-wrapper')[0]
+    }
+    rootdom = {top:dm.offsetTop,left:dm.offsetLeft}
+    // #endif
+    setTimeout(()=>{
+      if(this.rid === null){
+        this.$ownerInstance && this.$ownerInstance.callMethod('getRenderType')
+      }
+    },200)
+  },
+  destroyed(){
+    delete cfu.option[this.rid]
+    delete cfu.instance[this.rid]
+    delete cfe.option[this.rid]
+    delete cfe.instance[this.rid]
+  },
+  methods: {
+    //==============以下是ECharts的方法====================
+    ecinit(newVal, oldVal, owner, instance){
+      let cid = JSON.stringify(newVal.id)
+      this.rid = cid
+      that[cid] = this.$ownerInstance || instance
+      let eopts = JSON.parse(JSON.stringify(newVal))
+      let type = eopts.type;
+      //载入并覆盖默认配置
+      if (type && cfe.type.includes(type)) {
+        cfe.option[cid] = rddeepCloneAssign({}, cfe[type], eopts);
+      }else{
+        cfe.option[cid] = rddeepCloneAssign({}, eopts);
+      }
+      let newData = eopts.chartData;
+      if(newData){
+        //挂载categories和series
+        if(cfe.option[cid].xAxis && cfe.option[cid].xAxis.type && cfe.option[cid].xAxis.type === 'category'){
+          cfe.option[cid].xAxis.data = newData.categories
+        }
+        if(cfe.option[cid].yAxis && cfe.option[cid].yAxis.type && cfe.option[cid].yAxis.type === 'category'){
+          cfe.option[cid].yAxis.data = newData.categories
+        }
+        cfe.option[cid].series = []
+        for (var i = 0; i < newData.series.length; i++) {
+          cfe.option[cid].seriesTemplate = cfe.option[cid].seriesTemplate ? cfe.option[cid].seriesTemplate : {}
+          let Template = rddeepCloneAssign({},cfe.option[cid].seriesTemplate,newData.series[i])
+          cfe.option[cid].series.push(Template)
+        }
+      }
+      
+      if (typeof window.echarts === 'object') {
+          this.newEChart()
+      }else{
+        const script = document.createElement('script')
+        // #ifdef APP-VUE
+        script.src = './uni_modules/qiun-data-charts/static/app-plus/echarts.min.js'
+        // #endif
+        // #ifdef H5
+        const rooturl = window.location.origin
+        const directory = instance.getDataset().directory
+        script.src = rooturl + directory + 'uni_modules/qiun-data-charts/static/h5/echarts.min.js'
+        // #endif
+        script.onload = this.newEChart
+        document.head.appendChild(script)
+      }
+    },
+    ecresize(newVal, oldVal, owner, instance){
+      if(cfe.instance[this.rid]){
+        cfe.instance[this.rid].resize()
+      }
+    },
+    newEChart(){
+      let cid = this.rid
+      if(cfe.instance[cid] === undefined){
+        cfe.instance[cid] = echarts.init(that[cid].$el.children[0])
+        //ontap开启后才触发click事件
+        if(cfe.option[cid].ontap === true){
+          cfe.instance[cid].on('click', resdata => {
+            let event = JSON.parse(JSON.stringify({
+              x:resdata.event.offsetX,y:resdata.event.offsetY
+            }))
+            that[cid].callMethod('emitMsg',{name:"getIndex", params:{type:"getIndex", event:event, currentIndex:resdata.dataIndex, value:resdata.data, seriesName: resdata.seriesName,id:cid}})
+          })
+          // 增加ECharts的highlight消息,实现按下移动返回索引功能。add by onefish 创建于 2021-12-11 09:50
+          cfe.instance[cid].on('highlight', resdata => {
+            that[cid].callMethod('emitMsg',{name:"getHighlight", params:{type:"highlight", res:resdata, id:cid}})
+          })
+        }
+        this.updataEChart(cid,cfe.option[cid])
+      }else{
+        this.updataEChart(cid,cfe.option[cid])
+      }
+    },
+    updataEChart(cid,option){
+      //替换option内format属性为formatter的预定义方法
+      option = rdformatterAssign(option,cfe.formatter)
+      if(option.tooltip){
+        option.tooltip.show = option.tooltipShow?true:false;
+        option.tooltip.position = this.tooltipPosition()
+        //tooltipFormat方法,替换组件的tooltipFormat为config-echarts.js内对应的方法
+        if (typeof option.tooltipFormat === 'string' && cfe.formatter[option.tooltipFormat]) {
+          option.tooltip.formatter = option.tooltip.formatter ? option.tooltip.formatter : cfe.formatter[option.tooltipFormat]
+        }
+      }
+      // 颜色渐变添加的方法
+      if (option.series) {
+      	for (let i in option.series) {
+      		let linearGradient = option.series[i].linearGradient
+      		if (linearGradient) {
+      			option.series[i].color = new echarts.graphic.LinearGradient(linearGradient[0],linearGradient[1],linearGradient[2],linearGradient[3],linearGradient[4])
+      		}
+      	}
+      }
+      cfe.instance[cid].setOption(option, option.notMerge)
+      cfe.instance[cid].on('finished', function(){
+        that[cid].callMethod('emitMsg',{name:"complete",params:{type:"complete",complete:true,id:cid}})
+        if(cfe.instance[cid]){
+          cfe.instance[cid].off('finished')
+        }
+      });
+
+      //修复init初始化实例获取宽高不正确问题
+      if(
+        typeof that[cid].$el.children[0].clientWidth != 'undefined' &&
+          (
+            Math.abs( that[cid].$el.children[0].clientWidth - cfe.instance[cid].getWidth() )>3 ||
+            Math.abs( that[cid].$el.children[0].clientHeight - cfe.instance[cid].getHeight() )>3
+          )
+      ){this.ecresize();}
+    },
+    tooltipPosition(){
+      return (point, params, dom, rect, size) => {
+      	let x = point[0]
+      	let y = point[1]
+      	let viewWidth = size.viewSize[0]
+      	let viewHeight = size.viewSize[1]
+      	let boxWidth = size.contentSize[0]
+      	let boxHeight = size.contentSize[1]
+      	let posX = x + 30 
+      	let posY = y + 30 
+      	if (posX + boxWidth > viewWidth) { 
+      		posX = x - boxWidth - 30
+      	}
+      	if (posY + boxHeight > viewHeight) {
+      		posY = y - boxHeight - 30
+      	}
+      	return [posX, posY]
+      }
+    },
+    //==============以下是uCharts的方法====================
+    ucinit(newVal, oldVal, owner, instance){
+      if(JSON.stringify(newVal) == JSON.stringify(oldVal)){
+        return;
+      }
+      if(!newVal.canvasId){
+        return;
+      }
+      let cid = JSON.parse(JSON.stringify(newVal.canvasId))
+      this.rid = cid
+      that[cid] = this.$ownerInstance || instance
+      cfu.option[cid] = JSON.parse(JSON.stringify(newVal))
+      cfu.option[cid] = rdformatterAssign(cfu.option[cid],cfu.formatter)
+      let canvasdom = document.getElementById(cid)
+      if(canvasdom && canvasdom.children[0]){
+        cfu.option[cid].context = canvasdom.children[0].getContext("2d")
+        if(cfu.instance[cid] && cfu.option[cid] && cfu.option[cid].update === true){
+          this.updataUChart()
+        }else{
+          setTimeout(()=>{
+            cfu.option[cid].context.restore();
+            cfu.option[cid].context.save();
+            this.newUChart()
+          },100)
+        }
+      }
+    },
+    newUChart() {
+      let cid = this.rid
+      cfu.instance[cid] = new uChartsRD(cfu.option[cid])
+      cfu.instance[cid].addEventListener('renderComplete', () => {
+        that[cid].callMethod('emitMsg',{name:"complete",params:{type:"complete",complete:true,id:cid, opts: cfu.instance[cid].opts}})
+        cfu.instance[cid].delEventListener('renderComplete')
+      });
+      cfu.instance[cid].addEventListener('scrollLeft', () => {
+        that[cid].callMethod('emitMsg',{name:"scrollLeft",params:{type:"scrollLeft",scrollLeft:true,id:cid, opts: cfu.instance[cid].opts}})
+      });
+      cfu.instance[cid].addEventListener('scrollRight', () => {
+        that[cid].callMethod('emitMsg',{name:"scrollRight",params:{type:"scrollRight",scrollRight:true,id:cid, opts: cfu.instance[cid].opts}})
+      });
+    },
+    updataUChart() {
+      let cid = this.rid
+      cfu.instance[cid].updateData(cfu.option[cid])
+    },
+    tooltipDefault(item, category, index, opts) {
+      if (category) {
+        let data = item.data
+        if(typeof item.data === "object"){
+          data = item.data.value
+        }
+        return category + ' ' + item.name + ':' + data;
+      } else {
+        if (item.properties && item.properties.name) {
+          return item.properties.name ;
+        } else {
+          return item.name + ':' + item.data;
+        }
+      }
+    },
+    showTooltip(e,cid) {
+      let tc = cfu.option[cid].tooltipCustom
+      if (tc && tc !== undefined && tc !== null) {
+        let offset = undefined;
+        if (tc.x >= 0 && tc.y >= 0) {
+          offset = { x: tc.x, y: tc.y + 10 };
+        }
+        cfu.instance[cid].showToolTip(e, {
+          index: tc.index,
+          offset: offset,
+          textList: tc.textList,
+          formatter: (item, category, index, opts) => {
+            if (typeof cfu.option[cid].tooltipFormat === 'string' && cfu.formatter[cfu.option[cid].tooltipFormat]) {
+              return cfu.formatter[cfu.option[cid].tooltipFormat](item, category, index, opts);
+            } else {
+              return this.tooltipDefault(item, category, index, opts);
+            }
+          }
+        });
+      } else {
+        cfu.instance[cid].showToolTip(e, {
+          formatter: (item, category, index, opts) => {
+            if (typeof cfu.option[cid].tooltipFormat === 'string' && cfu.formatter[cfu.option[cid].tooltipFormat]) {
+              return cfu.formatter[cfu.option[cid].tooltipFormat](item, category, index, opts);
+            } else {
+              return this.tooltipDefault(item, category, index, opts);
+            }
+          }
+        });
+      }
+    },
+    tap(e) {
+      let cid = this.rid
+      let ontap = cfu.option[cid].ontap
+      let tooltipShow = cfu.option[cid].tooltipShow
+      let tapLegend = cfu.option[cid].tapLegend
+      if(ontap == false) return;
+      let currentIndex=null
+      let legendIndex=null
+      let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
+      let tmpe = {}
+      if(e.detail.x){//tap或者click的事件
+        tmpe = { x: e.detail.x - rchartdom.left, y:e.detail.y - rchartdom.top + rootdom.top}
+      }else{//mouse的事件
+        tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      }
+      e.changedTouches = [];
+      e.changedTouches.unshift(tmpe)
+      currentIndex=cfu.instance[cid].getCurrentDataIndex(e)
+      legendIndex=cfu.instance[cid].getLegendDataIndex(e)
+      if(tapLegend === true){
+        cfu.instance[cid].touchLegend(e);
+      }
+      if(tooltipShow==true){
+        this.showTooltip(e,cid)
+      }
+      that[cid].callMethod('emitMsg',{name:"getIndex",params:{type:"getIndex",event:tmpe,currentIndex:currentIndex,legendIndex:legendIndex,id:cid, opts: cfu.instance[cid].opts}})
+    },
+    touchStart(e) {
+      let cid = this.rid
+      let ontouch = cfu.option[cid].ontouch
+      if(ontouch == false) return;
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 1){
+        cfu.instance[cid].scrollStart(e);
+      }
+      that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"touchStart",event:e.changedTouches[0],id:cid, opts: cfu.instance[cid].opts}})
+    },
+    touchMove(e) {
+      let cid = this.rid
+      let ontouch = cfu.option[cid].ontouch
+      if(ontouch == false) return;
+      if(cfu.option[cid].enableScroll === true && e.changedTouches.length == 1){
+        cfu.instance[cid].scroll(e);
+      }
+      if(cfu.option[cid].ontap === true && cfu.option[cid].enableScroll === false && cfu.option[cid].onmovetip === true){
+        let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
+        let tmpe = { x: e.changedTouches[0].clientX - rchartdom.left, y:e.changedTouches[0].clientY - rchartdom.top + rootdom.top}
+        e.changedTouches.unshift(tmpe)
+        if(cfu.option[cid].tooltipShow === true){
+          this.showTooltip(e,cid)
+        }
+      }
+      if(ontouch === true && cfu.option[cid].enableScroll === true && cfu.option[cid].onzoom === true && e.changedTouches.length == 2){
+        cfu.instance[cid].dobuleZoom(e);
+      }
+      that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"touchMove",event:e.changedTouches[0],id:cid, opts: cfu.instance[cid].opts}})
+    },
+    touchEnd(e) {
+      let cid = this.rid
+      let ontouch = cfu.option[cid].ontouch
+      if(ontouch == false) return;
+      if(cfu.option[cid].enableScroll === true && e.touches.length == 0){
+        cfu.instance[cid].scrollEnd(e);
+      }
+      that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"touchEnd",event:e.changedTouches[0],id:cid, opts: cfu.instance[cid].opts}})
+    },
+    mouseDown(e) {
+      let cid = this.rid
+      let onmouse = cfu.option[cid].onmouse
+      if(onmouse == false) return;
+      let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
+      let tmpe = {}
+      tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      e.changedTouches = [];
+      e.changedTouches.unshift(tmpe)
+      cfu.instance[cid].scrollStart(e)
+      cfu.option[cid].mousedown=true;
+      that[cid].callMethod('emitMsg',{name:"getTouchStart",params:{type:"mouseDown",event:tmpe,id:cid, opts: cfu.instance[cid].opts}})
+    },
+    mouseMove(e) {
+      let cid = this.rid
+      let onmouse = cfu.option[cid].onmouse
+      let tooltipShow = cfu.option[cid].tooltipShow
+      if(onmouse == false) return;
+      let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
+      let tmpe = {}
+      tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      e.changedTouches = [];
+      e.changedTouches.unshift(tmpe)
+      if(cfu.option[cid].mousedown){
+        cfu.instance[cid].scroll(e)
+        that[cid].callMethod('emitMsg',{name:"getTouchMove",params:{type:"mouseMove",event:tmpe,id:cid, opts: cfu.instance[cid].opts}})
+      }else if(cfu.instance[cid]){
+        if(tooltipShow==true){
+          this.showTooltip(e,cid)
+        }
+      }
+    },
+    mouseUp(e) {
+      let cid = this.rid
+      let onmouse = cfu.option[cid].onmouse
+      if(onmouse == false) return;
+      let rchartdom = document.getElementById('UC'+cid).getBoundingClientRect()
+      let tmpe = {}
+      tmpe = { x: e.clientX - rchartdom.left, y:e.clientY - rchartdom.top + rootdom.top}
+      e.changedTouches = [];
+      e.changedTouches.unshift(tmpe)
+      cfu.instance[cid].scrollEnd(e)
+      cfu.option[cid].mousedown=false;
+      that[cid].callMethod('emitMsg',{name:"getTouchEnd",params:{type:"mouseUp",event:tmpe,id:cid, opts: cfu.instance[cid].opts}})
+    },
+  }
+}
+</script>
+<!-- #endif -->
+
+<style scoped>
+.chartsview {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex: 1;
+  justify-content: center;
+  align-items: center;
+}
+</style>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 42 - 0
uni_modules/qiun-data-charts/components/qiun-error/qiun-error.vue


+ 162 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading1.vue

@@ -0,0 +1,162 @@
+<template>
+	 <view class="container loading1">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading1',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+.container.loading1 {
+  -webkit-transform: rotate(45deg);
+          transform: rotate(45deg);
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+.loading1 .shape1 {
+  -webkit-animation: animation1shape1 0.5s ease 0s infinite alternate;
+          animation: animation1shape1 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, 16px);
+            transform: translate(16px, 16px);
+  }
+}
+
+@keyframes animation1shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, 16px);
+            transform: translate(16px, 16px);
+  }
+}
+.loading1 .shape2 {
+  -webkit-animation: animation1shape2 0.5s ease 0s infinite alternate;
+          animation: animation1shape2 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, 16px);
+            transform: translate(-16px, 16px);
+  }
+}
+
+@keyframes animation1shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, 16px);
+            transform: translate(-16px, 16px);
+  }
+}
+.loading1 .shape3 {
+  -webkit-animation: animation1shape3 0.5s ease 0s infinite alternate;
+          animation: animation1shape3 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, -16px);
+            transform: translate(16px, -16px);
+  }
+}
+
+@keyframes animation1shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(16px, -16px);
+            transform: translate(16px, -16px);
+  }
+}
+.loading1 .shape4 {
+  -webkit-animation: animation1shape4 0.5s ease 0s infinite alternate;
+          animation: animation1shape4 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation1shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, -16px);
+            transform: translate(-16px, -16px);
+  }
+}
+
+@keyframes animation1shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-16px, -16px);
+            transform: translate(-16px, -16px);
+  }
+}
+
+
+</style>

+ 170 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading2.vue

@@ -0,0 +1,170 @@
+<template>
+	 <view class="container loading2">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading2',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+.container.loading2 {
+  -webkit-transform: rotate(10deg);
+          transform: rotate(10deg);
+}
+.container.loading2 .shape {
+  border-radius: 5px;
+}
+.container.loading2{
+  -webkit-animation: rotation 1s infinite;
+          animation: rotation 1s infinite;
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+
+.loading2 .shape1 {
+  -webkit-animation: animation2shape1 0.5s ease 0s infinite alternate;
+          animation: animation2shape1 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, 20px);
+            transform: translate(20px, 20px);
+  }
+}
+
+@keyframes animation2shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, 20px);
+            transform: translate(20px, 20px);
+  }
+}
+.loading2 .shape2 {
+  -webkit-animation: animation2shape2 0.5s ease 0s infinite alternate;
+          animation: animation2shape2 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, 20px);
+            transform: translate(-20px, 20px);
+  }
+}
+
+@keyframes animation2shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, 20px);
+            transform: translate(-20px, 20px);
+  }
+}
+.loading2 .shape3 {
+  -webkit-animation: animation2shape3 0.5s ease 0s infinite alternate;
+          animation: animation2shape3 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, -20px);
+            transform: translate(20px, -20px);
+  }
+}
+
+@keyframes animation2shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(20px, -20px);
+            transform: translate(20px, -20px);
+  }
+}
+.loading2 .shape4 {
+  -webkit-animation: animation2shape4 0.5s ease 0s infinite alternate;
+          animation: animation2shape4 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation2shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, -20px);
+            transform: translate(-20px, -20px);
+  }
+}
+
+@keyframes animation2shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-20px, -20px);
+            transform: translate(-20px, -20px);
+  }
+}
+
+</style>

+ 173 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading3.vue

@@ -0,0 +1,173 @@
+<template>
+	 <view class="container loading3">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading3',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+ .container.loading3 {
+  -webkit-animation: rotation 1s infinite;
+          animation: rotation 1s infinite;
+}
+.container.loading3 .shape1 {
+  border-top-left-radius: 10px;
+}
+.container.loading3 .shape2 {
+  border-top-right-radius: 10px;
+}
+.container.loading3 .shape3 {
+  border-bottom-left-radius: 10px;
+}
+.container.loading3 .shape4 {
+  border-bottom-right-radius: 10px;
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+.loading3 .shape1 {
+  -webkit-animation: animation3shape1 0.5s ease 0s infinite alternate;
+          animation: animation3shape1 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, 5px);
+            transform: translate(5px, 5px);
+  }
+}
+
+@keyframes animation3shape1 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, 5px);
+            transform: translate(5px, 5px);
+  }
+}
+.loading3 .shape2 {
+  -webkit-animation: animation3shape2 0.5s ease 0s infinite alternate;
+          animation: animation3shape2 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, 5px);
+            transform: translate(-5px, 5px);
+  }
+}
+
+@keyframes animation3shape2 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, 5px);
+            transform: translate(-5px, 5px);
+  }
+}
+.loading3 .shape3 {
+  -webkit-animation: animation3shape3 0.5s ease 0s infinite alternate;
+          animation: animation3shape3 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, -5px);
+            transform: translate(5px, -5px);
+  }
+}
+
+@keyframes animation3shape3 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(5px, -5px);
+            transform: translate(5px, -5px);
+  }
+}
+.loading3 .shape4 {
+  -webkit-animation: animation3shape4 0.5s ease 0s infinite alternate;
+          animation: animation3shape4 0.5s ease 0s infinite alternate;
+}
+
+@-webkit-keyframes animation3shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, -5px);
+            transform: translate(-5px, -5px);
+  }
+}
+
+@keyframes animation3shape4 {
+  from {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  to {
+    -webkit-transform: translate(-5px, -5px);
+            transform: translate(-5px, -5px);
+  }
+}
+</style>

+ 222 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading4.vue

@@ -0,0 +1,222 @@
+<template>
+	 <view class="container loading5">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading5',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+.container.loading5 .shape {
+  width: 15px;
+  height: 15px;
+}
+
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+.loading5 .shape1 {
+  animation: animation5shape1 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+  50% {
+    -webkit-transform: translate(15px, 15px);
+            transform: translate(15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+}
+
+@keyframes animation5shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+  50% {
+    -webkit-transform: translate(15px, 15px);
+            transform: translate(15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+}
+.loading5 .shape2 {
+  animation: animation5shape2 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-15px, 15px);
+            transform: translate(-15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+}
+
+@keyframes animation5shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-15px, 15px);
+            transform: translate(-15px, 15px);
+  }
+  75% {
+    -webkit-transform: translate(0, 15px);
+            transform: translate(0, 15px);
+  }
+}
+.loading5 .shape3 {
+  animation: animation5shape3 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(15px, -15px);
+            transform: translate(15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+}
+
+@keyframes animation5shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(15px, 0);
+            transform: translate(15px, 0);
+  }
+  50% {
+    -webkit-transform: translate(15px, -15px);
+            transform: translate(15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+}
+.loading5 .shape4 {
+  animation: animation5shape4 2s ease 0s infinite reverse;
+}
+
+@-webkit-keyframes animation5shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+  50% {
+    -webkit-transform: translate(-15px, -15px);
+            transform: translate(-15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+}
+
+@keyframes animation5shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -15px);
+            transform: translate(0, -15px);
+  }
+  50% {
+    -webkit-transform: translate(-15px, -15px);
+            transform: translate(-15px, -15px);
+  }
+  75% {
+    -webkit-transform: translate(-15px, 0);
+            transform: translate(-15px, 0);
+  }
+}
+
+</style>

+ 229 - 0
uni_modules/qiun-data-charts/components/qiun-loading/loading5.vue

@@ -0,0 +1,229 @@
+<template>
+	 <view class="container loading6">
+		<view class="shape shape1"></view>
+		<view class="shape shape2"></view>
+		<view class="shape shape3"></view>
+		<view class="shape shape4"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'loading6',
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+<style scoped="true">
+.container {
+  width: 30px;
+  height: 30px;
+  position: relative;
+}
+
+.container.loading6 {
+  -webkit-animation: rotation 1s infinite;
+          animation: rotation 1s infinite;
+}
+.container.loading6 .shape {
+  width: 12px;
+  height: 12px;
+  border-radius: 2px;
+}
+.container .shape {
+  position: absolute;
+  width: 10px;
+  height: 10px;
+  border-radius: 1px;
+}
+.container .shape.shape1 {
+  left: 0;
+  background-color: #1890FF;
+}
+.container .shape.shape2 {
+  right: 0;
+  background-color: #91CB74;
+}
+.container .shape.shape3 {
+  bottom: 0;
+  background-color: #FAC858;
+}
+.container .shape.shape4 {
+  bottom: 0;
+  right: 0;
+  background-color: #EE6666;
+}
+
+
+.loading6 .shape1 {
+  -webkit-animation: animation6shape1 2s linear 0s infinite normal;
+          animation: animation6shape1 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+  50% {
+    -webkit-transform: translate(18px, 18px);
+            transform: translate(18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+}
+
+@keyframes animation6shape1 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+  50% {
+    -webkit-transform: translate(18px, 18px);
+            transform: translate(18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+}
+.loading6 .shape2 {
+  -webkit-animation: animation6shape2 2s linear 0s infinite normal;
+          animation: animation6shape2 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-18px, 18px);
+            transform: translate(-18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+}
+
+@keyframes animation6shape2 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(-18px, 18px);
+            transform: translate(-18px, 18px);
+  }
+  75% {
+    -webkit-transform: translate(0, 18px);
+            transform: translate(0, 18px);
+  }
+}
+.loading6 .shape3 {
+  -webkit-animation: animation6shape3 2s linear 0s infinite normal;
+          animation: animation6shape3 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(18px, -18px);
+            transform: translate(18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+}
+
+@keyframes animation6shape3 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(18px, 0);
+            transform: translate(18px, 0);
+  }
+  50% {
+    -webkit-transform: translate(18px, -18px);
+            transform: translate(18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+}
+.loading6 .shape4 {
+  -webkit-animation: animation6shape4 2s linear 0s infinite normal;
+          animation: animation6shape4 2s linear 0s infinite normal;
+}
+
+@-webkit-keyframes animation6shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+  50% {
+    -webkit-transform: translate(-18px, -18px);
+            transform: translate(-18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+}
+
+@keyframes animation6shape4 {
+  0% {
+    -webkit-transform: translate(0, 0);
+            transform: translate(0, 0);
+  }
+  25% {
+    -webkit-transform: translate(0, -18px);
+            transform: translate(0, -18px);
+  }
+  50% {
+    -webkit-transform: translate(-18px, -18px);
+            transform: translate(-18px, -18px);
+  }
+  75% {
+    -webkit-transform: translate(-18px, 0);
+            transform: translate(-18px, 0);
+  }
+}
+</style>

+ 36 - 0
uni_modules/qiun-data-charts/components/qiun-loading/qiun-loading.vue

@@ -0,0 +1,36 @@
+<template>
+	<view>
+	 <Loading1 v-if="loadingType==1"/>
+	 <Loading2 v-if="loadingType==2"/>
+	 <Loading3 v-if="loadingType==3"/>
+	 <Loading4 v-if="loadingType==4"/>
+	 <Loading5 v-if="loadingType==5"/>
+	</view>
+</template>
+
+<script>
+	import Loading1 from "./loading1.vue";
+	import Loading2 from "./loading2.vue";
+	import Loading3 from "./loading3.vue";
+	import Loading4 from "./loading4.vue";
+	import Loading5 from "./loading5.vue";
+	export default {
+		components:{Loading1,Loading2,Loading3,Loading4,Loading5},
+		name: 'qiun-loading',
+		props: {
+			loadingType: {
+				type: Number,
+				default: 2
+			},
+		},
+		data() {
+			return {
+				
+			};
+		},
+	}
+</script>
+
+<style>
+
+</style>

+ 422 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/config-echarts.js

@@ -0,0 +1,422 @@
+/*
+ * uCharts®
+ * 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360)、Vue、Taro等支持canvas的框架平台
+ * Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
+ * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+ * 复制使用请保留本段注释,感谢支持开源!
+ * 
+ * uCharts®官方网站
+ * https://www.uCharts.cn
+ * 
+ * 开源地址:
+ * https://gitee.com/uCharts/uCharts
+ * 
+ * uni-app插件市场地址:
+ * http://ext.dcloud.net.cn/plugin?id=271
+ * 
+ */
+
+// 通用配置项
+
+// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
+const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
+
+const cfe = {
+  //demotype为自定义图表类型
+	"type": ["pie", "ring", "rose", "funnel", "line", "column", "area", "radar", "gauge","candle","demotype"],
+  //增加自定义图表类型,如果需要categories,请在这里加入您的图表类型例如最后的"demotype"
+	"categories": ["line", "column", "area", "radar", "gauge", "candle","demotype"],
+  //instance为实例变量承载属性,option为eopts承载属性,不要删除
+	"instance": {},
+	"option": {},
+  //下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
+  "formatter":{
+    "tooltipDemo1":function(res){
+      let result = ''
+      for (let i in res) {
+      	if (i == 0) {
+      		result += res[i].axisValueLabel + '年销售额'
+      	}
+      	let value = '--'
+      	if (res[i].data !== null) {
+      		value = res[i].data
+      	}
+      	// #ifdef H5
+      	result += '\n' + res[i].seriesName + ':' + value + ' 万元'
+      	// #endif
+      	
+      	// #ifdef APP-PLUS
+      	result += '<br/>' + res[i].marker + res[i].seriesName + ':' + value + ' 万元'
+      	// #endif
+      }
+      return result;
+    },
+    legendFormat:function(name){
+      return "自定义图例+"+name;
+    },
+    yAxisFormatDemo:function (value, index) {
+      return value + '元';
+    },
+    seriesFormatDemo:function(res){
+      return res.name + '年' + res.value + '元';
+    }
+  },
+  //这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在eopts参数,会将demotype与eopts中option合并后渲染图表。
+  "demotype":{
+    "color": color,
+    //在这里填写echarts的option即可
+    
+  },
+  //下面是自定义配置,请添加项目所需的通用配置
+	"column": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'axis'
+		},
+		"grid": {
+			"top": 30,
+			"bottom": 50,
+			"right": 15,
+			"left": 40
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"toolbox": {
+			"show": false,
+		},
+		"xAxis": {
+			"type": 'category',
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+			"boundaryGap": true,
+			"data": []
+		},
+		"yAxis": {
+			"type": 'value',
+			"axisTick": {
+				"show": false,
+			},
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'bar',
+			"data": [],
+			"barwidth": 20,
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"line": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'axis'
+		},
+		"grid": {
+			"top": 30,
+			"bottom": 50,
+			"right": 15,
+			"left": 40
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"toolbox": {
+			"show": false,
+		},
+		"xAxis": {
+			"type": 'category',
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+			"boundaryGap": true,
+			"data": []
+		},
+		"yAxis": {
+			"type": 'value',
+			"axisTick": {
+				"show": false,
+			},
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'line',
+			"data": [],
+			"barwidth": 20,
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"area": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'axis'
+		},
+		"grid": {
+			"top": 30,
+			"bottom": 50,
+			"right": 15,
+			"left": 40
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"toolbox": {
+			"show": false,
+		},
+		"xAxis": {
+			"type": 'category',
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+			"boundaryGap": true,
+			"data": []
+		},
+		"yAxis": {
+			"type": 'value',
+			"axisTick": {
+				"show": false,
+			},
+			"axisLabel": {
+				"color": '#666666'
+			},
+			"axisLine": {
+				"lineStyle": {
+					"color": '#CCCCCC'
+				}
+			},
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'line',
+			"data": [],
+			"areaStyle": {},
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"pie": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item'
+		},
+		"grid": {
+			"top": 40,
+			"bottom": 30,
+			"right": 15,
+			"left": 15
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'pie',
+			"data": [],
+			"radius": '50%',
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+		},
+	},
+	"ring": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item'
+		},
+		"grid": {
+			"top": 40,
+			"bottom": 30,
+			"right": 15,
+			"left": 15
+		},
+		"legend": {
+			"bottom": 'left',
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'pie',
+			"data": [],
+			"radius": ['40%', '70%'],
+			"avoidLabelOverlap": false,
+			"label": {
+				"show": true,
+        "color": "#666666",
+				"position": 'top',
+			},
+			"labelLine": {
+				"show": true
+			},
+		},
+	},
+	"rose": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item'
+		},
+		"legend": {
+			"top": 'bottom'
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'pie',
+			"data": [],
+			"radius": "55%",
+			"center": ['50%', '50%'],
+			"roseType": 'area',
+		},
+	},
+	"funnel": {
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"tooltip": {
+			"trigger": 'item',
+			"formatter": "{b} : {c}%"
+		},
+		"legend": {
+			"top": 'bottom'
+		},
+		"seriesTemplate": {
+			"name": '',
+			"type": 'funnel',
+			"left": '10%',
+			"top": 60,
+			"bottom": 60,
+			"width": '80%',
+			"min": 0,
+			"max": 100,
+			"minSize": '0%',
+			"maxSize": '100%',
+			"sort": 'descending',
+			"gap": 2,
+			"label": {
+				"show": true,
+				"position": 'inside'
+			},
+			"labelLine": {
+				"length": 10,
+				"lineStyle": {
+					"width": 1,
+					"type": 'solid'
+				}
+			},
+			"itemStyle": {
+				"bordercolor": '#fff',
+				"borderwidth": 1
+			},
+			"emphasis": {
+				"label": {
+					"fontSize": 20
+				}
+			},
+			"data": [],
+		},
+	},
+	"gauge": {
+		"color": color,
+		"tooltip": {
+        "formatter": '{a} <br/>{b} : {c}%'
+    },
+		"seriesTemplate": {
+			"name": '业务指标',
+      "type": 'gauge',
+      "detail": {"formatter": '{value}%'},
+      "data": [{"value": 50, "name": '完成率'}]
+		},
+	},
+	"candle": {
+		"xAxis": {
+			"data": []
+		},
+		"yAxis": {},
+		"color": color,
+		"title": {
+			"text": ''
+		},
+		"dataZoom": [{
+				"type": 'inside',
+				"xAxisIndex": [0, 1],
+				"start": 10,
+				"end": 100
+			},
+			{
+				"show": true,
+				"xAxisIndex": [0, 1],
+				"type": 'slider',
+				"bottom": 10,
+				"start": 10,
+				"end": 100
+			}
+		],
+		"seriesTemplate": {
+			"name": '',
+			"type": 'k',
+			"data": [],
+		},
+	}
+}
+
+export default cfe;

+ 606 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/config-ucharts.js

@@ -0,0 +1,606 @@
+/*
+ * uCharts®
+ * 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360)、Vue、Taro等支持canvas的框架平台
+ * Copyright (c) 2021 QIUN®秋云 https://www.ucharts.cn All rights reserved.
+ * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+ * 复制使用请保留本段注释,感谢支持开源!
+ * 
+ * uCharts®官方网站
+ * https://www.uCharts.cn
+ * 
+ * 开源地址:
+ * https://gitee.com/uCharts/uCharts
+ * 
+ * uni-app插件市场地址:
+ * http://ext.dcloud.net.cn/plugin?id=271
+ * 
+ */
+
+// 主题颜色配置:如每个图表类型需要不同主题,请在对应图表类型上更改color属性
+const color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
+
+//事件转换函数,主要用作格式化x轴为时间轴,根据需求自行修改
+const formatDateTime = (timeStamp, returnType)=>{
+  var date = new Date();
+  date.setTime(timeStamp * 1000);
+  var y = date.getFullYear();
+  var m = date.getMonth() + 1;
+  m = m < 10 ? ('0' + m) : m;
+  var d = date.getDate();
+  d = d < 10 ? ('0' + d) : d;
+  var h = date.getHours();
+  h = h < 10 ? ('0' + h) : h;
+  var minute = date.getMinutes();
+  var second = date.getSeconds();
+  minute = minute < 10 ? ('0' + minute) : minute;
+  second = second < 10 ? ('0' + second) : second;
+  if(returnType == 'full'){return y + '-' + m + '-' + d + ' '+ h +':' + minute + ':' + second;}
+  if(returnType == 'y-m-d'){return y + '-' + m + '-' + d;}
+  if(returnType == 'h:m'){return  h +':' + minute;}
+  if(returnType == 'h:m:s'){return  h +':' + minute +':' + second;}
+  return [y, m, d, h, minute, second];
+}
+
+const cfu = {
+  //demotype为自定义图表类型,一般不需要自定义图表类型,只需要改根节点上对应的类型即可
+	"type":["pie","ring","rose","word","funnel","map","arcbar","line","column","mount","bar","area","radar","gauge","candle","mix","tline","tarea","scatter","bubble","demotype"],
+	"range":["饼状图","圆环图","玫瑰图","词云图","漏斗图","地图","圆弧进度条","折线图","柱状图","山峰图","条状图","区域图","雷达图","仪表盘","K线图","混合图","时间轴折线","时间轴区域","散点图","气泡图","自定义类型"],
+  //增加自定义图表类型,如果需要categories,请在这里加入您的图表类型,例如最后的"demotype"
+  //自定义类型时需要注意"tline","tarea","scatter","bubble"等时间轴(矢量x轴)类图表,没有categories,不需要加入categories
+	"categories":["line","column","mount","bar","area","radar","gauge","candle","mix","demotype"],
+  //instance为实例变量承载属性,不要删除
+  "instance":{},
+  //option为opts及eopts承载属性,不要删除
+  "option":{},
+  //下面是自定义format配置,因除H5端外的其他端无法通过props传递函数,只能通过此属性对应下标的方式来替换
+  "formatter":{
+    "yAxisDemo1":function(val, index, opts){return val+'元'},
+    "yAxisDemo2":function(val, index, opts){return val.toFixed(2)},
+    "xAxisDemo1":function(val, index, opts){return val+'年';},
+    "xAxisDemo2":function(val, index, opts){return formatDateTime(val,'h:m')},
+    "seriesDemo1":function(val, index, series, opts){return val+'元'},
+    "tooltipDemo1":function(item, category, index, opts){
+      if(index==0){
+      	return '随便用'+item.data+'年'
+      }else{
+      	return '其他我没改'+item.data+'天'
+      }
+    },
+    "pieDemo":function(val, index, series, opts){
+      if(index !== undefined){
+        return series[index].name+':'+series[index].data+'元'
+      }
+    },
+  },
+  //这里演示了自定义您的图表类型的option,可以随意命名,之后在组件上 type="demotype" 后,组件会调用这个花括号里的option,如果组件上还存在opts参数,会将demotype与opts中option合并后渲染图表。
+  "demotype":{
+    //我这里把曲线图当做了自定义图表类型,您可以根据需要随意指定类型或配置
+    "type": "line",
+    "color": color,
+    "padding": [15,10,0,15],
+    "xAxis": {
+      "disableGrid": true,
+    },
+    "yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+    },
+    "legend": {
+    },
+    "extra": {
+    	"line": {
+    		"type": "curve",
+    		"width": 2
+    	},
+    }
+  },
+  //下面是自定义配置,请添加项目所需的通用配置
+	"pie":{
+		"type": "pie",
+    "color": color,
+		"padding": [5,5,5,5],
+		"extra": {
+			"pie": {
+				"activeOpacity": 0.5,
+				"activeRadius": 10,
+				"offsetAngle": 0,
+				"labelWidth": 15,
+				"border": true,
+				"borderWidth": 3,
+				"borderColor": "#FFFFFF"
+			},
+		}
+	},
+	"ring":{
+		"type": "ring",
+    "color": color,
+		"padding": [5,5,5,5],
+		"rotate": false,
+		"dataLabel": true,
+		"legend": {
+			"show": true,
+			"position": "right",
+      "lineHeight": 25,
+		},
+		"title": {
+			"name": "收益率",
+			"fontSize": 15,
+			"color": "#666666"
+		},
+		"subtitle": {
+			"name": "70%",
+			"fontSize": 25,
+			"color": "#7cb5ec"
+		},
+		"extra": {
+			"ring": {
+				"ringWidth":30,
+				"activeOpacity": 0.5,
+				"activeRadius": 10,
+				"offsetAngle": 0,
+				"labelWidth": 15,
+				"border": true,
+				"borderWidth": 3,
+				"borderColor": "#FFFFFF"
+			},
+		},
+	},
+	"rose":{
+		"type": "rose",
+    "color": color,
+		"padding": [5,5,5,5],
+		"legend": {
+			"show": true,
+			"position": "left",
+      "lineHeight": 25,
+		},
+		"extra": {
+			"rose": {
+				"type": "area",
+				"minRadius": 50,
+				"activeOpacity": 0.5,
+				"activeRadius": 10,
+				"offsetAngle": 0,
+				"labelWidth": 15,
+				"border": false,
+				"borderWidth": 2,
+				"borderColor": "#FFFFFF"
+			},
+		}
+	},
+	"word":{
+		"type": "word",
+    "color": color,
+		"extra": {
+			"word": {
+				"type": "normal",
+				"autoColors": false
+			}
+		}
+	},
+	"funnel":{
+		"type": "funnel",
+    "color": color,
+		"padding": [15,15,0,15],
+		"extra": {
+			"funnel": {
+				"activeOpacity": 0.3,
+				"activeWidth": 10,
+				"border": true,
+				"borderWidth": 2,
+				"borderColor": "#FFFFFF",
+				"fillOpacity": 1,
+				"labelAlign": "right"
+			},
+		}
+	},
+	"map":{
+		"type": "map",
+    "color": color,
+		"padding": [0,0,0,0],
+    "dataLabel": true,
+		"extra": {
+			"map": {
+				"border": true,
+				"borderWidth": 1,
+				"borderColor": "#666666",
+				"fillOpacity": 0.6,
+				"activeBorderColor": "#F04864",
+				"activeFillColor": "#FACC14",
+				"activeFillOpacity": 1
+			},
+		}
+	},
+	"arcbar":{
+		"type": "arcbar",
+    "color": color,
+		"title": {
+			"name": "百分比",
+			"fontSize": 25,
+			"color": "#00FF00"
+		},
+		"subtitle": {
+			"name": "默认标题",
+			"fontSize": 15,
+			"color": "#666666"
+		},
+		"extra": {
+			"arcbar": {
+				"type": "default",
+				"width": 12,
+				"backgroundColor": "#E9E9E9",
+				"startAngle": 0.75,
+				"endAngle": 0.25,
+				"gap": 2
+			}
+		}
+	},
+	"line":{
+		"type": "line",
+    "color": color,
+		"padding": [15,10,0,15],
+		"xAxis": {
+      "disableGrid": true,
+		},
+		"yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+		},
+		"legend": {
+		},
+		"extra": {
+			"line": {
+				"type": "straight",
+				"width": 2,
+        "activeType": "hollow"
+			},
+		}
+	},
+  "tline":{
+  	"type": "line",
+    "color": color,
+  	"padding": [15,10,0,15],
+  	"xAxis": {
+      "disableGrid": false,
+      "boundaryGap":"justify",
+  	},
+  	"yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+      "data":[
+        {
+          "min":0,
+          "max":80
+        }
+      ]
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"line": {
+  			"type": "curve",
+  			"width": 2,
+        "activeType": "hollow"
+  		},
+  	}
+  },
+  "tarea":{
+  	"type": "area",
+    "color": color,
+  	"padding": [15,10,0,15],
+  	"xAxis": {
+      "disableGrid": true,
+      "boundaryGap":"justify",
+  	},
+  	"yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+      "data":[
+        {
+          "min":0,
+          "max":80
+        }
+      ]
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"area": {
+  			"type": "curve",
+  			"opacity": 0.2,
+  			"addLine": true,
+  			"width": 2,
+  			"gradient": true,
+        "activeType": "hollow"
+  		},
+  	}
+  },
+	"column":{
+		"type": "column",
+    "color": color,
+		"padding": [15,15,0,5],
+		"xAxis": {
+      "disableGrid": true,
+		},
+		"yAxis": {
+      "data":[{"min":0}]
+		},
+		"legend": {
+		},
+		"extra": {
+			"column": {
+				"type": "group",
+				"width": 30,
+				"activeBgColor": "#000000",
+				"activeBgOpacity": 0.08
+			},
+		}
+	},
+  "mount":{
+  	"type": "mount",
+    "color": color,
+  	"padding": [15,15,0,5],
+  	"xAxis": {
+      "disableGrid": true,
+  	},
+  	"yAxis": {
+      "data":[{"min":0}]
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"mount": {
+  			"type": "mount",
+  			"widthRatio": 1.5,
+  		},
+  	}
+  },
+  "bar":{
+  	"type": "bar",
+    "color": color,
+  	"padding": [15,30,0,5],
+  	"xAxis": {
+      "boundaryGap":"justify",
+      "disableGrid":false,
+      "min":0,
+      "axisLine":false
+  	},
+  	"yAxis": {
+  	},
+  	"legend": {
+  	},
+  	"extra": {
+  		"bar": {
+  			"type": "group",
+  			"width": 30,
+  			"meterBorde": 1,
+  			"meterFillColor": "#FFFFFF",
+  			"activeBgColor": "#000000",
+  			"activeBgOpacity": 0.08
+  		},
+  	}
+  },
+	"area":{
+		"type": "area",
+		"color": color,
+		"padding": [15,15,0,15],
+		"xAxis": {
+      "disableGrid": true,
+		},
+		"yAxis": {
+      "gridType": "dash",
+      "dashLength": 2,
+		},
+		"legend": {
+		},
+		"extra": {
+			"area": {
+				"type": "straight",
+				"opacity": 0.2,
+				"addLine": true,
+				"width": 2,
+				"gradient": false,
+        "activeType": "hollow"
+			},
+		}
+	},
+	"radar":{
+		"type": "radar",
+		"color": color,
+		"padding": [5,5,5,5],
+    "dataLabel": false,
+		"legend": {
+			"show": true,
+			"position": "right",
+      "lineHeight": 25,
+		},
+		"extra": {
+			"radar": {
+				"gridType": "radar",
+				"gridColor": "#CCCCCC",
+				"gridCount": 3,
+				"opacity": 0.2,
+				"max": 200,
+				"labelShow": true
+			},
+		}
+	},
+	"gauge":{
+		"type": "gauge",
+		"color": color,
+		"title": {
+			"name": "66Km/H",
+			"fontSize": 25,
+			"color": "#2fc25b",
+			"offsetY": 50
+		},
+		"subtitle": {
+			"name": "实时速度",
+			"fontSize": 15,
+			"color": "#1890ff",
+			"offsetY": -50
+		},
+		"extra": {
+			"gauge": {
+				"type": "default",
+				"width": 30,
+				"labelColor": "#666666",
+				"startAngle": 0.75,
+				"endAngle": 0.25,
+				"startNumber": 0,
+				"endNumber": 100,
+				"labelFormat": "",
+				"splitLine": {
+					"fixRadius": 0,
+					"splitNumber": 10,
+					"width": 30,
+					"color": "#FFFFFF",
+					"childNumber": 5,
+					"childWidth": 12
+				},
+				"pointer": {
+					"width": 24,
+					"color": "auto"
+				}
+			}
+		}
+	},
+	"candle":{
+		"type": "candle",
+		"color": color,
+		"padding": [15,15,0,15],
+		"enableScroll": true,
+		"enableMarkLine": true,
+		"dataLabel": false,
+		"xAxis": {
+			"labelCount": 4,
+			"itemCount": 40,
+			"disableGrid": true,
+			"gridColor": "#CCCCCC",
+			"gridType": "solid",
+			"dashLength": 4,
+			"scrollShow": true,
+			"scrollAlign": "left",
+			"scrollColor": "#A6A6A6",
+			"scrollBackgroundColor": "#EFEBEF"
+		},
+		"yAxis": {
+		},
+		"legend": {
+		},
+		"extra": {
+			"candle": {
+				"color": {
+					"upLine": "#f04864",
+					"upFill": "#f04864",
+					"downLine": "#2fc25b",
+					"downFill": "#2fc25b"
+				},
+				"average": {
+					"show": true,
+					"name": ["MA5","MA10","MA30"],
+					"day": [5,10,20],
+					"color": ["#1890ff","#2fc25b","#facc14"]
+				}
+			},
+			"markLine": {
+				"type": "dash",
+				"dashLength": 5,
+				"data": [
+					{
+						"value": 2150,
+						"lineColor": "#f04864",
+						"showLabel": true
+					},
+					{
+						"value": 2350,
+						"lineColor": "#f04864",
+						"showLabel": true
+					}
+				]
+			}
+		}
+	},
+	"mix":{
+		"type": "mix",
+		"color": color,
+		"padding": [15,15,0,15],
+		"xAxis": {
+      "disableGrid": true,
+		},
+		"yAxis": {
+			"disabled": false,
+			"disableGrid": false,
+			"splitNumber": 5,
+			"gridType": "dash",
+			"dashLength": 4,
+			"gridColor": "#CCCCCC",
+			"padding": 10,
+			"showTitle": true,
+			"data": []
+		},
+		"legend": {
+		},
+		"extra": {
+			"mix": {
+				"column": {
+					"width": 20
+				}
+			},
+		}
+	},
+	"scatter":{
+		"type": "scatter",
+		"color":color,
+		"padding":[15,15,0,15],
+    "dataLabel":false,
+    "xAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+      "splitNumber":5,
+      "boundaryGap":"justify",
+      "min":0
+    },
+    "yAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+    },
+    "legend": {
+    },
+    "extra": {
+    	"scatter": {
+    	},
+    }
+	},
+	"bubble":{
+		"type": "bubble",
+		"color":color,
+		"padding":[15,15,0,15],
+    "xAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+      "splitNumber":5,
+      "boundaryGap":"justify",
+      "min":0,
+      "max":250
+    },
+    "yAxis": {
+      "disableGrid": false,
+      "gridType":"dash",
+      "data":[{
+        "min":0,
+        "max":150
+      }]
+    },
+    "legend": {
+    },
+    "extra": {
+    	"bubble": {
+        "border":2,
+        "opacity": 0.5,
+    	},
+    }
+	}
+}
+
+export default cfu;

+ 5 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/readme.md

@@ -0,0 +1,5 @@
+# uCharts JSSDK说明
+1、如不使用uCharts组件,可直接引用u-charts.js,打包编译后会`自动压缩`,压缩后体积约为`120kb`。
+2、如果120kb的体积仍需压缩,请手到uCharts官网通过在线定制选择您需要的图表。
+3、config-ucharts.js为uCharts组件的用户配置文件,升级前请`自行备份config-ucharts.js`文件,以免被强制覆盖。
+4、config-echarts.js为ECharts组件的用户配置文件,升级前请`自行备份config-echarts.js`文件,以免被强制覆盖。

+ 7706 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.js

@@ -0,0 +1,7706 @@
+/*
+ * uCharts (R)
+ * 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360/快手)、Vue、Taro等支持canvas的框架平台
+ * Copyright (C) 2018-2022 QIUN (R) 秋云 https://www.ucharts.cn All rights reserved.
+ * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
+ * 复制使用请保留本段注释,感谢支持开源!
+ * 
+ * uCharts (R) 官方网站
+ * https://www.uCharts.cn
+ * 
+ * 开源地址:
+ * https://gitee.com/uCharts/uCharts
+ * 
+ * uni-app插件市场地址:
+ * http://ext.dcloud.net.cn/plugin?id=271
+ * 
+ */
+
+'use strict';
+
+var config = {
+  version: 'v2.5.0-20230101',
+  yAxisWidth: 15,
+  xAxisHeight: 22,
+  padding: [10, 10, 10, 10],
+  rotate: false,
+  fontSize: 13,
+  fontColor: '#666666',
+  dataPointShape: ['circle', 'circle', 'circle', 'circle'],
+  color: ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'],
+  linearColor: ['#0EE2F8', '#2BDCA8', '#FA7D8D', '#EB88E2', '#2AE3A0', '#0EE2F8', '#EB88E2', '#6773E3', '#F78A85'],
+  pieChartLinePadding: 15,
+  pieChartTextPadding: 5,
+  titleFontSize: 20,
+  subtitleFontSize: 15,
+  radarLabelTextMargin: 13,
+};
+
+var assign = function(target, ...varArgs) {
+  if (target == null) {
+    throw new TypeError('[uCharts] Cannot convert undefined or null to object');
+  }
+  if (!varArgs || varArgs.length <= 0) {
+    return target;
+  }
+  // 深度合并对象
+  function deepAssign(obj1, obj2) {
+    for (let key in obj2) {
+      obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" ?
+        deepAssign(obj1[key], obj2[key]) : obj1[key] = obj2[key];
+    }
+    return obj1;
+  }
+  varArgs.forEach(val => {
+    target = deepAssign(target, val);
+  });
+  return target;
+};
+
+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;
+  }
+};
+
+//兼容H5点击事件
+function getH5Offset(e) {
+  e.mp = {
+    changedTouches: []
+  };
+  e.mp.changedTouches.push({
+    x: e.offsetX,
+    y: e.offsetY
+  });
+  return e;
+}
+
+// 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('[uCharts] series数据需为Number格式');
+  }
+  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') {
+      if (num == num + 1) { //修复数据值过大num++无效的bug by 向日葵 @xrk_jy
+        break;
+      }
+      num++;
+    } else {
+      num--;
+    }
+  }
+  return num / multiple;
+}
+
+function calCandleMA(dayArr, nameArr, colorArr, kdata) {
+  let seriesTemp = [];
+  for (let k = 0; k < dayArr.length; k++) {
+    let seriesItem = {
+      data: [],
+      name: nameArr[k],
+      color: colorArr[k]
+    };
+    for (let i = 0, len = kdata.length; i < len; i++) {
+      if (i < dayArr[k]) {
+        seriesItem.data.push(null);
+        continue;
+      }
+      let sum = 0;
+      for (let j = 0; j < dayArr[k]; j++) {
+        sum += kdata[i - j][1];
+      }
+      seriesItem.data.push(+(sum / dayArr[k]).toFixed(3));
+    }
+    seriesTemp.push(seriesItem);
+  }
+  return seriesTemp;
+}
+
+function calValidDistance(self, distance, chartData, config, opts) {
+  var dataChartAreaWidth = opts.width - opts.area[1] - opts.area[3];
+  var dataChartWidth = chartData.eachSpacing * (opts.chartData.xAxisData.xAxisPoints.length - 1);
+  if(opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount.widthRatio > 1){
+    if(opts.extra.mount.widthRatio>2) opts.extra.mount.widthRatio = 2
+    dataChartWidth += (opts.extra.mount.widthRatio - 1)*chartData.eachSpacing;
+  }
+  var validDistance = distance;
+  if (distance >= 0) {
+    validDistance = 0;
+    self.uevent.trigger('scrollLeft');
+    self.scrollOption.position = 'left'
+    opts.xAxis.scrollPosition = 'left';
+  } else if (Math.abs(distance) >= dataChartWidth - dataChartAreaWidth) {
+    validDistance = dataChartAreaWidth - dataChartWidth;
+    self.uevent.trigger('scrollRight');
+    self.scrollOption.position = 'right'
+    opts.xAxis.scrollPosition = 'right';
+  } else {
+    self.scrollOption.position = distance
+    opts.xAxis.scrollPosition = distance;
+  }
+  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 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;
+    }
+  }
+  function isNotMiddlePointX(points, i) {
+    if (points[i - 1] && points[i + 1]) {
+      return points[i].x >= Math.max(points[i - 1].x, points[i + 1].x) || points[i].x <= Math.min(points[i - 1].x,
+        points[i + 1].x);
+    } 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;
+  }
+  if (isNotMiddlePoint(points, i + 1)) {
+    pBy = points[i + 1].y;
+  }
+  if (isNotMiddlePoint(points, i)) {
+    pAy = points[i].y;
+  }
+  if (isNotMiddlePointX(points, i + 1)) {
+    pBx = points[i + 1].x;
+  }
+  if (isNotMiddlePointX(points, i)) {
+    pAx = points[i].x;
+  }
+  if (pAy >= Math.max(points[i].y, points[i + 1].y) || pAy <= Math.min(points[i].y, points[i + 1].y)) {
+    pAy = points[i].y;
+  }
+  if (pBy >= Math.max(points[i].y, points[i + 1].y) || pBy <= Math.min(points[i].y, points[i + 1].y)) {
+    pBy = points[i + 1].y;
+  }
+  if (pAx >= Math.max(points[i].x, points[i + 1].x) || pAx <= Math.min(points[i].x, points[i + 1].x)) {
+    pAx = points[i].x;
+  }
+  if (pBx >= Math.max(points[i].x, points[i + 1].x) || pBx <= Math.min(points[i].x, points[i + 1].x)) {
+    pBx = points[i + 1].x;
+  }
+  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 fixPieSeries(series, opts, config){
+  let pieSeriesArr = [];
+  if(series.length>0 && series[0].data.constructor.toString().indexOf('Array') > -1){
+    opts._pieSeries_ = series;
+    let oldseries = series[0].data;
+    for (var i = 0; i < oldseries.length; i++) {
+      oldseries[i].formatter = series[0].formatter;
+      oldseries[i].data = oldseries[i].value;
+      pieSeriesArr.push(oldseries[i]);
+    }
+    opts.series = pieSeriesArr;
+  }else{
+    pieSeriesArr = series;
+  }
+  return pieSeriesArr;
+}
+
+function fillSeries(series, opts, config) {
+  var index = 0;
+  for (var i = 0; i < series.length; i++) {
+    let item = series[i];
+    if (!item.color) {
+      item.color = config.color[index];
+      index = (index + 1) % config.color.length;
+    }
+    if (!item.linearIndex) {
+      item.linearIndex = i;
+    }
+    if (!item.index) {
+      item.index = 0;
+    }
+    if (!item.type) {
+      item.type = opts.type;
+    }
+    if (typeof item.show == "undefined") {
+      item.show = true;
+    }
+    if (!item.type) {
+      item.type = opts.type;
+    }
+    if (!item.pointShape) {
+      item.pointShape = "circle";
+    }
+    if (!item.legendShape) {
+      switch (item.type) {
+        case 'line':
+          item.legendShape = "line";
+          break;
+        case 'column':
+        case 'bar':
+          item.legendShape = "rect";
+          break;
+        case 'area':
+        case 'mount':
+          item.legendShape = "triangle";
+          break;
+        default:
+          item.legendShape = "circle";
+      }
+    }
+  }
+  return series;
+}
+
+function fillCustomColor(linearType, customColor, series, config) {
+  var newcolor = customColor || [];
+  if (linearType == 'custom' && newcolor.length == 0 ) {
+    newcolor = config.linearColor;
+  }
+  if (linearType == 'custom' && newcolor.length < series.length) {
+    let chazhi = series.length - newcolor.length;
+    for (var i = 0; i < chazhi; i++) {
+      newcolor.push(config.linearColor[(i + 1) % config.linearColor.length]);
+    }
+  }
+  return newcolor;
+}
+
+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 if (range >= 0.01) {
+    limit = 0.01;
+  } else if (range >= 0.001) {
+    limit = 0.001;
+  } else if (range >= 0.0001) {
+    limit = 0.0001;
+  } else if (range >= 0.00001) {
+    limit = 0.00001;
+  } else {
+    limit = 0.000001;
+  }
+  return {
+    minRange: findRange(minData, 'lower', limit),
+    maxRange: findRange(maxData, 'upper', limit)
+  };
+}
+
+function measureText(text, fontSize, context) {
+  var width = 0;
+  text = String(text);
+  // #ifdef MP-ALIPAY || MP-BAIDU || APP-NVUE
+  context = false;
+  // #endif
+  if (context !== false && context !== undefined && context.setFontSize && context.measureText) {
+    context.setFontSize(fontSize);
+    return context.measureText(text).width;
+  } else {
+    var text = text.split('');
+    for (let i = 0; i < text.length; i++) {
+      let item = text[i];
+      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 (/:/.test(item)) {
+        width += 2.5;
+      } 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, len) {
+  var sum = new Array(len);
+  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.pix;
+      x = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pix / 2) * (opts.pix - 1)) * opts.pix;
+    } else {
+      x = touches.clientX * opts.pix;
+      y = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pix / 2) * (opts.pix - 1)) * opts.pix;
+    }
+  } else {
+    if (opts.rotate) {
+      y = opts.height - touches.x * opts.pix;
+      x = touches.y * opts.pix;
+    } else {
+      x = touches.x * opts.pix;
+      y = touches.y * opts.pix;
+    }
+  }
+  return {
+    x: x,
+    y: y
+  }
+}
+
+function getSeriesDataItem(series, index, group) {
+  var data = [];
+  var newSeries = [];
+  var indexIsArr = index.constructor.toString().indexOf('Array') > -1;
+  if(indexIsArr){
+    let tempSeries = filterSeries(series);
+    for (var i = 0; i < group.length; i++) {
+      newSeries.push(tempSeries[group[i]]);
+    }
+  }else{
+    newSeries = series;
+  };
+  for (let i = 0; i < newSeries.length; i++) {
+    let item = newSeries[i];
+    let tmpindex = -1;
+    if(indexIsArr){
+      tmpindex = index[i];
+    }else{
+      tmpindex = index;
+    }
+    if (item.data[tmpindex] !== null && typeof item.data[tmpindex] !== 'undefined' && item.show) {
+      let seriesItem = {};
+      seriesItem.color = item.color;
+      seriesItem.type = item.type;
+      seriesItem.style = item.style;
+      seriesItem.pointShape = item.pointShape;
+      seriesItem.disableLegend = item.disableLegend;
+      seriesItem.legendShape = item.legendShape;
+      seriesItem.name = item.name;
+      seriesItem.show = item.show;
+      seriesItem.data = item.formatter ? item.formatter(item.data[tmpindex]) : item.data[tmpindex];
+      data.push(seriesItem);
+    }
+  }
+  return data;
+}
+
+function getMaxTextListLength(list, fontSize, context) {
+  var lengthList = list.map(function(item) {
+    return measureText(item, fontSize, context);
+  });
+  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, opts, index, group, categories) {
+  var option = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
+  var calPoints = opts.chartData.calPoints?opts.chartData.calPoints:[];
+  let points = {};
+  if(group.length > 0){
+    let filterPoints = [];
+    for (let i = 0; i < group.length; i++) {
+      filterPoints.push(calPoints[group[i]])
+    }
+    points = filterPoints[0][index[0]];
+  }else{
+    for (let i = 0; i < calPoints.length; i++) {
+      if(calPoints[i][index]){
+        points = calPoints[i][index];
+        break;
+      }
+    }
+  };
+  var textList = seriesData.map(function(item) {
+    let titleText = null;
+    if (opts.categories && opts.categories.length>0) {
+      titleText = categories[index];
+    };
+    return {
+      text: option.formatter ? option.formatter(item, titleText, index, opts) : item.name + ': ' + item.data,
+      color: item.color,
+      legendShape: opts.extra.tooltip.legendShape == 'auto'? item.legendShape : opts.extra.tooltip.legendShape
+    };
+  });
+  var offset = {
+    x: Math.round(points.x),
+    y: Math.round(points.y)
+  };
+  return {
+    textList: textList,
+    offset: offset
+  };
+}
+
+function getMixToolTipData(seriesData, opts, index, categories) {
+  var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
+  var points = opts.chartData.xAxisPoints[index] + opts.chartData.eachSpacing / 2;
+  var textList = seriesData.map(function(item) {
+    return {
+      text: option.formatter ? option.formatter(item, categories[index], index, opts) : item.name + ': ' + item.data,
+      color: item.color,
+      disableLegend: item.disableLegend ? true : false,
+      legendShape: opts.extra.tooltip.legendShape == 'auto'? item.legendShape : opts.extra.tooltip.legendShape
+    };
+  });
+  textList = textList.filter(function(item) {
+    if (item.disableLegend !== true) {
+      return item;
+    }
+  });
+  var offset = {
+    x: Math.round(points),
+    y: 0
+  };
+  return {
+    textList: textList,
+    offset: offset
+  };
+}
+
+function getCandleToolTipData(series, seriesData, opts, index, categories, extra) {
+  var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
+  var calPoints = opts.chartData.calPoints;
+  let upColor = extra.color.upFill;
+  let downColor = extra.color.downFill;
+  //颜色顺序为开盘,收盘,最低,最高
+  let color = [upColor, upColor, downColor, upColor];
+  var textList = [];
+  seriesData.map(function(item) {
+    if (index == 0) {
+      if (item.data[1] - item.data[0] < 0) {
+        color[1] = downColor;
+      } else {
+        color[1] = upColor;
+      }
+    } else {
+      if (item.data[0] < series[index - 1][1]) {
+        color[0] = downColor;
+      }
+      if (item.data[1] < item.data[0]) {
+        color[1] = downColor;
+      }
+      if (item.data[2] > series[index - 1][1]) {
+        color[2] = upColor;
+      }
+      if (item.data[3] < series[index - 1][1]) {
+        color[3] = downColor;
+      }
+    }
+    let text1 = {
+      text: '开盘:' + item.data[0],
+      color: color[0],
+      legendShape: opts.extra.tooltip.legendShape == 'auto'? item.legendShape : opts.extra.tooltip.legendShape
+    };
+    let text2 = {
+      text: '收盘:' + item.data[1],
+      color: color[1],
+      legendShape: opts.extra.tooltip.legendShape == 'auto'? item.legendShape : opts.extra.tooltip.legendShape
+    };
+    let text3 = {
+      text: '最低:' + item.data[2],
+      color: color[2],
+      legendShape: opts.extra.tooltip.legendShape == 'auto'? item.legendShape : opts.extra.tooltip.legendShape
+    };
+    let text4 = {
+      text: '最高:' + item.data[3],
+      color: color[3],
+      legendShape: opts.extra.tooltip.legendShape == 'auto'? item.legendShape : opts.extra.tooltip.legendShape
+    };
+    textList.push(text1, text2, text3, text4);
+  });
+  var validCalPoints = [];
+  var offset = {
+    x: 0,
+    y: 0
+  };
+  for (let i = 0; i < calPoints.length; i++) {
+    let points = calPoints[i];
+    if (typeof points[index] !== 'undefined' && points[index] !== null) {
+      validCalPoints.push(points[index]);
+    }
+  }
+  offset.x = Math.round(validCalPoints[0][0].x);
+  return {
+    textList: textList,
+    offset: offset
+  };
+}
+
+function filterSeries(series) {
+  let tempSeries = [];
+  for (let i = 0; i < series.length; i++) {
+    if (series[i].show == true) {
+      tempSeries.push(series[i])
+    }
+  }
+  return tempSeries;
+}
+
+function findCurrentIndex(currentPoints, calPoints, opts, config) {
+  var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
+  var current={ index:-1, group:[] };
+  var spacing = opts.chartData.eachSpacing / 2;
+  let xAxisPoints = [];
+  if (calPoints && calPoints.length > 0) {
+    if (!opts.categories) {
+      spacing = 0;
+    }else{
+      for (let i = 1; i < opts.chartData.xAxisPoints.length; i++) {
+        xAxisPoints.push(opts.chartData.xAxisPoints[i] - spacing);
+      }
+      if ((opts.type == 'line' || opts.type == 'area') && opts.xAxis.boundaryGap == 'justify') {
+        xAxisPoints = opts.chartData.xAxisPoints;
+      }
+    }
+    if (isInExactChartArea(currentPoints, opts, config)) {
+      if (!opts.categories) {
+        let timePoints = Array(calPoints.length);
+        for (let i = 0; i < calPoints.length; i++) {
+          timePoints[i] = Array(calPoints[i].length)
+          for (let j = 0; j < calPoints[i].length; j++) {
+            timePoints[i][j] = (Math.abs(calPoints[i][j].x - currentPoints.x));
+          }
+        };
+        let pointValue =  Array(timePoints.length);
+        let pointIndex =  Array(timePoints.length);
+        for (let i = 0; i < timePoints.length; i++) {
+          pointValue[i] = Math.min.apply(null, timePoints[i]);
+          pointIndex[i] = timePoints[i].indexOf(pointValue[i]);
+        }
+        let minValue = Math.min.apply(null, pointValue);
+        current.index = [];
+        for (let i = 0; i < pointValue.length; i++) {
+          if(pointValue[i] == minValue){
+            current.group.push(i);
+            current.index.push(pointIndex[i]);
+          }
+        };
+      }else{
+        xAxisPoints.forEach(function(item, index) {
+          if (currentPoints.x + offset + spacing > item) {
+            current.index = index;
+          }
+        });
+      }
+    }
+  }
+  return current;
+}
+
+function findBarChartCurrentIndex(currentPoints, calPoints, opts, config) {
+  var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
+  var current={ index:-1, group:[] };
+  var spacing = opts.chartData.eachSpacing / 2;
+  let yAxisPoints = opts.chartData.yAxisPoints;
+  if (calPoints && calPoints.length > 0) {
+    if (isInExactChartArea(currentPoints, opts, config)) {
+      yAxisPoints.forEach(function(item, index) {
+        if (currentPoints.y + offset + spacing > item) {
+          current.index = index;
+        }
+      });
+    }
+  }
+  return current;
+}
+
+function findLegendIndex(currentPoints, legendData, opts) {
+  let currentIndex = -1;
+  let gap = 0;
+  if (isInExactLegendArea(currentPoints, legendData.area)) {
+    let points = legendData.points;
+    let index = -1;
+    for (let i = 0, len = points.length; i < len; i++) {
+      let item = points[i];
+      for (let j = 0; j < item.length; j++) {
+        index += 1;
+        let area = item[j]['area'];
+        if (area && currentPoints.x > area[0] - gap && currentPoints.x < area[2] + gap && currentPoints.y > area[1] - gap && currentPoints.y < area[3] + gap) {
+          currentIndex = index;
+          break;
+        }
+      }
+    }
+    return currentIndex;
+  }
+  return currentIndex;
+}
+
+function isInExactLegendArea(currentPoints, area) {
+  return currentPoints.x > area.start.x && currentPoints.x < area.end.x && currentPoints.y > area.start.y && currentPoints.y < area.end.y;
+}
+
+function isInExactChartArea(currentPoints, opts, config) {
+  return currentPoints.x <= opts.width - opts.area[1] + 10 && currentPoints.x >= opts.area[3] - 10 && currentPoints.y >= opts.area[0] && currentPoints.y <= opts.height - opts.area[2];
+}
+
+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 findFunnelChartCurrentIndex(currentPoints, funnelData) {
+  var currentIndex = -1;
+  for (var i = 0, len = funnelData.series.length; i < len; i++) {
+    var item = funnelData.series[i];
+    if (currentPoints.x > item.funnelArea[0] && currentPoints.x < item.funnelArea[2] && currentPoints.y > item.funnelArea[1] && currentPoints.y < item.funnelArea[3]) {
+      currentIndex = i;
+      break;
+    }
+  }
+  return currentIndex;
+}
+
+function findWordChartCurrentIndex(currentPoints, wordData) {
+  var currentIndex = -1;
+  for (var i = 0, len = wordData.length; i < len; i++) {
+    var item = wordData[i];
+    if (currentPoints.x > item.area[0] && currentPoints.x < item.area[2] && currentPoints.y > item.area[1] && currentPoints.y < item.area[3]) {
+      currentIndex = i;
+      break;
+    }
+  }
+  return currentIndex;
+}
+
+function findMapChartCurrentIndex(currentPoints, opts) {
+  var currentIndex = -1;
+  var cData = opts.chartData.mapData;
+  var data = opts.series;
+  var tmp = pointToCoordinate(currentPoints.y, currentPoints.x, cData.bounds, cData.scale, cData.xoffset, cData.yoffset);
+  var poi = [tmp.x, tmp.y];
+  for (var i = 0, len = data.length; i < len; i++) {
+    var item = data[i].geometry.coordinates;
+    if (isPoiWithinPoly(poi, item, opts.chartData.mapData.mercator)) {
+      currentIndex = i;
+      break;
+    }
+  }
+  return currentIndex;
+}
+
+function findRoseChartCurrentIndex(currentPoints, pieData, opts) {
+  var currentIndex = -1;
+  var series = getRoseDataPoints(opts._series_, opts.extra.rose.type, pieData.radius, pieData.radius);
+  if (pieData && pieData.center && isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) {
+    var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x);
+    angle = -angle;
+    if(opts.extra.rose && opts.extra.rose.offsetAngle){
+      angle = angle - opts.extra.rose.offsetAngle * Math.PI / 180;
+    }
+    for (var i = 0, len = series.length; i < len; i++) {
+      if (isInAngleRange(angle, series[i]._start_, series[i]._start_ + series[i]._rose_proportion_ * 2 * Math.PI)) {
+        currentIndex = i;
+        break;
+      }
+    }
+  }
+  return currentIndex;
+}
+
+function findPieChartCurrentIndex(currentPoints, pieData, opts) {
+  var currentIndex = -1;
+  var series = getPieDataPoints(pieData.series);
+  if (pieData && pieData.center && isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) {
+    var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x);
+    angle = -angle;
+    if(opts.extra.pie && opts.extra.pie.offsetAngle){
+      angle = angle - opts.extra.pie.offsetAngle * Math.PI / 180;
+    }
+    if(opts.extra.ring && opts.extra.ring.offsetAngle){
+      angle = angle - opts.extra.ring.offsetAngle * Math.PI / 180;
+    }
+    for (var i = 0, len = series.length; i < len; i++) {
+      if (isInAngleRange(angle, series[i]._start_, series[i]._start_ + series[i]._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,eachSeries) {
+  var newPoints = [];
+  var items = [];
+  points.forEach(function(item, index) {
+    if(eachSeries.connectNulls){
+      if (item !== null) {
+        items.push(item);
+      }
+    }else{
+      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, chartData, context) {
+  let legendData = {
+    area: {
+      start: {
+        x: 0,
+        y: 0
+      },
+      end: {
+        x: 0,
+        y: 0
+      },
+      width: 0,
+      height: 0,
+      wholeWidth: 0,
+      wholeHeight: 0
+    },
+    points: [],
+    widthArr: [],
+    heightArr: []
+  };
+  if (opts.legend.show === false) {
+    chartData.legendData = legendData;
+    return legendData;
+  }
+  let padding = opts.legend.padding * opts.pix;
+  let margin = opts.legend.margin * opts.pix;
+  let fontSize = opts.legend.fontSize ? opts.legend.fontSize * opts.pix : config.fontSize;
+  let shapeWidth = 15 * opts.pix;
+  let shapeRight = 5 * opts.pix;
+  let lineHeight = Math.max(opts.legend.lineHeight * opts.pix, fontSize);
+  if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
+    let legendList = [];
+    let widthCount = 0;
+    let widthCountArr = [];
+    let currentRow = [];
+    for (let i = 0; i < series.length; i++) {
+      let item = series[i];
+      const legendText = item.legendText ? item.legendText : item.name;
+      let itemWidth = shapeWidth + shapeRight + measureText(legendText || 'undefined', fontSize, context) + opts.legend.itemGap * opts.pix;
+      if (widthCount + itemWidth > opts.width - opts.area[1] - opts.area[3]) {
+        legendList.push(currentRow);
+        widthCountArr.push(widthCount - opts.legend.itemGap * opts.pix);
+        widthCount = itemWidth;
+        currentRow = [item];
+      } else {
+        widthCount += itemWidth;
+        currentRow.push(item);
+      }
+    }
+    if (currentRow.length) {
+      legendList.push(currentRow);
+      widthCountArr.push(widthCount - opts.legend.itemGap * opts.pix);
+      legendData.widthArr = widthCountArr;
+      let legendWidth = Math.max.apply(null, widthCountArr);
+      switch (opts.legend.float) {
+        case 'left':
+          legendData.area.start.x = opts.area[3];
+          legendData.area.end.x = opts.area[3] + legendWidth + 2 * padding;
+          break;
+        case 'right':
+          legendData.area.start.x = opts.width - opts.area[1] - legendWidth - 2 * padding;
+          legendData.area.end.x = opts.width - opts.area[1];
+          break;
+        default:
+          legendData.area.start.x = (opts.width - legendWidth) / 2 - padding;
+          legendData.area.end.x = (opts.width + legendWidth) / 2 + padding;
+      }
+      legendData.area.width = legendWidth + 2 * padding;
+      legendData.area.wholeWidth = legendWidth + 2 * padding;
+      legendData.area.height = legendList.length * lineHeight + 2 * padding;
+      legendData.area.wholeHeight = legendList.length * lineHeight + 2 * padding + 2 * margin;
+      legendData.points = legendList;
+    }
+  } else {
+    let len = series.length;
+    let maxHeight = opts.height - opts.area[0] - opts.area[2] - 2 * margin - 2 * padding;
+    let maxLength = Math.min(Math.floor(maxHeight / lineHeight), len);
+    legendData.area.height = maxLength * lineHeight + padding * 2;
+    legendData.area.wholeHeight = maxLength * lineHeight + padding * 2;
+    switch (opts.legend.float) {
+      case 'top':
+        legendData.area.start.y = opts.area[0] + margin;
+        legendData.area.end.y = opts.area[0] + margin + legendData.area.height;
+        break;
+      case 'bottom':
+        legendData.area.start.y = opts.height - opts.area[2] - margin - legendData.area.height;
+        legendData.area.end.y = opts.height - opts.area[2] - margin;
+        break;
+      default:
+        legendData.area.start.y = (opts.height - legendData.area.height) / 2;
+        legendData.area.end.y = (opts.height + legendData.area.height) / 2;
+    }
+    let lineNum = len % maxLength === 0 ? len / maxLength : Math.floor((len / maxLength) + 1);
+    let currentRow = [];
+    for (let i = 0; i < lineNum; i++) {
+      let temp = series.slice(i * maxLength, i * maxLength + maxLength);
+      currentRow.push(temp);
+    }
+    legendData.points = currentRow;
+    if (currentRow.length) {
+      for (let i = 0; i < currentRow.length; i++) {
+        let item = currentRow[i];
+        let maxWidth = 0;
+        for (let j = 0; j < item.length; j++) {
+          let itemWidth = shapeWidth + shapeRight + measureText(item[j].name || 'undefined', fontSize, context) + opts.legend.itemGap * opts.pix;
+          if (itemWidth > maxWidth) {
+            maxWidth = itemWidth;
+          }
+        }
+        legendData.widthArr.push(maxWidth);
+        legendData.heightArr.push(item.length * lineHeight + padding * 2);
+      }
+      let legendWidth = 0
+      for (let i = 0; i < legendData.widthArr.length; i++) {
+        legendWidth += legendData.widthArr[i];
+      }
+      legendData.area.width = legendWidth - opts.legend.itemGap * opts.pix + 2 * padding;
+      legendData.area.wholeWidth = legendData.area.width + padding;
+    }
+  }
+  switch (opts.legend.position) {
+    case 'top':
+      legendData.area.start.y = opts.area[0] + margin;
+      legendData.area.end.y = opts.area[0] + margin + legendData.area.height;
+      break;
+    case 'bottom':
+      legendData.area.start.y = opts.height - opts.area[2] - legendData.area.height - margin;
+      legendData.area.end.y = opts.height - opts.area[2] - margin;
+      break;
+    case 'left':
+      legendData.area.start.x = opts.area[3];
+      legendData.area.end.x = opts.area[3] + legendData.area.width;
+      break;
+    case 'right':
+      legendData.area.start.x = opts.width - opts.area[1] - legendData.area.width;
+      legendData.area.end.x = opts.width - opts.area[1];
+      break;
+  }
+  chartData.legendData = legendData;
+  return legendData;
+}
+
+function calCategoriesData(categories, opts, config, eachSpacing, context) {
+  var result = {
+    angle: 0,
+    xAxisHeight: opts.xAxis.lineHeight * opts.pix + opts.xAxis.marginTop * opts.pix
+  };
+  var fontSize = opts.xAxis.fontSize * opts.pix;
+  var categoriesTextLenth = categories.map(function(item,index) {
+    var xitem = opts.xAxis.formatter ? opts.xAxis.formatter(item,index,opts) : item;
+    return measureText(String(xitem), fontSize, context);
+  });
+  var maxTextLength = Math.max.apply(this, categoriesTextLenth);
+  if (opts.xAxis.rotateLabel == true) {
+    result.angle = opts.xAxis.rotateAngle * Math.PI / 180;
+    let tempHeight = opts.xAxis.marginTop * opts.pix * 2 +  Math.abs(maxTextLength * Math.sin(result.angle))
+    tempHeight = tempHeight < fontSize + opts.xAxis.marginTop * opts.pix * 2 ? tempHeight + opts.xAxis.marginTop * opts.pix * 2 : tempHeight;
+    result.xAxisHeight = tempHeight;
+  }
+  if (opts.enableScroll && opts.xAxis.scrollShow) {
+    result.xAxisHeight += 6 * opts.pix;
+  }
+  if (opts.xAxis.disabled){
+    result.xAxisHeight = 0;
+  }
+  return result;
+}
+
+function getXAxisTextList(series, opts, config, stack) {
+  var index = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : -1;
+  var data;
+  if (stack == 'stack') {
+    data = dataCombineStack(series, opts.categories.length);
+  } 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.toString().indexOf('Array') > -1) {
+        return item !== null;
+      } else {
+        return item.value !== null;
+      }
+    } else {
+      return item !== null;
+    }
+  });
+  data.map(function(item) {
+    if (typeof item === 'object') {
+      if (item.constructor.toString().indexOf('Array') > -1) {
+        if (opts.type == 'candle') {
+          item.map(function(subitem) {
+            sorted.push(subitem);
+          })
+        } else {
+          sorted.push(item[0]);
+        }
+      } else {
+        sorted.push(item.value);
+      }
+    } else {
+      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);
+  }
+  //为了兼容v1.9.0之前的项目
+  if (index > -1) {
+    if (typeof opts.xAxis.data[index].min === 'number') {
+      minData = Math.min(opts.xAxis.data[index].min, minData);
+    }
+    if (typeof opts.xAxis.data[index].max === 'number') {
+      maxData = Math.max(opts.xAxis.data[index].max, maxData);
+    }
+  } else {
+    if (typeof opts.xAxis.min === 'number') {
+      minData = Math.min(opts.xAxis.min, minData);
+    }
+    if (typeof opts.xAxis.max === 'number') {
+      maxData = Math.max(opts.xAxis.max, maxData);
+    }
+  }
+  if (minData === maxData) {
+    var rangeSpan = maxData || 10;
+    maxData += rangeSpan;
+  }
+  //var dataRange = getDataRange(minData, maxData);
+  var minRange = minData;
+  var maxRange = maxData;
+  var range = [];
+  var eachRange = (maxRange - minRange) / opts.xAxis.splitNumber;
+  for (var i = 0; i <= opts.xAxis.splitNumber; i++) {
+    range.push(minRange + eachRange * i);
+  }
+  return range;
+}
+
+function calXAxisData(series, opts, config, context) {
+  //堆叠图重算Y轴
+  var columnstyle = assign({}, {
+    type: ""
+  }, opts.extra.bar);
+  var result = {
+    angle: 0,
+    xAxisHeight: opts.xAxis.lineHeight * opts.pix + opts.xAxis.marginTop * opts.pix
+  };
+  result.ranges = getXAxisTextList(series, opts, config, columnstyle.type);
+  result.rangesFormat = result.ranges.map(function(item) {
+    //item = opts.xAxis.formatter ? opts.xAxis.formatter(item) : util.toFixed(item, 2);
+    item = util.toFixed(item, 2);
+    return item;
+  });
+  var xAxisScaleValues = result.ranges.map(function(item) {
+    // 如果刻度值是浮点数,则保留两位小数
+    item = util.toFixed(item, 2);
+    // 若有自定义格式则调用自定义的格式化函数
+    //item = opts.xAxis.formatter ? opts.xAxis.formatter(Number(item)) : item;
+    return item;
+  });
+  result = Object.assign(result, getXAxisPoints(xAxisScaleValues, opts, config));
+  // 计算X轴刻度的属性譬如每个刻度的间隔,刻度的起始点\结束点以及总长
+  var eachSpacing = result.eachSpacing;
+  var textLength = xAxisScaleValues.map(function(item) {
+    return measureText(item, opts.xAxis.fontSize * opts.pix, context);
+  });
+  if (opts.xAxis.disabled === true) {
+    result.xAxisHeight = 0;
+  }
+  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 = [];
+  for (let i = 0; i < series.length; i++) {
+    let each = series[i];
+    let listItem = {};
+    listItem.color = each.color;
+    listItem.legendShape = each.legendShape;
+    listItem.pointShape = each.pointShape;
+    listItem.data = [];
+    each.data.forEach(function(item, index) {
+      let tmp = {};
+      tmp.angle = angleList[index];
+      tmp.proportion = item / maxData;
+      tmp.value = item;
+      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, radius) {
+  var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
+  var count = 0;
+  var _start_ = 0;
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    count += item.data;
+  }
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    if (count === 0) {
+      item._proportion_ = 1 / series.length * process;
+    } else {
+      item._proportion_ = item.data / count * process;
+    }
+    item._radius_ = radius;
+  }
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item._start_ = _start_;
+    _start_ += 2 * item._proportion_ * Math.PI;
+  }
+  return series;
+}
+
+function getFunnelDataPoints(series, radius, option, eachSpacing) {
+  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  for (let i = 0; i < series.length; i++) {
+    if(option.type == 'funnel'){
+      series[i].radius = series[i].data / series[0].data * radius * process;
+    }else{
+      series[i].radius =  (eachSpacing * (series.length - i)) / (eachSpacing * series.length) * radius * process;
+    }
+    series[i]._proportion_ = series[i].data / series[0].data;
+  }
+  // if(option.type !== 'pyramid'){
+  //   series.reverse();
+  // }
+  return series;
+}
+
+function getRoseDataPoints(series, type, minRadius, radius) {
+  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  var count = 0;
+  var _start_ = 0;
+  var dataArr = [];
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    count += item.data;
+    dataArr.push(item.data);
+  }
+  var minData = Math.min.apply(null, dataArr);
+  var maxData = Math.max.apply(null, dataArr);
+  var radiusLength = radius - minRadius;
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    if (count === 0) {
+      item._proportion_ = 1 / series.length * process;
+      item._rose_proportion_ = 1 / series.length * process;
+    } else {
+      item._proportion_ = item.data / count * process;
+      if(type == 'area'){
+        item._rose_proportion_ = 1 / series.length * process;
+      }else{
+        item._rose_proportion_ = item.data / count * process;
+      }
+    }
+    item._radius_ = minRadius + radiusLength * ((item.data - minData) / (maxData - minData)) || radius;
+  }
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item._start_ = _start_;
+    _start_ += 2 * item._rose_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;
+  }
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    let totalAngle;
+    if (arcbarOption.type == 'circle') {
+      totalAngle = 2;
+    } else {
+      if(arcbarOption.direction == 'ccw'){
+        if (arcbarOption.startAngle < arcbarOption.endAngle) {
+          totalAngle = 2 + arcbarOption.startAngle - arcbarOption.endAngle;
+        } else {
+          totalAngle = arcbarOption.startAngle - arcbarOption.endAngle;
+        }
+      }else{
+        if (arcbarOption.endAngle < arcbarOption.startAngle) {
+          totalAngle = 2 + arcbarOption.endAngle - arcbarOption.startAngle;
+        } else {
+          totalAngle = arcbarOption.startAngle - arcbarOption.endAngle;
+        }
+      }
+    }
+    item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;
+    if(arcbarOption.direction == 'ccw'){
+      item._proportion_ = arcbarOption.startAngle - totalAngle * item.data * process ;
+    }
+    if (item._proportion_ >= 2) {
+      item._proportion_ = item._proportion_ % 2;
+    }
+  }
+  return series;
+}
+
+function getGaugeArcbarDataPoints(series, arcbarOption) {
+  var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
+  if (process == 1) {
+    process = 0.999999;
+  }
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    let totalAngle;
+    if (arcbarOption.type == 'circle') {
+      totalAngle = 2;
+    } else {
+      if (arcbarOption.endAngle < arcbarOption.startAngle) {
+        totalAngle = 2 + arcbarOption.endAngle - arcbarOption.startAngle;
+      } else {
+        totalAngle = arcbarOption.startAngle - arcbarOption.endAngle;
+      }
+    }
+    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;
+  if (endAngle < startAngle) {
+    totalAngle = 2 + endAngle - startAngle;
+  } else {
+    totalAngle = startAngle - endAngle;
+  }
+  let tempStartAngle = startAngle;
+  for (let i = 0; i < categories.length; i++) {
+    categories[i].value = categories[i].value === null ? 0 : categories[i].value;
+    categories[i]._startAngle_ = tempStartAngle;
+    categories[i]._endAngle_ = totalAngle * categories[i].value + startAngle;
+    if (categories[i]._endAngle_ >= 2) {
+      categories[i]._endAngle_ = categories[i]._endAngle_ % 2;
+    }
+    tempStartAngle = categories[i]._endAngle_;
+  }
+  return categories;
+}
+
+function getGaugeDataPoints(series, categories, gaugeOption) {
+  let process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    item.data = item.data === null ? 0 : item.data;
+    if (gaugeOption.pointer.color == 'auto') {
+      for (let i = 0; i < categories.length; i++) {
+        if (item.data <= categories[i].value) {
+          item.color = categories[i].color;
+          break;
+        }
+      }
+    } else {
+      item.color = gaugeOption.pointer.color;
+    }
+    let totalAngle;
+    if (gaugeOption.endAngle < gaugeOption.startAngle) {
+      totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
+    } else {
+      totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
+    }
+    item._endAngle_ = totalAngle * item.data + gaugeOption.startAngle;
+    item._oldAngle_ = gaugeOption.oldAngle;
+    if (gaugeOption.oldAngle < gaugeOption.endAngle) {
+      item._oldAngle_ += 2;
+    }
+    if (item.data >= 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, config, context, opts) {
+  series = getPieDataPoints(series);
+  let maxLength = 0;
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    let text = item.formatter ? item.formatter(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ * 100) + '%';
+    maxLength = Math.max(maxLength, measureText(text, item.textSize * opts.pix || config.fontSize, context));
+  }
+  return maxLength;
+}
+
+function fixColumeData(points, eachSpacing, columnLen, index, config, opts) {
+  return points.map(function(item) {
+    if (item === null) {
+      return null;
+    }
+    var seriesGap = 0;
+    var categoryGap = 0;
+    if (opts.type == 'mix') {
+      seriesGap = opts.extra.mix.column.seriesGap * opts.pix || 0;
+      categoryGap = opts.extra.mix.column.categoryGap * opts.pix || 0;
+    } else {
+      seriesGap = opts.extra.column.seriesGap * opts.pix || 0;
+      categoryGap = opts.extra.column.categoryGap * opts.pix || 0;
+    }
+    seriesGap =  Math.min(seriesGap, eachSpacing / columnLen)
+    categoryGap =  Math.min(categoryGap, eachSpacing / columnLen)
+    item.width = Math.ceil((eachSpacing - 2 * categoryGap - seriesGap * (columnLen - 1)) / columnLen);
+    if (opts.extra.mix && opts.extra.mix.column.width && +opts.extra.mix.column.width > 0) {
+      item.width = Math.min(item.width, +opts.extra.mix.column.width * opts.pix);
+    }
+    if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
+      item.width = Math.min(item.width, +opts.extra.column.width * opts.pix);
+    }
+    if (item.width <= 0) {
+      item.width = 1;
+    }
+    item.x += (index + 0.5 - columnLen / 2) * (item.width + seriesGap);
+    return item;
+  });
+}
+
+function fixBarData(points, eachSpacing, columnLen, index, config, opts) {
+  return points.map(function(item) {
+    if (item === null) {
+      return null;
+    }
+    var seriesGap = 0;
+    var categoryGap = 0;
+    seriesGap = opts.extra.bar.seriesGap * opts.pix || 0;
+    categoryGap = opts.extra.bar.categoryGap * opts.pix || 0;
+    seriesGap =  Math.min(seriesGap, eachSpacing / columnLen)
+    categoryGap =  Math.min(categoryGap, eachSpacing / columnLen)
+    item.width = Math.ceil((eachSpacing - 2 * categoryGap - seriesGap * (columnLen - 1)) / columnLen);
+    if (opts.extra.bar && opts.extra.bar.width && +opts.extra.bar.width > 0) {
+      item.width = Math.min(item.width, +opts.extra.bar.width * opts.pix);
+    }
+    if (item.width <= 0) {
+      item.width = 1;
+    }
+    item.y += (index + 0.5 - columnLen / 2) * (item.width + seriesGap);
+    return item;
+  });
+}
+
+function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) {
+  var categoryGap = opts.extra.column.categoryGap * opts.pix || 0;
+  return points.map(function(item) {
+    if (item === null) {
+      return null;
+    }
+    item.width = eachSpacing - 2 * categoryGap;
+    if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
+      item.width = Math.min(item.width, +opts.extra.column.width * opts.pix);
+    }
+    if (index > 0) {
+      item.width -= border;
+    }
+    return item;
+  });
+}
+
+function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts, series) {
+  var categoryGap = opts.extra.column.categoryGap * opts.pix || 0;
+  return points.map(function(item, indexn) {
+    if (item === null) {
+      return null;
+    }
+    item.width = Math.ceil(eachSpacing - 2 * categoryGap);
+    if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
+      item.width = Math.min(item.width, +opts.extra.column.width * opts.pix);
+    }
+    if (item.width <= 0) {
+      item.width = 1;
+    }
+    return item;
+  });
+}
+
+function fixBarStackData(points, eachSpacing, columnLen, index, config, opts, series) {
+  var categoryGap = opts.extra.bar.categoryGap * opts.pix || 0;
+  return points.map(function(item, indexn) {
+    if (item === null) {
+      return null;
+    }
+    item.width = Math.ceil(eachSpacing - 2 * categoryGap);
+    if (opts.extra.bar && opts.extra.bar.width && +opts.extra.bar.width > 0) {
+      item.width = Math.min(item.width, +opts.extra.bar.width * opts.pix);
+    }
+    if (item.width <= 0) {
+      item.width = 1;
+    }
+    return item;
+  });
+}
+
+function getXAxisPoints(categories, opts, config) {
+  var spacingValid = opts.width - opts.area[1] - opts.area[3];
+  var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length;
+  if ((opts.type == 'line' || opts.type == 'area' || opts.type == 'scatter' || opts.type == 'bubble' || opts.type == 'bar') && dataCount > 1 && opts.xAxis.boundaryGap == 'justify') {
+    dataCount -= 1;
+  }
+  var widthRatio = 0;
+  if(opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount.widthRatio > 1){
+    if(opts.extra.mount.widthRatio>2) opts.extra.mount.widthRatio = 2
+    widthRatio = opts.extra.mount.widthRatio - 1;
+    dataCount += widthRatio;
+  }
+  var eachSpacing = spacingValid / dataCount;
+  var xAxisPoints = [];
+  var startX = opts.area[3];
+  var endX = opts.width - opts.area[1];
+  categories.forEach(function(item, index) {
+    xAxisPoints.push(startX + widthRatio / 2 * eachSpacing + index * eachSpacing);
+  });
+  if (opts.xAxis.boundaryGap !== 'justify') {
+    if (opts.enableScroll === true) {
+      xAxisPoints.push(startX + widthRatio * eachSpacing + 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 - opts.area[0] - opts.area[2];
+  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 - Math.round(height) - opts.area[2];
+        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 boundaryGap = 'center';
+  if (opts.type == 'line' || opts.type == 'area' || opts.type == 'scatter' || opts.type == 'bubble' ) {
+    boundaryGap = opts.xAxis.boundaryGap;
+  }
+  var points = [];
+  var validHeight = opts.height - opts.area[0] - opts.area[2];
+  var validWidth = opts.width - opts.area[1] - opts.area[3];
+  data.forEach(function(item, index) {
+    if (item === null) {
+      points.push(null);
+    } else {
+      var point = {};
+      point.color = item.color;
+      point.x = xAxisPoints[index];
+      var value = item;
+      if (typeof item === 'object' && item !== null) {
+        if (item.constructor.toString().indexOf('Array') > -1) {
+          let xranges, xminRange, xmaxRange;
+          xranges = [].concat(opts.chartData.xAxisData.ranges);
+          xminRange = xranges.shift();
+          xmaxRange = xranges.pop();
+          value = item[1];
+          point.x = opts.area[3] + validWidth * (item[0] - xminRange) / (xmaxRange - xminRange);
+          if(opts.type == 'bubble'){
+            point.r = item[2];
+            point.t = item[3];
+          }
+        } else {
+          value = item.value;
+        }
+      }
+      if (boundaryGap == 'center') {
+        point.x += eachSpacing / 2;
+      }
+      var height = validHeight * (value - minRange) / (maxRange - minRange);
+      height *= process;
+      point.y = opts.height - height - opts.area[2];
+      points.push(point);
+    }
+  });
+  return points;
+}
+
+function getLineDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, lineOption, process){
+  var process = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 1;
+  var boundaryGap = opts.xAxis.boundaryGap;
+  var points = [];
+  var validHeight = opts.height - opts.area[0] - opts.area[2];
+  var validWidth = opts.width - opts.area[1] - opts.area[3];
+  data.forEach(function(item, index) {
+    if (item === null) {
+      points.push(null);
+    } else {
+      var point = {};
+      point.color = item.color;
+      if(lineOption.animation == 'vertical'){
+        point.x = xAxisPoints[index];
+        var value = item;
+        if (typeof item === 'object' && item !== null) {
+          if (item.constructor.toString().indexOf('Array') > -1) {
+            let xranges, xminRange, xmaxRange;
+            xranges = [].concat(opts.chartData.xAxisData.ranges);
+            xminRange = xranges.shift();
+            xmaxRange = xranges.pop();
+            value = item[1];
+            point.x = opts.area[3] + validWidth * (item[0] - xminRange) / (xmaxRange - xminRange);
+          } else {
+            value = item.value;
+          }
+        }
+        if (boundaryGap == 'center') {
+          point.x += eachSpacing / 2;
+        }
+        var height = validHeight * (value - minRange) / (maxRange - minRange);
+        height *= process;
+        point.y = opts.height - height - opts.area[2];
+        points.push(point);
+      }else{
+        point.x = xAxisPoints[0] + eachSpacing * index * process;
+        var value = item;
+        if (boundaryGap == 'center') {
+          point.x += eachSpacing / 2;
+        }
+        var height = validHeight * (value - minRange) / (maxRange - minRange);
+        point.y = opts.height - height - opts.area[2];
+        points.push(point);
+      }
+    }
+  });
+  return points;
+}
+
+function getColumnDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, zeroPoints, process){
+  var process = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 1;
+  var points = [];
+  var validHeight = opts.height - opts.area[0] - opts.area[2];
+  var validWidth = opts.width - opts.area[1] - opts.area[3];
+  data.forEach(function(item, index) {
+    if (item === null) {
+      points.push(null);
+    } else {
+      var point = {};
+      point.color = item.color;
+      point.x = xAxisPoints[index];
+      var value = item;
+      if (typeof item === 'object' && item !== null) {
+        if (item.constructor.toString().indexOf('Array') > -1) {
+          let xranges, xminRange, xmaxRange;
+          xranges = [].concat(opts.chartData.xAxisData.ranges);
+          xminRange = xranges.shift();
+          xmaxRange = xranges.pop();
+          value = item[1];
+          point.x = opts.area[3] + validWidth * (item[0] - xminRange) / (xmaxRange - xminRange);
+        } else {
+          value = item.value;
+        }
+      }
+      point.x += eachSpacing / 2;
+      var height = validHeight * (value * process - minRange) / (maxRange - minRange);
+      point.y = opts.height - height - opts.area[2];
+      points.push(point);
+    }
+  });
+  return points;
+}
+
+function getMountDataPoints(series, minRange, maxRange, xAxisPoints, eachSpacing, opts, mountOption, zeroPoints) {
+  var process = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 1;
+  var points = [];
+  var validHeight = opts.height - opts.area[0] - opts.area[2];
+  var validWidth = opts.width - opts.area[1] - opts.area[3];
+  var mountWidth = eachSpacing * mountOption.widthRatio;
+  series.forEach(function(item, index) {
+    if (item === null) {
+      points.push(null);
+    } else {
+      var point = {};
+      point.color = item.color;
+      point.x = xAxisPoints[index];
+      point.x += eachSpacing / 2;
+      var value = item.data;
+      var height = validHeight * (value * process - minRange) / (maxRange - minRange);
+      point.y = opts.height - height - opts.area[2];
+      point.value = value;
+      point.width = mountWidth;
+      points.push(point);
+    }
+  });
+  return points;
+}
+
+function getBarDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config) {
+  var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
+  var points = [];
+  var validHeight = opts.height - opts.area[0] - opts.area[2];
+  var validWidth = opts.width - opts.area[1] - opts.area[3];
+  data.forEach(function(item, index) {
+    if (item === null) {
+      points.push(null);
+    } else {
+      var point = {};
+      point.color = item.color;
+      point.y = yAxisPoints[index];
+      var value = item;
+      if (typeof item === 'object' && item !== null) {
+        value = item.value;
+      }
+      var height = validWidth * (value - minRange) / (maxRange - minRange);
+      height *= process;
+      point.height = height;
+      point.value = value;
+      point.x = height + opts.area[3];
+      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 - opts.area[0] - opts.area[2];
+  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;
+        if (typeof item === 'object' && item !== null) {
+          value = item.value;
+        }
+        var height = validHeight * (value - minRange) / (maxRange - minRange);
+        var height0 = 0;
+      }
+      var heightc = height0;
+      height *= process;
+      heightc *= process;
+      point.y = opts.height - Math.round(height) - opts.area[2];
+      point.y0 = opts.height - Math.round(heightc) - opts.area[2];
+      points.push(point);
+    }
+  });
+  return points;
+}
+
+function getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, seriesIndex, stackSeries) {
+  var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1;
+  var points = [];
+  var validHeight = opts.width - opts.area[1] - opts.area[3];
+  data.forEach(function(item, index) {
+    if (item === null) {
+      points.push(null);
+    } else {
+      var point = {};
+      point.color = item.color;
+      point.y = yAxisPoints[index];
+      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;
+        if (typeof item === 'object' && item !== null) {
+          value = item.value;
+        }
+        var height = validHeight * (value - minRange) / (maxRange - minRange);
+        var height0 = 0;
+      }
+      var heightc = height0;
+      height *= process;
+      heightc *= process;
+      point.height = height - heightc;
+      point.x = opts.area[3] + height;
+      point.x0 = opts.area[3] + heightc;
+      points.push(point);
+    }
+  });
+  return points;
+}
+
+function getYAxisTextList(series, opts, config, stack, yData) {
+  var index = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : -1;
+  var data;
+  if (stack == 'stack') {
+    data = dataCombineStack(series, opts.categories.length);
+  } 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.toString().indexOf('Array') > -1) {
+        return item !== null;
+      } else {
+        return item.value !== null;
+      }
+    } else {
+      return item !== null;
+    }
+  });
+  data.map(function(item) {
+    if (typeof item === 'object') {
+      if (item.constructor.toString().indexOf('Array') > -1) {
+        if (opts.type == 'candle') {
+          item.map(function(subitem) {
+            sorted.push(subitem);
+          })
+        } else {
+          sorted.push(item[1]);
+        }
+      } else {
+        sorted.push(item.value);
+      }
+    } else {
+      sorted.push(item);
+    }
+  })
+  var minData = yData.min || 0;
+  var maxData = yData.max || 0;
+  if (sorted.length > 0) {
+    minData = Math.min.apply(this, sorted);
+    maxData = Math.max.apply(this, sorted);
+  }
+  if (minData === maxData) {
+    if(maxData == 0){
+      maxData = 10;
+    }else{
+      minData = 0;
+    }
+  }
+  var dataRange = getDataRange(minData, maxData);
+  var minRange = (yData.min === undefined || yData.min === null) ? dataRange.minRange : yData.min;
+  var maxRange = (yData.max === undefined || yData.max === null) ? dataRange.maxRange : yData.max;
+  var eachRange = (maxRange - minRange) / opts.yAxis.splitNumber;
+  var range = [];
+  for (var i = 0; i <= opts.yAxis.splitNumber; i++) {
+    range.push(minRange + eachRange * i);
+  }
+  return range.reverse();
+}
+
+function calYAxisData(series, opts, config, context) {
+  //堆叠图重算Y轴
+  var columnstyle = assign({}, {
+    type: ""
+  }, opts.extra.column);
+  //如果是多Y轴,重新计算
+  var YLength = opts.yAxis.data.length;
+  var newSeries = new Array(YLength);
+  if (YLength > 0) {
+    for (let i = 0; i < YLength; i++) {
+      newSeries[i] = [];
+      for (let j = 0; j < series.length; j++) {
+        if (series[j].index == i) {
+          newSeries[i].push(series[j]);
+        }
+      }
+    }
+    var rangesArr = new Array(YLength);
+    var rangesFormatArr = new Array(YLength);
+    var yAxisWidthArr = new Array(YLength);
+
+    for (let i = 0; i < YLength; i++) {
+      let yData = opts.yAxis.data[i];
+      //如果总开关不显示,强制每个Y轴为不显示
+      if (opts.yAxis.disabled == true) {
+        yData.disabled = true;
+      }
+      if(yData.type === 'categories'){
+        if(!yData.formatter){
+          yData.formatter = (val,index,opts) => {return val + (yData.unit || '')};
+        }
+        yData.categories = yData.categories || opts.categories;
+        rangesArr[i] = yData.categories;
+      }else{
+        if(!yData.formatter){
+          yData.formatter = (val,index,opts) => {return util.toFixed(val, yData.tofix || 0) + (yData.unit || '')};
+        }
+        rangesArr[i] = getYAxisTextList(newSeries[i], opts, config, columnstyle.type, yData, i);
+      }
+      let yAxisFontSizes = yData.fontSize * opts.pix || config.fontSize;
+      yAxisWidthArr[i] = {
+        position: yData.position ? yData.position : 'left',
+        width: 0
+      };
+      rangesFormatArr[i] = rangesArr[i].map(function(items,index) {
+        items = yData.formatter(items,index,opts);
+        yAxisWidthArr[i].width = Math.max(yAxisWidthArr[i].width, measureText(items, yAxisFontSizes, context) + 5);
+        return items;
+      });
+      let calibration = yData.calibration ? 4 * opts.pix : 0;
+      yAxisWidthArr[i].width += calibration + 3 * opts.pix;
+      if (yData.disabled === true) {
+        yAxisWidthArr[i].width = 0;
+      }
+    }
+  } else {
+    var rangesArr = new Array(1);
+    var rangesFormatArr = new Array(1);
+    var yAxisWidthArr = new Array(1);
+    if(opts.type === 'bar'){
+      rangesArr[0] = opts.categories;
+      if(!opts.yAxis.formatter){
+        opts.yAxis.formatter = (val,index,opts) => {return val + (opts.yAxis.unit || '')}
+      }
+    }else{
+      if(!opts.yAxis.formatter){
+        opts.yAxis.formatter = (val,index,opts) => {return val.toFixed(opts.yAxis.tofix ) + (opts.yAxis.unit || '')}
+      }
+      rangesArr[0] = getYAxisTextList(series, opts, config, columnstyle.type, {});
+    }
+    yAxisWidthArr[0] = {
+      position: 'left',
+      width: 0
+    };
+    var yAxisFontSize = opts.yAxis.fontSize * opts.pix || config.fontSize;
+    rangesFormatArr[0] = rangesArr[0].map(function(item,index) {
+      item = opts.yAxis.formatter(item,index,opts);
+      yAxisWidthArr[0].width = Math.max(yAxisWidthArr[0].width, measureText(item, yAxisFontSize, context) + 5);
+      return item;
+    });
+    yAxisWidthArr[0].width += 3 * opts.pix;
+    if (opts.yAxis.disabled === true) {
+      yAxisWidthArr[0] = {
+        position: 'left',
+        width: 0
+      };
+      opts.yAxis.data[0] = {
+        disabled: true
+      };
+    } else {
+      opts.yAxis.data[0] = {
+        disabled: false,
+        position: 'left',
+        max: opts.yAxis.max,
+        min: opts.yAxis.min,
+        formatter: opts.yAxis.formatter
+      };
+      if(opts.type === 'bar'){
+        opts.yAxis.data[0].categories = opts.categories;
+        opts.yAxis.data[0].type = 'categories';
+      }
+    }
+  }
+  return {
+    rangesFormat: rangesFormatArr,
+    ranges: rangesArr,
+    yAxisWidth: yAxisWidthArr
+  };
+}
+
+function calTooltipYAxisData(point, series, opts, config, eachSpacing) {
+  let ranges = [].concat(opts.chartData.yAxisData.ranges);
+  let spacingValid = opts.height - opts.area[0] - opts.area[2];
+  let minAxis = opts.area[0];
+  let items = [];
+  for (let i = 0; i < ranges.length; i++) {
+    let maxVal = Math.max.apply(this, ranges[i]);
+    let minVal = Math.min.apply(this, ranges[i]);
+    let item = maxVal - (maxVal - minVal) * (point - minAxis) / spacingValid;
+    item = opts.yAxis.data && opts.yAxis.data[i].formatter ? opts.yAxis.data[i].formatter(item, i, opts) : item.toFixed(0);
+    items.push(String(item))
+  }
+  return items;
+}
+
+function calMarkLineData(points, opts) {
+  let minRange, maxRange;
+  let spacingValid = opts.height - opts.area[0] - opts.area[2];
+  for (let i = 0; i < points.length; i++) {
+    points[i].yAxisIndex = points[i].yAxisIndex ? points[i].yAxisIndex : 0;
+    let range = [].concat(opts.chartData.yAxisData.ranges[points[i].yAxisIndex]);
+    minRange = range.pop();
+    maxRange = range.shift();
+    let height = spacingValid * (points[i].value - minRange) / (maxRange - minRange);
+    points[i].y = opts.height - Math.round(height) - opts.area[2];
+  }
+  return points;
+}
+
+function contextRotate(context, opts) {
+  if (opts.rotateLock !== true) {
+    context.translate(opts.height, 0);
+    context.rotate(90 * Math.PI / 180);
+  } else if (opts._rotate_ !== true) {
+    context.translate(opts.height, 0);
+    context.rotate(90 * Math.PI / 180);
+    opts._rotate_ = true;
+  }
+}
+
+function drawPointShape(points, color, shape, context, opts) {
+  context.beginPath();
+  if (opts.dataPointShapeType == 'hollow') {
+    context.setStrokeStyle(color);
+    context.setFillStyle(opts.background);
+    context.setLineWidth(2 * opts.pix);
+  } else {
+    context.setStrokeStyle("#ffffff");
+    context.setFillStyle(color);
+    context.setLineWidth(1 * opts.pix);
+  }
+  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 + 2.5 * opts.pix, item.y);
+        context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
+      }
+    });
+  } else if (shape === 'square') {
+    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);
+      }
+    });
+  } else if (shape === 'none') {
+    return;
+  }
+  context.closePath();
+  context.fill();
+  context.stroke();
+}
+
+function drawActivePoint(points, color, shape, context, opts, option, seriesIndex) {
+  if(!opts.tooltip){
+    return
+  }
+  if(opts.tooltip.group.length>0 && opts.tooltip.group.includes(seriesIndex) == false){
+    return
+  }
+  var pointIndex = typeof opts.tooltip.index === 'number' ? opts.tooltip.index : opts.tooltip.index[opts.tooltip.group.indexOf(seriesIndex)];
+  context.beginPath();
+  if (option.activeType == 'hollow') {
+    context.setStrokeStyle(color);
+    context.setFillStyle(opts.background);
+    context.setLineWidth(2 * opts.pix);
+  } else {
+    context.setStrokeStyle("#ffffff");
+    context.setFillStyle(color);
+    context.setLineWidth(1 * opts.pix);
+  }
+  if (shape === 'diamond') {
+    points.forEach(function(item, index) {
+      if (item !== null && pointIndex == index ) {
+        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 && pointIndex == index) {
+        context.moveTo(item.x + 2.5 * opts.pix, item.y);
+        context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
+      }
+    });
+  } else if (shape === 'square') {
+    points.forEach(function(item, index) {
+      if (item !== null && pointIndex == index) {
+        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 && pointIndex == index) {
+        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);
+      }
+    });
+  } else if (shape === 'none') {
+    return;
+  }
+  context.closePath();
+  context.fill();
+  context.stroke();
+}
+
+function drawRingTitle(opts, config, context, center) {
+  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 || opts.fontColor;
+  var subtitleFontColor = opts.subtitle.color || opts.fontColor;
+  var titleHeight = title ? titlefontSize : 0;
+  var subtitleHeight = subtitle ? subtitlefontSize : 0;
+  var margin = 5;
+  if (subtitle) {
+    var textWidth = measureText(subtitle, subtitlefontSize * opts.pix, context);
+    var startX = center.x - textWidth / 2 + (opts.subtitle.offsetX|| 0) * opts.pix ;
+    var startY = center.y + subtitlefontSize * opts.pix / 2 + (opts.subtitle.offsetY || 0) * opts.pix;
+    if (title) {
+      startY += (titleHeight * opts.pix + margin) / 2;
+    }
+    context.beginPath();
+    context.setFontSize(subtitlefontSize * opts.pix);
+    context.setFillStyle(subtitleFontColor);
+    context.fillText(subtitle, startX, startY);
+    context.closePath();
+    context.stroke();
+  }
+  if (title) {
+    var _textWidth = measureText(title, titlefontSize * opts.pix, context);
+    var _startX = center.x - _textWidth / 2 + (opts.title.offsetX || 0);
+    var _startY = center.y + titlefontSize * opts.pix / 2 + (opts.title.offsetY || 0) * opts.pix;
+    if (subtitle) {
+      _startY -= (subtitleHeight * opts.pix + margin) / 2;
+    }
+    context.beginPath();
+    context.setFontSize(titlefontSize * opts.pix);
+    context.setFillStyle(titleFontColor);
+    context.fillText(title, _startX, _startY);
+    context.closePath();
+    context.stroke();
+  }
+}
+
+function drawPointText(points, series, config, context, opts) {
+  // 绘制数据文案
+  var data = series.data;
+  var textOffset = series.textOffset ? series.textOffset : 0;
+  points.forEach(function(item, index) {
+    if (item !== null) {
+      context.beginPath();
+      var fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
+      context.setFontSize(fontSize);
+      context.setFillStyle(series.textColor || opts.fontColor);
+      var value = data[index]
+      if (typeof data[index] === 'object' && data[index] !== null) {
+        if (data[index].constructor.toString().indexOf('Array')>-1) {
+          value = data[index][1];
+        } else {
+          value = data[index].value
+        }
+      }
+      var formatVal = series.formatter ? series.formatter(value,index,series,opts) : value;
+      context.setTextAlign('center');
+      context.fillText(String(formatVal), item.x, item.y - 4 + textOffset * opts.pix);
+      context.closePath();
+      context.stroke();
+      context.setTextAlign('left');
+    }
+  });
+}
+
+function drawColumePointText(points, series, config, context, opts) {
+  // 绘制数据文案
+  var data = series.data;
+  var textOffset = series.textOffset ? series.textOffset : 0;
+  var Position = opts.extra.column.labelPosition;
+  points.forEach(function(item, index) {
+    if (item !== null) {
+      context.beginPath();
+      var fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
+      context.setFontSize(fontSize);
+      context.setFillStyle(series.textColor || opts.fontColor);
+      var value = data[index]
+      if (typeof data[index] === 'object' && data[index] !== null) {
+        if (data[index].constructor.toString().indexOf('Array')>-1) {
+          value = data[index][1];
+        } else {
+          value = data[index].value
+        }
+      }
+      var formatVal = series.formatter ? series.formatter(value,index,series,opts) : value;
+      context.setTextAlign('center');
+      var startY = item.y - 4 * opts.pix + textOffset * opts.pix;
+      if(item.y > series.zeroPoints){
+        startY = item.y + textOffset * opts.pix + fontSize;
+      }
+      if(Position == 'insideTop'){
+        startY = item.y + fontSize + textOffset * opts.pix;
+        if(item.y > series.zeroPoints){
+          startY = item.y - textOffset * opts.pix - 4 * opts.pix;
+        }
+      }
+      if(Position == 'center'){
+        startY = item.y + textOffset * opts.pix + (opts.height - opts.area[2] - item.y + fontSize)/2;
+        if(series.zeroPoints < opts.height - opts.area[2]){
+          startY = item.y + textOffset * opts.pix + (series.zeroPoints - item.y + fontSize)/2;
+        }
+        if(item.y > series.zeroPoints){
+          startY = item.y - textOffset * opts.pix - (item.y - series.zeroPoints - fontSize)/2;
+        }
+        if(opts.extra.column.type == 'stack'){
+          startY = item.y + textOffset * opts.pix + (item.y0 - item.y + fontSize)/2;
+        }
+      }
+      if(Position == 'bottom'){
+        startY = opts.height - opts.area[2] + textOffset * opts.pix - 4 * opts.pix;
+        if(series.zeroPoints < opts.height - opts.area[2]){
+          startY = series.zeroPoints + textOffset * opts.pix - 4 * opts.pix;
+        }
+        if(item.y > series.zeroPoints){
+          startY = series.zeroPoints - textOffset * opts.pix + fontSize + 2 * opts.pix;
+        }
+        if(opts.extra.column.type == 'stack'){
+          startY = item.y0 + textOffset * opts.pix - 4 * opts.pix;
+        }
+      }
+      context.fillText(String(formatVal), item.x, startY);
+      context.closePath();
+      context.stroke();
+      context.setTextAlign('left');
+    }
+  });
+}
+
+function drawMountPointText(points, series, config, context, opts, zeroPoints) {
+  // 绘制数据文案
+  var data = series.data;
+  var textOffset = series.textOffset ? series.textOffset : 0;
+  var Position = opts.extra.mount.labelPosition;
+  points.forEach(function(item, index) {
+    if (item !== null) {
+      context.beginPath();
+      var fontSize = series[index].textSize ? series[index].textSize * opts.pix : config.fontSize;
+      context.setFontSize(fontSize);
+      context.setFillStyle(series[index].textColor || opts.fontColor);
+      var value = item.value
+      var formatVal = series[index].formatter ? series[index].formatter(value,index,series,opts) : value;
+      context.setTextAlign('center');
+      var startY = item.y - 4 * opts.pix + textOffset * opts.pix;
+      if(item.y > zeroPoints){
+        startY = item.y + textOffset * opts.pix + fontSize;
+      }
+      context.fillText(String(formatVal), item.x, startY);
+      context.closePath();
+      context.stroke();
+      context.setTextAlign('left');
+    }
+  });
+}
+
+function drawBarPointText(points, series, config, context, opts) {
+  // 绘制数据文案
+  var data = series.data;
+  var textOffset = series.textOffset ? series.textOffset : 0;
+  points.forEach(function(item, index) {
+    if (item !== null) {
+      context.beginPath();
+      var fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
+      context.setFontSize(fontSize);
+      context.setFillStyle(series.textColor || opts.fontColor);
+      var value = data[index]
+      if (typeof data[index] === 'object' && data[index] !== null) {
+        value = data[index].value ;
+      }
+      var formatVal = series.formatter ? series.formatter(value,index,series,opts) : value;
+      context.setTextAlign('left');
+      context.fillText(String(formatVal), item.x + 4 * opts.pix , item.y + fontSize / 2 - 3 );
+      context.closePath();
+      context.stroke();
+    }
+  });
+}
+
+function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) {
+  radius -= gaugeOption.width / 2 + gaugeOption.labelOffset * opts.pix;
+  radius = radius < 10 ? 10 : radius;
+  let totalAngle;
+  if (gaugeOption.endAngle < gaugeOption.startAngle) {
+    totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
+  } else {
+    totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
+  }
+  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 < gaugeOption.splitLine.splitNumber + 1; i++) {
+    var pos = {
+      x: radius * Math.cos(nowAngle * Math.PI),
+      y: radius * Math.sin(nowAngle * Math.PI)
+    };
+    var labelText = gaugeOption.formatter ? gaugeOption.formatter(nowNumber,i,opts) : nowNumber;
+    pos.x += centerPosition.x - measureText(labelText, config.fontSize, context) / 2;
+    pos.y += centerPosition.y;
+    var startX = pos.x;
+    var startY = pos.y;
+    context.beginPath();
+    context.setFontSize(config.fontSize);
+    context.setFillStyle(gaugeOption.labelColor || opts.fontColor);
+    context.fillText(labelText, startX, startY + config.fontSize / 2);
+    context.closePath();
+    context.stroke();
+    nowAngle += splitAngle;
+    if (nowAngle >= 2) {
+      nowAngle = nowAngle % 2;
+    }
+    nowNumber += splitNumber;
+  }
+}
+
+function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) {
+  var radarOption = opts.extra.radar || {};
+  angleList.forEach(function(angle, index) {
+    if(radarOption.labelPointShow === true && opts.categories[index] !== ''){
+      var posPoint = {
+        x: radius * Math.cos(angle),
+        y: radius * Math.sin(angle)
+      };
+      var posPointAxis = convertCoordinateOrigin(posPoint.x, posPoint.y, centerPosition);
+      context.setFillStyle(radarOption.labelPointColor);
+      context.beginPath();
+      context.arc(posPointAxis.x, posPointAxis.y, radarOption.labelPointRadius * opts.pix, 0, 2 * Math.PI, false);
+      context.closePath();
+      context.fill();
+    }
+    if(radarOption.labelShow === true){
+      var pos = {
+        x: (radius + config.radarLabelTextMargin * opts.pix) * Math.cos(angle),
+        y: (radius + config.radarLabelTextMargin * opts.pix) * 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] || '', config.fontSize, context) / 2;
+      } else if (pos.x < 0) {
+        startX -= measureText(opts.categories[index] || '', config.fontSize, context);
+      }
+      context.beginPath();
+      context.setFontSize(config.fontSize);
+      context.setFillStyle(radarOption.labelColor || opts.fontColor);
+      context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2);
+      context.closePath();
+      context.stroke();
+    }
+  });
+
+}
+
+function drawPieText(series, opts, config, context, radius, center) {
+  var lineRadius = config.pieChartLinePadding;
+  var textObjectCollection = [];
+  var lastTextObject = null;
+  var seriesConvert = series.map(function(item,index) {
+    var text = item.formatter ? item.formatter(item,index,series,opts) : util.toFixed(item._proportion_.toFixed(4) * 100) + '%';
+    text = item.labelText ? item.labelText : text;
+    var arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._proportion_ / 2);
+    if (item._rose_proportion_) {
+      arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._rose_proportion_ / 2);
+    }
+    var color = item.color;
+    var radius = item._radius_;
+    return {
+      arc: arc,
+      text: text,
+      color: color,
+      radius: radius,
+      textColor: item.textColor,
+      textSize: item.textSize,
+      labelShow: item.labelShow
+    };
+  });
+  for (let i = 0; i < seriesConvert.length; i++) {
+    let item = seriesConvert[i];
+    // line end
+    let orginX1 = Math.cos(item.arc) * (item.radius + lineRadius);
+    let orginY1 = Math.sin(item.arc) * (item.radius + lineRadius);
+    // line start
+    let orginX2 = Math.cos(item.arc) * item.radius;
+    let orginY2 = Math.sin(item.arc) * item.radius;
+    // text start
+    let orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding;
+    let orginY3 = orginY1;
+    let textWidth = measureText(item.text, item.textSize * opts.pix || config.fontSize, context);
+    let 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;
+    }
+    let 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,
+      textColor: item.textColor,
+      textSize: item.textSize
+    };
+    lastTextObject = avoidCollision(textObject, lastTextObject);
+    textObjectCollection.push(lastTextObject);
+  }
+  for (let i = 0; i < textObjectCollection.length; i++) {
+    if(seriesConvert[i].labelShow === false){
+      continue;
+    }
+    let item = textObjectCollection[i];
+    let lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center);
+    let lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center);
+    let textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center);
+    context.setLineWidth(1 * opts.pix);
+    context.setFontSize(item.textSize * opts.pix || config.fontSize);
+    context.beginPath();
+    context.setStrokeStyle(item.color);
+    context.setFillStyle(item.color);
+    context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
+    let curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x;
+    let 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 * opts.pix, 0, 2 * Math.PI);
+    context.closePath();
+    context.fill();
+    context.beginPath();
+    context.setFontSize(item.textSize * opts.pix || config.fontSize);
+    context.setFillStyle(item.textColor || opts.fontColor);
+    context.fillText(item.text, textStartX, textPosition.y + 3);
+    context.closePath();
+    context.stroke();
+    context.closePath();
+  }
+}
+
+function drawToolTipSplitLine(offsetX, opts, config, context) {
+  var toolTipOption = opts.extra.tooltip || {};
+  toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType;
+  toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength;
+  var startY = opts.area[0];
+  var endY = opts.height - opts.area[2];
+  if (toolTipOption.gridType == 'dash') {
+    context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
+  }
+  context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
+  context.setLineWidth(1 * opts.pix);
+  context.beginPath();
+  context.moveTo(offsetX, startY);
+  context.lineTo(offsetX, endY);
+  context.stroke();
+  context.setLineDash([]);
+  if (toolTipOption.xAxisLabel) {
+    let labelText = opts.categories[opts.tooltip.index];
+    context.setFontSize(config.fontSize);
+    let textWidth = measureText(labelText, config.fontSize, context);
+    let textX = offsetX - 0.5 * textWidth;
+    let textY = endY + 2 * opts.pix;
+    context.beginPath();
+    context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity || config.toolTipOpacity));
+    context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
+    context.setLineWidth(1 * opts.pix);
+    context.rect(textX - toolTipOption.boxPadding * opts.pix, textY, textWidth + 2 * toolTipOption.boxPadding * opts.pix, config.fontSize + 2 * toolTipOption.boxPadding * opts.pix);
+    context.closePath();
+    context.stroke();
+    context.fill();
+    context.beginPath();
+    context.setFontSize(config.fontSize);
+    context.setFillStyle(toolTipOption.labelFontColor || opts.fontColor);
+    context.fillText(String(labelText), textX, textY + toolTipOption.boxPadding * opts.pix + config.fontSize);
+    context.closePath();
+    context.stroke();
+  }
+}
+
+function drawMarkLine(opts, config, context) {
+  let markLineOption = assign({}, {
+    type: 'solid',
+    dashLength: 4,
+    data: []
+  }, opts.extra.markLine);
+  let startX = opts.area[3];
+  let endX = opts.width - opts.area[1];
+  let points = calMarkLineData(markLineOption.data, opts);
+  for (let i = 0; i < points.length; i++) {
+    let item = assign({}, {
+      lineColor: '#DE4A42',
+      showLabel: false,
+      labelFontSize: 13,
+      labelPadding: 6,
+      labelFontColor: '#666666',
+      labelBgColor: '#DFE8FF',
+      labelBgOpacity: 0.8,
+      labelAlign: 'left',
+      labelOffsetX: 0,
+      labelOffsetY: 0,
+    }, points[i]);
+    if (markLineOption.type == 'dash') {
+      context.setLineDash([markLineOption.dashLength, markLineOption.dashLength]);
+    }
+    context.setStrokeStyle(item.lineColor);
+    context.setLineWidth(1 * opts.pix);
+    context.beginPath();
+    context.moveTo(startX, item.y);
+    context.lineTo(endX, item.y);
+    context.stroke();
+    context.setLineDash([]);
+    if (item.showLabel) {
+      let fontSize = item.labelFontSize * opts.pix;
+      let labelText = item.labelText ? item.labelText : item.value;
+      context.setFontSize(fontSize);
+      let textWidth = measureText(labelText, fontSize, context);
+      let bgWidth = textWidth + item.labelPadding * opts.pix * 2;
+      let bgStartX = item.labelAlign == 'left' ? opts.area[3] - bgWidth : opts.width - opts.area[1];
+      bgStartX += item.labelOffsetX;
+      let bgStartY = item.y - 0.5 * fontSize - item.labelPadding * opts.pix;
+      bgStartY += item.labelOffsetY;
+      let textX = bgStartX + item.labelPadding * opts.pix;
+      let textY = item.y;
+      context.setFillStyle(hexToRgb(item.labelBgColor, item.labelBgOpacity));
+      context.setStrokeStyle(item.labelBgColor);
+      context.setLineWidth(1 * opts.pix);
+      context.beginPath();
+      context.rect(bgStartX, bgStartY, bgWidth, fontSize + 2 * item.labelPadding * opts.pix);
+      context.closePath();
+      context.stroke();
+      context.fill();
+      context.setFontSize(fontSize);
+      context.setTextAlign('left');
+      context.setFillStyle(item.labelFontColor);
+      context.fillText(String(labelText), textX, bgStartY + fontSize + item.labelPadding * opts.pix/2);
+      context.stroke();
+      context.setTextAlign('left');
+    }
+  }
+}
+
+function drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints) {
+  var toolTipOption = assign({}, {
+    gridType: 'solid',
+    dashLength: 4
+  }, opts.extra.tooltip);
+  var startX = opts.area[3];
+  var endX = opts.width - opts.area[1];
+  if (toolTipOption.gridType == 'dash') {
+    context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
+  }
+  context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
+  context.setLineWidth(1 * opts.pix);
+  context.beginPath();
+  context.moveTo(startX, opts.tooltip.offset.y);
+  context.lineTo(endX, opts.tooltip.offset.y);
+  context.stroke();
+  context.setLineDash([]);
+  if (toolTipOption.yAxisLabel) {
+    let boxPadding = toolTipOption.boxPadding * opts.pix;
+    let labelText = calTooltipYAxisData(opts.tooltip.offset.y, opts.series, opts, config, eachSpacing);
+    let widthArr = opts.chartData.yAxisData.yAxisWidth;
+    let tStartLeft = opts.area[3];
+    let tStartRight = opts.width - opts.area[1];
+    for (let i = 0; i < labelText.length; i++) {
+      context.setFontSize(toolTipOption.fontSize * opts.pix);
+      let textWidth = measureText(labelText[i], toolTipOption.fontSize * opts.pix, context);
+      let bgStartX, bgEndX, bgWidth;
+      if (widthArr[i].position == 'left') {
+        bgStartX = tStartLeft - (textWidth + boxPadding * 2) - 2 * opts.pix;
+        bgEndX = Math.max(bgStartX, bgStartX + textWidth + boxPadding * 2);
+      } else {
+        bgStartX = tStartRight + 2 * opts.pix;
+        bgEndX = Math.max(bgStartX + widthArr[i].width, bgStartX + textWidth + boxPadding * 2);
+      }
+      bgWidth = bgEndX - bgStartX;
+      let textX = bgStartX + (bgWidth - textWidth) / 2;
+      let textY = opts.tooltip.offset.y;
+      context.beginPath();
+      context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption.labelBgOpacity || config.toolTipOpacity));
+      context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
+      context.setLineWidth(1 * opts.pix);
+      context.rect(bgStartX, textY - 0.5 * config.fontSize - boxPadding, bgWidth, config.fontSize + 2 * boxPadding);
+      context.closePath();
+      context.stroke();
+      context.fill();
+      context.beginPath();
+      context.setFontSize(config.fontSize);
+      context.setFillStyle(toolTipOption.labelFontColor || opts.fontColor);
+      context.fillText(labelText[i], textX, textY + 0.5 * config.fontSize);
+      context.closePath();
+      context.stroke();
+      if (widthArr[i].position == 'left') {
+        tStartLeft -= (widthArr[i].width + opts.yAxis.padding * opts.pix);
+      } else {
+        tStartRight += widthArr[i].width + opts.yAxis.padding * opts.pix;
+      }
+    }
+  }
+}
+
+function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) {
+  var toolTipOption = assign({}, {
+    activeBgColor: '#000000',
+    activeBgOpacity: 0.08,
+    activeWidth: eachSpacing
+  }, opts.extra.column);
+  toolTipOption.activeWidth = toolTipOption.activeWidth > eachSpacing ? eachSpacing : toolTipOption.activeWidth;
+  var startY = opts.area[0];
+  var endY = opts.height - opts.area[2];
+  context.beginPath();
+  context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
+  context.rect(offsetX - toolTipOption.activeWidth / 2, startY, toolTipOption.activeWidth, endY - startY);
+  context.closePath();
+  context.fill();
+  context.setFillStyle("#FFFFFF");
+}
+
+function drawBarToolTipSplitArea(offsetX, opts, config, context, eachSpacing) {
+  var toolTipOption = assign({}, {
+    activeBgColor: '#000000',
+    activeBgOpacity: 0.08
+  }, opts.extra.bar);
+  var startX = opts.area[3];
+  var endX = opts.width - opts.area[1];
+  context.beginPath();
+  context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
+  context.rect( startX ,offsetX - eachSpacing / 2 ,  endX - startX,eachSpacing);
+  context.closePath();
+  context.fill();
+  context.setFillStyle("#FFFFFF");
+}
+
+
+function drawToolTip(textList, offset, opts, config, context, eachSpacing, xAxisPoints) {
+  var toolTipOption = assign({}, {
+    showBox: true,
+    showArrow: true,
+    showCategory: false,
+    bgColor: '#000000',
+    bgOpacity: 0.7,
+    borderColor: '#000000',
+    borderWidth: 0,
+    borderRadius: 0,
+    borderOpacity: 0.7,
+    boxPadding: 3,
+    fontColor: '#FFFFFF',
+    fontSize: 13,
+    lineHeight: 20,
+    legendShow: true,
+    legendShape: 'auto',
+    splitLine: true,
+  }, opts.extra.tooltip);
+  if(toolTipOption.showCategory==true && opts.categories){
+    textList.unshift({text:opts.categories[opts.tooltip.index],color:null})
+  }
+  var fontSize = toolTipOption.fontSize * opts.pix;
+  var lineHeight = toolTipOption.lineHeight * opts.pix;
+  var boxPadding = toolTipOption.boxPadding * opts.pix;
+  var legendWidth = fontSize;
+  var legendMarginRight = 5 * opts.pix;
+  if(toolTipOption.legendShow == false){
+    legendWidth = 0;
+    legendMarginRight = 0;
+  }
+  var arrowWidth = toolTipOption.showArrow ? 8 * opts.pix : 0;
+  var isOverRightBorder = false;
+  if (opts.type == 'line' || opts.type == 'mount' || opts.type == 'area' || opts.type == 'candle' || opts.type == 'mix') {
+    if (toolTipOption.splitLine == true) {
+      drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
+    }
+  }
+  offset = assign({
+    x: 0,
+    y: 0
+  }, offset);
+  offset.y -= 8 * opts.pix;
+  var textWidth = textList.map(function(item) {
+    return measureText(item.text, fontSize, context);
+  });
+  var toolTipWidth = legendWidth + legendMarginRight + 4 * boxPadding + Math.max.apply(null, textWidth);
+  var toolTipHeight = 2 * boxPadding + textList.length * lineHeight;
+  if (toolTipOption.showBox == false) {
+    return
+  }
+  // if beyond the right border
+  if (offset.x - Math.abs(opts._scrollDistance_ || 0) + arrowWidth + toolTipWidth > opts.width) {
+    isOverRightBorder = true;
+  }
+  if (toolTipHeight + offset.y > opts.height) {
+    offset.y = opts.height - toolTipHeight;
+  }
+  // draw background rect
+  context.beginPath();
+  context.setFillStyle(hexToRgb(toolTipOption.bgColor, toolTipOption.bgOpacity));
+  context.setLineWidth(toolTipOption.borderWidth * opts.pix);
+  context.setStrokeStyle(hexToRgb(toolTipOption.borderColor, toolTipOption.borderOpacity));
+  var radius = toolTipOption.borderRadius;
+  if (isOverRightBorder) {
+    // 增加左侧仍然超出的判断
+    if(toolTipWidth + arrowWidth > opts.width){
+      offset.x = opts.width + Math.abs(opts._scrollDistance_ || 0) + arrowWidth + (toolTipWidth - opts.width)
+    }
+    if(toolTipWidth > offset.x){
+      offset.x = opts.width + Math.abs(opts._scrollDistance_ || 0) + arrowWidth + (toolTipWidth - opts.width)
+    }
+    if (toolTipOption.showArrow) {
+      context.moveTo(offset.x, offset.y + 10 * opts.pix);
+      context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pix + 5 * opts.pix);
+    }
+    context.arc(offset.x - arrowWidth - radius, offset.y + toolTipHeight - radius, radius, 0, Math.PI / 2, false);
+    context.arc(offset.x - arrowWidth - Math.round(toolTipWidth) + radius, offset.y + toolTipHeight - radius, radius,
+      Math.PI / 2, Math.PI, false);
+    context.arc(offset.x - arrowWidth - Math.round(toolTipWidth) + radius, offset.y + radius, radius, -Math.PI, -Math.PI / 2, false);
+    context.arc(offset.x - arrowWidth - radius, offset.y + radius, radius, -Math.PI / 2, 0, false);
+    if (toolTipOption.showArrow) {
+      context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pix - 5 * opts.pix);
+      context.lineTo(offset.x, offset.y + 10 * opts.pix);
+    }
+  } else {
+    if (toolTipOption.showArrow) {
+      context.moveTo(offset.x, offset.y + 10 * opts.pix);
+      context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pix - 5 * opts.pix);
+    }
+    context.arc(offset.x + arrowWidth + radius, offset.y + radius, radius, -Math.PI, -Math.PI / 2, false);
+    context.arc(offset.x + arrowWidth + Math.round(toolTipWidth) - radius, offset.y + radius, radius, -Math.PI / 2, 0,
+      false);
+    context.arc(offset.x + arrowWidth + Math.round(toolTipWidth) - radius, offset.y + toolTipHeight - radius, radius, 0,
+      Math.PI / 2, false);
+    context.arc(offset.x + arrowWidth + radius, offset.y + toolTipHeight - radius, radius, Math.PI / 2, Math.PI, false);
+    if (toolTipOption.showArrow) {
+      context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pix + 5 * opts.pix);
+      context.lineTo(offset.x, offset.y + 10 * opts.pix);
+    }
+  }
+  context.closePath();
+  context.fill();
+  if (toolTipOption.borderWidth > 0) {
+    context.stroke();
+  }
+  // draw legend
+  if(toolTipOption.legendShow){
+    textList.forEach(function(item, index) {
+      if (item.color !== null) {
+        context.beginPath();
+        context.setFillStyle(item.color);
+        var startX = offset.x + arrowWidth + 2 * boxPadding;
+        var startY = offset.y + (lineHeight - fontSize) / 2 + lineHeight * index + boxPadding + 1;
+        if (isOverRightBorder) {
+          startX = offset.x - toolTipWidth - arrowWidth + 2 * boxPadding;
+        }
+        switch (item.legendShape) {
+          case 'line':
+            context.moveTo(startX, startY + 0.5 * legendWidth - 2 * opts.pix);
+            context.fillRect(startX, startY + 0.5 * legendWidth - 2 * opts.pix, legendWidth, 4 * opts.pix);
+            break;
+          case 'triangle':
+            context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
+            context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
+            context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
+            context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
+            break;
+          case 'diamond':
+            context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
+            context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * legendWidth);
+            context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
+            context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * legendWidth);
+            context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
+            break;
+          case 'circle':
+            context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth);
+            context.arc(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth, 5 * opts.pix, 0, 2 * Math.PI);
+            break;
+          case 'rect':
+            context.moveTo(startX, startY + 0.5 * legendWidth - 5 * opts.pix);
+            context.fillRect(startX, startY + 0.5 * legendWidth - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
+            break;
+          case 'square':
+            context.moveTo(startX + 2 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
+            context.fillRect(startX + 2 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix, 10 * opts.pix, 10 * opts.pix);
+            break;
+          default:
+            context.moveTo(startX, startY + 0.5 * legendWidth - 5 * opts.pix);
+            context.fillRect(startX, startY + 0.5 * legendWidth - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
+        }
+        context.closePath();
+        context.fill();
+      }
+    });
+  }
+  
+  // draw text list
+  textList.forEach(function(item, index) {
+    var startX = offset.x + arrowWidth + 2 * boxPadding + legendWidth + legendMarginRight;
+    if (isOverRightBorder) {
+      startX = offset.x - toolTipWidth - arrowWidth + 2 * boxPadding + legendWidth + legendMarginRight;
+    }
+    var startY = offset.y + lineHeight * index + (lineHeight - fontSize)/2 - 1 + boxPadding + fontSize;
+    context.beginPath();
+    context.setFontSize(fontSize);
+    context.setTextBaseline('normal');
+    context.setFillStyle(toolTipOption.fontColor);
+    context.fillText(item.text, startX, startY);
+    context.closePath();
+    context.stroke();
+  });
+}
+
+function drawColumnDataPoints(series, opts, config, context) {
+  let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  let columnOption = assign({}, {
+    type: 'group',
+    width: eachSpacing / 2,
+    meterBorder: 4,
+    meterFillColor: '#FFFFFF',
+    barBorderCircle: false,
+    barBorderRadius: [],
+    seriesGap: 2,
+    linearType: 'none',
+    linearOpacity: 1,
+    customColor: [],
+    colorStop: 0,
+    labelPosition: 'outside'
+  }, opts.extra.column);
+  let calPoints = [];
+  context.save();
+  let leftNum = -2;
+  let rightNum = xAxisPoints.length + 2;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
+    rightNum = leftNum + opts.xAxis.itemCount + 4;
+  }
+  if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
+    drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing);
+  }
+  columnOption.customColor = fillCustomColor(columnOption.linearType, columnOption.customColor, series, config);
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    
+    // 计算0轴坐标
+    let spacingValid = opts.height - opts.area[0] - opts.area[2];
+    let zeroHeight = spacingValid * (0 - minRange) / (maxRange - minRange);
+    let zeroPoints = opts.height - Math.round(zeroHeight) - opts.area[2];
+    eachSeries.zeroPoints = zeroPoints;
+    var data = eachSeries.data;
+    switch (columnOption.type) {
+      case 'group':
+        var points = getColumnDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, zeroPoints, 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);
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          //fix issues/I27B1N yyoinge & Joeshu
+          if (item !== null && i > leftNum && i < rightNum) {
+            var startX = item.x - item.width / 2;
+            var height = opts.height - item.y - opts.area[2];
+            context.beginPath();
+            var fillColor = item.color || eachSeries.color
+            var strokeColor = item.color || eachSeries.color
+            if (columnOption.linearType !== 'none') {
+              var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
+              //透明渐变
+              if (columnOption.linearType == 'opacity') {
+                grd.addColorStop(0, hexToRgb(fillColor, columnOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              } else {
+                grd.addColorStop(0, hexToRgb(columnOption.customColor[eachSeries.linearIndex], columnOption.linearOpacity));
+                grd.addColorStop(columnOption.colorStop, hexToRgb(columnOption.customColor[eachSeries.linearIndex],columnOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              }
+              fillColor = grd
+            }
+            // 圆角边框
+            if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) || columnOption.barBorderCircle === true) {
+              const left = startX;
+              const top = item.y > zeroPoints ? zeroPoints : item.y;
+              const width = item.width;
+              const height = Math.abs(zeroPoints - item.y);
+              if (columnOption.barBorderCircle) {
+                columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
+              }
+              if(item.y > zeroPoints){
+                columnOption.barBorderRadius = [0, 0,width / 2, width / 2];
+              }
+              let [r0, r1, r2, r3] = columnOption.barBorderRadius;
+              let minRadius = Math.min(width/2,height/2);
+              r0 = r0 > minRadius ? minRadius : r0;
+              r1 = r1 > minRadius ? minRadius : r1;
+              r2 = r2 > minRadius ? minRadius : r2;
+              r3 = r3 > minRadius ? minRadius : r3;
+              r0 = r0 < 0 ? 0 : r0;
+              r1 = r1 < 0 ? 0 : r1;
+              r2 = r2 < 0 ? 0 : r2;
+              r3 = r3 < 0 ? 0 : r3;
+              context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
+              context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
+              context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
+              context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
+            } else {
+              context.moveTo(startX, item.y);
+              context.lineTo(startX + item.width, item.y);
+              context.lineTo(startX + item.width, zeroPoints);
+              context.lineTo(startX, zeroPoints);
+              context.lineTo(startX, item.y);
+              context.setLineWidth(1)
+              context.setStrokeStyle(strokeColor);
+            }
+            context.setFillStyle(fillColor);
+            context.closePath();
+            //context.stroke();
+            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);
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          if (item !== null && i > leftNum && i < rightNum) {
+            context.beginPath();
+            var fillColor = item.color || eachSeries.color;
+            var startX = item.x - item.width / 2 + 1;
+            var height = opts.height - item.y - opts.area[2];
+            var height0 = opts.height - item.y0 - opts.area[2];
+            if (seriesIndex > 0) {
+              height -= height0;
+            }
+            context.setFillStyle(fillColor);
+            context.moveTo(startX, item.y);
+            context.fillRect(startX, item.y, item.width, 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.meterBorder);
+          for (let i = 0; i < points.length; i++) {
+            let item = points[i];
+            if (item !== null && i > leftNum && i < rightNum) {
+              //画背景颜色
+              context.beginPath();
+              if (seriesIndex == 0 && columnOption.meterBorder > 0) {
+                context.setStrokeStyle(eachSeries.color);
+                context.setLineWidth(columnOption.meterBorder * opts.pix);
+              }
+              if(seriesIndex == 0){
+                context.setFillStyle(columnOption.meterFillColor);
+              }else{
+                context.setFillStyle(item.color || eachSeries.color);
+              }
+              var startX = item.x - item.width / 2;
+              var height = opts.height - item.y - opts.area[2];
+              if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) || columnOption.barBorderCircle === true) {
+                const left = startX;
+                const top = item.y;
+                const width = item.width;
+                const height = zeroPoints - item.y;
+                if (columnOption.barBorderCircle) {
+                  columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
+                }
+                let [r0, r1, r2, r3] = columnOption.barBorderRadius;
+                let minRadius = Math.min(width/2,height/2);
+                r0 = r0 > minRadius ? minRadius : r0;
+                r1 = r1 > minRadius ? minRadius : r1;
+                r2 = r2 > minRadius ? minRadius : r2;
+                r3 = r3 > minRadius ? minRadius : r3;
+                r0 = r0 < 0 ? 0 : r0;
+                r1 = r1 < 0 ? 0 : r1;
+                r2 = r2 < 0 ? 0 : r2;
+                r3 = r3 < 0 ? 0 : r3;
+                context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
+                context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
+                context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
+                context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
+                context.fill();
+              }else{
+                context.moveTo(startX, item.y);
+                context.lineTo(startX + item.width, item.y);
+                context.lineTo(startX + item.width, zeroPoints);
+                context.lineTo(startX, zeroPoints);
+                context.lineTo(startX, item.y);
+                context.fill();
+              }
+              if (seriesIndex == 0 && columnOption.meterBorder > 0) {
+                context.closePath();
+                context.stroke();
+              }
+            }
+          }
+        break;
+    }
+  });
+
+  if (opts.dataLabel !== false && process === 1) {
+    series.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+      minRange = ranges.pop();
+      maxRange = ranges.shift();
+      var data = eachSeries.data;
+      switch (columnOption.type) {
+        case 'group':
+          var points = getColumnDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+          points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
+          drawColumePointText(points, eachSeries, config, context, opts);
+          break;
+        case 'stack':
+          var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex, series, process);
+          drawColumePointText(points, eachSeries, config, context, opts);
+          break;
+        case 'meter':
+          var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+          drawColumePointText(points, eachSeries, config, context, opts);
+          break;
+      }
+    });
+  }
+  context.restore();
+  return {
+    xAxisPoints: xAxisPoints,
+    calPoints: calPoints,
+    eachSpacing: eachSpacing
+  };
+}
+
+function drawMountDataPoints(series, opts, config, context) {
+  let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  let mountOption = assign({}, {
+    type: 'mount',
+    widthRatio: 1,
+    borderWidth: 1,
+    barBorderCircle: false,
+    barBorderRadius: [],
+    linearType: 'none',
+    linearOpacity: 1,
+    customColor: [],
+    colorStop: 0,
+  }, opts.extra.mount);
+  mountOption.widthRatio = mountOption.widthRatio <= 0 ? 0 : mountOption.widthRatio;
+  mountOption.widthRatio = mountOption.widthRatio >= 2 ? 2 : mountOption.widthRatio;
+  let calPoints = [];
+  context.save();
+  let leftNum = -2;
+  let rightNum = xAxisPoints.length + 2;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
+    rightNum = leftNum + opts.xAxis.itemCount + 4;
+  }
+  mountOption.customColor = fillCustomColor(mountOption.linearType, mountOption.customColor, series, config);
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[0]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    
+    // 计算0轴坐标
+    let spacingValid = opts.height - opts.area[0] - opts.area[2];
+    let zeroHeight = spacingValid * (0 - minRange) / (maxRange - minRange);
+    let zeroPoints = opts.height - Math.round(zeroHeight) - opts.area[2];
+    
+    var points = getMountDataPoints(series, minRange, maxRange, xAxisPoints, eachSpacing, opts, mountOption, zeroPoints, process);
+    switch (mountOption.type) {
+      case 'bar':
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          if (item !== null && i > leftNum && i < rightNum) {
+            var startX = item.x - eachSpacing*mountOption.widthRatio/2;
+            var height = opts.height - item.y - opts.area[2];
+            context.beginPath();
+            var fillColor = item.color || series[i].color
+            var strokeColor = item.color || series[i].color
+            if (mountOption.linearType !== 'none') {
+              var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
+              //透明渐变
+              if (mountOption.linearType == 'opacity') {
+                grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              } else {
+                grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption.linearOpacity));
+                grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i].linearIndex],mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              }
+              fillColor = grd
+            }
+            // 圆角边框
+            if ((mountOption.barBorderRadius && mountOption.barBorderRadius.length === 4) || mountOption.barBorderCircle === true) {
+              const left = startX;
+              const top = item.y > zeroPoints ? zeroPoints : item.y;
+              const width = item.width;
+              const height = Math.abs(zeroPoints - item.y);
+              if (mountOption.barBorderCircle) {
+                mountOption.barBorderRadius = [width / 2, width / 2, 0, 0];
+              }
+              if(item.y > zeroPoints){
+                mountOption.barBorderRadius = [0, 0,width / 2, width / 2];
+              }
+              let [r0, r1, r2, r3] = mountOption.barBorderRadius;
+              let minRadius = Math.min(width/2,height/2);
+              r0 = r0 > minRadius ? minRadius : r0;
+              r1 = r1 > minRadius ? minRadius : r1;
+              r2 = r2 > minRadius ? minRadius : r2;
+              r3 = r3 > minRadius ? minRadius : r3;
+              r0 = r0 < 0 ? 0 : r0;
+              r1 = r1 < 0 ? 0 : r1;
+              r2 = r2 < 0 ? 0 : r2;
+              r3 = r3 < 0 ? 0 : r3;
+              context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
+              context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
+              context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
+              context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
+            } else {
+              context.moveTo(startX, item.y);
+              context.lineTo(startX + item.width, item.y);
+              context.lineTo(startX + item.width, zeroPoints);
+              context.lineTo(startX, zeroPoints);
+              context.lineTo(startX, item.y);
+            }
+            context.setStrokeStyle(strokeColor);
+            context.setFillStyle(fillColor);
+            if(mountOption.borderWidth > 0){
+              context.setLineWidth(mountOption.borderWidth * opts.pix);
+              context.closePath();
+              context.stroke();
+            }
+            context.fill();
+          }
+        };
+        break;
+      case 'triangle':
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          if (item !== null && i > leftNum && i < rightNum) {
+            var startX = item.x - eachSpacing*mountOption.widthRatio/2;
+            var height = opts.height - item.y - opts.area[2];
+            context.beginPath();
+            var fillColor = item.color || series[i].color
+            var strokeColor = item.color || series[i].color
+            if (mountOption.linearType !== 'none') {
+              var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
+              //透明渐变
+              if (mountOption.linearType == 'opacity') {
+                grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              } else {
+                grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption.linearOpacity));
+                grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i].linearIndex],mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              }
+              fillColor = grd
+            }
+            context.moveTo(startX, zeroPoints);
+            context.lineTo(item.x, item.y);
+            context.lineTo(startX + item.width, zeroPoints);
+            context.setStrokeStyle(strokeColor);
+            context.setFillStyle(fillColor);
+            if(mountOption.borderWidth > 0){
+              context.setLineWidth(mountOption.borderWidth * opts.pix);
+              context.stroke();
+            }
+            context.fill();
+          }
+        };
+        break;
+      case 'mount':
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          if (item !== null && i > leftNum && i < rightNum) {
+            var startX = item.x - eachSpacing*mountOption.widthRatio/2;
+            var height = opts.height - item.y - opts.area[2];
+            context.beginPath();
+            var fillColor = item.color || series[i].color
+            var strokeColor = item.color || series[i].color
+            if (mountOption.linearType !== 'none') {
+              var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
+              //透明渐变
+              if (mountOption.linearType == 'opacity') {
+                grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              } else {
+                grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption.linearOpacity));
+                grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i].linearIndex],mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              }
+              fillColor = grd
+            }
+            context.moveTo(startX, zeroPoints);
+            context.bezierCurveTo(item.x - item.width/4, zeroPoints, item.x - item.width/4, item.y, item.x, item.y);
+            context.bezierCurveTo(item.x + item.width/4, item.y, item.x + item.width/4, zeroPoints, startX + item.width, zeroPoints);
+            context.setStrokeStyle(strokeColor);
+            context.setFillStyle(fillColor);
+            if(mountOption.borderWidth > 0){
+              context.setLineWidth(mountOption.borderWidth * opts.pix);
+              context.stroke();
+            }
+            context.fill();
+          }
+        };
+        break;
+      case 'sharp':
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          if (item !== null && i > leftNum && i < rightNum) {
+            var startX = item.x - eachSpacing*mountOption.widthRatio/2;
+            var height = opts.height - item.y - opts.area[2];
+            context.beginPath();
+            var fillColor = item.color || series[i].color
+            var strokeColor = item.color || series[i].color
+            if (mountOption.linearType !== 'none') {
+              var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
+              //透明渐变
+              if (mountOption.linearType == 'opacity') {
+                grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              } else {
+                grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption.linearOpacity));
+                grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i].linearIndex],mountOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              }
+              fillColor = grd
+            }
+            context.moveTo(startX, zeroPoints);
+            context.quadraticCurveTo(item.x - 0, zeroPoints - height/4, item.x, item.y);
+            context.quadraticCurveTo(item.x + 0, zeroPoints - height/4, startX + item.width, zeroPoints)
+            context.setStrokeStyle(strokeColor);
+            context.setFillStyle(fillColor);
+            if(mountOption.borderWidth > 0){
+              context.setLineWidth(mountOption.borderWidth * opts.pix);
+              context.stroke();
+            }
+            context.fill();
+          }
+        };
+        break;
+    }
+
+  if (opts.dataLabel !== false && process === 1) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[0]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    var points = getMountDataPoints(series, minRange, maxRange, xAxisPoints, eachSpacing, opts, mountOption, zeroPoints, process);
+    drawMountPointText(points, series, config, context, opts, zeroPoints);
+  }
+  context.restore();
+  return {
+    xAxisPoints: xAxisPoints,
+    calPoints: points,
+    eachSpacing: eachSpacing
+  };
+}
+
+function drawBarDataPoints(series, opts, config, context) {
+  let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  let yAxisPoints = [];
+  let eachSpacing = (opts.height - opts.area[0] - opts.area[2])/opts.categories.length;
+  for (let i = 0; i < opts.categories.length; i++) {
+    yAxisPoints.push(opts.area[0] + eachSpacing / 2 + eachSpacing * i);
+  }
+  let columnOption = assign({}, {
+    type: 'group',
+    width: eachSpacing / 2,
+    meterBorder: 4,
+    meterFillColor: '#FFFFFF',
+    barBorderCircle: false,
+    barBorderRadius: [],
+    seriesGap: 2,
+    linearType: 'none',
+    linearOpacity: 1,
+    customColor: [],
+    colorStop: 0,
+  }, opts.extra.bar);
+  let calPoints = [];
+  context.save();
+  let leftNum = -2;
+  let rightNum = yAxisPoints.length + 2;
+  if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
+    drawBarToolTipSplitArea(opts.tooltip.offset.y, opts, config, context, eachSpacing);
+  }
+  columnOption.customColor = fillCustomColor(columnOption.linearType, columnOption.customColor, series, config);
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.xAxisData.ranges);
+    maxRange = ranges.pop();
+    minRange = ranges.shift();
+    var data = eachSeries.data;
+    switch (columnOption.type) {
+      case 'group':
+        var points = getBarDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, process);
+        var tooltipPoints = getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, seriesIndex, series, process);
+        calPoints.push(tooltipPoints);
+        points = fixBarData(points, eachSpacing, series.length, seriesIndex, config, opts);
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          //fix issues/I27B1N yyoinge & Joeshu
+          if (item !== null && i > leftNum && i < rightNum) {
+            //var startX = item.x - item.width / 2;
+            var startX = opts.area[3];
+            var startY = item.y - item.width / 2;
+            var height = item.height;
+            context.beginPath();
+            var fillColor = item.color || eachSeries.color
+            var strokeColor = item.color || eachSeries.color
+            if (columnOption.linearType !== 'none') {
+              var grd = context.createLinearGradient(startX, item.y, item.x, item.y);
+              //透明渐变
+              if (columnOption.linearType == 'opacity') {
+                grd.addColorStop(0, hexToRgb(fillColor, columnOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              } else {
+                grd.addColorStop(0, hexToRgb(columnOption.customColor[eachSeries.linearIndex], columnOption.linearOpacity));
+                grd.addColorStop(columnOption.colorStop, hexToRgb(columnOption.customColor[eachSeries.linearIndex],columnOption.linearOpacity));
+                grd.addColorStop(1, hexToRgb(fillColor, 1));
+              }
+              fillColor = grd
+            }
+            // 圆角边框
+            if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) || columnOption.barBorderCircle === true) {
+              const left = startX;
+              const width = item.width;
+              const top = item.y - item.width / 2;
+              const height = item.height;
+              if (columnOption.barBorderCircle) {
+                columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
+              }
+              let [r0, r1, r2, r3] = columnOption.barBorderRadius;
+              let minRadius = Math.min(width/2,height/2);
+              r0 = r0 > minRadius ? minRadius : r0;
+              r1 = r1 > minRadius ? minRadius : r1;
+              r2 = r2 > minRadius ? minRadius : r2;
+              r3 = r3 > minRadius ? minRadius : r3;
+              r0 = r0 < 0 ? 0 : r0;
+              r1 = r1 < 0 ? 0 : r1;
+              r2 = r2 < 0 ? 0 : r2;
+              r3 = r3 < 0 ? 0 : r3;
+              
+              context.arc(left + r3, top + r3, r3, -Math.PI, -Math.PI / 2);
+              context.arc(item.x - r0, top + r0, r0, -Math.PI / 2, 0);
+              context.arc(item.x - r1, top + width - r1, r1, 0, Math.PI / 2);
+              context.arc(left + r2, top + width - r2, r2, Math.PI / 2, Math.PI);
+            } else {
+              context.moveTo(startX, startY);
+              context.lineTo(item.x, startY);
+              context.lineTo(item.x, startY + item.width);
+              context.lineTo(startX, startY + item.width);
+              context.lineTo(startX, startY);
+              context.setLineWidth(1)
+              context.setStrokeStyle(strokeColor);
+            }
+            context.setFillStyle(fillColor);
+            context.closePath();
+            //context.stroke();
+            context.fill();
+          }
+        };
+        break;
+      case 'stack':
+        // 绘制堆叠数据图
+        var points = getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, seriesIndex, series, process);
+        calPoints.push(points);
+        points = fixBarStackData(points, eachSpacing, series.length, seriesIndex, config, opts, series);
+        for (let i = 0; i < points.length; i++) {
+          let item = points[i];
+          if (item !== null && i > leftNum && i < rightNum) {
+            context.beginPath();
+            var fillColor = item.color || eachSeries.color;
+            var startX = item.x0;
+            context.setFillStyle(fillColor);
+            context.moveTo(startX, item.y - item.width/2);
+            context.fillRect(startX, item.y - item.width/2, item.height , item.width);
+            context.closePath();
+            context.fill();
+          }
+        };
+        break;
+    }
+  });
+
+  if (opts.dataLabel !== false && process === 1) {
+    series.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.xAxisData.ranges);
+      maxRange = ranges.pop();
+      minRange = ranges.shift();
+      var data = eachSeries.data;
+      switch (columnOption.type) {
+        case 'group':
+          var points = getBarDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, process);
+          points = fixBarData(points, eachSpacing, series.length, seriesIndex, config, opts);
+          drawBarPointText(points, eachSeries, config, context, opts);
+          break;
+        case 'stack':
+          var points = getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, seriesIndex, series, process);
+          drawBarPointText(points, eachSeries, config, context, opts);
+          break;
+      }
+    });
+  }
+  return {
+    yAxisPoints: yAxisPoints,
+    calPoints: calPoints,
+    eachSpacing: eachSpacing
+  };
+}
+
+function drawCandleDataPoints(series, seriesMA, opts, config, context) {
+  var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
+  var candleOption = assign({}, {
+    color: {},
+    average: {}
+  }, opts.extra.candle);
+  candleOption.color = assign({}, {
+    upLine: '#f04864',
+    upFill: '#f04864',
+    downLine: '#2fc25b',
+    downFill: '#2fc25b'
+  }, candleOption.color);
+  candleOption.average = assign({}, {
+    show: false,
+    name: [],
+    day: [],
+    color: config.color
+  }, candleOption.average);
+  opts.extra.candle = candleOption;
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  let calPoints = [];
+  context.save();
+  let leftNum = -2;
+  let rightNum = xAxisPoints.length + 2;
+  let leftSpace = 0;
+  let rightSpace = opts.width + eachSpacing;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
+    rightNum = leftNum + opts.xAxis.itemCount + 4;
+    leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
+    rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
+  }
+  //画均线
+  if (candleOption.average.show || seriesMA) { //Merge pull request !12 from 邱贵翔
+    seriesMA.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+      minRange = ranges.pop();
+      maxRange = ranges.shift();
+      var data = eachSeries.data;
+      var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+      var splitPointList = splitPoints(points,eachSeries);
+      for (let i = 0; i < splitPointList.length; i++) {
+        let points = splitPointList[i];
+        context.beginPath();
+        context.setStrokeStyle(eachSeries.color);
+        context.setLineWidth(1);
+        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);
+          let startPoint = 0;
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              var ctrlPoint = createCurveControlPoints(points, j - 1);
+              context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x,
+                item.y);
+            }
+          }
+          context.moveTo(points[0].x, points[0].y);
+        }
+        context.closePath();
+        context.stroke();
+      }
+    });
+  }
+  //画K线
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    var data = eachSeries.data;
+    var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+    calPoints.push(points);
+    var splitPointList = splitPoints(points,eachSeries);
+    for (let i = 0; i < splitPointList[0].length; i++) {
+      if (i > leftNum && i < rightNum) {
+        let item = splitPointList[0][i];
+        context.beginPath();
+        //如果上涨
+        if (data[i][1] - data[i][0] > 0) {
+          context.setStrokeStyle(candleOption.color.upLine);
+          context.setFillStyle(candleOption.color.upFill);
+          context.setLineWidth(1 * opts.pix);
+          context.moveTo(item[3].x, item[3].y); //顶点
+          context.lineTo(item[1].x, item[1].y); //收盘中间点
+          context.lineTo(item[1].x - eachSpacing / 4, item[1].y); //收盘左侧点
+          context.lineTo(item[0].x - eachSpacing / 4, item[0].y); //开盘左侧点
+          context.lineTo(item[0].x, item[0].y); //开盘中间点
+          context.lineTo(item[2].x, item[2].y); //底点
+          context.lineTo(item[0].x, item[0].y); //开盘中间点
+          context.lineTo(item[0].x + eachSpacing / 4, item[0].y); //开盘右侧点
+          context.lineTo(item[1].x + eachSpacing / 4, item[1].y); //收盘右侧点
+          context.lineTo(item[1].x, item[1].y); //收盘中间点
+          context.moveTo(item[3].x, item[3].y); //顶点
+        } else {
+          context.setStrokeStyle(candleOption.color.downLine);
+          context.setFillStyle(candleOption.color.downFill);
+          context.setLineWidth(1 * opts.pix);
+          context.moveTo(item[3].x, item[3].y); //顶点
+          context.lineTo(item[0].x, item[0].y); //开盘中间点
+          context.lineTo(item[0].x - eachSpacing / 4, item[0].y); //开盘左侧点
+          context.lineTo(item[1].x - eachSpacing / 4, item[1].y); //收盘左侧点
+          context.lineTo(item[1].x, item[1].y); //收盘中间点
+          context.lineTo(item[2].x, item[2].y); //底点
+          context.lineTo(item[1].x, item[1].y); //收盘中间点
+          context.lineTo(item[1].x + eachSpacing / 4, item[1].y); //收盘右侧点
+          context.lineTo(item[0].x + eachSpacing / 4, item[0].y); //开盘右侧点
+          context.lineTo(item[0].x, item[0].y); //开盘中间点
+          context.moveTo(item[3].x, item[3].y); //顶点
+        }
+        context.closePath();
+        context.fill();
+        context.stroke();
+      }
+    }
+  });
+  context.restore();
+  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 areaOption = assign({}, {
+    type: 'straight',
+    opacity: 0.2,
+    addLine: false,
+    width: 2,
+    gradient: false,
+    activeType: 'none'
+  }, opts.extra.area);
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  let endY = opts.height - opts.area[2];
+  let calPoints = [];
+  context.save();
+  let leftSpace = 0;
+  let rightSpace = opts.width + eachSpacing;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
+    rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
+  }
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    let data = eachSeries.data;
+    let points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+    calPoints.push(points);
+    let splitPointList = splitPoints(points,eachSeries);
+    for (let i = 0; i < splitPointList.length; i++) {
+      let points = splitPointList[i];
+      // 绘制区域数
+      context.beginPath();
+      context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity));
+      if (areaOption.gradient) {
+        let gradient = context.createLinearGradient(0, opts.area[0], 0, opts.height - opts.area[2]);
+        gradient.addColorStop('0', hexToRgb(eachSeries.color, areaOption.opacity));
+        gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
+        context.setFillStyle(gradient);
+      } else {
+        context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity));
+      }
+      context.setLineWidth(areaOption.width * opts.pix);
+      if (points.length > 1) {
+        let firstPoint = points[0];
+        let lastPoint = points[points.length - 1];
+        context.moveTo(firstPoint.x, firstPoint.y);
+        let startPoint = 0;
+        if (areaOption.type === 'curve') {
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              let ctrlPoint = createCurveControlPoints(points, j - 1);
+              context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y);
+            }
+          };
+        } 
+        if (areaOption.type === 'straight') {
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              context.lineTo(item.x, item.y);
+            }
+          };
+        }
+        if (areaOption.type === 'step') {
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              context.lineTo(item.x, points[j - 1].y);
+              context.lineTo(item.x, item.y);
+            }
+          };
+        }
+        context.lineTo(lastPoint.x, endY);
+        context.lineTo(firstPoint.x, endY);
+        context.lineTo(firstPoint.x, firstPoint.y);
+      } else {
+        let 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();
+      //画连线
+      if (areaOption.addLine) {
+        if (eachSeries.lineType == 'dash') {
+          let dashLength = eachSeries.dashLength ? eachSeries.dashLength : 8;
+          dashLength *= opts.pix;
+          context.setLineDash([dashLength, dashLength]);
+        }
+        context.beginPath();
+        context.setStrokeStyle(eachSeries.color);
+        context.setLineWidth(areaOption.width * opts.pix);
+        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);
+          let startPoint = 0;
+          if (areaOption.type === 'curve') {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                let ctrlPoint = createCurveControlPoints(points, j - 1);
+                context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y);
+              }
+            };
+          }
+          if (areaOption.type === 'straight') {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                context.lineTo(item.x, item.y);
+              }
+            };
+          }
+          if (areaOption.type === 'step') {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                context.lineTo(item.x, points[j - 1].y);
+                context.lineTo(item.x, item.y);
+              }
+            };
+          }
+          context.moveTo(points[0].x, points[0].y);
+        }
+        context.stroke();
+        context.setLineDash([]);
+      }
+    }
+    //画点
+    if (opts.dataPointShape !== false) {
+      drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
+    }
+    drawActivePoint(points, eachSeries.color, eachSeries.pointShape, context, opts, areaOption,seriesIndex);
+  });
+
+  if (opts.dataLabel !== false && process === 1) {
+    series.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+      minRange = ranges.pop();
+      maxRange = ranges.shift();
+      var data = eachSeries.data;
+      var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+      drawPointText(points, eachSeries, config, context, opts);
+    });
+  }
+  context.restore();
+  return {
+    xAxisPoints: xAxisPoints,
+    calPoints: calPoints,
+    eachSpacing: eachSpacing
+  };
+}
+
+function drawScatterDataPoints(series, opts, config, context) {
+  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  var scatterOption = assign({}, {
+    type: 'circle'
+  }, opts.extra.scatter);
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  var calPoints = [];
+  context.save();
+  let leftSpace = 0;
+  let rightSpace = opts.width + eachSpacing;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
+    rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
+  }
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    var data = eachSeries.data;
+    var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+    context.beginPath();
+    context.setStrokeStyle(eachSeries.color);
+    context.setFillStyle(eachSeries.color);
+    context.setLineWidth(1 * opts.pix);
+    var shape = eachSeries.pointShape;
+    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 + 2.5 * opts.pix, item.y);
+          context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
+        }
+      });
+    } else if (shape === 'square') {
+      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);
+        }
+      });
+    } else if (shape === 'triangle') {
+      return;
+    }
+    context.closePath();
+    context.fill();
+    context.stroke();
+  });
+  if (opts.dataLabel !== false && process === 1) {
+    series.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+      minRange = ranges.pop();
+      maxRange = ranges.shift();
+      var data = eachSeries.data;
+      var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+      drawPointText(points, eachSeries, config, context, opts);
+    });
+  }
+  context.restore();
+  return {
+    xAxisPoints: xAxisPoints,
+    calPoints: calPoints,
+    eachSpacing: eachSpacing
+  };
+}
+
+function drawBubbleDataPoints(series, opts, config, context) {
+  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  var bubbleOption = assign({}, {
+    opacity: 1,
+    border:2
+  }, opts.extra.bubble);
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  var calPoints = [];
+  context.save();
+  let leftSpace = 0;
+  let rightSpace = opts.width + eachSpacing;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
+    rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
+  }
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    var data = eachSeries.data;
+    var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+    context.beginPath();
+    context.setStrokeStyle(eachSeries.color);
+    context.setLineWidth(bubbleOption.border * opts.pix);
+    context.setFillStyle(hexToRgb(eachSeries.color, bubbleOption.opacity));
+    points.forEach(function(item, index) {
+      context.moveTo(item.x + item.r, item.y);
+      context.arc(item.x, item.y, item.r * opts.pix, 0, 2 * Math.PI, false);
+    });
+    context.closePath();
+    context.fill();
+    context.stroke();
+    
+    if (opts.dataLabel !== false && process === 1) {
+      points.forEach(function(item, index) {
+        context.beginPath();
+        var fontSize = eachSeries.textSize * opts.pix || config.fontSize;
+        context.setFontSize(fontSize);
+        context.setFillStyle(eachSeries.textColor || "#FFFFFF");
+        context.setTextAlign('center');
+        context.fillText(String(item.t), item.x, item.y + fontSize/2);
+        context.closePath();
+        context.stroke();
+        context.setTextAlign('left');
+      });
+    }
+  });
+  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 lineOption = assign({}, {
+    type: 'straight',
+    width: 2,
+    activeType: 'none',
+    linearType: 'none',
+    onShadow: false,
+    animation: 'vertical',
+  }, opts.extra.line);
+  lineOption.width *= opts.pix;
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  var calPoints = [];
+  context.save();
+  let leftSpace = 0;
+  let rightSpace = opts.width + eachSpacing;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
+    rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
+  }
+  series.forEach(function(eachSeries, seriesIndex) {
+    // 这段很神奇的代码用于解决ios16的setStrokeStyle失效的bug
+    context.beginPath();
+    context.setStrokeStyle(eachSeries.color);
+    context.moveTo(-10000, -10000);
+    context.lineTo(-10001, -10001);
+    context.stroke();
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    var data = eachSeries.data;
+    var points = getLineDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, lineOption, process);
+    calPoints.push(points);
+    var splitPointList = splitPoints(points,eachSeries);
+    if (eachSeries.lineType == 'dash') {
+      let dashLength = eachSeries.dashLength ? eachSeries.dashLength : 8;
+      dashLength *= opts.pix;
+      context.setLineDash([dashLength, dashLength]);
+    }
+    context.beginPath();
+    var strokeColor = eachSeries.color;
+    if (lineOption.linearType !== 'none' && eachSeries.linearColor && eachSeries.linearColor.length > 0) {
+      var grd = context.createLinearGradient(opts.chartData.xAxisData.startX, opts.height/2, opts.chartData.xAxisData.endX, opts.height/2);
+      for (var i = 0; i < eachSeries.linearColor.length; i++) {
+        grd.addColorStop(eachSeries.linearColor[i][0], hexToRgb(eachSeries.linearColor[i][1], 1));
+      }
+      strokeColor = grd
+    }
+    context.setStrokeStyle(strokeColor);
+    if (lineOption.onShadow == true && eachSeries.setShadow && eachSeries.setShadow.length > 0) {
+      context.setShadow(eachSeries.setShadow[0], eachSeries.setShadow[1], eachSeries.setShadow[2], eachSeries.setShadow[3]);
+    }else{
+      context.setShadow(0, 0, 0, 'rgba(0,0,0,0)');
+    }
+    context.setLineWidth(lineOption.width);
+    splitPointList.forEach(function(points, index) {
+      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);
+        let startPoint = 0;
+        if (lineOption.type === 'curve') {
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              var ctrlPoint = createCurveControlPoints(points, j - 1);
+              context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y);
+            }
+          };
+        }
+        if (lineOption.type === 'straight') {
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              context.lineTo(item.x, item.y);
+            }
+          };
+        }
+        if (lineOption.type === 'step') {
+          for (let j = 0; j < points.length; j++) {
+            let item = points[j];
+            if (startPoint == 0 && item.x > leftSpace) {
+              context.moveTo(item.x, item.y);
+              startPoint = 1;
+            }
+            if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+              context.lineTo(item.x, points[j - 1].y);
+              context.lineTo(item.x, item.y);
+            }
+          };
+        }
+        context.moveTo(points[0].x, points[0].y);
+      }
+    });
+    context.stroke();
+    context.setLineDash([]);
+    if (opts.dataPointShape !== false) {
+      drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
+    }
+    drawActivePoint(points, eachSeries.color, eachSeries.pointShape, context, opts, lineOption);
+  });
+  if (opts.dataLabel !== false && process === 1) {
+    series.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+      minRange = ranges.pop();
+      maxRange = ranges.shift();
+      var data = eachSeries.data;
+      var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+      drawPointText(points, eachSeries, config, context, opts);
+    });
+  }
+  context.restore();
+  return {
+    xAxisPoints: xAxisPoints,
+    calPoints: calPoints,
+    eachSpacing: eachSpacing
+  };
+}
+
+function drawMixDataPoints(series, opts, config, context) {
+  let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    eachSpacing = xAxisData.eachSpacing;
+  let columnOption = assign({}, {
+    width: eachSpacing / 2,
+    barBorderCircle: false,
+    barBorderRadius: [],
+    seriesGap: 2,
+    linearType: 'none',
+    linearOpacity: 1,
+    customColor: [],
+    colorStop: 0,
+  }, opts.extra.mix.column);
+  let areaOption = assign({}, {
+    opacity: 0.2,
+    gradient: false
+  }, opts.extra.mix.area);
+  let lineOption = assign({}, {
+    width: 2
+  }, opts.extra.mix.line);
+  let endY = opts.height - opts.area[2];
+  let calPoints = [];
+  var columnIndex = 0;
+  var columnLength = 0;
+  series.forEach(function(eachSeries, seriesIndex) {
+    if (eachSeries.type == 'column') {
+      columnLength += 1;
+    }
+  });
+  context.save();
+  let leftNum = -2;
+  let rightNum = xAxisPoints.length + 2;
+  let leftSpace = 0;
+  let rightSpace = opts.width + eachSpacing;
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
+    context.translate(opts._scrollDistance_, 0);
+    leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
+    rightNum = leftNum + opts.xAxis.itemCount + 4;
+    leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
+    rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
+  }
+  columnOption.customColor = fillCustomColor(columnOption.linearType, columnOption.customColor, series, config);
+  series.forEach(function(eachSeries, seriesIndex) {
+    let ranges, minRange, maxRange;
+    ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+    minRange = ranges.pop();
+    maxRange = ranges.shift();
+    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);
+      for (let i = 0; i < points.length; i++) {
+        let item = points[i];
+        if (item !== null && i > leftNum && i < rightNum) {
+          var startX = item.x - item.width / 2;
+          var height = opts.height - item.y - opts.area[2];
+          context.beginPath();
+          var fillColor = item.color || eachSeries.color
+          var strokeColor = item.color || eachSeries.color
+          if (columnOption.linearType !== 'none') {
+            var grd = context.createLinearGradient(startX, item.y, startX, opts.height - opts.area[2]);
+            //透明渐变
+            if (columnOption.linearType == 'opacity') {
+              grd.addColorStop(0, hexToRgb(fillColor, columnOption.linearOpacity));
+              grd.addColorStop(1, hexToRgb(fillColor, 1));
+            } else {
+              grd.addColorStop(0, hexToRgb(columnOption.customColor[eachSeries.linearIndex], columnOption.linearOpacity));
+              grd.addColorStop(columnOption.colorStop, hexToRgb(columnOption.customColor[eachSeries.linearIndex], columnOption.linearOpacity));
+              grd.addColorStop(1, hexToRgb(fillColor, 1));
+            }
+            fillColor = grd
+          }
+          // 圆角边框
+          if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) || columnOption.barBorderCircle) {
+            const left = startX;
+            const top = item.y;
+            const width = item.width;
+            const height = opts.height - opts.area[2] - item.y;
+            if (columnOption.barBorderCircle) {
+              columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
+            }
+            let [r0, r1, r2, r3] = columnOption.barBorderRadius;
+            let minRadius = Math.min(width/2,height/2);
+            r0 = r0 > minRadius ? minRadius : r0;
+            r1 = r1 > minRadius ? minRadius : r1;
+            r2 = r2 > minRadius ? minRadius : r2;
+            r3 = r3 > minRadius ? minRadius : r3;
+            r0 = r0 < 0 ? 0 : r0;
+            r1 = r1 < 0 ? 0 : r1;
+            r2 = r2 < 0 ? 0 : r2;
+            r3 = r3 < 0 ? 0 : r3;
+            context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
+            context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
+            context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
+            context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
+          } else {
+            context.moveTo(startX, item.y);
+            context.lineTo(startX + item.width, item.y);
+            context.lineTo(startX + item.width, opts.height - opts.area[2]);
+            context.lineTo(startX, opts.height - opts.area[2]);
+            context.lineTo(startX, item.y);
+            context.setLineWidth(1)
+            context.setStrokeStyle(strokeColor);
+          }
+          context.setFillStyle(fillColor);
+          context.closePath();
+          context.fill();
+        }
+      }
+      columnIndex += 1;
+    }
+    //绘制区域图数据
+    if (eachSeries.type == 'area') {
+      let splitPointList = splitPoints(points,eachSeries);
+      for (let i = 0; i < splitPointList.length; i++) {
+        let points = splitPointList[i];
+        // 绘制区域数据
+        context.beginPath();
+        context.setStrokeStyle(eachSeries.color);
+        context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity));
+        if (areaOption.gradient) {
+          let gradient = context.createLinearGradient(0, opts.area[0], 0, opts.height - opts.area[2]);
+          gradient.addColorStop('0', hexToRgb(eachSeries.color, areaOption.opacity));
+          gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
+          context.setFillStyle(gradient);
+        } else {
+          context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity));
+        }
+        context.setLineWidth(2 * opts.pix);
+        if (points.length > 1) {
+          var firstPoint = points[0];
+          let lastPoint = points[points.length - 1];
+          context.moveTo(firstPoint.x, firstPoint.y);
+          let startPoint = 0;
+          if (eachSeries.style === 'curve') {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                var ctrlPoint = createCurveControlPoints(points, j - 1);
+                context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y, item.x, item.y);
+              }
+            };
+          } else {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                context.lineTo(item.x, item.y);
+              }
+            };
+          }
+          context.lineTo(lastPoint.x, endY);
+          context.lineTo(firstPoint.x, endY);
+          context.lineTo(firstPoint.x, firstPoint.y);
+        } else {
+          let 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();
+      }
+    }
+    // 绘制折线数据图
+    if (eachSeries.type == 'line') {
+      var splitPointList = splitPoints(points,eachSeries);
+      splitPointList.forEach(function(points, index) {
+        if (eachSeries.lineType == 'dash') {
+          let dashLength = eachSeries.dashLength ? eachSeries.dashLength : 8;
+          dashLength *= opts.pix;
+          context.setLineDash([dashLength, dashLength]);
+        }
+        context.beginPath();
+        context.setStrokeStyle(eachSeries.color);
+        context.setLineWidth(lineOption.width * opts.pix);
+        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);
+          let startPoint = 0;
+          if (eachSeries.style == 'curve') {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                var ctrlPoint = createCurveControlPoints(points, j - 1);
+                context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x, ctrlPoint.ctrB.y,
+                  item.x, item.y);
+              }
+            }
+          } else {
+            for (let j = 0; j < points.length; j++) {
+              let item = points[j];
+              if (startPoint == 0 && item.x > leftSpace) {
+                context.moveTo(item.x, item.y);
+                startPoint = 1;
+              }
+              if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
+                context.lineTo(item.x, item.y);
+              }
+            }
+          }
+          context.moveTo(points[0].x, points[0].y);
+        }
+        context.stroke();
+        context.setLineDash([]);
+      });
+    }
+    // 绘制点数据图
+    if (eachSeries.type == 'point') {
+      eachSeries.addPoint = true;
+    }
+    if (eachSeries.addPoint == true && eachSeries.type !== 'column') {
+      drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
+    }
+  });
+  if (opts.dataLabel !== false && process === 1) {
+    var columnIndex = 0;
+    series.forEach(function(eachSeries, seriesIndex) {
+      let ranges, minRange, maxRange;
+      ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
+      minRange = ranges.pop();
+      maxRange = ranges.shift();
+      var data = eachSeries.data;
+      var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
+      if (eachSeries.type !== 'column') {
+        drawPointText(points, eachSeries, config, context, opts);
+      } else {
+        points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
+        drawPointText(points, eachSeries, config, context, opts);
+        columnIndex += 1;
+      }
+    });
+  }
+  context.restore();
+  return {
+    xAxisPoints: xAxisPoints,
+    calPoints: calPoints,
+    eachSpacing: eachSpacing,
+  }
+}
+
+
+function drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints) {
+  var toolTipOption = opts.extra.tooltip || {};
+  if (toolTipOption.horizentalLine && opts.tooltip && process === 1 && (opts.type == 'line' || opts.type == 'area' || opts.type == 'column' || opts.type == 'mount' || opts.type == 'candle' || opts.type == 'mix')) {
+    drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints)
+  }
+  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, eachSpacing, xAxisPoints);
+  }
+  context.restore();
+
+}
+
+function drawXAxis(categories, opts, config, context) {
+
+  let xAxisData = opts.chartData.xAxisData,
+    xAxisPoints = xAxisData.xAxisPoints,
+    startX = xAxisData.startX,
+    endX = xAxisData.endX,
+    eachSpacing = xAxisData.eachSpacing;
+  var boundaryGap = 'center';
+  if (opts.type == 'bar' || opts.type == 'line' || opts.type == 'area'|| opts.type == 'scatter' || opts.type == 'bubble') {
+    boundaryGap = opts.xAxis.boundaryGap;
+  }
+  var startY = opts.height - opts.area[2];
+  var endY = opts.area[0];
+
+  //绘制滚动条
+  if (opts.enableScroll && opts.xAxis.scrollShow) {
+    var scrollY = opts.height - opts.area[2] + config.xAxisHeight;
+    var scrollScreenWidth = endX - startX;
+    var scrollTotalWidth = eachSpacing * (xAxisPoints.length - 1);
+    if(opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount.widthRatio > 1){
+      if(opts.extra.mount.widthRatio>2) opts.extra.mount.widthRatio = 2
+      scrollTotalWidth += (opts.extra.mount.widthRatio - 1)*eachSpacing;
+    }
+    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.pix);
+    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.pix);
+    context.setStrokeStyle(opts.xAxis.scrollColor || "#A6A6A6");
+    context.moveTo(startX + scrollLeft, scrollY);
+    context.lineTo(startX + scrollLeft + scrollWidth, scrollY);
+    context.stroke();
+    context.closePath();
+    context.setLineCap('butt');
+  }
+  context.save();
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
+    context.translate(opts._scrollDistance_, 0);
+  }
+  //绘制X轴刻度线
+  if (opts.xAxis.calibration === true) {
+    context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
+    context.setLineCap('butt');
+    context.setLineWidth(1 * opts.pix);
+    xAxisPoints.forEach(function(item, index) {
+      if (index > 0) {
+        context.beginPath();
+        context.moveTo(item - eachSpacing / 2, startY);
+        context.lineTo(item - eachSpacing / 2, startY + 3 * opts.pix);
+        context.closePath();
+        context.stroke();
+      }
+    });
+  }
+  //绘制X轴网格
+  if (opts.xAxis.disableGrid !== true) {
+    context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
+    context.setLineCap('butt');
+    context.setLineWidth(1 * opts.pix);
+    if (opts.xAxis.gridType == 'dash') {
+      context.setLineDash([opts.xAxis.dashLength * opts.pix, opts.xAxis.dashLength * opts.pix]);
+    }
+    opts.xAxis.gridEval = opts.xAxis.gridEval || 1;
+    xAxisPoints.forEach(function(item, index) {
+      if (index % opts.xAxis.gridEval == 0) {
+        context.beginPath();
+        context.moveTo(item, startY);
+        context.lineTo(item, endY);
+        context.stroke();
+      }
+    });
+    context.setLineDash([]);
+  }
+  //绘制X轴文案
+  if (opts.xAxis.disabled !== true) {
+    // 对X轴列表做抽稀处理
+    //默认全部显示X轴标签
+    let maxXAxisListLength = categories.length;
+    //如果设置了X轴单屏数量
+    if (opts.xAxis.labelCount) {
+      //如果设置X轴密度
+      if (opts.xAxis.itemCount) {
+        maxXAxisListLength = Math.ceil(categories.length / opts.xAxis.itemCount * opts.xAxis.labelCount);
+      } else {
+        maxXAxisListLength = opts.xAxis.labelCount;
+      }
+      maxXAxisListLength -= 1;
+    }
+
+    let ratio = Math.ceil(categories.length / maxXAxisListLength);
+
+    let newCategories = [];
+    let cgLength = categories.length;
+    for (let i = 0; i < cgLength; i++) {
+      if (i % ratio !== 0) {
+        newCategories.push("");
+      } else {
+        newCategories.push(categories[i]);
+      }
+    }
+    newCategories[cgLength - 1] = categories[cgLength - 1];
+    var xAxisFontSize = opts.xAxis.fontSize * opts.pix || config.fontSize;
+    if (config._xAxisTextAngle_ === 0) {
+      newCategories.forEach(function(item, index) {
+        var xitem = opts.xAxis.formatter ? opts.xAxis.formatter(item,index,opts) : item;
+        var offset = -measureText(String(xitem), xAxisFontSize, context) / 2;
+        if (boundaryGap == 'center') {
+          offset += eachSpacing / 2;
+        }
+        var scrollHeight = 0;
+        if (opts.xAxis.scrollShow) {
+          scrollHeight = 6 * opts.pix;
+        }
+        // 如果在主视图区域内
+        var _scrollDistance_ = opts._scrollDistance_ || 0;
+        var truePoints = boundaryGap == 'center' ? xAxisPoints[index] + eachSpacing / 2 : xAxisPoints[index];
+        if((truePoints - Math.abs(_scrollDistance_)) >= (opts.area[3] - 1) && (truePoints - Math.abs(_scrollDistance_)) <= (opts.width - opts.area[1] + 1)){
+          context.beginPath();
+          context.setFontSize(xAxisFontSize);
+          context.setFillStyle(opts.xAxis.fontColor || opts.fontColor);
+          context.fillText(String(xitem), xAxisPoints[index] + offset, startY + opts.xAxis.marginTop * opts.pix + (opts.xAxis.lineHeight - opts.xAxis.fontSize) * opts.pix / 2 + opts.xAxis.fontSize * opts.pix);
+          context.closePath();
+          context.stroke();
+        }
+      });
+    } else {
+      newCategories.forEach(function(item, index) {
+        var xitem = opts.xAxis.formatter ? opts.xAxis.formatter(item) : item;
+        // 如果在主视图区域内
+        var _scrollDistance_ = opts._scrollDistance_ || 0;
+        var truePoints = boundaryGap == 'center' ? xAxisPoints[index] + eachSpacing / 2 : xAxisPoints[index];
+        if((truePoints - Math.abs(_scrollDistance_)) >= (opts.area[3] - 1) && (truePoints - Math.abs(_scrollDistance_)) <= (opts.width - opts.area[1] + 1)){
+          context.save();
+          context.beginPath();
+          context.setFontSize(xAxisFontSize);
+          context.setFillStyle(opts.xAxis.fontColor || opts.fontColor);
+          var textWidth = measureText(String(xitem), xAxisFontSize, context);
+          var offsetX = xAxisPoints[index];
+          if (boundaryGap == 'center') {
+            offsetX = xAxisPoints[index] + eachSpacing / 2;
+          }
+          var scrollHeight = 0;
+          if (opts.xAxis.scrollShow) {
+            scrollHeight = 6 * opts.pix;
+          }
+          var offsetY = startY + opts.xAxis.marginTop * opts.pix + xAxisFontSize - xAxisFontSize * Math.abs(Math.sin(config._xAxisTextAngle_));
+          if(opts.xAxis.rotateAngle < 0){
+            offsetX -= xAxisFontSize / 2;
+            textWidth = 0;
+          }else{
+            offsetX += xAxisFontSize / 2;
+            textWidth = -textWidth;
+          }
+          context.translate(offsetX, offsetY);
+          context.rotate(-1 * config._xAxisTextAngle_);
+          context.fillText(String(xitem), textWidth , 0 );
+          context.closePath();
+          context.stroke();
+          context.restore();
+        }
+      });
+    }
+  }
+  context.restore();
+  
+  //画X轴标题
+  if (opts.xAxis.title) {
+    context.beginPath();
+    context.setFontSize(opts.xAxis.titleFontSize * opts.pix);
+    context.setFillStyle(opts.xAxis.titleFontColor);
+    context.fillText(String(opts.xAxis.title), opts.width - opts.area[1] + opts.xAxis.titleOffsetX * opts.pix,opts.height - opts.area[2] + opts.xAxis.marginTop * opts.pix + (opts.xAxis.lineHeight - opts.xAxis.titleFontSize) * opts.pix / 2 + (opts.xAxis.titleFontSize + opts.xAxis.titleOffsetY) * opts.pix);
+    context.closePath();
+    context.stroke();
+  }
+  
+  //绘制X轴轴线
+  if (opts.xAxis.axisLine) {
+    context.beginPath();
+    context.setStrokeStyle(opts.xAxis.axisLineColor);
+    context.setLineWidth(1 * opts.pix);
+    context.moveTo(startX, opts.height - opts.area[2]);
+    context.lineTo(endX, opts.height - opts.area[2]);
+    context.stroke();
+  }
+}
+
+function drawYAxisGrid(categories, opts, config, context) {
+  if (opts.yAxis.disableGrid === true) {
+    return;
+  }
+  let spacingValid = opts.height - opts.area[0] - opts.area[2];
+  let eachSpacing = spacingValid / opts.yAxis.splitNumber;
+  let startX = opts.area[3];
+  let xAxisPoints = opts.chartData.xAxisData.xAxisPoints,
+    xAxiseachSpacing = opts.chartData.xAxisData.eachSpacing;
+  let TotalWidth = xAxiseachSpacing * (xAxisPoints.length - 1);
+  if(opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount.widthRatio > 1 ){
+    if(opts.extra.mount.widthRatio>2) opts.extra.mount.widthRatio = 2
+    TotalWidth += (opts.extra.mount.widthRatio - 1) * xAxiseachSpacing;
+  }
+  let endX = startX + TotalWidth;
+  let points = [];
+  let startY = 1
+  if (opts.xAxis.axisLine === false) {
+    startY = 0
+  }
+  for (let i = startY; i < opts.yAxis.splitNumber + 1; i++) {
+    points.push(opts.height - opts.area[2] - eachSpacing * i);
+  }
+  context.save();
+  if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
+    context.translate(opts._scrollDistance_, 0);
+  }
+  if (opts.yAxis.gridType == 'dash') {
+    context.setLineDash([opts.yAxis.dashLength * opts.pix, opts.yAxis.dashLength * opts.pix]);
+  }
+  context.setStrokeStyle(opts.yAxis.gridColor);
+  context.setLineWidth(1 * opts.pix);
+  points.forEach(function(item, index) {
+    context.beginPath();
+    context.moveTo(startX, item);
+    context.lineTo(endX, item);
+    context.stroke();
+  });
+  context.setLineDash([]);
+  context.restore();
+}
+
+function drawYAxis(series, opts, config, context) {
+  if (opts.yAxis.disabled === true) {
+    return;
+  }
+  var spacingValid = opts.height - opts.area[0] - opts.area[2];
+  var eachSpacing = spacingValid / opts.yAxis.splitNumber;
+  var startX = opts.area[3];
+  var endX = opts.width - opts.area[1];
+  var endY = opts.height - opts.area[2];
+  // set YAxis background
+  context.beginPath();
+  context.setFillStyle(opts.background);
+  if (opts.enableScroll == true && opts.xAxis.scrollPosition && opts.xAxis.scrollPosition !== 'left') {
+    context.fillRect(0, 0, startX, endY + 2 * opts.pix);
+  }
+  if (opts.enableScroll == true && opts.xAxis.scrollPosition && opts.xAxis.scrollPosition !== 'right') {
+    context.fillRect(endX, 0, opts.width, endY + 2 * opts.pix);
+  }
+  context.closePath();
+  context.stroke();
+  
+  let tStartLeft = opts.area[3];
+  let tStartRight = opts.width - opts.area[1];
+  let tStartCenter = opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2;
+  if (opts.yAxis.data) {
+    for (let i = 0; i < opts.yAxis.data.length; i++) {
+      let yData = opts.yAxis.data[i];
+      var points = [];
+      if(yData.type === 'categories'){
+        for (let i = 0; i <= yData.categories.length; i++) {
+          points.push(opts.area[0] + spacingValid / yData.categories.length / 2 + spacingValid / yData.categories.length * i);
+        }
+      }else{
+        for (let i = 0; i <= opts.yAxis.splitNumber; i++) {
+          points.push(opts.area[0] + eachSpacing * i);
+        }
+      }
+      if (yData.disabled !== true) {
+        let rangesFormat = opts.chartData.yAxisData.rangesFormat[i];
+        let yAxisFontSize = yData.fontSize ? yData.fontSize * opts.pix : config.fontSize;
+        let yAxisWidth = opts.chartData.yAxisData.yAxisWidth[i];
+        let textAlign = yData.textAlign || "right";
+        //画Y轴刻度及文案
+        rangesFormat.forEach(function(item, index) {
+          var pos = points[index];
+          context.beginPath();
+          context.setFontSize(yAxisFontSize);
+          context.setLineWidth(1 * opts.pix);
+          context.setStrokeStyle(yData.axisLineColor || '#cccccc');
+          context.setFillStyle(yData.fontColor || opts.fontColor);
+          let tmpstrat = 0;
+          let gapwidth = 4 * opts.pix;
+          if (yAxisWidth.position == 'left') {
+            //画刻度线
+            if (yData.calibration == true) {
+              context.moveTo(tStartLeft, pos);
+              context.lineTo(tStartLeft - 3 * opts.pix, pos);
+              gapwidth += 3 * opts.pix;
+            }
+            //画文字
+            switch (textAlign) {
+              case "left":
+                context.setTextAlign('left');
+                tmpstrat = tStartLeft - yAxisWidth.width
+                break;
+              case "right":
+                context.setTextAlign('right');
+                tmpstrat = tStartLeft - gapwidth
+                break;
+              default:
+                context.setTextAlign('center');
+                tmpstrat = tStartLeft - yAxisWidth.width / 2
+            }
+            context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
+
+          } else if (yAxisWidth.position == 'right') {
+            //画刻度线
+            if (yData.calibration == true) {
+              context.moveTo(tStartRight, pos);
+              context.lineTo(tStartRight + 3 * opts.pix, pos);
+              gapwidth += 3 * opts.pix;
+            }
+            switch (textAlign) {
+              case "left":
+                context.setTextAlign('left');
+                tmpstrat = tStartRight + gapwidth
+                break;
+              case "right":
+                context.setTextAlign('right');
+                tmpstrat = tStartRight + yAxisWidth.width
+                break;
+              default:
+                context.setTextAlign('center');
+                tmpstrat = tStartRight + yAxisWidth.width / 2
+            }
+            context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
+          } else if (yAxisWidth.position == 'center') {
+            //画刻度线
+            if (yData.calibration == true) {
+              context.moveTo(tStartCenter, pos);
+              context.lineTo(tStartCenter - 3 * opts.pix, pos);
+              gapwidth += 3 * opts.pix;
+            }
+            //画文字
+            switch (textAlign) {
+              case "left":
+                context.setTextAlign('left');
+                tmpstrat = tStartCenter - yAxisWidth.width
+                break;
+              case "right":
+                context.setTextAlign('right');
+                tmpstrat = tStartCenter - gapwidth
+                break;
+              default:
+                context.setTextAlign('center');
+                tmpstrat = tStartCenter - yAxisWidth.width / 2
+            }
+            context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
+          }
+          context.closePath();
+          context.stroke();
+          context.setTextAlign('left');
+        });
+        //画Y轴轴线
+        if (yData.axisLine !== false) {
+          context.beginPath();
+          context.setStrokeStyle(yData.axisLineColor || '#cccccc');
+          context.setLineWidth(1 * opts.pix);
+          if (yAxisWidth.position == 'left') {
+            context.moveTo(tStartLeft, opts.height - opts.area[2]);
+            context.lineTo(tStartLeft, opts.area[0]);
+          } else if (yAxisWidth.position == 'right') {
+            context.moveTo(tStartRight, opts.height - opts.area[2]);
+            context.lineTo(tStartRight, opts.area[0]);
+          } else if (yAxisWidth.position == 'center') {
+            context.moveTo(tStartCenter, opts.height - opts.area[2]);
+            context.lineTo(tStartCenter, opts.area[0]);
+          }
+          context.stroke();
+        }
+        //画Y轴标题
+        if (opts.yAxis.showTitle) {
+          let titleFontSize = yData.titleFontSize * opts.pix || config.fontSize;
+          let title = yData.title;
+          context.beginPath();
+          context.setFontSize(titleFontSize);
+          context.setFillStyle(yData.titleFontColor || opts.fontColor);
+          if (yAxisWidth.position == 'left') {
+            context.fillText(title, tStartLeft - measureText(title, titleFontSize, context) / 2 + (yData.titleOffsetX || 0), opts.area[0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
+          } else if (yAxisWidth.position == 'right') {
+            context.fillText(title, tStartRight - measureText(title, titleFontSize, context) / 2 + (yData.titleOffsetX || 0), opts.area[0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
+          } else if (yAxisWidth.position == 'center') {
+            context.fillText(title, tStartCenter - measureText(title, titleFontSize, context) / 2 + (yData.titleOffsetX || 0), opts.area[0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
+          }
+          context.closePath();
+          context.stroke();
+        }
+        if (yAxisWidth.position == 'left') {
+          tStartLeft -= (yAxisWidth.width + opts.yAxis.padding * opts.pix);
+        } else {
+          tStartRight += yAxisWidth.width + opts.yAxis.padding * opts.pix;
+        }
+      }
+    }
+  }
+
+}
+
+function drawLegend(series, opts, config, context, chartData) {
+  if (opts.legend.show === false) {
+    return;
+  }
+  let legendData = chartData.legendData;
+  let legendList = legendData.points;
+  let legendArea = legendData.area;
+  let padding = opts.legend.padding * opts.pix;
+  let fontSize = opts.legend.fontSize * opts.pix;
+  let shapeWidth = 15 * opts.pix;
+  let shapeRight = 5 * opts.pix;
+  let itemGap = opts.legend.itemGap * opts.pix;
+  let lineHeight = Math.max(opts.legend.lineHeight * opts.pix, fontSize);
+  //画背景及边框
+  context.beginPath();
+  context.setLineWidth(opts.legend.borderWidth * opts.pix);
+  context.setStrokeStyle(opts.legend.borderColor);
+  context.setFillStyle(opts.legend.backgroundColor);
+  context.moveTo(legendArea.start.x, legendArea.start.y);
+  context.rect(legendArea.start.x, legendArea.start.y, legendArea.width, legendArea.height);
+  context.closePath();
+  context.fill();
+  context.stroke();
+  legendList.forEach(function(itemList, listIndex) {
+    let width = 0;
+    let height = 0;
+    width = legendData.widthArr[listIndex];
+    height = legendData.heightArr[listIndex];
+    let startX = 0;
+    let startY = 0;
+    if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
+      switch (opts.legend.float) {
+        case 'left':
+          startX = legendArea.start.x + padding;
+        break;
+        case 'right':
+          startX = legendArea.start.x + legendArea.width - width;
+        break;
+        default:
+        startX = legendArea.start.x + (legendArea.width - width) / 2;
+      }
+      startY = legendArea.start.y + padding + listIndex * lineHeight;
+    } else {
+      if (listIndex == 0) {
+        width = 0;
+      } else {
+        width = legendData.widthArr[listIndex - 1];
+      }
+      startX = legendArea.start.x + padding + width;
+      startY = legendArea.start.y + padding + (legendArea.height - height) / 2;
+    }
+    context.setFontSize(config.fontSize);
+    for (let i = 0; i < itemList.length; i++) {
+      let item = itemList[i];
+      item.area = [0, 0, 0, 0];
+      item.area[0] = startX;
+      item.area[1] = startY;
+      item.area[3] = startY + lineHeight;
+      context.beginPath();
+      context.setLineWidth(1 * opts.pix);
+      context.setStrokeStyle(item.show ? item.color : opts.legend.hiddenColor);
+      context.setFillStyle(item.show ? item.color : opts.legend.hiddenColor);
+      switch (item.legendShape) {
+        case 'line':
+          context.moveTo(startX, startY + 0.5 * lineHeight - 2 * opts.pix);
+          context.fillRect(startX, startY + 0.5 * lineHeight - 2 * opts.pix, 15 * opts.pix, 4 * opts.pix);
+          break;
+        case 'triangle':
+          context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
+          context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
+          context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
+          context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
+          break;
+        case 'diamond':
+          context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
+          context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * lineHeight);
+          context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
+          context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * lineHeight);
+          context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
+          break;
+        case 'circle':
+          context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight);
+          context.arc(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight, 5 * opts.pix, 0, 2 * Math.PI);
+          break;
+        case 'rect':
+          context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pix);
+          context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
+          break;
+        case 'square':
+          context.moveTo(startX + 5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
+          context.fillRect(startX + 5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix, 10 * opts.pix, 10 * opts.pix);
+          break;
+        case 'none':
+          break;
+        default:
+          context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pix);
+          context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pix, 15 * opts.pix, 10 * opts.pix);
+      }
+      context.closePath();
+      context.fill();
+      context.stroke();
+      startX += shapeWidth + shapeRight;
+      let fontTrans = 0.5 * lineHeight + 0.5 * fontSize - 2;
+      const legendText = item.legendText ? item.legendText : item.name;
+      context.beginPath();
+      context.setFontSize(fontSize);
+      context.setFillStyle(item.show ? opts.legend.fontColor : opts.legend.hiddenColor);
+      context.fillText(legendText, startX, startY + fontTrans);
+      context.closePath();
+      context.stroke();
+      if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
+        startX += measureText(legendText, fontSize, context) + itemGap;
+        item.area[2] = startX;
+      } else {
+        item.area[2] = startX + measureText(legendText, fontSize, context) + itemGap;;
+        startX -= shapeWidth + shapeRight;
+        startY += lineHeight;
+      }
+    }
+  });
+}
+
+function drawPieDataPoints(series, opts, config, context) {
+  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  var pieOption = assign({}, {
+    activeOpacity: 0.5,
+    activeRadius: 10,
+    offsetAngle: 0,
+    labelWidth: 15,
+    ringWidth: 30,
+    customRadius: 0,
+    border: false,
+    borderWidth: 2,
+    borderColor: '#FFFFFF',
+    centerColor: '#FFFFFF',
+    linearType: 'none',
+    customColor: [],
+  }, opts.type == "pie" ? opts.extra.pie : opts.extra.ring);
+  var centerPosition = {
+    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
+    y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
+  };
+  if (config.pieChartLinePadding == 0) {
+    config.pieChartLinePadding = pieOption.activeRadius * opts.pix;
+  }
+
+  var radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding);
+  radius = radius < 10 ? 10 : radius;
+  if (pieOption.customRadius > 0) {
+    radius = pieOption.customRadius * opts.pix;
+  }
+  series = getPieDataPoints(series, radius, process);
+  var activeRadius = pieOption.activeRadius * opts.pix;
+  pieOption.customColor = fillCustomColor(pieOption.linearType, pieOption.customColor, series, config);
+  series = series.map(function(eachSeries) {
+    eachSeries._start_ += (pieOption.offsetAngle) * Math.PI / 180;
+    return eachSeries;
+  });
+  series.forEach(function(eachSeries, seriesIndex) {
+    if (opts.tooltip) {
+      if (opts.tooltip.index == seriesIndex) {
+        context.beginPath();
+        context.setFillStyle(hexToRgb(eachSeries.color, pieOption.activeOpacity || 0.5));
+        context.moveTo(centerPosition.x, centerPosition.y);
+        context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_ + activeRadius, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI);
+        context.closePath();
+        context.fill();
+      }
+    }
+    context.beginPath();
+    context.setLineWidth(pieOption.borderWidth * opts.pix);
+    context.lineJoin = "round";
+    context.setStrokeStyle(pieOption.borderColor);
+    var fillcolor = eachSeries.color;
+    if (pieOption.linearType == 'custom') {
+      var grd;
+      if(context.createCircularGradient){
+        grd = context.createCircularGradient(centerPosition.x, centerPosition.y, eachSeries._radius_)
+      }else{
+        grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0,centerPosition.x, centerPosition.y, eachSeries._radius_)
+      }
+      grd.addColorStop(0, hexToRgb(pieOption.customColor[eachSeries.linearIndex], 1))
+      grd.addColorStop(1, hexToRgb(eachSeries.color, 1))
+      fillcolor = grd
+    }
+    context.setFillStyle(fillcolor);
+    context.moveTo(centerPosition.x, centerPosition.y);
+    context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI);
+    context.closePath();
+    context.fill();
+    if (pieOption.border == true) {
+      context.stroke();
+    }
+  });
+  if (opts.type === 'ring') {
+    var innerPieWidth = radius * 0.6;
+    if (typeof pieOption.ringWidth === 'number' && pieOption.ringWidth > 0) {
+      innerPieWidth = Math.max(0, radius - pieOption.ringWidth * opts.pix);
+    }
+    context.beginPath();
+    context.setFillStyle(pieOption.centerColor);
+    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) {
+    drawPieText(series, opts, config, context, radius, centerPosition);
+  }
+  if (process === 1 && opts.type === 'ring') {
+    drawRingTitle(opts, config, context, centerPosition);
+  }
+  return {
+    center: centerPosition,
+    radius: radius,
+    series: series
+  };
+}
+
+function drawRoseDataPoints(series, opts, config, context) {
+  var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  var roseOption = assign({}, {
+    type: 'area',
+    activeOpacity: 0.5,
+    activeRadius: 10,
+    offsetAngle: 0,
+    labelWidth: 15,
+    border: false,
+    borderWidth: 2,
+    borderColor: '#FFFFFF',
+    linearType: 'none',
+    customColor: [],
+  }, opts.extra.rose);
+  if (config.pieChartLinePadding == 0) {
+    config.pieChartLinePadding = roseOption.activeRadius * opts.pix;
+  }
+  var centerPosition = {
+    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
+    y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
+  };
+  var radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config.pieChartLinePadding - config.pieChartTextPadding);
+  radius = radius < 10 ? 10 : radius;
+  var minRadius = roseOption.minRadius || radius * 0.5;
+  if(radius < minRadius){
+    radius = minRadius + 10;
+  }
+  series = getRoseDataPoints(series, roseOption.type, minRadius, radius, process);
+  var activeRadius = roseOption.activeRadius * opts.pix;
+  roseOption.customColor = fillCustomColor(roseOption.linearType, roseOption.customColor, series, config);
+  series = series.map(function(eachSeries) {
+    eachSeries._start_ += (roseOption.offsetAngle || 0) * Math.PI / 180;
+    return eachSeries;
+  });
+  series.forEach(function(eachSeries, seriesIndex) {
+    if (opts.tooltip) {
+      if (opts.tooltip.index == seriesIndex) {
+        context.beginPath();
+        context.setFillStyle(hexToRgb(eachSeries.color, roseOption.activeOpacity || 0.5));
+        context.moveTo(centerPosition.x, centerPosition.y);
+        context.arc(centerPosition.x, centerPosition.y, activeRadius + eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._rose_proportion_ * Math.PI);
+        context.closePath();
+        context.fill();
+      }
+    }
+    context.beginPath();
+    context.setLineWidth(roseOption.borderWidth * opts.pix);
+    context.lineJoin = "round";
+    context.setStrokeStyle(roseOption.borderColor);
+    var fillcolor = eachSeries.color;
+    if (roseOption.linearType == 'custom') {
+      var grd;
+      if(context.createCircularGradient){
+        grd = context.createCircularGradient(centerPosition.x, centerPosition.y, eachSeries._radius_)
+      }else{
+        grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0,centerPosition.x, centerPosition.y, eachSeries._radius_)
+      }
+      grd.addColorStop(0, hexToRgb(roseOption.customColor[eachSeries.linearIndex], 1))
+      grd.addColorStop(1, hexToRgb(eachSeries.color, 1))
+      fillcolor = grd
+    }
+    context.setFillStyle(fillcolor);
+    context.moveTo(centerPosition.x, centerPosition.y);
+    context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries._start_ + 2 * eachSeries._rose_proportion_ * Math.PI);
+    context.closePath();
+    context.fill();
+    if (roseOption.border == true) {
+      context.stroke();
+    }
+  });
+
+  if (opts.dataLabel !== false && process === 1) {
+    drawPieText(series, opts, config, context, radius, centerPosition);
+  }
+  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 = assign({}, {
+    startAngle: 0.75,
+    endAngle: 0.25,
+    type: 'default',
+    direction: 'cw',
+    lineCap: 'round',
+    width: 12 ,
+    gap: 2 ,
+    linearType: 'none',
+    customColor: [],
+  }, opts.extra.arcbar);
+  series = getArcbarDataPoints(series, arcbarOption, process);
+  var centerPosition;
+  if (arcbarOption.centerX || arcbarOption.centerY) {
+    centerPosition = {
+      x: arcbarOption.centerX ? arcbarOption.centerX : opts.width / 2,
+      y: arcbarOption.centerY ? arcbarOption.centerY : opts.height / 2
+    };
+  } else {
+    centerPosition = {
+      x: opts.width / 2,
+      y: opts.height / 2
+    };
+  }
+  var radius;
+  if (arcbarOption.radius) {
+    radius = arcbarOption.radius;
+  } else {
+    radius = Math.min(centerPosition.x, centerPosition.y);
+    radius -= 5 * opts.pix;
+    radius -= arcbarOption.width / 2;
+  }
+  radius = radius < 10 ? 10 : radius;
+  arcbarOption.customColor = fillCustomColor(arcbarOption.linearType, arcbarOption.customColor, series, config);
+  
+  for (let i = 0; i < series.length; i++) {
+    let eachSeries = series[i];
+    //背景颜色
+    context.setLineWidth(arcbarOption.width * opts.pix);
+    context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9');
+    context.setLineCap(arcbarOption.lineCap);
+    context.beginPath();
+    if (arcbarOption.type == 'default') {
+      context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap * opts.pix) * i, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * Math.PI, arcbarOption.direction == 'ccw');
+    } else {
+      context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap * opts.pix) * i, 0, 2 * Math.PI, arcbarOption.direction == 'ccw');
+    }
+    context.stroke();
+    //进度条
+    var fillColor = eachSeries.color
+    if(arcbarOption.linearType == 'custom'){
+      var grd = context.createLinearGradient(centerPosition.x - radius, centerPosition.y, centerPosition.x + radius, centerPosition.y);
+      grd.addColorStop(1, hexToRgb(arcbarOption.customColor[eachSeries.linearIndex], 1))
+      grd.addColorStop(0, hexToRgb(eachSeries.color, 1))
+      fillColor = grd;
+    }
+    context.setLineWidth(arcbarOption.width * opts.pix);
+    context.setStrokeStyle(fillColor);
+    context.setLineCap(arcbarOption.lineCap);
+    context.beginPath();
+    context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap * opts.pix) * i, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ * Math.PI, arcbarOption.direction == 'ccw');
+    context.stroke();
+  }
+  drawRingTitle(opts, config, context, centerPosition);
+  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 = assign({}, {
+    type: 'default',
+    startAngle: 0.75,
+    endAngle: 0.25,
+    width: 15,
+    labelOffset:13,
+    splitLine: {
+      fixRadius: 0,
+      splitNumber: 10,
+      width: 15,
+      color: '#FFFFFF',
+      childNumber: 5,
+      childWidth: 5
+    },
+    pointer: {
+      width: 15,
+      color: 'auto'
+    }
+  }, opts.extra.gauge);
+  if (gaugeOption.oldAngle == undefined) {
+    gaugeOption.oldAngle = gaugeOption.startAngle;
+  }
+  if (gaugeOption.oldData == undefined) {
+    gaugeOption.oldData = 0;
+  }
+  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);
+  radius -= 5 * opts.pix;
+  radius -= gaugeOption.width / 2;
+  radius = radius < 10 ? 10 : radius;
+  var innerRadius = radius - gaugeOption.width;
+  var totalAngle = 0;
+  //判断仪表盘的样式:default百度样式,progress新样式
+  if (gaugeOption.type == 'progress') {
+    //## 第一步画中心圆形背景和进度条背景
+    //中心圆形背景
+    var pieRadius = radius - gaugeOption.width * 3;
+    context.beginPath();
+    let gradient = context.createLinearGradient(centerPosition.x, centerPosition.y - pieRadius, centerPosition.x, centerPosition.y + pieRadius);
+    //配置渐变填充(起点:中心点向上减半径;结束点中心点向下加半径)
+    gradient.addColorStop('0', hexToRgb(series[0].color, 0.3));
+    gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
+    context.setFillStyle(gradient);
+    context.arc(centerPosition.x, centerPosition.y, pieRadius, 0, 2 * Math.PI, false);
+    context.fill();
+    //画进度条背景
+    context.setLineWidth(gaugeOption.width);
+    context.setStrokeStyle(hexToRgb(series[0].color, 0.3));
+    context.setLineCap('round');
+    context.beginPath();
+    context.arc(centerPosition.x, centerPosition.y, innerRadius, gaugeOption.startAngle * Math.PI, gaugeOption.endAngle * Math.PI, false);
+    context.stroke();
+    //## 第二步画刻度线
+    if (gaugeOption.endAngle < gaugeOption.startAngle) {
+      totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
+    } else {
+      totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
+    }
+    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 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;
+    context.save();
+    context.translate(centerPosition.x, centerPosition.y);
+    context.rotate((gaugeOption.startAngle - 1) * Math.PI);
+    let len = gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1;
+    let proc = series[0].data * process;
+    for (let i = 0; i < len; i++) {
+      context.beginPath();
+      //刻度线随进度变色
+      if (proc > (i / len)) {
+        context.setStrokeStyle(hexToRgb(series[0].color, 1));
+      } else {
+        context.setStrokeStyle(hexToRgb(series[0].color, 0.3));
+      }
+      context.setLineWidth(3 * opts.pix);
+      context.moveTo(startX, 0);
+      context.lineTo(endX, 0);
+      context.stroke();
+      context.rotate(childAngle * Math.PI);
+    }
+    context.restore();
+    //## 第三步画进度条
+    series = getGaugeArcbarDataPoints(series, gaugeOption, process);
+    context.setLineWidth(gaugeOption.width);
+    context.setStrokeStyle(series[0].color);
+    context.setLineCap('round');
+    context.beginPath();
+    context.arc(centerPosition.x, centerPosition.y, innerRadius, gaugeOption.startAngle * Math.PI, series[0]._proportion_ * Math.PI, false);
+    context.stroke();
+    //## 第四步画指针
+    let pointerRadius = radius - gaugeOption.width * 2.5;
+    context.save();
+    context.translate(centerPosition.x, centerPosition.y);
+    context.rotate((series[0]._proportion_ - 1) * Math.PI);
+    context.beginPath();
+    context.setLineWidth(gaugeOption.width / 3);
+    let gradient3 = context.createLinearGradient(0, -pointerRadius * 0.6, 0, pointerRadius * 0.6);
+    gradient3.addColorStop('0', hexToRgb('#FFFFFF', 0));
+    gradient3.addColorStop('0.5', hexToRgb(series[0].color, 1));
+    gradient3.addColorStop('1.0', hexToRgb('#FFFFFF', 0));
+    context.setStrokeStyle(gradient3);
+    context.arc(0, 0, pointerRadius, 0.85 * Math.PI, 1.15 * Math.PI, false);
+    context.stroke();
+    context.beginPath();
+    context.setLineWidth(1);
+    context.setStrokeStyle(series[0].color);
+    context.setFillStyle(series[0].color);
+    context.moveTo(-pointerRadius - gaugeOption.width / 3 / 2, -4);
+    context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2 - 4, 0);
+    context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2, 4);
+    context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2, -4);
+    context.stroke();
+    context.fill();
+    context.restore();
+    //default百度样式
+  } else {
+    //画背景
+    context.setLineWidth(gaugeOption.width);
+    context.setLineCap('butt');
+    for (let i = 0; i < categories.length; i++) {
+      let eachCategories = categories[i];
+      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();
+    //画刻度线
+    if (gaugeOption.endAngle < gaugeOption.startAngle) {
+      totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
+    } else {
+      totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
+    }
+    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.pix);
+      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.pix);
+      context.moveTo(startX, 0);
+      context.lineTo(childendX, 0);
+      context.stroke();
+      context.rotate(childAngle * Math.PI);
+    }
+    context.restore();
+    //画指针
+    series = getGaugeDataPoints(series, categories, gaugeOption, process);
+    for (let i = 0; i < series.length; i++) {
+      let eachSeries = series[i];
+      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, centerPosition);
+  if (process === 1 && opts.type === 'gauge') {
+    opts.extra.gauge.oldAngle = series[0]._proportion_;
+    opts.extra.gauge.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 = assign({}, {
+    gridColor: '#cccccc',
+    gridType: 'radar',
+    gridEval:1,
+    axisLabel:false,
+    axisLabelTofix:0,
+    labelShow:true,
+    labelColor:'#666666',
+    labelPointShow:false,
+    labelPointRadius:3,
+    labelPointColor:'#cccccc',
+    opacity: 0.2,
+    gridCount: 3,
+    border:false,
+    borderWidth:2,
+    linearType: 'none',
+    customColor: [],
+  }, opts.extra.radar);
+  var coordinateAngle = getRadarCoordinateSeries(opts.categories.length);
+  var centerPosition = {
+    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
+    y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
+  };
+  var xr = (opts.width - opts.area[1] - opts.area[3]) / 2
+  var yr = (opts.height - opts.area[0] - opts.area[2]) / 2
+  var radius = Math.min(xr - (getMaxTextListLength(opts.categories, config.fontSize, context) + config.radarLabelTextMargin), yr - config.radarLabelTextMargin);
+  radius -= config.radarLabelTextMargin * opts.pix;
+  radius = radius < 10 ? 10 : radius;
+  radius = radarOption.radius ? radarOption.radius : radius;
+  // 画分割线
+  context.beginPath();
+  context.setLineWidth(1 * opts.pix);
+  context.setStrokeStyle(radarOption.gridColor);
+  coordinateAngle.forEach(function(angle,index) {
+    var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition);
+    context.moveTo(centerPosition.x, centerPosition.y);
+    if (index % radarOption.gridEval == 0) {
+      context.lineTo(pos.x, pos.y);
+    }
+  });
+  context.stroke();
+  context.closePath();
+  
+  // 画背景网格
+  var _loop = function _loop(i) {
+    var startPos = {};
+    context.beginPath();
+    context.setLineWidth(1 * opts.pix);
+    context.setStrokeStyle(radarOption.gridColor);
+    if (radarOption.gridType == 'radar') {
+      coordinateAngle.forEach(function(angle, index) {
+        var pos = convertCoordinateOrigin(radius / radarOption.gridCount * i * Math.cos(angle), radius /
+          radarOption.gridCount * 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);
+    } else {
+      var pos = convertCoordinateOrigin(radius / radarOption.gridCount * i * Math.cos(1.5), radius / radarOption.gridCount * i * Math.sin(1.5), centerPosition);
+      context.arc(centerPosition.x, centerPosition.y, centerPosition.y - pos.y, 0, 2 * Math.PI, false);
+    }
+    context.stroke();
+    context.closePath();
+  };
+  for (var i = 1; i <= radarOption.gridCount; i++) {
+    _loop(i);
+  }
+  radarOption.customColor = fillCustomColor(radarOption.linearType, radarOption.customColor, series, config);
+  var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process);
+  radarDataPoints.forEach(function(eachSeries, seriesIndex) {
+    // 绘制区域数据
+    context.beginPath();
+    context.setLineWidth(radarOption.borderWidth * opts.pix);
+    context.setStrokeStyle(eachSeries.color);
+    
+    var fillcolor = hexToRgb(eachSeries.color, radarOption.opacity);
+    if (radarOption.linearType == 'custom') {
+      var grd;
+      if(context.createCircularGradient){
+        grd = context.createCircularGradient(centerPosition.x, centerPosition.y, radius)
+      }else{
+        grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0,centerPosition.x, centerPosition.y, radius)
+      }
+      grd.addColorStop(0, hexToRgb(radarOption.customColor[series[seriesIndex].linearIndex], radarOption.opacity))
+      grd.addColorStop(1, hexToRgb(eachSeries.color, radarOption.opacity))
+      fillcolor = grd
+    }
+    
+    context.setFillStyle(fillcolor);
+    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();
+    if(radarOption.border === true){
+      context.stroke();
+    }
+    context.closePath();
+    if (opts.dataPointShape !== false) {
+      var points = eachSeries.data.map(function(item) {
+        return item.position;
+      });
+      drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
+    }
+  });
+  // 画刻度值
+  if(radarOption.axisLabel === true){
+    const maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series)));
+    const stepLength = radius / radarOption.gridCount;
+    const fontSize = opts.fontSize * opts.pix;
+    context.setFontSize(fontSize);
+    context.setFillStyle(opts.fontColor);
+    context.setTextAlign('left');
+    for (var i = 0; i < radarOption.gridCount + 1; i++) {
+      let label = i * maxData / radarOption.gridCount;
+      label = label.toFixed(radarOption.axisLabelTofix);
+      context.fillText(String(label), centerPosition.x + 3 * opts.pix, centerPosition.y - i * stepLength + fontSize / 2);
+    }
+  }
+  
+  // draw label text
+  drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context);
+  
+  // draw dataLabel
+  if (opts.dataLabel !== false && process === 1) {
+    radarDataPoints.forEach(function(eachSeries, seriesIndex) {
+      context.beginPath();
+      var fontSize = eachSeries.textSize * opts.pix || config.fontSize;
+      context.setFontSize(fontSize);
+      context.setFillStyle(eachSeries.textColor || opts.fontColor);
+      eachSeries.data.forEach(function(item, index) {
+        //如果是中心点垂直的上下点位
+        if(Math.abs(item.position.x - centerPosition.x)<2){
+          //如果在上面
+          if(item.position.y < centerPosition.y){
+            context.setTextAlign('center');
+            context.fillText(item.value, item.position.x, item.position.y - 4);
+          }else{
+            context.setTextAlign('center');
+            context.fillText(item.value, item.position.x, item.position.y + fontSize + 2);
+          }
+        }else{
+          //如果在左侧
+          if(item.position.x < centerPosition.x){
+            context.setTextAlign('right');
+            context.fillText(item.value, item.position.x - 4, item.position.y + fontSize / 2 - 2);
+          }else{
+            context.setTextAlign('left');
+            context.fillText(item.value, item.position.x + 4, item.position.y + fontSize / 2 - 2);
+          }
+        }
+      });
+      context.closePath();
+      context.stroke();
+    });
+    context.setTextAlign('left');
+  }
+  
+  return {
+    center: centerPosition,
+    radius: radius,
+    angleList: coordinateAngle
+  };
+}
+
+// 经纬度转墨卡托
+function lonlat2mercator(longitude, latitude) {
+  var mercator = Array(2);
+  var x = longitude * 20037508.34 / 180;
+  var y = Math.log(Math.tan((90 + latitude) * Math.PI / 360)) / (Math.PI / 180);
+  y = y * 20037508.34 / 180;
+  mercator[0] = x;
+  mercator[1] = y;
+  return mercator;
+}
+
+// 墨卡托转经纬度
+function mercator2lonlat(longitude, latitude) {
+  var lonlat = Array(2)
+  var x = longitude / 20037508.34 * 180;
+  var y = latitude / 20037508.34 * 180;
+  y = 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
+  lonlat[0] = x;
+  lonlat[1] = y;
+  return lonlat;
+}
+
+function getBoundingBox(data) {
+  var bounds = {},coords;
+  bounds.xMin = 180;
+  bounds.xMax = 0;
+  bounds.yMin = 90;
+  bounds.yMax = 0
+  for (var i = 0; i < data.length; i++) {
+    var coorda = data[i].geometry.coordinates
+    for (var k = 0; k < coorda.length; k++) {
+      coords = coorda[k];
+      if (coords.length == 1) {
+        coords = coords[0]
+      }
+      for (var j = 0; j < coords.length; j++) {
+        var longitude = coords[j][0];
+        var latitude = coords[j][1];
+        var point = {
+          x: longitude,
+          y: latitude
+        }
+        bounds.xMin = bounds.xMin < point.x ? bounds.xMin : point.x;
+        bounds.xMax = bounds.xMax > point.x ? bounds.xMax : point.x;
+        bounds.yMin = bounds.yMin < point.y ? bounds.yMin : point.y;
+        bounds.yMax = bounds.yMax > point.y ? bounds.yMax : point.y;
+      }
+    }
+  }
+  return bounds;
+}
+
+function coordinateToPoint(latitude, longitude, bounds, scale, xoffset, yoffset) {
+  return {
+    x: (longitude - bounds.xMin) * scale + xoffset,
+    y: (bounds.yMax - latitude) * scale + yoffset
+  };
+}
+
+function pointToCoordinate(pointY, pointX, bounds, scale, xoffset, yoffset) {
+  return {
+    x: (pointX - xoffset) / scale + bounds.xMin,
+    y: bounds.yMax - (pointY - yoffset) / scale
+  };
+}
+
+function isRayIntersectsSegment(poi, s_poi, e_poi) {
+  if (s_poi[1] == e_poi[1]) {
+    return false;
+  }
+  if (s_poi[1] > poi[1] && e_poi[1] > poi[1]) {
+    return false;
+  }
+  if (s_poi[1] < poi[1] && e_poi[1] < poi[1]) {
+    return false;
+  }
+  if (s_poi[1] == poi[1] && e_poi[1] > poi[1]) {
+    return false;
+  }
+  if (e_poi[1] == poi[1] && s_poi[1] > poi[1]) {
+    return false;
+  }
+  if (s_poi[0] < poi[0] && e_poi[1] < poi[1]) {
+    return false;
+  }
+  let xseg = e_poi[0] - (e_poi[0] - s_poi[0]) * (e_poi[1] - poi[1]) / (e_poi[1] - s_poi[1]);
+  if (xseg < poi[0]) {
+    return false;
+  } else {
+    return true;
+  }
+}
+
+function isPoiWithinPoly(poi, poly, mercator) {
+  let sinsc = 0;
+  for (let i = 0; i < poly.length; i++) {
+    let epoly = poly[i][0];
+    if (poly.length == 1) {
+      epoly = poly[i][0]
+    }
+    for (let j = 0; j < epoly.length - 1; j++) {
+      let s_poi = epoly[j];
+      let e_poi = epoly[j + 1];
+      if (mercator) {
+        s_poi = lonlat2mercator(epoly[j][0], epoly[j][1]);
+        e_poi = lonlat2mercator(epoly[j + 1][0], epoly[j + 1][1]);
+      }
+      if (isRayIntersectsSegment(poi, s_poi, e_poi)) {
+        sinsc += 1;
+      }
+    }
+  }
+  if (sinsc % 2 == 1) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+function drawMapDataPoints(series, opts, config, context) {
+  var mapOption = assign({}, {
+    border: true,
+    mercator: false,
+    borderWidth: 1,
+    active:true,
+    borderColor: '#666666',
+    fillOpacity: 0.6,
+    activeBorderColor: '#f04864',
+    activeFillColor: '#facc14',
+    activeFillOpacity: 1
+  }, opts.extra.map);
+  var coords, point;
+  var data = series;
+  var bounds = getBoundingBox(data);
+  if (mapOption.mercator) {
+    var max = lonlat2mercator(bounds.xMax, bounds.yMax)
+    var min = lonlat2mercator(bounds.xMin, bounds.yMin)
+    bounds.xMax = max[0]
+    bounds.yMax = max[1]
+    bounds.xMin = min[0]
+    bounds.yMin = min[1]
+  }
+  var xScale = opts.width / Math.abs(bounds.xMax - bounds.xMin);
+  var yScale = opts.height / Math.abs(bounds.yMax - bounds.yMin);
+  var scale = xScale < yScale ? xScale : yScale;
+  var xoffset = opts.width / 2 - Math.abs(bounds.xMax - bounds.xMin) / 2 * scale;
+  var yoffset = opts.height / 2 - Math.abs(bounds.yMax - bounds.yMin) / 2 * scale;
+  for (var i = 0; i < data.length; i++) {
+    context.beginPath();
+    context.setLineWidth(mapOption.borderWidth * opts.pix);
+    context.setStrokeStyle(mapOption.borderColor);
+    context.setFillStyle(hexToRgb(series[i].color, series[i].fillOpacity||mapOption.fillOpacity));
+    if (mapOption.active == true && opts.tooltip) {
+      if (opts.tooltip.index == i) {
+        context.setStrokeStyle(mapOption.activeBorderColor);
+        context.setFillStyle(hexToRgb(mapOption.activeFillColor, mapOption.activeFillOpacity));
+      }
+    }
+    var coorda = data[i].geometry.coordinates
+    for (var k = 0; k < coorda.length; k++) {
+      coords = coorda[k];
+      if (coords.length == 1) {
+        coords = coords[0]
+      }
+      for (var j = 0; j < coords.length; j++) {
+        var gaosi = Array(2);
+        if (mapOption.mercator) {
+          gaosi = lonlat2mercator(coords[j][0], coords[j][1])
+        } else {
+          gaosi = coords[j]
+        }
+        point = coordinateToPoint(gaosi[1], gaosi[0], bounds, scale, xoffset, yoffset)
+        if (j === 0) {
+          context.beginPath();
+          context.moveTo(point.x, point.y);
+        } else {
+          context.lineTo(point.x, point.y);
+        }
+      }
+      context.fill();
+      if (mapOption.border == true) {
+        context.stroke();
+      }
+    }
+  }
+  if (opts.dataLabel == true) {
+    for (var i = 0; i < data.length; i++) {
+      var centerPoint = data[i].properties.centroid;
+      if (centerPoint) {
+        if (mapOption.mercator) {
+          centerPoint = lonlat2mercator(data[i].properties.centroid[0], data[i].properties.centroid[1])
+        }
+        point = coordinateToPoint(centerPoint[1], centerPoint[0], bounds, scale, xoffset, yoffset);
+        let fontSize = data[i].textSize * opts.pix || config.fontSize;
+        let fontColor = data[i].textColor || opts.fontColor;
+        if(mapOption.active && mapOption.activeTextColor && opts.tooltip && opts.tooltip.index == i){
+          fontColor = mapOption.activeTextColor;
+        }
+        let text = data[i].properties.name;
+        context.beginPath();
+        context.setFontSize(fontSize)
+        context.setFillStyle(fontColor)
+        context.fillText(text, point.x - measureText(text, fontSize, context) / 2, point.y + fontSize / 2);
+        context.closePath();
+        context.stroke();
+      }
+    }
+  }
+  opts.chartData.mapData = {
+    bounds: bounds,
+    scale: scale,
+    xoffset: xoffset,
+    yoffset: yoffset,
+    mercator: mapOption.mercator
+  }
+  drawToolTipBridge(opts, config, context, 1);
+  context.draw();
+}
+
+function normalInt(min, max, iter) {
+  iter = iter == 0 ? 1 : iter;
+  var arr = [];
+  for (var i = 0; i < iter; i++) {
+    arr[i] = Math.random();
+  };
+  return Math.floor(arr.reduce(function(i, j) {
+    return i + j
+  }) / iter * (max - min)) + min;
+};
+
+function collisionNew(area, points, width, height) {
+  var isIn = false;
+  for (let i = 0; i < points.length; i++) {
+    if (points[i].area) {
+      if (area[3] < points[i].area[1] || area[0] > points[i].area[2] || area[1] > points[i].area[3] || area[2] < points[i].area[0]) {
+        if (area[0] < 0 || area[1] < 0 || area[2] > width || area[3] > height) {
+          isIn = true;
+          break;
+        } else {
+          isIn = false;
+        }
+      } else {
+        isIn = true;
+        break;
+      }
+    }
+  }
+  return isIn;
+};
+
+function getWordCloudPoint(opts, type, context) {
+  let points = opts.series;
+  switch (type) {
+    case 'normal':
+      for (let i = 0; i < points.length; i++) {
+        let text = points[i].name;
+        let tHeight = points[i].textSize * opts.pix;
+        let tWidth = measureText(text, tHeight, context);
+        let x, y;
+        let area;
+        let breaknum = 0;
+        while (true) {
+          breaknum++;
+          x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
+          y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
+          area = [x - 5 + opts.width / 2, y - 5 - tHeight + opts.height / 2, x + tWidth + 5 + opts.width / 2, y + 5 +
+            opts.height / 2
+          ];
+          let isCollision = collisionNew(area, points, opts.width, opts.height);
+          if (!isCollision) break;
+          if (breaknum == 1000) {
+            area = [-100, -100, -100, -100];
+            break;
+          }
+        };
+        points[i].area = area;
+      }
+      break;
+    case 'vertical':
+      function Spin() {
+        //获取均匀随机值,是否旋转,旋转的概率为(1-0.5)
+        if (Math.random() > 0.7) {
+          return true;
+        } else {
+          return false
+        };
+      };
+      for (let i = 0; i < points.length; i++) {
+        let text = points[i].name;
+        let tHeight = points[i].textSize * opts.pix;
+        let tWidth = measureText(text, tHeight, context);
+        let isSpin = Spin();
+        let x, y, area, areav;
+        let breaknum = 0;
+        while (true) {
+          breaknum++;
+          let isCollision;
+          if (isSpin) {
+            x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
+            y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
+            area = [y - 5 - tWidth + opts.width / 2, (-x - 5 + opts.height / 2), y + 5 + opts.width / 2, (-x + tHeight + 5 + opts.height / 2)];
+            areav = [opts.width - (opts.width / 2 - opts.height / 2) - (-x + tHeight + 5 + opts.height / 2) - 5, (opts.height / 2 - opts.width / 2) + (y - 5 - tWidth + opts.width / 2) - 5, opts.width - (opts.width / 2 - opts.height / 2) - (-x + tHeight + 5 + opts.height / 2) + tHeight, (opts.height / 2 - opts.width / 2) + (y - 5 - tWidth + opts.width / 2) + tWidth + 5];
+            isCollision = collisionNew(areav, points, opts.height, opts.width);
+          } else {
+            x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
+            y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
+            area = [x - 5 + opts.width / 2, y - 5 - tHeight + opts.height / 2, x + tWidth + 5 + opts.width / 2, y + 5 + opts.height / 2];
+            isCollision = collisionNew(area, points, opts.width, opts.height);
+          }
+          if (!isCollision) break;
+          if (breaknum == 1000) {
+            area = [-1000, -1000, -1000, -1000];
+            break;
+          }
+        };
+        if (isSpin) {
+          points[i].area = areav;
+          points[i].areav = area;
+        } else {
+          points[i].area = area;
+        }
+        points[i].rotate = isSpin;
+      };
+      break;
+  }
+  return points;
+}
+
+function drawWordCloudDataPoints(series, opts, config, context) {
+  let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  let wordOption = assign({}, {
+    type: 'normal',
+    autoColors: true
+  }, opts.extra.word);
+  if (!opts.chartData.wordCloudData) {
+    opts.chartData.wordCloudData = getWordCloudPoint(opts, wordOption.type, context);
+  }
+  context.beginPath();
+  context.setFillStyle(opts.background);
+  context.rect(0, 0, opts.width, opts.height);
+  context.fill();
+  context.save();
+  let points = opts.chartData.wordCloudData;
+  context.translate(opts.width / 2, opts.height / 2);
+  for (let i = 0; i < points.length; i++) {
+    context.save();
+    if (points[i].rotate) {
+      context.rotate(90 * Math.PI / 180);
+    }
+    let text = points[i].name;
+    let tHeight = points[i].textSize * opts.pix;
+    let tWidth = measureText(text, tHeight, context);
+    context.beginPath();
+    context.setStrokeStyle(points[i].color);
+    context.setFillStyle(points[i].color);
+    context.setFontSize(tHeight);
+    if (points[i].rotate) {
+      if (points[i].areav[0] > 0) {
+        if (opts.tooltip) {
+          if (opts.tooltip.index == i) {
+            context.strokeText(text, (points[i].areav[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) / 2, (points[i].areav[1] + 5 + tHeight - opts.height / 2) * process);
+          } else {
+            context.fillText(text, (points[i].areav[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) / 2, (points[i].areav[1] + 5 + tHeight - opts.height / 2) * process);
+          }
+        } else {
+          context.fillText(text, (points[i].areav[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) / 2, (points[i].areav[1] + 5 + tHeight - opts.height / 2) * process);
+        }
+      }
+    } else {
+      if (points[i].area[0] > 0) {
+        if (opts.tooltip) {
+          if (opts.tooltip.index == i) {
+            context.strokeText(text, (points[i].area[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) / 2, (points[i].area[1] + 5 + tHeight - opts.height / 2) * process);
+          } else {
+            context.fillText(text, (points[i].area[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) / 2, (points[i].area[1] + 5 + tHeight - opts.height / 2) * process);
+          }
+        } else {
+          context.fillText(text, (points[i].area[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) / 2, (points[i].area[1] + 5 + tHeight - opts.height / 2) * process);
+        }
+      }
+    }
+    context.stroke();
+    context.restore();
+  }
+  context.restore();
+}
+
+function drawFunnelDataPoints(series, opts, config, context) {
+  let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
+  let funnelOption = assign({}, {
+    type:'funnel',
+    activeWidth: 10,
+    activeOpacity: 0.3,
+    border: false,
+    borderWidth: 2,
+    borderColor: '#FFFFFF',
+    fillOpacity: 1,
+    minSize: 0,
+    labelAlign: 'right',
+    linearType: 'none',
+    customColor: [],
+  }, opts.extra.funnel);
+  let eachSpacing = (opts.height - opts.area[0] - opts.area[2]) / series.length;
+  let centerPosition = {
+    x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
+    y: opts.height - opts.area[2]
+  };
+  let activeWidth = funnelOption.activeWidth * opts.pix;
+  let radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - activeWidth, (opts.height - opts.area[0] - opts.area[2]) / 2 - activeWidth);
+  let seriesNew = getFunnelDataPoints(series, radius, funnelOption, eachSpacing, process);
+  context.save();
+  context.translate(centerPosition.x, centerPosition.y);
+  funnelOption.customColor = fillCustomColor(funnelOption.linearType, funnelOption.customColor, series, config);
+  if(funnelOption.type == 'pyramid'){
+    for (let i = 0; i < seriesNew.length; i++) {
+      if (i == seriesNew.length -1) {
+        if (opts.tooltip) {
+          if (opts.tooltip.index == i) {
+            context.beginPath();
+            context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
+            context.moveTo(-activeWidth, -eachSpacing);
+            context.lineTo(-seriesNew[i].radius - activeWidth, 0);
+            context.lineTo(seriesNew[i].radius + activeWidth, 0);
+            context.lineTo(activeWidth, -eachSpacing);
+            context.lineTo(-activeWidth, -eachSpacing);
+            context.closePath();
+            context.fill();
+          }
+        }
+        seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing * (i + 1), centerPosition.x + seriesNew[i].radius, centerPosition.y - eachSpacing * i];
+        context.beginPath();
+        context.setLineWidth(funnelOption.borderWidth * opts.pix);
+        context.setStrokeStyle(funnelOption.borderColor);
+        var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
+        if (funnelOption.linearType == 'custom') {
+          var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -eachSpacing);
+          grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption.fillOpacity));
+          grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          fillColor = grd
+        }
+        context.setFillStyle(fillColor);
+        context.moveTo(0, -eachSpacing);
+        context.lineTo(-seriesNew[i].radius, 0);
+        context.lineTo(seriesNew[i].radius, 0);
+        context.lineTo(0, -eachSpacing);
+        context.closePath();
+        context.fill();
+        if (funnelOption.border == true) {
+          context.stroke();
+        }
+      } else {
+        if (opts.tooltip) {
+          if (opts.tooltip.index == i) {
+            context.beginPath();
+            context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
+            context.moveTo(0, 0);
+            context.lineTo(-seriesNew[i].radius - activeWidth, 0);
+            context.lineTo(-seriesNew[i + 1].radius - activeWidth, -eachSpacing);
+            context.lineTo(seriesNew[i + 1].radius + activeWidth, -eachSpacing);
+            context.lineTo(seriesNew[i].radius + activeWidth, 0);
+            context.lineTo(0, 0);
+            context.closePath();
+            context.fill();
+          }
+        }
+        seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing * (i + 1), centerPosition.x + seriesNew[i].radius, centerPosition.y - eachSpacing * i];
+        context.beginPath();
+        context.setLineWidth(funnelOption.borderWidth * opts.pix);
+        context.setStrokeStyle(funnelOption.borderColor);
+        var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
+        if (funnelOption.linearType == 'custom') {
+          var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -eachSpacing);
+          grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption.fillOpacity));
+          grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          fillColor = grd
+        }
+        context.setFillStyle(fillColor);
+        context.moveTo(0, 0);
+        context.lineTo(-seriesNew[i].radius, 0);
+        context.lineTo(-seriesNew[i + 1].radius, -eachSpacing);
+        context.lineTo(seriesNew[i + 1].radius, -eachSpacing);
+        context.lineTo(seriesNew[i].radius, 0);
+        context.lineTo(0, 0);
+        context.closePath();
+        context.fill();
+        if (funnelOption.border == true) {
+          context.stroke();
+        }
+      }
+      context.translate(0, -eachSpacing)
+    }
+  }else{
+    context.translate(0, - (seriesNew.length - 1) * eachSpacing);
+    for (let i = 0; i < seriesNew.length; i++) {
+      if (i == seriesNew.length - 1) {
+        if (opts.tooltip) {
+          if (opts.tooltip.index == i) {
+            context.beginPath();
+            context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
+            context.moveTo(-activeWidth - funnelOption.minSize/2, 0);
+            context.lineTo(-seriesNew[i].radius - activeWidth, -eachSpacing);
+            context.lineTo(seriesNew[i].radius + activeWidth, -eachSpacing);
+            context.lineTo(activeWidth + funnelOption.minSize/2, 0);
+            context.lineTo(-activeWidth - funnelOption.minSize/2, 0);
+            context.closePath();
+            context.fill();
+          }
+        }
+        seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing, centerPosition.x + seriesNew[i].radius, centerPosition.y ];
+        context.beginPath();
+        context.setLineWidth(funnelOption.borderWidth * opts.pix);
+        context.setStrokeStyle(funnelOption.borderColor);
+        var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
+        if (funnelOption.linearType == 'custom') {
+          var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -eachSpacing);
+          grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption.fillOpacity));
+          grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          fillColor = grd
+        }
+        context.setFillStyle(fillColor);
+        context.moveTo(0, 0);
+        context.lineTo(-funnelOption.minSize/2, 0);
+        context.lineTo(-seriesNew[i].radius, -eachSpacing);
+        context.lineTo(seriesNew[i].radius, -eachSpacing);
+        context.lineTo(funnelOption.minSize/2, 0);
+        context.lineTo(0, 0);
+        context.closePath();
+        context.fill();
+        if (funnelOption.border == true) {
+          context.stroke();
+        }
+      } else {
+        if (opts.tooltip) {
+          if (opts.tooltip.index == i) {
+            context.beginPath();
+            context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
+            context.moveTo(0, 0);
+            context.lineTo(-seriesNew[i + 1].radius - activeWidth, 0);
+            context.lineTo(-seriesNew[i].radius - activeWidth, -eachSpacing);
+            context.lineTo(seriesNew[i].radius + activeWidth, -eachSpacing);
+            context.lineTo(seriesNew[i + 1].radius + activeWidth, 0);
+            context.lineTo(0, 0);
+            context.closePath();
+            context.fill();
+          }
+        }
+        seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing * (seriesNew.length - i), centerPosition.x + seriesNew[i].radius, centerPosition.y - eachSpacing * (seriesNew.length - i - 1)];
+        context.beginPath();
+        context.setLineWidth(funnelOption.borderWidth * opts.pix);
+        context.setStrokeStyle(funnelOption.borderColor);
+        var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
+        if (funnelOption.linearType == 'custom') {
+          var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -eachSpacing);
+          grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption.fillOpacity));
+          grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
+          fillColor = grd
+        }
+        context.setFillStyle(fillColor);
+        context.moveTo(0, 0);
+        context.lineTo(-seriesNew[i + 1].radius, 0);
+        context.lineTo(-seriesNew[i].radius, -eachSpacing);
+        context.lineTo(seriesNew[i].radius, -eachSpacing);
+        context.lineTo(seriesNew[i + 1].radius, 0);
+        context.lineTo(0, 0);
+        context.closePath();
+        context.fill();
+        if (funnelOption.border == true) {
+          context.stroke();
+        }
+      }
+      context.translate(0, eachSpacing)
+    }
+  }
+  
+  context.restore();
+  if (opts.dataLabel !== false && process === 1) {
+    drawFunnelText(seriesNew, opts, context, eachSpacing, funnelOption.labelAlign, activeWidth, centerPosition);
+  }
+  if (process === 1) {
+    drawFunnelCenterText(seriesNew, opts, context, eachSpacing, funnelOption.labelAlign, activeWidth, centerPosition);
+  }
+  return {
+    center: centerPosition,
+    radius: radius,
+    series: seriesNew
+  };
+}
+
+function drawFunnelText(series, opts, context, eachSpacing, labelAlign, activeWidth, centerPosition) {
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    if(item.labelShow === false){
+      continue;
+    }
+    let startX, endX, startY, fontSize;
+    let text = item.formatter ? item.formatter(item,i,series,opts) : util.toFixed(item._proportion_ * 100) + '%';
+    text = item.labelText ? item.labelText : text;
+    if (labelAlign == 'right') {
+      if (i == series.length -1) {
+        startX = (item.funnelArea[2] + centerPosition.x) / 2;
+      } else {
+        startX = (item.funnelArea[2] + series[i + 1].funnelArea[2]) / 2;
+      }
+      endX = startX + activeWidth * 2;
+      startY = item.funnelArea[1] + eachSpacing / 2;
+      fontSize = item.textSize * opts.pix || opts.fontSize * opts.pix;
+      context.setLineWidth(1 * opts.pix);
+      context.setStrokeStyle(item.color);
+      context.setFillStyle(item.color);
+      context.beginPath();
+      context.moveTo(startX, startY);
+      context.lineTo(endX, startY);
+      context.stroke();
+      context.closePath();
+      context.beginPath();
+      context.moveTo(endX, startY);
+      context.arc(endX, startY, 2 * opts.pix, 0, 2 * Math.PI);
+      context.closePath();
+      context.fill();
+      context.beginPath();
+      context.setFontSize(fontSize);
+      context.setFillStyle(item.textColor || opts.fontColor);
+      context.fillText(text, endX + 5, startY + fontSize / 2 - 2);
+      context.closePath();
+      context.stroke();
+      context.closePath();
+    }
+    if (labelAlign == 'left') {
+      if (i == series.length -1) {
+        startX = (item.funnelArea[0] + centerPosition.x) / 2;
+      } else {
+        startX = (item.funnelArea[0] + series[i + 1].funnelArea[0]) / 2;
+      }
+      endX = startX - activeWidth * 2;
+      startY = item.funnelArea[1] + eachSpacing / 2;
+      fontSize = item.textSize * opts.pix || opts.fontSize * opts.pix;
+      context.setLineWidth(1 * opts.pix);
+      context.setStrokeStyle(item.color);
+      context.setFillStyle(item.color);
+      context.beginPath();
+      context.moveTo(startX, startY);
+      context.lineTo(endX, startY);
+      context.stroke();
+      context.closePath();
+      context.beginPath();
+      context.moveTo(endX, startY);
+      context.arc(endX, startY, 2, 0, 2 * Math.PI);
+      context.closePath();
+      context.fill();
+      context.beginPath();
+      context.setFontSize(fontSize);
+      context.setFillStyle(item.textColor || opts.fontColor);
+      context.fillText(text, endX - 5 - measureText(text, fontSize, context), startY + fontSize / 2 - 2);
+      context.closePath();
+      context.stroke();
+      context.closePath();
+    }
+  }
+}
+
+function drawFunnelCenterText(series, opts, context, eachSpacing, labelAlign, activeWidth, centerPosition) {
+  for (let i = 0; i < series.length; i++) {
+    let item = series[i];
+    let startY, fontSize;
+    if (item.centerText) {
+      startY = item.funnelArea[1] + eachSpacing / 2;
+      fontSize = item.centerTextSize * opts.pix || opts.fontSize * opts.pix;
+      context.beginPath();
+      context.setFontSize(fontSize);
+      context.setFillStyle(item.centerTextColor || "#FFFFFF");
+      context.fillText(item.centerText, centerPosition.x - measureText(item.centerText, fontSize, context) / 2, startY + fontSize / 2 - 2);
+      context.closePath();
+      context.stroke();
+      context.closePath();
+    }
+  }
+}
+
+
+function drawCanvas(opts, context) {
+  context.save();
+  context.translate(0, 0.5);
+  context.restore();
+  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 || 'easeInOut';
+  var delay = 17;
+  function createAnimationFrame() {
+    if (typeof setTimeout !== 'undefined') {
+      return function(step, delay) {
+        setTimeout(function() {
+          var timeStamp = +new Date();
+          step(timeStamp);
+        }, delay);
+      };
+    } else if (typeof requestAnimationFrame !== 'undefined') {
+      return requestAnimationFrame;
+    } 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);
+}
+
+Animation.prototype.stop = function() {
+  this.isStop = true;
+};
+
+function drawCharts(type, opts, config, context) {
+  var _this = this;
+  var series = opts.series;
+  //兼容ECharts饼图类数据格式
+  if (type === 'pie' || type === 'ring' || type === 'mount' || type === 'rose' || type === 'funnel') {
+    series = fixPieSeries(series, opts, config);
+  }
+  var categories = opts.categories;
+  if (type === 'mount') {
+    categories = [];
+    for (let j = 0; j < series.length; j++) {
+      if(series[j].show !== false) categories.push(series[j].name)
+    }
+    opts.categories = categories;
+  }
+  series = fillSeries(series, opts, config);
+  var duration = opts.animation ? opts.duration : 0;
+  _this.animationInstance && _this.animationInstance.stop();
+  var seriesMA = null;
+  if (type == 'candle') {
+    let average = assign({}, opts.extra.candle.average);
+    if (average.show) {
+      seriesMA = calCandleMA(average.day, average.name, average.color, series[0].data);
+      seriesMA = fillSeries(seriesMA, opts, config);
+      opts.seriesMA = seriesMA;
+    } else if (opts.seriesMA) {
+      seriesMA = opts.seriesMA = fillSeries(opts.seriesMA, opts, config);
+    } else {
+      seriesMA = series;
+    }
+  } else {
+    seriesMA = series;
+  }
+  /* 过滤掉show=false的series */
+  opts._series_ = series = filterSeries(series);
+  //重新计算图表区域
+  opts.area = new Array(4);
+  //复位绘图区域
+  for (let j = 0; j < 4; j++) {
+    opts.area[j] = opts.padding[j] * opts.pix;
+  }
+  //通过计算三大区域:图例、X轴、Y轴的大小,确定绘图区域
+  var _calLegendData = calLegendData(seriesMA, opts, config, opts.chartData, context),
+    legendHeight = _calLegendData.area.wholeHeight,
+    legendWidth = _calLegendData.area.wholeWidth;
+
+  switch (opts.legend.position) {
+    case 'top':
+      opts.area[0] += legendHeight;
+      break;
+    case 'bottom':
+      opts.area[2] += legendHeight;
+      break;
+    case 'left':
+      opts.area[3] += legendWidth;
+      break;
+    case 'right':
+      opts.area[1] += legendWidth;
+      break;
+  }
+
+  let _calYAxisData = {},
+    yAxisWidth = 0;
+  if (opts.type === 'line' || opts.type === 'column'|| opts.type === 'mount' || opts.type === 'area' || opts.type === 'mix' || opts.type === 'candle' || opts.type === 'scatter'  || opts.type === 'bubble' || opts.type === 'bar') {
+      _calYAxisData = calYAxisData(series, opts, config, context);
+      yAxisWidth = _calYAxisData.yAxisWidth;
+    //如果显示Y轴标题
+    if (opts.yAxis.showTitle) {
+      let maxTitleHeight = 0;
+      for (let i = 0; i < opts.yAxis.data.length; i++) {
+        maxTitleHeight = Math.max(maxTitleHeight, opts.yAxis.data[i].titleFontSize ? opts.yAxis.data[i].titleFontSize * opts.pix : config.fontSize)
+      }
+      opts.area[0] += maxTitleHeight;
+    }
+    let rightIndex = 0,
+      leftIndex = 0;
+    //计算主绘图区域左右位置
+    for (let i = 0; i < yAxisWidth.length; i++) {
+      if (yAxisWidth[i].position == 'left') {
+        if (leftIndex > 0) {
+          opts.area[3] += yAxisWidth[i].width + opts.yAxis.padding * opts.pix;
+        } else {
+          opts.area[3] += yAxisWidth[i].width;
+        }
+        leftIndex += 1;
+      } else if (yAxisWidth[i].position == 'right') {
+        if (rightIndex > 0) {
+          opts.area[1] += yAxisWidth[i].width + opts.yAxis.padding * opts.pix;
+        } else {
+          opts.area[1] += yAxisWidth[i].width;
+        }
+        rightIndex += 1;
+      }
+    }
+  } else {
+    config.yAxisWidth = yAxisWidth;
+  }
+  opts.chartData.yAxisData = _calYAxisData;
+
+  if (opts.categories && opts.categories.length && opts.type !== 'radar' && opts.type !== 'gauge' && opts.type !== 'bar') {
+    opts.chartData.xAxisData = getXAxisPoints(opts.categories, opts, config);
+    let _calCategoriesData = calCategoriesData(opts.categories, opts, config, opts.chartData.xAxisData.eachSpacing, context),
+      xAxisHeight = _calCategoriesData.xAxisHeight,
+      angle = _calCategoriesData.angle;
+    config.xAxisHeight = xAxisHeight;
+    config._xAxisTextAngle_ = angle;
+    opts.area[2] += xAxisHeight;
+    opts.chartData.categoriesData = _calCategoriesData;
+  } else {
+    if (opts.type === 'line' || opts.type === 'area' || opts.type === 'scatter' || opts.type === 'bubble' || opts.type === 'bar') {
+      opts.chartData.xAxisData = calXAxisData(series, opts, config, context);
+      categories = opts.chartData.xAxisData.rangesFormat;
+      let _calCategoriesData = calCategoriesData(categories, opts, config, opts.chartData.xAxisData.eachSpacing, context),
+        xAxisHeight = _calCategoriesData.xAxisHeight,
+        angle = _calCategoriesData.angle;
+      config.xAxisHeight = xAxisHeight;
+      config._xAxisTextAngle_ = angle;
+      opts.area[2] += xAxisHeight;
+      opts.chartData.categoriesData = _calCategoriesData;
+    } else {
+      opts.chartData.xAxisData = {
+        xAxisPoints: []
+      };
+    }
+  }
+
+  //计算右对齐偏移距离
+  if (opts.enableScroll && opts.xAxis.scrollAlign == 'right' && opts._scrollDistance_ === undefined) {
+    let offsetLeft = 0,
+      xAxisPoints = opts.chartData.xAxisData.xAxisPoints,
+      startX = opts.chartData.xAxisData.startX,
+      endX = opts.chartData.xAxisData.endX,
+      eachSpacing = opts.chartData.xAxisData.eachSpacing;
+    let totalWidth = eachSpacing * (xAxisPoints.length - 1);
+    let screenWidth = endX - startX;
+    offsetLeft = screenWidth - totalWidth;
+    _this.scrollOption.currentOffset = offsetLeft;
+    _this.scrollOption.startTouchX = offsetLeft;
+    _this.scrollOption.distance = 0;
+    _this.scrollOption.lastMoveTime = 0;
+    opts._scrollDistance_ = offsetLeft;
+  }
+
+  if (type === 'pie' || type === 'ring' || type === 'rose') {
+    config._pieTextMaxLength_ = opts.dataLabel === false ? 0 : getPieTextMaxLength(seriesMA, config, context, opts);
+  }
+  
+  switch (type) {
+    case 'word':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          drawWordCloudDataPoints(series, opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'map':
+      context.clearRect(0, 0, opts.width, opts.height);
+      drawMapDataPoints(series, opts, config, context);
+      setTimeout(()=>{
+        this.uevent.trigger('renderComplete');
+      },50)
+      break;
+    case 'funnel':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.funnelData = drawFunnelDataPoints(series, opts, config, context, process);
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'line':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          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;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'scatter':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          drawYAxisGrid(categories, opts, config, context);
+          drawXAxis(categories, opts, config, context);
+          var _drawScatterDataPoints = drawScatterDataPoints(series, opts, config, context, process),
+            xAxisPoints = _drawScatterDataPoints.xAxisPoints,
+            calPoints = _drawScatterDataPoints.calPoints,
+            eachSpacing = _drawScatterDataPoints.eachSpacing;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'bubble':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          drawYAxisGrid(categories, opts, config, context);
+          drawXAxis(categories, opts, config, context);
+          var _drawBubbleDataPoints = drawBubbleDataPoints(series, opts, config, context, process),
+            xAxisPoints = _drawBubbleDataPoints.xAxisPoints,
+            calPoints = _drawBubbleDataPoints.calPoints,
+            eachSpacing = _drawBubbleDataPoints.eachSpacing;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'mix':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          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;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'column':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          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;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'mount':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          drawYAxisGrid(categories, opts, config, context);
+          drawXAxis(categories, opts, config, context);
+          var _drawMountDataPoints = drawMountDataPoints(series, opts, config, context, process),
+            xAxisPoints = _drawMountDataPoints.xAxisPoints,
+            calPoints = _drawMountDataPoints.calPoints,
+            eachSpacing = _drawMountDataPoints.eachSpacing;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'bar':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          drawXAxis(categories, opts, config, context);
+          var _drawBarDataPoints = drawBarDataPoints(series, opts, config, context, process),
+            yAxisPoints = _drawBarDataPoints.yAxisPoints,
+            calPoints = _drawBarDataPoints.calPoints,
+            eachSpacing = _drawBarDataPoints.eachSpacing;
+          opts.chartData.yAxisPoints = yAxisPoints;
+          opts.chartData.xAxisPoints = opts.chartData.xAxisData.xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, yAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'area':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          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;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'ring':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.pieData = drawPieDataPoints(series, opts, config, context, process);
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'pie':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.pieData = drawPieDataPoints(series, opts, config, context, process);
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'rose':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.pieData = drawRoseDataPoints(series, opts, config, context, process);
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'radar':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process);
+          drawLegend(opts.series, opts, config, context, opts.chartData);
+          drawToolTipBridge(opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'arcbar':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.arcbarData = drawArcbarDataPoints(series, opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'gauge':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          opts.chartData.gaugeData = drawGaugeDataPoints(categories, series, opts, config, context, process);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+    case 'candle':
+      this.animationInstance = new Animation({
+        timing: opts.timing,
+        duration: duration,
+        onProcess: function onProcess(process) {
+          context.clearRect(0, 0, opts.width, opts.height);
+          if (opts.rotate) {
+            contextRotate(context, opts);
+          }
+          drawYAxisGrid(categories, opts, config, context);
+          drawXAxis(categories, opts, config, context);
+          var _drawCandleDataPoints = drawCandleDataPoints(series, seriesMA, opts, config, context, process),
+            xAxisPoints = _drawCandleDataPoints.xAxisPoints,
+            calPoints = _drawCandleDataPoints.calPoints,
+            eachSpacing = _drawCandleDataPoints.eachSpacing;
+          opts.chartData.xAxisPoints = xAxisPoints;
+          opts.chartData.calPoints = calPoints;
+          opts.chartData.eachSpacing = eachSpacing;
+          drawYAxis(series, opts, config, context);
+          if (opts.enableMarkLine !== false && process === 1) {
+            drawMarkLine(opts, config, context);
+          }
+          if (seriesMA) {
+            drawLegend(seriesMA, opts, config, context, opts.chartData);
+          } else {
+            drawLegend(opts.series, opts, config, context, opts.chartData);
+          }
+          drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
+          drawCanvas(opts, context);
+        },
+        onAnimationFinish: function onAnimationFinish() {
+          _this.uevent.trigger('renderComplete');
+        }
+      });
+      break;
+  }
+}
+
+function uChartsEvent() {
+  this.events = {};
+}
+
+uChartsEvent.prototype.addEventListener = function(type, listener) {
+  this.events[type] = this.events[type] || [];
+  this.events[type].push(listener);
+};
+
+uChartsEvent.prototype.delEventListener = function(type) {
+  this.events[type] = [];
+};
+
+uChartsEvent.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.log('[uCharts] '+e);
+      }
+    });
+  }
+};
+
+var uCharts = function uCharts(opts) {
+  opts.pix = opts.pixelRatio ? opts.pixelRatio : 1;
+  opts.fontSize = opts.fontSize ? opts.fontSize : 13;
+  opts.fontColor = opts.fontColor ? opts.fontColor : config.fontColor;
+  if (opts.background == "" || opts.background == "none") {
+    opts.background = "#FFFFFF"
+  }
+  opts.title = assign({}, opts.title);
+  opts.subtitle = assign({}, opts.subtitle);
+  opts.duration = opts.duration ? opts.duration : 1000;
+  opts.yAxis = assign({}, {
+    data: [],
+    showTitle: false,
+    disabled: false,
+    disableGrid: false,
+    gridSet: 'number',
+    splitNumber: 5,
+    gridType: 'solid',
+    dashLength: 4 * opts.pix,
+    gridColor: '#cccccc',
+    padding: 10,
+    fontColor: '#666666'
+  }, opts.yAxis);
+  opts.xAxis = assign({}, {
+    rotateLabel: false,
+    rotateAngle:45,
+    disabled: false,
+    disableGrid: false,
+    splitNumber: 5,
+    calibration:false,
+    fontColor: '#666666',
+    fontSize: 13,
+    lineHeight: 20,
+    marginTop: 0,
+    gridType: 'solid',
+    dashLength: 4,
+    scrollAlign: 'left',
+    boundaryGap: 'center',
+    axisLine: true,
+    axisLineColor: '#cccccc',
+    titleFontSize: 13,
+    titleOffsetY: 0,
+    titleOffsetX: 0,
+    titleFontColor: '#666666'
+  }, opts.xAxis);
+  opts.xAxis.scrollPosition = opts.xAxis.scrollAlign;
+  opts.legend = assign({}, {
+    show: true,
+    position: 'bottom',
+    float: 'center',
+    backgroundColor: 'rgba(0,0,0,0)',
+    borderColor: 'rgba(0,0,0,0)',
+    borderWidth: 0,
+    padding: 5,
+    margin: 5,
+    itemGap: 10,
+    fontSize: opts.fontSize,
+    lineHeight: opts.fontSize,
+    fontColor: opts.fontColor,
+    formatter: {},
+    hiddenColor: '#CECECE'
+  }, opts.legend);
+  opts.extra = assign({
+    tooltip:{
+      legendShape: 'auto'
+    }
+  }, opts.extra);
+  opts.rotate = opts.rotate ? true : false;
+  opts.animation = opts.animation ? true : false;
+  opts.rotate = opts.rotate ? true : false;
+  opts.canvas2d = opts.canvas2d ? true : false;
+  
+  let config$$1 = assign({}, config);
+  config$$1.color = opts.color ? opts.color : config$$1.color;
+  if (opts.type == 'pie') {
+    config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.pie.labelWidth * opts.pix || config$$1.pieChartLinePadding * opts.pix;
+  }
+  if (opts.type == 'ring') {
+    config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.ring.labelWidth * opts.pix || config$$1.pieChartLinePadding * opts.pix;
+  }
+  if (opts.type == 'rose') {
+    config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.rose.labelWidth * opts.pix || config$$1.pieChartLinePadding * opts.pix;
+  }
+  config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding * opts.pix;
+
+  //屏幕旋转
+  config$$1.rotate = opts.rotate;
+  if (opts.rotate) {
+    let tempWidth = opts.width;
+    let tempHeight = opts.height;
+    opts.width = tempHeight;
+    opts.height = tempWidth;
+  }
+
+  //适配高分屏
+  opts.padding = opts.padding ? opts.padding : config$$1.padding;
+  config$$1.yAxisWidth = config.yAxisWidth * opts.pix;
+  config$$1.fontSize = opts.fontSize * opts.pix;
+  config$$1.titleFontSize = config.titleFontSize * opts.pix;
+  config$$1.subtitleFontSize = config.subtitleFontSize * opts.pix;
+  if(!opts.context){
+    throw new Error('[uCharts] 未获取到context!注意:v2.0版本后,需要自行获取canvas的绘图上下文并传入opts.context!');
+  }
+  this.context = opts.context;
+  if (!this.context.setTextAlign) {
+    this.context.setStrokeStyle = function(e) {
+      return this.strokeStyle = e;
+    }
+    this.context.setLineWidth = function(e) {
+      return this.lineWidth = e;
+    }
+    this.context.setLineCap = function(e) {
+      return this.lineCap = e;
+    }
+    this.context.setFontSize = function(e) {
+      return this.font = e + "px sans-serif";
+    }
+    this.context.setFillStyle = function(e) {
+      return this.fillStyle = e;
+    }
+    this.context.setTextAlign = function(e) {
+      return this.textAlign = e;
+    }
+    this.context.setTextBaseline = function(e) {
+      return this.textBaseline = e;
+    }
+    this.context.setShadow = function(offsetX,offsetY,blur,color) {
+      this.shadowColor = color;
+      this.shadowOffsetX = offsetX;
+      this.shadowOffsetY = offsetY;
+      this.shadowBlur = blur;
+    }
+    this.context.draw = function() {}
+  }
+  //兼容NVUEsetLineDash
+  if(!this.context.setLineDash){
+    this.context.setLineDash = function(e) {}
+  }
+  opts.chartData = {};
+  this.uevent = new uChartsEvent();
+  this.scrollOption = {
+    currentOffset: 0,
+    startTouchX: 0,
+    distance: 0,
+    lastMoveTime: 0
+  };
+  this.opts = opts;
+  this.config = config$$1;
+  drawCharts.call(this, opts.type, opts, config$$1, this.context);
+};
+
+uCharts.prototype.updateData = function() {
+  let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+  this.opts = assign({}, this.opts, data);
+  this.opts.updateData = true;
+  let scrollPosition = data.scrollPosition || 'current';
+  switch (scrollPosition) {
+    case 'current':
+      this.opts._scrollDistance_ = this.scrollOption.currentOffset;
+      break;
+    case 'left':
+      this.opts._scrollDistance_ = 0;
+      this.scrollOption = {
+        currentOffset: 0,
+        startTouchX: 0,
+        distance: 0,
+        lastMoveTime: 0
+      };
+      break;
+    case 'right':
+      let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config, this.context), yAxisWidth = _calYAxisData.yAxisWidth;
+      this.config.yAxisWidth = yAxisWidth;
+      let offsetLeft = 0;
+      let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config), 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,
+        lastMoveTime: 0
+      };
+      this.opts._scrollDistance_ = offsetLeft;
+      break;
+  }
+  drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
+};
+
+uCharts.prototype.zoom = function() {
+  var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount;
+  if (this.opts.enableScroll !== true) {
+    console.log('[uCharts] 请启用滚动条后使用')
+    return;
+  }
+  //当前屏幕中间点
+  let centerPoint = Math.round(Math.abs(this.scrollOption.currentOffset) / this.opts.chartData.eachSpacing) + Math.round(this.opts.xAxis.itemCount / 2);
+  this.opts.animation = false;
+  this.opts.xAxis.itemCount = val.itemCount;
+  //重新计算x轴偏移距离
+  let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config, this.context),
+    yAxisWidth = _calYAxisData.yAxisWidth;
+  this.config.yAxisWidth = yAxisWidth;
+  let offsetLeft = 0;
+  let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
+    xAxisPoints = _getXAxisPoints0.xAxisPoints,
+    startX = _getXAxisPoints0.startX,
+    endX = _getXAxisPoints0.endX,
+    eachSpacing = _getXAxisPoints0.eachSpacing;
+  let centerLeft = eachSpacing * centerPoint;
+  let screenWidth = endX - startX;
+  let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1);
+  offsetLeft = screenWidth / 2 - centerLeft;
+  if (offsetLeft > 0) {
+    offsetLeft = 0;
+  }
+  if (offsetLeft < MaxLeft) {
+    offsetLeft = MaxLeft;
+  }
+  this.scrollOption = {
+    currentOffset: offsetLeft,
+    startTouchX: 0,
+    distance: 0,
+    lastMoveTime: 0
+  };
+  calValidDistance(this, offsetLeft, this.opts.chartData, this.config, this.opts);
+  this.opts._scrollDistance_ = offsetLeft;
+  drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
+};
+
+uCharts.prototype.dobuleZoom = function(e) {
+  if (this.opts.enableScroll !== true) {
+    console.log('[uCharts] 请启用滚动条后使用')
+    return;
+  }
+  const tcs = e.changedTouches;
+  if (tcs.length < 2) {
+    return;
+  }
+  for (var i = 0; i < tcs.length; i++) {
+    tcs[i].x = tcs[i].x ? tcs[i].x : tcs[i].clientX;
+    tcs[i].y = tcs[i].y ? tcs[i].y : tcs[i].clientY;
+  }
+  const ntcs = [getTouches(tcs[0], this.opts, e),getTouches(tcs[1], this.opts, e)]; 
+  const xlength = Math.abs(ntcs[0].x - ntcs[1].x);
+  // 记录初始的两指之间的数据
+  if(!this.scrollOption.moveCount){
+    let cts0 = {changedTouches:[{x:tcs[0].x,y:this.opts.area[0] / this.opts.pix + 2}]};
+    let cts1 = {changedTouches:[{x:tcs[1].x,y:this.opts.area[0] / this.opts.pix + 2}]};
+    if(this.opts.rotate){
+      cts0 = {changedTouches:[{x:this.opts.height / this.opts.pix - this.opts.area[0] / this.opts.pix - 2,y:tcs[0].y}]};
+      cts1 = {changedTouches:[{x:this.opts.height / this.opts.pix - this.opts.area[0] / this.opts.pix - 2,y:tcs[1].y}]};
+    }
+    const moveCurrent1 = this.getCurrentDataIndex(cts0).index;
+    const moveCurrent2 = this.getCurrentDataIndex(cts1).index;
+    const moveCount = Math.abs(moveCurrent1 - moveCurrent2);
+    this.scrollOption.moveCount = moveCount;
+    this.scrollOption.moveCurrent1 = Math.min(moveCurrent1, moveCurrent2);
+    this.scrollOption.moveCurrent2 = Math.max(moveCurrent1, moveCurrent2);
+    return;
+  }
+  
+  let currentEachSpacing = xlength / this.scrollOption.moveCount;
+  let itemCount = (this.opts.width - this.opts.area[1] - this.opts.area[3]) / currentEachSpacing;
+  itemCount = itemCount <= 2 ? 2 : itemCount;
+  itemCount = itemCount >= this.opts.categories.length ? this.opts.categories.length : itemCount;
+  this.opts.animation = false;
+  this.opts.xAxis.itemCount = itemCount;
+  // 重新计算滚动条偏移距离
+  let offsetLeft = 0;
+  let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
+    xAxisPoints = _getXAxisPoints0.xAxisPoints,
+    startX = _getXAxisPoints0.startX,
+    endX = _getXAxisPoints0.endX,
+    eachSpacing = _getXAxisPoints0.eachSpacing;
+  let currentLeft = eachSpacing * this.scrollOption.moveCurrent1;
+  let screenWidth = endX - startX;
+  let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1);
+  offsetLeft = -currentLeft+Math.min(ntcs[0].x,ntcs[1].x)-this.opts.area[3]-eachSpacing;
+  if (offsetLeft > 0) {
+    offsetLeft = 0;
+  }
+  if (offsetLeft < MaxLeft) {
+    offsetLeft = MaxLeft;
+  }
+  this.scrollOption.currentOffset= offsetLeft;
+  this.scrollOption.startTouchX= 0;
+  this.scrollOption.distance=0;
+  calValidDistance(this, offsetLeft, this.opts.chartData, this.config, this.opts);
+  this.opts._scrollDistance_ = offsetLeft;
+  drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
+}
+
+uCharts.prototype.stopAnimation = function() {
+  this.animationInstance && this.animationInstance.stop();
+};
+
+uCharts.prototype.addEventListener = function(type, listener) {
+  this.uevent.addEventListener(type, listener);
+};
+
+uCharts.prototype.delEventListener = function(type) {
+  this.uevent.delEventListener(type);
+};
+
+uCharts.prototype.getCurrentDataIndex = function(e) {
+  var touches = null;
+  if (e.changedTouches) {
+    touches = e.changedTouches[0];
+  } else {
+    touches = e.mp.changedTouches[0];
+  }
+  if (touches) {
+    let _touches$ = getTouches(touches, this.opts, e);
+    if (this.opts.type === 'pie' || this.opts.type === 'ring') {
+      return findPieChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.pieData, this.opts);
+    } else if (this.opts.type === 'rose') {
+      return findRoseChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.pieData, this.opts);
+    } else if (this.opts.type === 'radar') {
+      return findRadarChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.radarData, this.opts.categories.length);
+    } else if (this.opts.type === 'funnel') {
+      return findFunnelChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.funnelData);
+    } else if (this.opts.type === 'map') {
+      return findMapChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts);
+    } else if (this.opts.type === 'word') {
+      return findWordChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.wordCloudData);
+    } else if (this.opts.type === 'bar') {
+      return findBarChartCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.calPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset));
+    } else {
+      return findCurrentIndex({
+        x: _touches$.x,
+        y: _touches$.y
+      }, this.opts.chartData.calPoints, this.opts, this.config, Math.abs(this.scrollOption.currentOffset));
+    }
+  }
+  return -1;
+};
+
+uCharts.prototype.getLegendDataIndex = function(e) {
+  var touches = null;
+  if (e.changedTouches) {
+    touches = e.changedTouches[0];
+  } else {
+    touches = e.mp.changedTouches[0];
+  }
+  if (touches) {
+    let _touches$ = getTouches(touches, this.opts, e);
+    return findLegendIndex({
+      x: _touches$.x,
+      y: _touches$.y
+    }, this.opts.chartData.legendData);
+  }
+  return -1;
+};
+
+uCharts.prototype.touchLegend = function(e) {
+  var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+  var touches = null;
+  if (e.changedTouches) {
+    touches = e.changedTouches[0];
+  } else {
+    touches = e.mp.changedTouches[0];
+  }
+  if (touches) {
+    var _touches$ = getTouches(touches, this.opts, e);
+    var index = this.getLegendDataIndex(e);
+    if (index >= 0) {
+      if (this.opts.type == 'candle') {
+        this.opts.seriesMA[index].show = !this.opts.seriesMA[index].show;
+      } else {
+        this.opts.series[index].show = !this.opts.series[index].show;
+      }
+      this.opts.animation = option.animation ? true : false;
+      this.opts._scrollDistance_ = this.scrollOption.currentOffset;
+      drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
+    }
+  }
+
+};
+
+uCharts.prototype.showToolTip = function(e) {
+  var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+  var touches = null;
+  if (e.changedTouches) {
+    touches = e.changedTouches[0];
+  } else {
+    touches = e.mp.changedTouches[0];
+  }
+  if (!touches) {
+    console.log("[uCharts] 未获取到event坐标信息");
+  }
+  var _touches$ = getTouches(touches, this.opts, e);
+  var currentOffset = this.scrollOption.currentOffset;
+  var opts = assign({}, this.opts, {
+    _scrollDistance_: currentOffset,
+    animation: false
+  });
+  if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'column' || this.opts.type === 'scatter' || this.opts.type === 'bubble') {
+    var current = this.getCurrentDataIndex(e);
+    var index = option.index == undefined ? current.index : option.index;
+    if (index > -1 || index.length>0) {
+      var seriesData = getSeriesDataItem(this.opts.series, index, current.group);
+      if (seriesData.length !== 0) {
+        var _getToolTipData = getToolTipData(seriesData, this.opts, index, current.group, this.opts.categories, option),
+          textList = _getToolTipData.textList,
+          offset = _getToolTipData.offset;
+        offset.y = _touches$.y;
+        opts.tooltip = {
+          textList: option.textList !== undefined ? option.textList : textList,
+          offset: option.offset !== undefined ? option.offset : offset,
+          option: option,
+          index: index,
+          group: current.group
+        };
+      }
+    }
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'mount') {
+    var index = option.index == undefined ? this.getCurrentDataIndex(e).index : option.index;
+    if (index > -1) {
+      var opts = assign({}, this.opts, {animation: false});
+      var seriesData = assign({}, opts._series_[index]);
+      var textList = [{
+        text: option.formatter ? option.formatter(seriesData, undefined, index, opts) : seriesData.name + ': ' + seriesData.data,
+        color: seriesData.color,
+        legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this.opts.extra.tooltip.legendShape
+      }];
+      var offset = {
+        x: opts.chartData.calPoints[index].x,
+        y: _touches$.y
+      };
+      opts.tooltip = {
+        textList: option.textList ? option.textList : textList,
+        offset: option.offset !== undefined ? option.offset : offset,
+        option: option,
+        index: index
+      };
+    }
+    
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'bar') {
+    var current = this.getCurrentDataIndex(e);
+    var index = option.index == undefined ? current.index : option.index;
+    if (index > -1 || index.length>0) {
+      var seriesData = getSeriesDataItem(this.opts.series, index, current.group);
+      if (seriesData.length !== 0) {
+        var _getToolTipData = getToolTipData(seriesData, this.opts, index, current.group, this.opts.categories, option),
+          textList = _getToolTipData.textList,
+          offset = _getToolTipData.offset;
+        offset.x = _touches$.x;
+        opts.tooltip = {
+          textList: option.textList !== undefined ? option.textList : textList,
+          offset: option.offset !== undefined ? option.offset : offset,
+          option: option,
+          index: index
+        };
+      }
+    }
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'mix') {
+    var current = this.getCurrentDataIndex(e);
+    var index = option.index == undefined ? current.index : option.index;
+    if (index > -1) {
+      var currentOffset = this.scrollOption.currentOffset;
+      var opts = assign({}, this.opts, {
+        _scrollDistance_: currentOffset,
+        animation: false
+      });
+      var seriesData = getSeriesDataItem(this.opts.series, index);
+      if (seriesData.length !== 0) {
+        var _getMixToolTipData = getMixToolTipData(seriesData, this.opts, index, this.opts.categories, option),
+          textList = _getMixToolTipData.textList,
+          offset = _getMixToolTipData.offset;
+        offset.y = _touches$.y;
+        opts.tooltip = {
+          textList: option.textList ? option.textList : textList,
+          offset: option.offset !== undefined ? option.offset : offset,
+          option: option,
+          index: index
+        };
+      }
+    }
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'candle') {
+    var current = this.getCurrentDataIndex(e);
+    var index = option.index == undefined ? current.index : option.index;
+    if (index > -1) {
+      var currentOffset = this.scrollOption.currentOffset;
+      var opts = assign({}, this.opts, {
+        _scrollDistance_: currentOffset,
+        animation: false
+      });
+      var seriesData = getSeriesDataItem(this.opts.series, index);
+      if (seriesData.length !== 0) {
+        var _getToolTipData = getCandleToolTipData(this.opts.series[0].data, seriesData, this.opts, index, this.opts.categories, this.opts.extra.candle, option),
+          textList = _getToolTipData.textList,
+          offset = _getToolTipData.offset;
+        offset.y = _touches$.y;
+        opts.tooltip = {
+          textList: option.textList ? option.textList : textList,
+          offset: option.offset !== undefined ? option.offset : offset,
+          option: option,
+          index: index
+        };
+      }
+    }
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose' || this.opts.type === 'funnel') {
+    var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
+    if (index > -1) {
+      var opts = assign({}, this.opts, {animation: false});
+      var seriesData = assign({}, opts._series_[index]);
+      var textList = [{
+        text: option.formatter ? option.formatter(seriesData, undefined, index, opts) : seriesData.name + ': ' + seriesData.data,
+        color: seriesData.color,
+        legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this.opts.extra.tooltip.legendShape
+      }];
+      var offset = {
+        x: _touches$.x,
+        y: _touches$.y
+      };
+      opts.tooltip = {
+        textList: option.textList ? option.textList : textList,
+        offset: option.offset !== undefined ? option.offset : offset,
+        option: option,
+        index: index
+      };
+    }
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'map') {
+    var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
+    if (index > -1) {
+      var opts = assign({}, this.opts, {animation: false});
+      var seriesData = assign({}, this.opts.series[index]);
+      seriesData.name = seriesData.properties.name
+      var textList = [{
+        text: option.formatter ? option.formatter(seriesData, undefined, index, this.opts) : seriesData.name,
+        color: seriesData.color,
+        legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this.opts.extra.tooltip.legendShape
+      }];
+      var offset = {
+        x: _touches$.x,
+        y: _touches$.y
+      };
+      opts.tooltip = {
+        textList: option.textList ? option.textList : textList,
+        offset: option.offset !== undefined ? option.offset : offset,
+        option: option,
+        index: index
+      };
+    }
+    opts.updateData = false;
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'word') {
+    var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
+    if (index > -1) {
+      var opts = assign({}, this.opts, {animation: false});
+      var seriesData = assign({}, this.opts.series[index]);
+      var textList = [{
+        text: option.formatter ? option.formatter(seriesData, undefined, index, this.opts) : seriesData.name,
+        color: seriesData.color,
+        legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this.opts.extra.tooltip.legendShape
+      }];
+      var offset = {
+        x: _touches$.x,
+        y: _touches$.y
+      };
+      opts.tooltip = {
+        textList: option.textList ? option.textList : textList,
+        offset: option.offset !== undefined ? option.offset : offset,
+        option: option,
+        index: index
+      };
+    }
+    opts.updateData = false;
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+  if (this.opts.type === 'radar') {
+    var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
+    if (index > -1) {
+      var opts = assign({}, this.opts, {animation: false});
+      var seriesData = getSeriesDataItem(this.opts.series, index);
+      if (seriesData.length !== 0) {
+        var textList = seriesData.map((item) => {
+          return {
+            text: option.formatter ? option.formatter(item, this.opts.categories[index], index, this.opts) : item.name + ': ' + item.data,
+            color: item.color,
+            legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : this.opts.extra.tooltip.legendShape
+          };
+        });
+        var offset = {
+          x: _touches$.x,
+          y: _touches$.y
+        };
+        opts.tooltip = {
+          textList: option.textList ? option.textList : textList,
+          offset: option.offset !== undefined ? option.offset : offset,
+          option: option,
+          index: index
+        };
+      }
+    }
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+  }
+};
+
+uCharts.prototype.translate = function(distance) {
+  this.scrollOption = {
+    currentOffset: distance,
+    startTouchX: distance,
+    distance: 0,
+    lastMoveTime: 0
+  };
+  let opts = assign({}, this.opts, {
+    _scrollDistance_: distance,
+    animation: false
+  });
+  drawCharts.call(this, this.opts.type, opts, this.config, this.context);
+};
+
+uCharts.prototype.scrollStart = function(e) {
+  var touches = null;
+  if (e.changedTouches) {
+    touches = e.changedTouches[0];
+  } else {
+    touches = e.mp.changedTouches[0];
+  }
+  var _touches$ = getTouches(touches, this.opts, e);
+  if (touches && this.opts.enableScroll === true) {
+    this.scrollOption.startTouchX = _touches$.x;
+  }
+};
+
+uCharts.prototype.scroll = function(e) {
+  if (this.scrollOption.lastMoveTime === 0) {
+    this.scrollOption.lastMoveTime = Date.now();
+  }
+  let Limit = this.opts.touchMoveLimit || 60;
+  let currMoveTime = Date.now();
+  let duration = currMoveTime - this.scrollOption.lastMoveTime;
+  if (duration < Math.floor(1000 / Limit)) return;
+  if (this.scrollOption.startTouchX == 0) return;
+  this.scrollOption.lastMoveTime = currMoveTime;
+  var touches = null;
+  if (e.changedTouches) {
+    touches = e.changedTouches[0];
+  } else {
+    touches = e.mp.changedTouches[0];
+  }
+  if (touches && this.opts.enableScroll === true) {
+    var _touches$ = getTouches(touches, this.opts, e);
+    var _distance;
+    _distance = _touches$.x - this.scrollOption.startTouchX;
+    var currentOffset = this.scrollOption.currentOffset;
+    var validDistance = calValidDistance(this, currentOffset + _distance, this.opts.chartData, this.config, this.opts);
+    this.scrollOption.distance = _distance = validDistance - currentOffset;
+    var opts = assign({}, this.opts, {
+      _scrollDistance_: currentOffset + _distance,
+      animation: false
+    });
+		this.opts = opts;
+    drawCharts.call(this, opts.type, opts, this.config, this.context);
+    return currentOffset + _distance;
+  }
+};
+
+uCharts.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;
+    this.scrollOption.moveCount = 0;
+  }
+};
+
+export default uCharts;

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 17 - 0
uni_modules/qiun-data-charts/js_sdk/u-charts/u-charts.min.js


+ 201 - 0
uni_modules/qiun-data-charts/license.md

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 80 - 0
uni_modules/qiun-data-charts/package.json

@@ -0,0 +1,80 @@
+{
+  "id": "qiun-data-charts",
+  "displayName": "秋云 ucharts echarts 高性能跨全端图表组件",
+  "version": "2.5.0-20230101",
+  "description": "uCharts 新增正负柱状图!支持H5及APP用 ucharts echarts 渲染图表,uniapp可视化首选组件",
+  "keywords": [
+    "ucharts",
+    "echarts",
+    "f2",
+    "图表",
+    "可视化"
+],
+  "repository": "https://gitee.com/uCharts/uCharts",
+"engines": {
+  },
+"dcloudext": {
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": "474119"
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "插件不采集任何数据",
+      "permissions": "无"
+    },
+    "npmurl": "https://www.npmjs.com/~qiun",
+    "type": "component-vue"
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "y"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "y",
+          "IE": "y",
+          "Edge": "y",
+          "Firefox": "y",
+          "Safari": "y"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "y",
+          "百度": "y",
+          "字节跳动": "y",
+          "QQ": "y"
+        },
+        "快应用": {
+          "华为": "y",
+          "联盟": "y"
+        },
+        "Vue": {
+            "vue2": "y",
+            "vue3": "y"
+        }
+      }
+    }
+  }
+}

+ 84 - 0
uni_modules/qiun-data-charts/readme.md

@@ -0,0 +1,84 @@
+![logo](https://img-blog.csdnimg.cn/4a276226973841468c1be356f8d9438b.png)
+
+
+[![star](https://gitee.com/uCharts/uCharts/badge/star.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/stargazers)
+[![fork](https://gitee.com/uCharts/uCharts/badge/fork.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/members)
+[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+[![npm package](https://img.shields.io/npm/v/@qiun/ucharts.svg?style=flat-square)](https://www.npmjs.com/~qiun)
+
+
+## uCharts简介
+
+`uCharts`是一款基于`canvas API`开发的适用于所有前端应用的图表库,开发者编写一套代码,可运行到 Web、iOS、Android(基于 uni-app / taro )、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等更多支持 canvas API 的平台。
+
+## 官方网站
+
+## [https://www.ucharts.cn](https://www.ucharts.cn)
+
+## 快速体验
+
+一套代码编到多个平台,依次扫描二维码,亲自体验uCharts图表跨平台效果!其他平台请自行编译。
+
+![](https://www.ucharts.cn/images/web/guide/qrcode20220224.png)
+
+![](https://img-blog.csdnimg.cn/7d0115593ff24ac39a224fb7c6ed72a4.png)
+
+## 致开发者
+
+感谢各位开发者`五年`来对秋云及uCharts的支持,uCharts的进步离不开各位开发者的鼓励与贡献。为更好的帮助各位开发者使用图表工具,我们推出了新版官网,增加了在线定制、问答社区、在线配置等一些增值服务,为确保您能更好的应用图表组件,建议您先`仔细阅读官网指南`以及`常见问题`,而不是下载下来`直接使用`。如仍然不能解决,请到`官网社区`或开通会员后加入`专属VIP会员群`提问将会很快得到回答。
+
+## 视频教程
+
+## [uCharts新手入门教程](https://www.bilibili.com/video/BV1qA411Q7se/?share_source=copy_web&vd_source=42a1242f9aaade6427736af69eb2e1d9)
+
+
+## 社群支持
+
+uCharts官方拥有5个2000人的QQ群及专属VIP会员群支持,庞大的用户量证明我们一直在努力,请各位放心使用!uCharts的开源图表组件的开发,团队付出了大量的时间与精力,经过四来的考验,不会有比较明显的bug,请各位放心使用。如果您有更好的想法,可以在`码云提交Pull Requests`以帮助更多开发者完成需求,再次感谢各位对uCharts的鼓励与支持!
+
+#### 官方交流群
+- 交流群1:371774600(已满)
+- 交流群2:619841586(已满)
+- 交流群3:955340127(已满)
+- 交流群4:641669795(已满)
+- 交流群5:236294809(只能扫码加入)
+
+![](https://www.ucharts.cn/images/web/qq5.jpg)
+
+- 口令`uniapp`
+
+#### 专属VIP会员群
+- 开通会员后详见【账号详情】页面中顶部的滚动通知
+- 口令`您的用户ID`
+
+## 版权信息
+
+uCharts始终坚持开源,遵循 [Apache Licence 2.0](https://www.apache.org/licenses/LICENSE-2.0.html) 开源协议,意味着您无需支付任何费用,即可将uCharts应用到您的产品中。
+
+注意:这并不意味着您可以将uCharts应用到非法的领域,比如涉及赌博,暴力等方面。如因此产生纠纷或法律问题,uCharts相关方及秋云科技不承担任何责任。
+
+## 合作伙伴
+
+[![DIY官网](https://www.ucharts.cn/images/web/guide/links/diy-gw.png)](https://www.diygw.com/)
+[![HasChat](https://www.ucharts.cn/images/web/guide/links/haschat.png)](https://gitee.com/howcode/has-chat)
+[![uViewUI](https://www.ucharts.cn/images/web/guide/links/uView.png)](https://www.uviewui.com/)
+[![图鸟UI](https://www.ucharts.cn/images/web/guide/links/tuniao.png)](https://ext.dcloud.net.cn/plugin?id=7088)
+[![thorui](https://www.ucharts.cn/images/web/guide/links/thorui.png)](https://ext.dcloud.net.cn/publisher?id=202)
+[![FirstUI](https://www.ucharts.cn/images/web/guide/links/first.png)](https://www.firstui.cn/)
+[![nProUI](https://www.ucharts.cn/images/web/guide/links/nPro.png)](https://ext.dcloud.net.cn/plugin?id=5169)
+[![GraceUI](https://www.ucharts.cn/images/web/guide/links/grace.png)](https://www.graceui.com/)
+
+
+## 更新记录
+
+详见官网指南中说明,[点击此处查看](https://www.ucharts.cn/v2/#/guide/index?id=100)
+
+
+## 相关链接
+- [uCharts官网](https://www.ucharts.cn)
+- [DCloud插件市场地址](https://ext.dcloud.net.cn/plugin?id=271)
+- [uCharts码云开源托管地址](https://gitee.com/uCharts/uCharts) [![star](https://gitee.com/uCharts/uCharts/badge/star.svg?theme=gvp)](https://gitee.com/uCharts/uCharts/stargazers)
+- [uCharts npm开源地址](https://www.ucharts.cn)
+- [ECharts官网](https://echarts.apache.org/zh/index.html)
+- [ECharts配置手册](https://echarts.apache.org/zh/option.html)
+- [图表组件在项目中的应用 ReportPlus数据报表](https://www.ucharts.cn/v2/#/layout/info?id=1) 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 22 - 0
uni_modules/qiun-data-charts/static/app-plus/echarts.min.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 22 - 0
uni_modules/qiun-data-charts/static/h5/echarts.min.js


+ 6 - 0
uni_modules/uni-wifi/changelog.md

@@ -0,0 +1,6 @@
+## 1.0.6(2023-11-13)
++ 统一错误码格式
++ 修复部分真机未链接wifi可能卡死的bug
+## 1.0.0(2022-12-05)
+实现Android/iOS平台Wi-Fi功能模块  
+注:iOS平台仅支持获取已连接的 Wi-Fi 信息

+ 122 - 0
uni_modules/uni-wifi/package.json

@@ -0,0 +1,122 @@
+{
+  "id": "uni-wifi",
+  "displayName": "uni-wifi",
+  "version": "1.0.6",
+  "description": "wifi管理",
+  "keywords": [
+    "wifi"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.96"
+  },
+  "dcloudext": {
+    "type": "uts",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "插件不采集任何数据",
+      "permissions": "Android平台:\n<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>\n<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>\n<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>\n<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\niOS平台:\niOS13及以上平台获取Wifi信息需要定位权限"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "uni-ext-api": {
+      "uni": {
+        "startWifi": {
+          "web": false
+        },
+        "stopWifi": {
+          "web": false
+        },
+        "connectWifi": {
+          "web": false
+        },
+        "getConnectedWifi": {
+          "web": false
+        },
+        "getWifiList": {
+          "web": false
+        },
+        "onGetWifiList": {
+          "web": false
+        },
+        "offGetWifiList": {
+          "web": false
+        },
+        "onWifiConnected": {
+          "web": false
+        },
+        "offWifiConnected": {
+          "web": false
+        },
+        "onWifiConnectedWithPartialInfo": {
+          "web": false
+        },
+        "offWifiConnectedWithPartialInfo": {
+          "web": false
+        }
+      }
+    },
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y"
+      },
+      "client": {
+        "Vue": {
+          "vue2": "y",
+          "vue3": "y"
+        },
+        "App": {
+          "app-android": {
+            "minVersion": "19"
+          },
+          "app-ios": {
+            "minVersion": "9"
+          }
+        },
+        "H5-mobile": {
+          "Safari": "n",
+          "Android Browser": "n",
+          "微信浏览器(Android)": "n",
+          "QQ浏览器(Android)": "n"
+        },
+        "H5-pc": {
+          "Chrome": "n",
+          "IE": "n",
+          "Edge": "n",
+          "Firefox": "n",
+          "Safari": "n"
+        },
+        "小程序": {
+          "微信": "n",
+          "阿里": "n",
+          "百度": "n",
+          "字节跳动": "n",
+          "QQ": "n",
+          "钉钉": "n",
+          "快手": "n",
+          "飞书": "n",
+          "京东": "n"
+        },
+        "快应用": {
+          "华为": "n",
+          "联盟": "n"
+        }
+      }
+    }
+  }
+}

+ 145 - 0
uni_modules/uni-wifi/readme.md

@@ -0,0 +1,145 @@
+## 使用说明  
+
+Wi-Fi功能模块
+
+
+### App-iOS平台注意事项  
+- iOS平台App获取Wi-Fi信息需要开启“Access WiFi information”能力  
+  登录苹果开发者网站,在“Certificates, Identifiers & Profiles”页面选择“Identifiers”中选择对应的App ID,确保开启“Access WiFi information”,保存后重新生成profile文件  
+- iOS13及以上系统,获取当前连接的Wi-Fi信息需要先获取系统定位权限,因此在iOS13及以上系统使用此接口时,会触发定位权限申请的弹窗  
+
+### App-Android平台注意事项  
+- 如果是自定义基座,需要具备下面的权限
+
+```
+<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+```
+
+
+###uni.startWifi(OBJECT)
+
+初始化Wi-Fi模块。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi)
+
+
+### uni.stopWifi(OBJECT)
+
+关闭 Wi-Fi 模块。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi)
+
+
+### uni.getConnectedWifi(OBJECT)
+
+获取已连接的 Wi-Fi 信息
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#getconnectedwifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#getconnectedwifi)
+
+
+### uni.getWifiList(OBJECT)
+
+请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList](https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.onGetWifiList(CALLBACK)
+
+监听获取到 Wi-Fi 列表数据事件。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList](https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.offGetWifiList(CALLBACK)
+
+移除获取到 Wi-Fi 列表数据事件的监听函数。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList](https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.connectWifi(OBJECT)
+
+连接 Wi-Fi。若已知 Wi-Fi 信息,可以直接利用该接口连接。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi](https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.onWifiConnected(CALLBACK)
+
+监听连接上 Wi-Fi 的事件。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected](https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.offWifiConnected(CALLBACK)
+
+移除连接上 Wi-Fi 的事件的监听函数。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected](https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.onWifiConnectedWithPartialInfo(CALLBACK)
+
+监听连接上 Wi-Fi 的事件。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo](https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+
+
+### uni.offWifiConnectedWithPartialInfo(CALLBACK)
+
+移除连接上 Wi-Fi 的事件的监听函数。
+
+> 使用文档:[https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnectedWithPartialInfo](https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnectedWithPartialInfo)
+
+**平台差异说明**
+
+|App-Android|App-iOS|
+|:-:|:-:|
+|√|x|
+

+ 3 - 0
uni_modules/uni-wifi/utssdk/app-android/config.json

@@ -0,0 +1,3 @@
+{
+  "minSdkVersion": "19"
+}

+ 802 - 0
uni_modules/uni-wifi/utssdk/app-android/index.uts

@@ -0,0 +1,802 @@
+import Context from "android.content.Context";
+import WifiManager from "android.net.wifi.WifiManager";
+import WifiInfo from "android.net.wifi.WifiInfo";
+import Manifest from "android.Manifest";
+import PackageManager from "android.content.pm.PackageManager";
+import ScanResult from "android.net.wifi.ScanResult";
+import BroadcastReceiver from "android.content.BroadcastReceiver";
+import ActivityCompat from "androidx.core.app.ActivityCompat";
+import IntentFilter from "android.content.IntentFilter";
+import Intent from "android.content.Intent";
+
+import WifiConfiguration from 'android.net.wifi.WifiConfiguration';
+import AuthAlgorithm from 'android.net.wifi.WifiConfiguration.AuthAlgorithm';
+import KeyMgmt from 'android.net.wifi.WifiConfiguration.KeyMgmt';
+import TextUtils from 'android.text.TextUtils';
+import Build from 'android.os.Build';
+
+import { UniWifiResult, UniWifiInfoWithPartialInfo,GetConnectedWifiOptions, WifiConnectOption, WifiOption, UniWifiInfo,UniWifiCallback ,UniWifiResultCallback,UniWifiResultCallbackWithPartialInfo,UniGetWifiListCallback} from "../interface.uts"
+import { WifiFailImpl, getErrcode,UniErrorSubject } from '../unierror';
+
+
+/**
+	* 全局数据储存
+	*/
+class Global {
+	static mReceiver : CustomBroadcastReceiver | null = null;
+	static WIFI_AUTH_OPEN : string = "";
+	static WIFI_AUTH_ROAM : String = "[ESS]";
+	// 扫描wifi结果
+	static scanList : AndroidUniWifiInfo[] = []
+	// 获取wifi列表监听
+	static onGetWifiListCallback : UniGetWifiListCallback|null = null
+	static supendGetWifiSuccess : UniWifiResultCallback|null = null
+	static supendGetWifiComplete :UniWifiResultCallback|null = null
+	// wifi链接监听
+	static onWifiConnectCallbackList : UniWifiResultCallback[] = []
+	static onWifiConnectWithPartialInfoCallbackList : UniWifiResultCallbackWithPartialInfo[] = []
+}
+
+
+/**
+	* 是否是标准的16进制字符
+	*/
+function isHex(key : string) : boolean {
+	for (var i = key.length - 1; i >= 0; i--) {
+		let c = key.charAt(i);
+		if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
+			&& c <= 'f')) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+/**
+	* 判断是否是wep格式的key
+	*/
+function isHexWepKey(wepKey : string) : boolean {
+	let len = wepKey.length;
+
+	// WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
+	if (len != 10 && len != 26 && len != 58) {
+		return false;
+	}
+
+	return isHex(wepKey);
+}
+/**
+ * android 平台特有的Wifi信息对象,主要是加了加密信息这个字段
+ */
+export type AndroidUniWifiInfo = {
+	SSID : string;
+	BSSID ?: string;
+	secure : boolean;
+	signalStrength : number;
+	frequency : number;
+	securityType : string;
+}
+
+function wrapUniWifiInfoFromAndroid(androidInfo : AndroidUniWifiInfo) : UniWifiInfo {
+	let ret : UniWifiInfo = {
+		SSID: androidInfo.SSID,
+		BSSID: androidInfo.BSSID,
+		secure: androidInfo.secure,
+		signalStrength: androidInfo.signalStrength,
+		frequency: androidInfo.frequency,
+	}
+	return ret
+}
+/**
+ * 从扫描结果中提取统一的wifi数据结构
+ */
+function wrapUniWifiInfoFromScan(scanResult : ScanResult) : AndroidUniWifiInfo {
+
+	let ret : AndroidUniWifiInfo = {
+		SSID: "",
+		secure: false,
+		signalStrength: 0,
+		frequency: 0,
+		securityType: "NONE"
+	}
+	if (scanResult != null) {
+		// 如果是通过扫描列表得到的数据,进行封装
+		ret.BSSID = scanResult.BSSID;
+		ret.SSID = scanResult.SSID;
+
+		ret.signalStrength = scanResult.level;
+		ret.frequency = scanResult.frequency;
+
+		// 是否安全,微信的标准是是否需要密码。 来源:https://developers.weixin.qq.com/community/develop/doc/00064cf1790458db19cddf9925ac00?highLine=WifiInfo
+		ret.secure = false;
+		let capabilities = scanResult.capabilities.trim();
+		if ((capabilities.equals(Global.WIFI_AUTH_OPEN) || capabilities.equals(Global.WIFI_AUTH_ROAM))) {
+			ret.secure = false;
+		} else {
+			ret.secure = true;
+		}
+
+		/*扩展字段*/
+		ret.securityType = getSecurityType(scanResult);
+	}
+
+	return ret
+}
+/**
+ * 从链接信息中提取统一的wifi数据结构
+ */
+function wrapUniWifiInfoFromConnectInfo(connectInfo : WifiInfo) : UniWifiInfo {
+	let ret : UniWifiInfo = {
+		SSID: "",
+		secure: false,
+		signalStrength: 0,
+		frequency: 0,
+	}
+
+
+	if (connectInfo.getSSID() != null) {
+		let s = connectInfo.getSSID();
+		// 微信不带,这里需要去掉引号
+		if (s.length > 2 && s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') {
+			s = s.substring(1, s.length - 1);
+		}
+		ret.SSID = s;
+	}
+
+	ret.BSSID = connectInfo.getBSSID();
+	//Android返回的值是-100~0,而微信API规范是0~100,值越大信号越好,需要+100拉齐
+	ret.signalStrength = connectInfo.getRssi() + 100;
+	ret.frequency = connectInfo.getFrequency();
+
+
+	return ret
+}
+
+
+/**
+ * 连接wifi时使用,根据用户输入内容包装为系统需要的wifi配置对象
+ **/
+@Suppress("DEPRECATION")
+function wrapWifiConfiguration(SSID : string, password ?: string, passwordType : string) : WifiConfiguration {
+
+	let config = new WifiConfiguration();
+	config.status = WifiConfiguration.Status.ENABLED;
+	config.allowedAuthAlgorithms.clear();
+	config.allowedGroupCiphers.clear();
+	config.allowedKeyManagement.clear();
+	config.allowedPairwiseCiphers.clear();
+	config.allowedProtocols.clear();
+	config.SSID = "\"".concat(SSID).concat("\"");
+
+
+	// nopass
+	if ("NONE".equals(passwordType) || password == null) {
+		config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+	}
+	// wep
+	else if ("WEP".equals(passwordType)) {
+		if (password != null && !TextUtils.isEmpty(password)) {
+			if (isHexWepKey(password)) {
+				config.wepKeys[0] = password;
+			} else {
+				config.wepKeys[0] = "\"".concat(password).concat("\"");
+			}
+		}
+		config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
+		config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
+		config.allowedKeyManagement.set(KeyMgmt.NONE);
+		config.wepTxKeyIndex = 0;
+	}
+	// wpa
+	else if ("WPA".equals(passwordType)) {
+		config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+		config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+		config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+		config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+		config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+		config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
+		config.preSharedKey = "\"".concat(password).concat("\"");
+	}
+
+	return config;
+}
+
+
+/**
+ * 判断当前wifi的加密类型
+ */
+function getSecurityType(result : ScanResult) : string {
+	if (result.capabilities.contains("WEP")) {
+		return "WEP";
+	} else if (result.capabilities.contains("PSK")) {
+		return "WPA";
+	} else if (result.capabilities.contains("EAP")) {
+		return "EAP";
+	}
+	return "NONE";
+}
+
+
+function zeroCountNum(source ?: string) : number {
+	if (source == null) {
+		return 0
+	}
+	var splitted = source.split(":")
+	var countNum = 0;
+	for (perItem in splitted) {
+		if (perItem == "00") {
+			countNum += 1
+		}
+	}
+	return countNum
+}
+
+
+/**
+	* 自定义wifi变化广播监听器
+	*/
+@Suppress("UNUSED_PARAMETER", "DEPRECATION")
+class CustomBroadcastReceiver extends BroadcastReceiver {
+
+	mWifiManager : WifiManager | null = null;
+
+	constructor(wifiManager : WifiManager) {
+		super();
+		this.mWifiManager = wifiManager;
+	}
+
+	override onReceive(_context : Context, intent : Intent) : void {
+
+
+		if (intent.action == WifiManager.WIFI_STATE_CHANGED_ACTION) {
+
+			let state =
+				intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
+
+			if (state == WifiManager.WIFI_STATE_ENABLED) {
+				// 获取当前的connectInfo 并且进行数据封装
+				let uniWifiInfo = new UniWifiInfo("","",false,0,0)
+				//做一些异步操作
+				setTimeout(function () {
+					// BroadcastReceiver 中不能执行耗时任务,需要使用setTimeout
+					// @ts-ignore
+					let winfo = this.mWifiManager!.getConnectionInfo();
+
+          if(winfo != null && winfo.bssid != null && zeroCountNum(winfo.bssid) < 3){
+              //  当前设备链接到了某个具体的wifi.封装成数据对象
+              uniWifiInfo = wrapUniWifiInfoFromConnectInfo(winfo)
+              let res = new UniWifiResult(0,UniErrorSubject,'onWifiConnected:ok',uniWifiInfo)
+
+              // wifi状态可用了,分发当前的链接状态给已注册的监听集合
+              for (let perCallback in Global.onWifiConnectCallbackList) {
+                perCallback(res);
+              }
+              // 封装仅SSID 数据对象
+              let connectedWithPartialInfo = new UniWifiInfoWithPartialInfo(uniWifiInfo.SSID)
+
+              for (let perCallback in Global.onWifiConnectWithPartialInfoCallbackList) {
+                perCallback(connectedWithPartialInfo);
+              }
+          } else {
+            // 开启了wifi 开关,但是尚未链接到某个具体的wifi
+          }
+
+				}, 100);
+			}
+
+		}
+
+
+		if (intent.action == WifiManager.SCAN_RESULTS_AVAILABLE_ACTION) {
+			startWifiScaning = false;
+			// wifi 扫描结果回调
+			let results = this.mWifiManager!.scanResults;
+
+			if (results != null) {
+				Global.scanList = []
+				for (let scanResult in results) {
+					if (scanResult.SSID == null) {
+						continue;
+					}
+					Global.scanList.push(wrapUniWifiInfoFromScan(scanResult));
+				}
+
+				// 挨个通知,所有的监听器
+				if(Global.onGetWifiListCallback != null){
+					const data = new UTSJSONObject();
+					data["wifiList"] = Global.scanList
+					Global.onGetWifiListCallback?.(data);
+					/**
+					 * 确保onGetWifiList 只会被执行一次
+					 */
+					Global.onGetWifiListCallback = null
+				}
+
+			}
+
+      let ret = new UniWifiResult(0,UniErrorSubject,"getWifiList:ok",null)
+			if(Global.supendGetWifiSuccess != null){
+				Global.supendGetWifiSuccess?.(ret)
+				Global.supendGetWifiSuccess = null
+			}
+			if(Global.supendGetWifiComplete != null){
+				Global.supendGetWifiComplete?.(ret)
+				Global.supendGetWifiComplete = null
+			}
+		}
+	}
+
+}
+
+
+
+/************************* 下面是对外提供的函数 *************************/
+/**
+ * start wifi是否正在扫描
+ */
+var startWifiScaning = false
+
+/**
+ * 开启wifi
+ */
+@Suppress("DEPRECATION")
+export function startWifiImpl(option : WifiOption) {
+
+
+  // 具备了权限,继续前进
+  let wifiManager : WifiManager =
+  	UTSAndroid.getAppContext()!.getSystemService(Context.WIFI_SERVICE) as WifiManager
+  // 用户没有开启wifi 总开关
+  if (!wifiManager.isWifiEnabled()) {
+  	// wifi 没开启
+    let failResult = new WifiFailImpl(getErrcode(12005));
+  	option.fail?.(failResult);
+  	option.complete?.(failResult);
+  	return;
+  }
+  // 初始化wifi 状态广播监听,后续所有的api,均基于此
+  if(Global.mReceiver != null){
+  	// 说明已经注册过了
+    let result = UniWifiResult(0,UniErrorSubject,"startWifi:ok",null)
+
+  	option.success?.(result)
+  	option.complete?.(result)
+  	return
+  }
+
+
+  Global.mReceiver = new CustomBroadcastReceiver(wifiManager)
+
+  let filter = new IntentFilter()
+  filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
+  // @ts-ignore
+  filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
+  // @ts-ignore
+  filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
+
+  UTSAndroid.getUniActivity()!.registerReceiver(Global.mReceiver, filter)
+
+  /**
+  	* activity 被销毁时,取消注册
+  	*/
+  UTSAndroid.onAppActivityDestroy(function () {
+
+  	if (Global.mReceiver != null) {
+  		UTSAndroid.getUniActivity()!.unregisterReceiver(Global.mReceiver)
+  		Global.mReceiver = null
+
+  		Global.scanList = []
+  		Global.onGetWifiListCallback = null
+  		Global.onWifiConnectCallbackList = []
+  		Global.onWifiConnectWithPartialInfoCallbackList = []
+  	}
+
+  });
+  startWifiScaning = true
+  // 开始扫描
+  wifiManager.startScan()
+
+  let result = UniWifiResult(0,UniErrorSubject,"startWifi:ok",null)
+  option.success?.(result)
+  option.complete?.(result)
+
+}
+
+@Suppress("DEPRECATION")
+export function startWifi(option : WifiOption) {
+
+  /**
+   * 准备权限
+   */
+  let permissionNeed = ["android.permission.ACCESS_FINE_LOCATION"];
+  UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionNeed, function (allRight:boolean,_grantedList:string[]) {
+  	if (allRight) {
+  		// 交给目前的location 引擎,真实执行
+  		startWifiImpl(option)
+  	}
+  }, function (_doNotAskAgain:boolean,_grantedList:string[]) {
+  	let err = new WifiFailImpl(getErrcode(12001));
+  	option.fail?.(err)
+  	option.complete?.(err)
+  })
+
+}
+
+/**
+	* 获取wifi列表
+	*/
+@Suppress("DEPRECATION")
+export function getWifiList(option : WifiOption) {
+
+
+	if (Global.mReceiver == null) {
+		// 还没调用startWifi 提示报错
+    let err = new WifiFailImpl(getErrcode(12000));
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+
+	let wifiManager : WifiManager =
+		UTSAndroid.getAppContext()!.getSystemService(Context.WIFI_SERVICE) as WifiManager
+
+  if(option.success != null){
+    Global.supendGetWifiSuccess = option.success
+  }
+	if(option.complete != null){
+    Global.supendGetWifiComplete = option.complete
+  }
+
+	wifiManager.startScan()
+
+}
+
+
+
+/**
+	* wifi 链接成功的回调注册
+	*/
+export function onWifiConnected(callback : UniWifiResultCallback) {
+	Global.onWifiConnectCallbackList.push(callback)
+}
+
+
+export function onWifiConnectedWithPartialInfo(callback : UniWifiResultCallbackWithPartialInfo) {
+	Global.onWifiConnectWithPartialInfoCallbackList.push(callback)
+}
+
+
+/**
+ * wifi 链接成功的回调取消注册
+ */
+export function offWifiConnected(callback? : UniWifiResultCallback) {
+
+	if(callback == null){
+		Global.onWifiConnectCallbackList = []
+		return
+	}
+
+	let callbackIndex = Global.onWifiConnectCallbackList.indexOf(callback)
+	if (callbackIndex >= 0) {
+		Global.onWifiConnectCallbackList.splice(callbackIndex, 1);
+	}
+}
+
+/**
+ * 不具备详细信息的wifi 反注册
+ */
+export function offWifiConnectedWithPartialInfo(callback? : UniWifiResultCallbackWithPartialInfo) {
+
+	if(callback == null){
+		Global.onWifiConnectWithPartialInfoCallbackList = []
+		return
+	}
+
+	let callbackIndex = Global.onWifiConnectWithPartialInfoCallbackList.indexOf(callback)
+	if (callbackIndex >= 0) {
+		Global.onWifiConnectWithPartialInfoCallbackList.splice(callbackIndex, 1);
+	}
+}
+
+/**
+	* 注册Wifi列表的监听事件
+	*/
+export function onGetWifiList(callback : UniGetWifiListCallback) {
+	Global.onGetWifiListCallback = callback
+}
+
+/**
+ * 取消注册Wifi列表的监听事件
+ */
+export function offGetWifiList(callback? : UniWifiCallback) {
+	Global.onGetWifiListCallback = null
+	Global.supendGetWifiComplete = null
+	Global.supendGetWifiSuccess = null
+}
+
+
+/**
+ * 真正执行wifi链接逻辑
+ */
+function realWifiConnect(option : WifiConnectOption){
+
+	if (Global.mReceiver == null || Global.scanList.length < 1) {
+
+    let err = new WifiFailImpl(getErrcode(12000));
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+
+	// 执行后续的逻辑
+	let scanWifiInfo : AndroidUniWifiInfo | null = null
+	for (let scanResult in Global.scanList) {
+		if (scanResult.SSID.equals(option.SSID)) {
+			scanWifiInfo = scanResult
+		}
+	}
+
+	if (scanWifiInfo == null) {
+		// 不在扫描列表中返回错误
+    let err = new WifiFailImpl(getErrcode(12000));
+		option.fail?.(err)
+		option.complete?.(err)
+		return
+	}
+
+	let wifiConfigration = wrapWifiConfiguration(scanWifiInfo.SSID, option.password, scanWifiInfo.securityType);
+	wifiConfigration.BSSID = scanWifiInfo.BSSID
+	let wifiManager : WifiManager =
+		UTSAndroid.getAppContext()!.getSystemService(Context.WIFI_SERVICE) as WifiManager
+
+	// 如果已经存在了指定wifi 配置,移除之
+	let targetExistConfig : WifiConfiguration | null = null
+	let existingConfigs = wifiManager.getConfiguredNetworks();
+	for (let existingConfig in existingConfigs) {
+		if (existingConfig.SSID.equals("\"" + option.SSID + "\"")) {
+			targetExistConfig = existingConfig
+		}
+	}
+	// 如果wifi已经保存了当前ssid的配置,可能是别的应用添加的。android系统要求,需要删除掉重新添加
+	if (targetExistConfig != null) {
+		let removeRet = wifiManager.removeNetwork(targetExistConfig.networkId);
+
+		if (!removeRet) {
+
+			// add since 2023-03-28,如果当前系统大于等于android10, 则明确当前系统不支持
+			if(Build.VERSION.SDK_INT > 28){
+				// 系统大于android 9
+        let err = new WifiFailImpl(getErrcode(12001));
+				option.fail?.(err)
+				option.complete?.(err)
+			}else{
+				// 移除之前的配置失败了,返回错误,需要用户手动取消保存一下
+        let err = new WifiFailImpl(getErrcode(12013));
+				option.fail?.(err)
+				option.complete?.(err)
+			}
+
+
+			return
+		}
+
+	}
+
+	let currentConnect = wifiManager.getConnectionInfo()
+	if (currentConnect.networkId >= 0) {
+		wifiManager.disableNetwork(currentConnect.networkId)
+	} else {
+		wifiManager.removeNetwork(currentConnect.networkId)
+	}
+	wifiManager.disconnect()
+
+	let connected = false;
+	try {
+
+		let netID = wifiManager.addNetwork(wifiConfigration);
+		// 如果-1 说明没添加上,报错即可
+		if (netID < 0) {
+      let err = new WifiFailImpl(getErrcode(12002));
+			option.fail?.(err)
+			option.complete?.(err)
+
+			return
+		}
+
+
+		let enabled = wifiManager.enableNetwork(netID, true);
+		if (!enabled) {
+      let err = new WifiFailImpl(getErrcode(12007));
+			option.fail?.(err)
+			option.complete?.(err)
+
+			return
+		}
+		connected = wifiManager.reconnect();
+
+	} catch (e) {
+		connected = false;
+		console.log(e);
+	}
+
+	if (!connected) {
+		// 出错了,返回错误
+		// 兜底的报错
+    let err = new WifiFailImpl(getErrcode(12010));
+		option.fail?.(err)
+		option.complete?.(err)
+		return
+	}
+
+  let result = new UniWifiResult(0,UniErrorSubject,"getWifiList:ok",null)
+
+	wifiManager.saveConfiguration()
+	//scanWifiInfo 根据 partialInfo 填充给返回字段
+	if (option.partialInfo != null && option.partialInfo == true) {
+		let wifiPartialInfo : UniWifiInfo = {
+			SSID: scanWifiInfo.SSID
+		}
+		result.wifi = wifiPartialInfo
+	} else {
+		result.wifi = wrapUniWifiInfoFromAndroid(scanWifiInfo)
+	}
+
+
+	option.success?.(result)
+	option.complete?.(result)
+}
+
+/**
+ * 链接指定wifi
+ */
+@Suppress("UNUSED_PARAMETER", "DEPRECATION")
+export function connectWifi(option : WifiConnectOption) {
+
+	if (option.maunal == true) {
+		// 指定了手动模式
+		let manunalIntent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
+		UTSAndroid.getUniActivity()!.startActivity(manunalIntent);
+
+    
+     let result = new UniWifiResult(0,UniErrorSubject,"connectWifi:ok",null)
+
+		option.success?.(result)
+		option.complete?.(result)
+		return
+	}
+
+
+
+	// add since 2022-03-28 ,增加逻辑,如果正在扫描中,则可以等待5s
+	if(startWifiScaning){
+		let taskCount = 0
+		let taskId:number  = 0
+		taskId = setInterval(function(){
+
+			taskCount += 1;
+			if(taskCount >= 5 || startWifiScaning == false){
+				// 超过10s了。或者扫描过程结束了
+				clearInterval(taskId)
+				realWifiConnect(option)
+			}
+		},2000)
+
+		UTSAndroid.onAppActivityDestroy(function () {
+			clearInterval(taskId)
+		});
+	}else{
+		realWifiConnect(option)
+	}
+
+
+
+}
+
+
+/**
+	* 关闭wifi
+	*/
+export function stopWifi(option : WifiOption) {
+	// 需要先开启wifi,才能使用后续的功能
+	if (Global.mReceiver == null) {
+    let err = new WifiFailImpl(getErrcode(12000));
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+	try {
+		UTSAndroid.getUniActivity()!.unregisterReceiver(Global.mReceiver)
+	} catch (e) {
+		// 多次调用
+		//TODO handle the exception
+	}
+
+	Global.onGetWifiListCallback = null
+	Global.onWifiConnectWithPartialInfoCallbackList = []
+	Global.onWifiConnectCallbackList = []
+	Global.mReceiver = null
+
+  let ret = new UniWifiResult(0,UniErrorSubject,"stopWifi:ok",null)
+	option.success?.(ret)
+	option.complete?.(ret)
+
+}
+
+/**
+ * 获取当前连接中的wifi信息
+ */
+@Suppress("DEPRECATION")
+export function getConnectedWifi(option : GetConnectedWifiOptions) {
+
+	let wifiInfo : UniWifiInfo = {
+		SSID: ""
+	}
+
+
+	if (Global.mReceiver == null) {
+		// 还没调用startWifi 提示报错
+    let err = new WifiFailImpl(getErrcode(12000));
+		option.fail?.(err)
+		option.complete?.(err)
+
+		return
+	}
+
+	// 需要先校验权限,没有位置权限无法获取wifi
+	if (ActivityCompat.checkSelfPermission(UTSAndroid.getUniActivity()!, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+		// 尚不具备权限,返回错误
+    let err = new WifiFailImpl(getErrcode(12001));
+		option.fail?.(err)
+		option.complete?.(err)
+		return;
+	}
+
+
+
+	const context = UTSAndroid.getAppContext();
+	if (context != null) {
+		const wm = context.getSystemService(
+			Context.WIFI_SERVICE
+		) as WifiManager;
+		// 测试android 12上可以使用
+		//@ts-ignore
+		const winfo = wm.getConnectionInfo();
+
+		wifiInfo = wrapUniWifiInfoFromConnectInfo(winfo);
+
+    let res = new UniWifiResult(0,UniErrorSubject,"getConnectedWifi:ok",null)
+
+		// 判断一下是否wifi 关闭了
+		if (option.partialInfo!= null) {
+			let ret : UniWifiInfo = {
+				SSID: wifiInfo.SSID
+			}
+			res.wifi = ret;
+		} else {
+			if (wifiInfo.BSSID == null || zeroCountNum(wifiInfo.BSSID) > 3) {
+         let err = new WifiFailImpl(getErrcode(12005));
+				option.fail?.(err)
+				option.complete?.(err)
+				return
+			}
+			res.wifi = wifiInfo;
+		}
+
+
+		option.success?.(res)
+		option.complete?.(res)
+		return
+	}
+
+  let err = new WifiFailImpl(getErrcode(12000));
+	option.fail?.(err)
+	option.complete?.(err)
+}
+

+ 8 - 0
uni_modules/uni-wifi/utssdk/app-ios/Info.plist

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+  <dict>
+    <key>NSLocationWhenInUseUsageDescription</key>
+    <string>使用期间获取位置权限</string>
+  </dict>
+</plist>

+ 8 - 0
uni_modules/uni-wifi/utssdk/app-ios/UTS.entitlements

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.developer.networking.wifi-info</key>
+	<true/>
+</dict>
+</plist>

+ 9 - 0
uni_modules/uni-wifi/utssdk/app-ios/config.json

@@ -0,0 +1,9 @@
+{
+	"frameworks": [
+		"CoreLocation.framework",
+		"SystemConfiguration.framework"
+	],
+	"validArchitectures": [
+		"arm64", "armv7"
+	],"deploymentTarget": "9"
+}

+ 268 - 0
uni_modules/uni-wifi/utssdk/app-ios/index.uts

@@ -0,0 +1,268 @@
+import { CLLocationManager, CLAuthorizationStatus, CLLocationManagerDelegate } from 'CoreLocation'
+import { CaptiveNetwork, kCNNetworkInfoKeySSID, kCNNetworkInfoKeyBSSID } from 'SystemConfiguration.CaptiveNetwork';
+import { NSArray, NSDictionary } from 'Foundation';
+import { CFString } from 'CoreFoundation';
+import { UIDevice } from 'UIKit';
+import { UniWifiResultCallbackWithPartialInfo, UniGetWifiListCallback, UniWifiResultCallback, WifiOption, WifiConnectOption, GetConnectedWifiOptions, UniWifiInfo, UniWifiResult, UniWifiCallback, StartWifi, StopWifi, GetWifiList, OnGetWifiList, OffGetWifiList, GetConnectedWifi, ConnectWifi, OnWifiConnected, OnWifiConnectedWithPartialInfo, OffWifiConnected, OffWifiConnectedWithPartialInfo, SetWifiList } from "../interface.uts"
+import { WifiFailImpl, getErrcode } from '../unierror';
+
+/*
+ * 系统定位权限获取类
+ */
+class LocationPromiseService implements CLLocationManagerDelegate  {
+	static promiseCompletionHandler: ((res: boolean)=>void)[] = []
+
+	manager?: CLLocationManager
+
+	constructor(manager?: CLLocationManager) {
+		this.manager = manager
+	}
+
+	initlizeManager(): boolean {
+		if (this.manager == null) {
+			this.manager = new CLLocationManager()
+			this.manager!.delegate = this
+		}
+		return true
+	}
+
+	locationManager(manager: CLLocationManager, @argumentLabel("didChangeAuthorization") status: CLAuthorizationStatus) {
+		if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
+			LocationPromiseService.promiseCompletionHandler.forEach((handler): void => {
+				handler(true)
+			})
+		} else if (status == CLAuthorizationStatus.notDetermined) {
+			manager.requestWhenInUseAuthorization()
+		} else if (status == CLAuthorizationStatus.denied) {
+			LocationPromiseService.promiseCompletionHandler.forEach((handler): void => {
+				handler(false)
+			})
+		}
+	}
+	requestPromise(@escaping completion: (res: boolean)=>void) {
+		let status: CLAuthorizationStatus = CLLocationManager.authorizationStatus()
+		if (status == CLAuthorizationStatus.notDetermined) {
+			if (this.initlizeManager() == true) {
+				this.manager!.requestWhenInUseAuthorization()
+				LocationPromiseService.promiseCompletionHandler.push(completion)
+			}
+		} else if (status == CLAuthorizationStatus.authorizedAlways || status == CLAuthorizationStatus.authorizedWhenInUse) {
+			completion(true)
+		} else if (status == CLAuthorizationStatus.denied) {
+			if (CLLocationManager.locationServicesEnabled() == false && this.initlizeManager() == true) {
+				this.manager!.requestWhenInUseAuthorization()
+				LocationPromiseService.promiseCompletionHandler.push(completion)
+			}
+		}
+	}
+}
+
+const locationPromiseService: LocationPromiseService = new LocationPromiseService(null)
+
+/*
+ * 获取系统定位权限
+ */
+function requestLocationPromise(@escaping completion: (res: boolean)=>void) {
+	locationPromiseService.requestPromise(completion)
+}
+
+/*
+ * 获取当前连接的wifi信息(通过定位权限)
+ */
+function fetchConnectedWifiWithLocationPromise(option: GetConnectedWifiOptions) {
+	let arr = CNCopySupportedInterfaces()
+	let wifiInfo: UniWifiInfo = {
+		BSSID: "",
+		SSID: "",
+		secure: false,
+		signalStrength: 0,
+		frequency: 0
+	}
+
+	if (arr != null) {
+		let list = arr! as NSArray
+		let index: Int = 0
+		while (index < list.count) {
+			let item = list[index]
+			let interfaceName = item as string
+			let dic = CNCopyCurrentNetworkInfo(interfaceName as CFString)
+			if (dic != null) {
+				let dict = dic! as NSDictionary
+				let SSID = dict[kCNNetworkInfoKeySSID as string]
+				let BSSID = dict[kCNNetworkInfoKeyBSSID as string]
+
+				if (SSID != null && BSSID != null) {
+					let ssid = SSID! as string
+					let bssid = BSSID! as string
+					wifiInfo.SSID = ssid
+					wifiInfo.BSSID = bssid
+					wifiInfo.secure = false
+					wifiInfo.signalStrength = 0
+					wifiInfo.frequency = 0
+					break;
+				}
+			}
+			index++
+		}
+
+		if (wifiInfo.BSSID!.length > 0 && wifiInfo.SSID.length > 0) {
+			let res: UniWifiResult = {
+				errSubject: "uni-getConnectedWifi",
+				errCode: 0,
+				errMsg: "getConnectedWifi:ok",
+				wifi: wifiInfo,
+			}
+			option.success?.(res)
+			option.complete?.(res)
+		}else {
+      let err = new WifiFailImpl(getErrcode(12010));
+			option.fail?.(err)
+			option.complete?.(err)
+		}
+	}else {
+    let err = new WifiFailImpl(getErrcode(12010));
+		option.fail?.(err)
+		option.complete?.(err)
+	}
+}
+
+
+
+/*
+ * 保存全局数据信息
+ */
+class UniWiFiModuleGloabInfo {
+	static alreadyStartWifi: boolean = false
+}
+
+/* =================================== 对外暴露的接口 ==============================================*/
+
+
+
+/*
+ * 初始化wifi模块
+ */
+export const startWifi: StartWifi = function (option: WifiOption) {
+	UniWiFiModuleGloabInfo.alreadyStartWifi = true
+	let res: UniWifiResult = {
+		errSubject: "uni-startWifi",
+		errCode: 0,
+		errMsg: "startWifi:ok",
+		wifi: null
+	}
+	option.success?.(res)
+	option.complete?.(res)
+}
+
+/*
+ * 停止wifi模块
+ */
+export const stopWifi: StopWifi = function (option: WifiOption) {
+	UniWiFiModuleGloabInfo.alreadyStartWifi = false
+	LocationPromiseService.promiseCompletionHandler = []
+	let res: UniWifiResult = {
+		errSubject: "uni-stopWifi",
+		errCode: 0,
+		errMsg: "stopWifi:ok",
+		wifi: null
+	}
+	option.success?.(res)
+	option.complete?.(res)
+}
+
+/*
+ * 获取wifi列表, 在调用之前需要引导用户跳转到系统设置-WIFI设置页面,系统搜索周边wifi后app才能接收到回调
+ */
+export const getWifiList: GetWifiList = function (option: WifiOption) {
+  let err = new WifiFailImpl(getErrcode(12001));
+	option.fail?.(err)
+	option.complete?.(err)
+}
+
+/* 获取wifi列表的回调
+ * note: 请在getWifiList方法的回调里调用该方法
+ */
+export const onGetWifiList: OnGetWifiList = function (callback: UniGetWifiListCallback) {
+
+}
+
+/*
+ *	注销获取wifi列表的回调
+ */
+export const offGetWifiList: OffGetWifiList = function (callback: UniWifiCallback) {
+
+}
+
+
+/*
+ * 获取当前连接的wifi信息
+ */
+export const getConnectedWifi: GetConnectedWifi = function (option: GetConnectedWifiOptions) {
+	if (UniWiFiModuleGloabInfo.alreadyStartWifi == false) {
+    let err = new WifiFailImpl(getErrcode(12000));
+		option.fail?.(err)
+		option.complete?.(err)
+	} else{
+		if (UIDevice.current.systemVersion >= "13.0") {
+			requestLocationPromise((success) => {
+				if (success == true) {
+					fetchConnectedWifiWithLocationPromise(option)
+				}else {
+          let err = new WifiFailImpl(getErrcode(12007));
+					option.fail?.(err)
+					option.complete?.(err)
+				}
+			})
+		} else{
+			fetchConnectedWifiWithLocationPromise(option)
+		}
+	}
+}
+
+/*
+ * 连接wifi
+ */
+export const connectWifi: ConnectWifi = function (option: WifiConnectOption) {
+
+  let err = new WifiFailImpl(getErrcode(12001));
+	option.fail?.(err)
+	option.complete?.(err)
+}
+
+
+/*
+ * 连上wifi事件的监听函数
+ */
+export const onWifiConnected: OnWifiConnected = function (callback: UniWifiResultCallback) {
+
+}
+
+/*
+ * 连上wifi事件的监听函数, wifiInfo仅包含ssid
+ */
+export const onWifiConnectedWithPartialInfo: OnWifiConnectedWithPartialInfo = function (callback: UniWifiResultCallbackWithPartialInfo) {
+
+}
+
+/*
+ *	移除连接上wifi的事件的监听函数,不传此参数则移除所有监听函数。
+ */
+export const offWifiConnected: OffWifiConnected = function (callback: UniWifiCallback | null) {
+
+}
+
+/*
+ *	移除连接上wifi的事件的监听函数,不传此参数则移除所有监听函数。
+ */
+export const offWifiConnectedWithPartialInfo: OffWifiConnectedWithPartialInfo = function (callback: UniWifiResultCallbackWithPartialInfo | null) {
+
+}
+
+/*
+ * 设置 wifiList 中 AP 的相关信息。在 onGetWifiList 回调后调用,iOS特有接口。
+ */
+export const setWifiList: SetWifiList = function (option: WifiOption) {
+  let err = new WifiFailImpl(getErrcode(12001));
+	option.fail?.(err)
+	option.complete?.(err)
+}

+ 388 - 0
uni_modules/uni-wifi/utssdk/index.d.ts

@@ -0,0 +1,388 @@
+declare namespace UniNamespace {
+
+  type UniWifiComplete = any
+  type WifiSuccessCallback = (res : UniWifiResult) => void
+  type WifiFailCallback = (err : UniWifiFail) => void
+  type WifiCompleteCallback = (res : UniWifiComplete) => void
+  type UniWifiCallback = () => void
+
+
+  type WifiErrorCode = 1300002
+
+  interface UniWifiInfo {
+    SSID : string;
+    BSSID ?: string;
+    secure ?: boolean;
+    signalStrength ?: number;
+    frequency ?: number;
+  }
+
+  interface UniWifiResult {
+    errCode : number,
+    errSubject : string,
+    errMsg : string,
+    wifi : UniWifiInfo | null
+  }
+
+  interface UniWifiFail {
+    errCode : WifiErrorCode
+  }
+
+  interface WifiConnectOption {
+    SSID : string | null;
+    BSSID : string | null;
+    password : string | null;
+    maunal : boolean | null;
+    partialInfo : boolean | null; //ios不生效
+    success : WifiSuccessCallback | null;
+    fail : WifiFailCallback | null;
+    complete : WifiCompleteCallback | null;
+  }
+
+  interface GetConnectedWifiOptions {
+    partialInfo : boolean | null;
+    success : WifiSuccessCallback | null;
+    fail : WifiFailCallback | null;
+    complete ?: WifiCompleteCallback | null;
+  }
+
+
+  interface WifiOption {
+    success : WifiSuccessCallback | null,
+    fail : WifiFailCallback | null,
+    complete : InstallApkCompleteCallback | null
+  }
+
+  interface UniWifiInfoWithPartialInfo  {
+  	SSID : string;
+  }
+
+  type UniGetWifiListCallback = (wifiInfo:UTSJSONObject) => void
+
+  type UniWifiResultCallback = (wifiInfo:UniWifiResult) => void
+
+  type UniWifiResultCallbackWithPartialInfo = (wifiInfo:UniWifiInfoWithPartialInfo) => void
+
+}
+
+declare interface Uni {
+
+  /**
+   * 初始化Wi-Fi模块
+   *
+   * @param {WifiOption} option
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { after: 'stopWifi' }
+   */
+  startWifi(option : UniNamespace.WifiOption): void,
+
+  /**
+   * 关闭 Wi-Fi 模块
+   *
+   * @param {WifiOption} option
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { before: 'startWifi' }
+   */
+  stopWifi(option : UniNamespace.WifiOption) : void,
+  /**
+   * @param {WifiConnectOption} option
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": ">=4.4 && <10.0",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest {
+  	generated: false,
+  	pollution: false,
+  	cases:[
+  		{
+  			before: 'startWifi',
+  			after: 'stopWifi',
+  			input: [{
+  				maunal:false,
+  				SSID:"Xiaomi_20D0",
+  				password:"streamApp!2016",
+  			}],
+  			output:{
+  					callbackType: 'success',
+  					value: { errCode: 12013 ,errMsg: "connectWifi:wifi config may be expired",errSubject: "uni-connectWifi"}
+  				}
+  		}
+  	]
+  }
+  */
+  connectWifi(option : UniNamespace.WifiConnectOption) : void,
+  /**
+   * 请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。
+   * @param {WifiOption} option
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { before: 'startWifi', after: 'stopWifi' }
+  */
+  getWifiList(option : UniNamespace.WifiOption) : void,
+  /**
+   * 监听获取到 Wi-Fi 列表数据事件。
+   *
+   * @param {UniWifiCallback} callback
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest  { expectCallback: true }
+   * @autotest {
+  	 generated: false,
+  	 pollution: false,
+  	 expectCallback: true,
+  	 before: 'startWifi',
+  	 after: 'onGetWifiListAfter',
+  	 cases: [
+  		 {
+  			 output: {
+  				 value: 0,
+  				 returnKey: '.wifiList.length',
+  				 jestExpectSyntax: 'toBeGreaterThan'
+  			 },
+  		 }
+  	 ]
+  }
+   */
+  onGetWifiList(callback : UniNamespace.UniGetWifiListCallback) : void,
+  /**
+   * 移除获取到 Wi-Fi 列表数据事件的监听函数。
+   *
+   * @param {UniWifiCallback} callback
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { expectCallback: true }
+   */
+  offGetWifiList(callback : UniNamespace.UniWifiCallback) : void,
+  /**
+   * 获取已连接的 Wi-Fi 信息
+   *
+   * @param {GetConnectedWifiOptions} option
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#getConnectedWifi
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { before: 'startWifi', after: 'stopWifi' }
+   */
+  getConnectedWifi(option : UniNamespace.GetConnectedWifiOptions) : void,
+  /**
+   * 监听连接上 Wi-Fi 的事件
+   *
+   * @param {UniWifiCallback} callback
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { expectCallback: true }
+   */
+  onWifiConnected(callback : UniNamespace.UniWifiResultCallback) : void,
+  /**
+   * 监听连接上 Wi-Fi 的事件。
+   *
+   * @param {UniWifiCallback} callback
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { expectCallback: true }
+   */
+  onWifiConnectedWithPartialInfo(callback : UniNamespace.UniWifiResultCallbackWithPartialInfo) : void,
+  /**
+   * 移除连接上 Wi-Fi 的事件的监听函数。
+   *
+   * @param {UniWifiCallback} callback
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "4.4.4",
+   *            "uniVer": "3.7.0",
+   *            "unixVer": "3.9.0"
+   *        },
+   *        "ios": {
+   *            "osVer": "9.0",
+   *            "uniVer": "3.7.7",
+   *            "unixVer": "3.9.0"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { expectCallback: true }
+   */
+  offWifiConnected(callback ?: UniNamespace.UniWifiCallback) : void,
+
+  /**
+   * 移除连接上 Wi-Fi 的事件的监听函数。
+   *
+   * @param {UniWifiCallback} callback
+   * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnectedWithPartialInfo
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "x",
+   *            "uniVer": "x",
+   *            "unixVer": "x"
+   *        },
+   *        "ios": {
+   *            "osVer": "x",
+   *            "uniVer": "x",
+   *            "unixVer": "x"
+   *   	  }
+   *    }
+   * }
+   * @uniVersion 3.7.7
+   * @uniVueVersion 2,3  //支持的vue版本
+   * @autotest { expectCallback: true }
+   */
+  offWifiConnectedWithPartialInfo(callback ?: UniNamespace.UniWifiResultCallbackWithPartialInfo) : void,
+  /**
+   * SetWifiList  暂未实现
+   *
+   * @uniPlatform {
+   *    "app": {
+   *        "android": {
+   *            "osVer": "x",
+   *            "uniVer": "x",
+   *            "unixVer": "x"
+   *        },
+   *        "ios": {
+   *            "osVer": "x",
+   *            "uniVer": "x",
+   *            "unixVer": "x"
+   *   	  }
+   *    }
+   * }
+   */
+  setWifiList(option : UniNamespace.WifiOption) : void,
+
+
+}

+ 424 - 0
uni_modules/uni-wifi/utssdk/interface.uts

@@ -0,0 +1,424 @@
+/**
+ * Wifi 函数通用入参封装
+ */
+export type WifiOption = {
+	success ?: (res : UniWifiResult) => void;
+	fail ?: (res : UniError) => void;
+	complete ?: (res : any) => void;
+};
+
+/**
+ * Wifi 链接参数封装
+ */
+export type WifiConnectOption = {
+	SSID ?: string;
+	BSSID ?: string;
+	password ?: string;
+	maunal ?: boolean;
+	partialInfo ?: boolean; //ios不生效
+	success ?: (res : UniWifiResult) => void;
+	fail ?: (res : UniError) => void;
+	complete ?: (res : any) => void;
+}
+
+/**
+ * 获取当前链接的wifi信息
+ */
+export type GetConnectedWifiOptions = {
+	partialInfo ?: boolean
+	success ?: (res : UniWifiResult) => void
+	fail ?: (res : UniError) => void
+	complete ?: (res : any) => void
+}
+
+/*
+ * 对外暴露的wifi信息
+ */
+export type UniWifiInfo = {
+	SSID : string;
+	BSSID ?: string;
+	secure ?: boolean;
+	signalStrength ?: number;
+	frequency ?: number;
+}
+
+export type UniWifiInfoWithPartialInfo = {
+	SSID : string;
+}
+
+
+export type UniWifiResult = {
+	errCode : number,
+	errSubject : string,
+	errMsg : string,
+	wifi : UniWifiInfo | null
+}
+
+export type UniWifiCallback = () => void
+
+export type UniGetWifiListCallback = (wifiInfo:UTSJSONObject) => void
+
+export type UniWifiResultCallback = (wifiInfo:UniWifiResult) => void
+
+export type UniWifiResultCallbackWithPartialInfo = (wifiInfo:UniWifiInfoWithPartialInfo) => void
+
+
+export type StartWifi = (option : WifiOption) => void
+
+export type StopWifi = (option : WifiOption) => void
+
+export type GetWifiList = (option : WifiOption) => void
+
+export type OnGetWifiList = (callback : UniGetWifiListCallback) => void
+
+export type OffGetWifiList = (callback : UniWifiCallback) => void
+
+export type GetConnectedWifi = (option : GetConnectedWifiOptions) => void
+
+export type ConnectWifi = (option : WifiConnectOption) => void
+
+export type OnWifiConnected = (callback : UniWifiResultCallback) => void
+
+export type OnWifiConnectedWithPartialInfo = (callback : UniWifiResultCallbackWithPartialInfo) => void
+
+export type OffWifiConnected = (callback : UniWifiCallback | null) => void
+
+export type OffWifiConnectedWithPartialInfo = (callback : UniWifiResultCallbackWithPartialInfo | null) => void
+
+export type SetWifiList = (option : WifiOption) => void
+
+
+/**
+ * 错误码
+ * - 12000 尚未初始化
+ * - 12001 当前系统不支持相关能力
+ * - 12002 密码错误
+ * - 12005 Android 特有,未打开 Wi-Fi 开关
+ * - 12007 用户拒绝授权链接 Wi-Fi
+ * - 12010 系统其他错误
+ * - 12013 系统保存的 Wi-Fi 配置过期,建议忘记 Wi-Fi 后重试,仅 Android 支持
+ */
+export type WifiErrorCode = 12000 |12001 | 12002 |  12005 | 12007 | 12010 | 12013;
+
+export interface WifiFail extends IUniError{
+	errCode: WifiErrorCode
+};
+
+
+
+interface Uni {
+	/**
+	 * 初始化Wi-Fi模块
+	 *
+	 * @param {WifiOption} option
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#startwifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { after: 'stopWifi' }
+	 */
+	startWifi(option : WifiOption): void,
+	/**
+	 * 关闭 Wi-Fi 模块
+	 *
+	 * @param {WifiOption} option
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#stopwifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { before: 'startWifi' }
+	 */
+	stopWifi(option : WifiOption) : void,
+	/**
+	 * @param {WifiConnectOption} option
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#connectWifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": ">=4.4 && <10.0",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest {
+		generated: false,
+		pollution: false,
+		cases:[
+			{
+				before: 'startWifi',
+				after: 'stopWifi',
+				input: [{
+					maunal:false,
+					SSID:"Xiaomi_20D0",
+					password:"streamApp!2016",
+				}],
+				output:{
+						callbackType: 'success',
+						value: { errCode: 12013 ,errMsg: "connectWifi:wifi config may be expired",errSubject: "uni-connectWifi"}
+					}
+			}
+		]
+	}
+	*/
+	connectWifi(option : WifiConnectOption) : void,
+	/**
+	 * 请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。
+	 * @param {WifiOption} option
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#getWifiList
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { before: 'startWifi', after: 'stopWifi' }
+	*/
+	getWifiList(option : WifiOption) : void,
+	/**
+	 * 监听获取到 Wi-Fi 列表数据事件。
+	 *
+	 * @param {UniWifiCallback} callback
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onGetWifiList
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest  { expectCallback: true }
+	 * @autotest {
+		 generated: false,
+		 pollution: false,
+		 expectCallback: true,
+		 before: 'startWifi',
+		 after: 'onGetWifiListAfter',
+		 cases: [
+			 {
+				 output: {
+					 value: 0,
+					 returnKey: '.wifiList.length',
+					 jestExpectSyntax: 'toBeGreaterThan'
+				 },
+			 }
+		 ]
+	}
+	 */
+	onGetWifiList(callback : UniGetWifiListCallback) : void,
+	/**
+	 * 移除获取到 Wi-Fi 列表数据事件的监听函数。
+	 *
+	 * @param {UniWifiCallback} callback
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offGetWifiList
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	offGetWifiList(callback : UniWifiCallback) : void,
+	/**
+	 * 获取已连接的 Wi-Fi 信息
+	 *
+	 * @param {GetConnectedWifiOptions} option
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#getConnectedWifi
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { before: 'startWifi', after: 'stopWifi' }
+	 */
+	getConnectedWifi(option : GetConnectedWifiOptions) : void,
+	/**
+	 * 监听连接上 Wi-Fi 的事件
+	 *
+	 * @param {UniWifiCallback} callback
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnected
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	onWifiConnected(callback : UniWifiResultCallback) : void,
+	/**
+	 * 监听连接上 Wi-Fi 的事件。
+	 *
+	 * @param {UniWifiCallback} callback
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#onWifiConnectedWithPartialInfo
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	onWifiConnectedWithPartialInfo(callback : UniWifiResultCallbackWithPartialInfo) : void,
+	/**
+	 * 移除连接上 Wi-Fi 的事件的监听函数。
+	 *
+	 * @param {UniWifiCallback} callback
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnected
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "4.4.4",
+	 *            "uniVer": "3.7.0",
+	 *            "unixVer": "3.9.0"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "9.0",
+	 *            "uniVer": "3.7.7",
+	 *            "unixVer": "3.9.0"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	offWifiConnected(callback : UniWifiCallback | null) : void,
+	/**
+	 * 移除连接上 Wi-Fi 的事件的监听函数。
+	 *
+	 * @param {UniWifiCallback} callback
+	 * @tutorial https://uniapp.dcloud.net.cn/api/system/wifi.html#offWifiConnectedWithPartialInfo
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *   	  }
+	 *    }
+	 * }
+	 * @uniVersion 3.7.7
+	 * @uniVueVersion 2,3  //支持的vue版本
+	 * @autotest { expectCallback: true }
+	 */
+	offWifiConnectedWithPartialInfo(callback : UniWifiResultCallbackWithPartialInfo | null) : void,
+	/**
+	 * SetWifiList  暂未实现
+	 *
+	 * @uniPlatform {
+	 *    "app": {
+	 *        "android": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *        },
+	 *        "ios": {
+	 *            "osVer": "x",
+	 *            "uniVer": "x",
+	 *            "unixVer": "x"
+	 *   	  }
+	 *    }
+	 * }
+	 */
+	setWifiList(option : WifiOption) : void,
+}

+ 35 - 0
uni_modules/uni-wifi/utssdk/uni.autotest.js

@@ -0,0 +1,35 @@
+export function startWifi() {
+	return new Promise((resolve, reject) => {
+		uni.startWifi({
+			success: () => {
+				console.log('startWifi success');
+				resolve()
+			},
+			complete: () => {
+				console.log('startWifi fail');
+				resolve()
+			}
+		})
+	})
+}
+
+export function stopWifi() {
+	return new Promise((resolve, reject) => {
+		uni.stopWifi({
+			complete: resolve
+		})
+	})
+}
+
+export function onGetWifiListAfter() {
+	return new Promise((resolve, reject) => {
+		uni.getWifiList({
+			success() {
+				setTimeout(resolve, 500)
+			},
+			complete() {
+				stopWifi().finally(resolve)
+			}
+		})
+	})
+}

+ 59 - 0
uni_modules/uni-wifi/utssdk/unierror.uts

@@ -0,0 +1,59 @@
+import { WifiErrorCode, WifiFail} from "./interface.uts"
+
+/**
+ * 错误主题
+ */
+export const UniErrorSubject = 'uni-wifi';
+/**
+ * 错误码
+ * @UniError
+ */
+export const WifiUniErrors : Map<WifiErrorCode, string> = new Map([
+
+	/**
+	 * 未先调用 startWifi 接口
+	 */
+	[12000, 'not init.'],
+	/**
+	 * 当前系统不支持相关能力
+	 */
+	[12001, 'system not support'],
+  /**
+   * 密码错误
+   */
+  [12002, 'password error Wi-Fi'],
+	/**
+	 * Android 特有,未打开 Wi-Fi 开关
+	 */
+	[12005, 'wifi not turned on'],
+	/**
+	 * 用户拒绝授权链接 Wi-Fi
+	 */
+	[12007, 'user denied'],
+	/**
+	 * 系统其他错误,需要在 errmsg 打印具体的错误原因
+	 */
+	[12010, 'unknown error'],
+  /**
+   * 系统保存的 Wi-Fi 配置过期,建议忘记 Wi-Fi 后重试,仅 Android 支持
+   */
+  [12013, 'wifi config may be expired'],
+
+]);
+
+
+export function getErrcode(errCode : number) : WifiErrorCode {
+	const res = WifiUniErrors[errCode];
+	return res == null ? 12000 : errCode;
+}
+
+
+export class WifiFailImpl extends UniError implements WifiFail {
+	constructor(errCode : WifiErrorCode) {
+		super();
+		this.errSubject = UniErrorSubject;
+		this.errCode = errCode;
+		this.errMsg = WifiUniErrors[errCode] ?? "";
+	}
+}
+

+ 21 - 0
uni_modules/uview-plus/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 https://uiadmin.net/uview-plus
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 74 - 0
uni_modules/uview-plus/README.md

@@ -0,0 +1,74 @@
+<p align="center">
+    <img alt="logo" src="https://uiadmin.net/uview-plus/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
+</p>
+<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uview-plus 3.0</h3>
+<h3 align="center">多平台快速开发的UI框架</h3>
+
+[![stars](https://img.shields.io/github/stars/ijry/uview-plus?style=flat-square&logo=GitHub)](https://github.com/ijry/uview-plus)
+[![forks](https://img.shields.io/github/forks/ijry/uview-plus?style=flat-square&logo=GitHub)](https://github.com/ijry/uview-plus)
+[![issues](https://img.shields.io/github/issues/ijry/uview-plus?style=flat-square&logo=GitHub)](https://github.com/ijry/uview-plus/issues)
+[![release](https://img.shields.io/github/v/release/ijry/uview-plus?style=flat-square)](https://gitee.com/jry/uview-plus/releases)
+[![license](https://img.shields.io/github/license/ijry/uview-plus?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
+
+## 说明
+
+uview-plus,是uni-app全面兼容vue3/nvue/鸿蒙/uni-app-x(即将发布)的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。uview-plus是基于uView2.x移植的支持vue3的版本,感谢uView。
+
+## 可视化设计
+
+uview-plus现已推出免费可视化设计,可以方便的进行页面可视化设计,导出源码即可使用。极大提高前端页面开发效率;如产品经理设计师直接使用更可作为高保真高可用原型制作工具,让设计稿即代码,无需传统的设计稿开发还原步骤。
+
+<img src="https://s3.bmp.ovh/imgs/2024/11/24/fd58d00071e6e5df.png" width="900" height="auto" >
+<img src="https://s3.bmp.ovh/imgs/2024/11/24/8e85a519fe627fb1.png" width="900" height="auto" >
+
+
+## 文档
+[官方文档:https://uview-plus.jiangruyi.com](https://uview-plus.jiangruyi.com)
+[备用文档:https://uiadmin.net/uview-plus](https://uiadmin.net/uview-plus)
+
+
+## 预览
+
+您可以通过**微信**扫码,查看最佳的演示效果。
+<br>
+<br>
+<img src="https://uview-plus.jiangruyi.com/common/h5_qrcode.png" width="220" height="220" >
+
+## 链接
+
+- [官方文档](https://uview-plus.jiangruyi.com)
+- [更新日志](https://uview-plus.jiangruyi.com/components/changelog.html)
+- [升级指南](https://uview-plus.jiangruyi.com/components/changeGuide.html)
+- [关于我们](https://uview-plus.jiangruyi.com/cooperation/about.html)
+
+## 交流反馈
+
+欢迎加入我们的QQ群交流反馈:[点此跳转](https://uview-plus.jiangruyi.com/components/addQQGroup.html)
+
+## 关于PR
+
+> 我们非常乐意接受各位的优质PR,但在此之前我希望您了解uview-plus是一个需要兼容多个平台的(小程序、h5、ios app、android app)包括nvue页面、vue页面。
+> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢!
+
+## 安装
+
+#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?name=uview-plus](https://ext.dcloud.net.cn/plugin?name=uview-plus)
+
+请通过[官网安装文档](https://uview-plus.jiangruyi.com/components/install.html)了解更详细的内容
+
+## 快速上手
+
+请通过[快速上手](https://uview-plus.jiangruyi.com/components/quickstart.html)了解更详细的内容
+
+## 使用方法
+配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
+
+```html
+<template>
+	<u-button text="按钮"></u-button>
+</template>
+```
+
+## 版权信息
+uview-plus遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uview-plus应用到您的产品中。
+

+ 912 - 0
uni_modules/uview-plus/changelog.md

@@ -0,0 +1,912 @@
+## 3.4.49(2025-07-11)
+feat: picker支持bgColor、round、duration和overlayOpacity属性
+
+## 3.4.48(2025-07-10)
+fix: 官方文档Card示例组件多行显示省略号样式异常
+
+feat: album组件支持自定义preview事件
+
+## 3.4.47(2025-07-09)
+fix: 修复datetime-picker打开时,数值可能出现对不上的问题
+
+feat: Subsection 分段器添加支持从 list中读取激活文字颜色和未激活文字颜色
+
+fix: 修复modal定义confirmButton
+
+fix: safe-bottom底部安全距离在小程序优先用JS计算
+
+feat: 新增tree树形组件
+
+## 3.4.46(2025-07-08)
+feat: 上传组件预览视频支持videoPreviewObjectFit参数
+
+feat: td增加多个样式props
+
+fix: 修复noticeBar字号增大时文字遮挡
+
+feat: 项目工程增加pinia
+
+## 3.4.45(2025-07-01)
+fix: 修复picker-data组件缺少name
+
+fix: 优化picker高度单位
+
+## 3.4.44(2025-06-30)
+fix: 修复indexList中stikcy属性写死的问题(always true)
+
+feat: 搜索框添加新的右侧插槽
+
+fix: 修复indexList中丢失的select event
+
+fix: 解决因为层级问题导致点击picker选择器无法正常弹出
+
+## 3.4.43(2025-06-16)
+feat: table2支持header插槽
+
+## 3.4.42(2025-06-12)
+fix: 修复qrcode中默认id问题及canvas2时App无法绘制二维码 感谢@jiaruiyan
+
+## 3.4.41(2025-06-11)
+feat: qrcode支持 新参数useRootHeightAndWidth 是否使用根节点的宽高 感谢@YJR
+
+feat: toast支持设置zIndex层级
+
+
+
+## 3.4.40(2025-06-06)
+fix: 升级二维码 canvas -> canvas2 感谢@yjr
+
+## 3.4.39(2025-05-31)
+fix: 修改步骤条微信小程序下的布局 感谢@jiaruiyan
+
+fix: u-tabs在屏幕尺寸发生变化时滑块位置没有发生变化 感谢@aqzhft
+
+fix: 鸿蒙平台不支持plus.runtime.openWeb 感谢@aqzhft
+
+## 3.4.38(2025-05-30)
+fix: 修复picker-data快捷组件缺少index
+
+fix: 修复picker组件双向绑定初始化及取消后复原再次打开后的当前项目
+
+## 3.4.37(2025-05-29)
+feat: modal支持设置动画时间
+
+fix: DatetimePicker v-model 绑定异步设置无效 (#803)
+
+## 3.4.36(2025-05-28)
+fix: lazy-load图片为空时显示错误
+
+## 3.4.35(2025-05-28)
+feat: 进度条支持从右往左加载
+
+## 3.4.34(2025-05-28)
+feat: table2支持自定义标题和单元格样式
+
+## 3.4.33(2025-05-27)
+fix: 修复小程序cate-tab第一次切换时没反应 感谢@jiaruiyan
+
+fix: 修复datetimepicker传入空字符串时导致组件崩溃 感谢@jiaruiyan
+
+fix: 修复album带单位的字符串参与计算导致的计算数据错误 感谢@jiaruiyan
+
+## 3.4.32(2025-05-26)
+feat: 增加状态栏独立颜色配置支持支付宝小程序状态栏对背景色识别的不友好的情况
+
+fix: 抖音二维码兼容修复
+
+feat: cate-tab组件增加rightTop插槽 #715
+
+fix: 修改 test.promise(res) 预期结果不一致
+
+## 3.4.31(2025-05-17)
+fix: 修复parse富文本组件导致鸿蒙运行白屏
+
+fix: 去除演示项目中uni.$u用法便于兼容鸿蒙
+
+feat: modal新增popupBottom插槽适用类似关闭按钮与内容区域分离的场景
+
+## 3.4.30(2025-05-16)
+feat: 新增pagination分页器组件
+
+feat: popup新增bottom插槽适用类似关闭按钮与内容区域分离的场景
+
+## 3.4.29(2025-05-15)
+fix: 修复table2横向滚动样式
+
+fix: 修复table2组件宽度兼容
+
+fix: 修复image显示png图片时默认背景色问题
+
+feat: cate-tab新增height参数便于设置组件高度
+
+feat: 在index.js种导出digit.js便于使用
+
+fix: 修复tag组件缺失iconColor属性
+
+fix: 优化index-list的setValueForTouch方法逻辑 #708
+
+feat: number-box支持change事件返回变动是点击了增加还是减少按钮
+
+fix: 修复table2在小程序下部分情形不显示表格
+
+## 3.4.28(2025-05-12)
+feat: 新增table表格组件
+
+feat: 新增element-plus风格的table2组件
+
+## 3.4.27(2025-05-06)
+fix: 修复card组件props
+
+## 3.4.26(2025-05-06)
+fix: 修复test工具引入
+
+feat: card组件支持全局设置props默认值
+
+fix: 修复image在加载错误情况下高度和宽度不正确问题
+
+fix: 修复picker-data快捷组件默认picker选中
+
+fix: 修复日历month子组件缺失emits定义
+
+## 3.4.25(2025-04-27)
+fix: up-form编译在微信小程序里样式缺失 #640
+
+fix: number-box输入为空时自动设为最小值
+
+feat: picker与datetimepicke组件hasInput模式支持inputProps属性
+
+## 3.4.24(2025-04-25)
+fix: 修复upload上传逻辑(感谢@semdy)
+
+## 3.4.23(2025-04-24)
+chore: 补全chooseFile TS类型(感谢@semdy)
+
+feat: u-search组件的图标支持显示在右边(感谢@semdy)
+
+chore: 修正chooseFile返回的数据TS类型(感谢@semdy)
+
+fix: PR导致缺失name影响uplad自动上传扩展名
+
+
+## 3.4.22(2025-04-22)
+fix: 修复自动上传偶发的success被覆盖为uploading
+
+fix: float-button缺少key #677
+
+fix: upload组件完善优化(感谢@semdy)
+
+fix: toolbar组件confirmColor属性默认改为空,以便默认使用主题色、标题字体加粗(感谢@semdy)
+
+## 3.4.21(2025-04-21)
+feat: subsection分段器支持双向绑定current
+
+feat: select组件支持maxHeight属性
+
+feat: datetime-picker支持inputBorder属性
+
+## 3.4.20(2025-04-17)
+fix: 修复navbar-mini提示border不存在
+
+feat: status-bar支持对外暴露状态栏高度值
+
+feat: upload支持自定义自动上传后处理逻辑便于对接不同规范后端
+
+feat: 优化tag组件插槽
+
+
+## 3.4.19(2025-04-14)
+fix: 修复model组件增加contentStyle带来的语法问题
+
+## 3.4.18(2025-04-14)
+fix: upload组件支持所有文件类型的onClickPreview事件
+
+## 3.4.17(2025-04-11)
+feat: select组件text插槽增加scope传递currentLabel
+
+## 3.4.16(2025-04-10)
+fix: 修复安卓新加载字体方式导致Cannot read property '$page' of undefined
+
+## 3.4.15(2025-04-10)
+improvment: 优化移步加载数据时swiper组件displayMultipleItems报错
+
+feat: modal增加contentStyle属性
+
+fix: 修复下拉菜单收起动画缺失
+
+fix: 修复sticky的offset属性值为响应式数据时失效 #237
+
+
+## 3.4.14(2025-04-09)
+feat: 支持自托管内置图标及扩展自定义图标
+
+## 3.4.13(2025-04-08)
+fix: tabs点击当前tab触发change事件
+
+## 3.4.12(2025-04-02)
+fix: dropdown关闭后遮挡页面内容 #653
+
+fix u-sticky.vue Uncaught TypeError: e.querySelector is not a function at uni-app-view.umd.js
+
+## 3.4.11(2025-03-31)
+fix: 优化upload组件预览视频的弹窗占位
+
+## 3.4.10(2025-03-28)
+feat: select组件新增多个props属性及优化
+
+fix: 修复cate-tab报错index is not defined #661
+
+
+## 3.4.9(2025-03-27)
+fix: 修复upload组件split报错
+
+fix: 修复float-button缺少flex样式
+
+## 3.4.8(2025-03-27)
+fix: 修复upload组件split报错
+
+fix: 移除mapState
+
+## 3.4.7(2025-03-26)
+fix: 修复action-sheet-data和picker-data数据回显
+
+fix:  优化upload组件视频封面兼容
+
+## 3.4.6(2025-03-25)
+feat: checkbox触发change时携带name参数
+
+feat: upload组件支持服务器本机和阿里云OSS自动上传功能及上传进度条
+
+feat: upload组件支持视频预览及oss上传时获取视频封面图
+
+feat: 新增up-action-sheet-data快捷组件
+
+feat: 新增up-picker-data快捷组件
+
+## 3.4.5(2025-03-24)
+feat: tag组件新增textSize/height/padding/borderRadius属性
+
+feat: 新增genLightColor自动计算浅色方法及tag组件支持autoBgColor自动计算背景色
+
+## 3.4.4(2025-03-13)
+feat: modal增加异步操作进行中点击取消弹出提示特性防止操作被中断
+
+fix: 修复toast组件show方法类型声明
+
+## 3.4.3(2025-03-12)
+fix: 修复textarea自动增高时在输入时高度异常
+
+## 3.4.2(2025-03-11)
+feat: step组件增加title插槽及增加辅助class便于自定义样式
+
+## 3.4.1(2025-03-11)
+feat: 新机制确保setConfig与http在nvue等环境下生效
+
+## 3.3.74(2025-03-06)
+fix: CateTab语法问题
+
+## 3.3.73(2025-03-06)
+feat: CateTab新增v-model:current属性
+
+## 3.3.72(2025-02-28)
+feat: tabs组件支持icon图标及插槽
+
+## 3.3.71(2025-02-27)
+feat: 折叠面板collapse增加titileStyle/iconStyle/rightIconStyle属性
+
+feat: 折叠面板组件新增cellCustomStyle/cellCustomClass属性
+
+fix: select组件盒模型
+
+## 3.3.70(2025-02-24)
+fix: 修改u-checkbox-group组件changes事件发生位置
+
+## 3.3.69(2025-02-19)
+picker允许传递禁用颜色props
+
+slider组件isRange状态下增加min max插槽分开显示内容
+
+feat: 新增经典下拉框组件up-select
+
+## 3.3.68(2025-02-12)
+fix: 修复weekText类型
+
+feat: 日历增加单选与多选指定禁止选中的日期功能
+
+fix: NumberBox删除数字时取值有误 #613
+
+## 3.3.67(2025-02-11)
+feat: navbar支持返回全局拦截器配置
+
+feat: 表单-校验-支持无提示-得到校验结果
+
+feat: picker传递hasInput属性时候,可以禁用输入框点击
+
+## 3.3.66(2025-02-09)
+feat: steps-item增加content插槽
+
+## 3.3.65(2025-02-05)
+feat: number-box组件新增按钮圆角/按钮宽度/数据框背景色/迷你模式
+## 3.3.64(2025-01-18)
+feat: 日历组件支持自定义星期文案
+
+## 3.3.63(2025-01-13)
+fix: cate-tab支持支付宝小程序
+
+fix: textarea 修复 placeholder-style
+
+fix: 修复在图片加载及加载失败时容器宽度
+
+fix: waterfall组件报错Maximum recursive updates
+
+## 3.3.62(2025-01-10)
+feat: sleder滑动选择器双滑块增加外层触发值的变动功能
+
+fix: picker支持hasInput优化
+
+## 3.3.61(2024-12-31)
+fix: 修复微信getSystemInfoSync接口废弃警告
+
+fix: 'u-status-bar' symbol missing
+
+## 3.3.60(2024-12-30)
+feat: 日期组件支持禁用
+
+fix: ts定义修复 #600
+
+feat: Tabs组件选中时增加一个active的class #595
+
+## 3.3.59(2024-12-30)
+fix: Property "isH5" was accessed during render
+
+## 3.3.58(2024-12-26)
+fix: slider组件change事件传参
+
+## 3.3.57(2024-12-23)
+fix: slider组件change事件传参
+
+feat: 更新u-picker组件增加当前选中class类名
+
+## 3.3.56(2024-12-18)
+feat: 在u-alert组件中添加关闭事件
+
+## 3.3.55(2024-12-17)
+add: swiper增加双向绑定
+
+## 3.3.54(2024-12-11)
+add: qrcode支持props控制是否开启点击预览
+
+add: 新增cate-tab垂直分类组件
+
+## 3.3.53(2024-12-10)
+fix: 修复popup居中模式点击内容区域触发关闭
+
+## 3.3.52(2024-12-09)
+add: notice-bar支持justifyContent属性
+
+## 3.3.51(2024-12-09)
+add: radio增加label插槽
+
+## 3.3.50(2024-12-05)
+fix: 优化popup等对禁止背景滚动机制
+
+add: slider在弹窗使用示例
+
+fix: card组件类名问题
+
+## 3.3.49(2024-12-02)
+fix: 去除album多余的$u引用
+
+fix: 优化图片组件兼容性
+
+add: picker组件增加zIndex属性
+
+add: text增加是否占满剩余空间属性
+
+add: input颜色示例
+
+## 3.3.48(2024-11-29)
+add: 文本行数限制样式提高到10行
+
+del: 去除不跨端的inputmode
+## 3.3.47(2024-11-28)
+fix: 时间选择器在hasInput模式下部分机型键盘弹出
+
+## 3.3.46(2024-11-26)
+fix: 修复text传递事件参数
+
+## 3.3.45(2024-11-24)
+add: navbar组件支持配置标题颜色
+
+fix: 边框按钮警告类型下颜色变量使用错误
+
+## 3.3.43(2024-11-18)
+fix: 支持瀑布流组件v-model置为[]
+
+add: 新增字符串路径访问工具方法getValueByPath
+
+add: 新增float-button悬浮按钮组件
+
+## 3.3.42(2024-11-15)
+add: button组件支持stop参数阻止冒泡
+
+## 3.3.41(2024-11-13)
+fix: u-radio-group invalid import
+
+improvement: 优化图片组件宽高及修复事件event传递
+
+## 3.3.40(2024-11-11)
+add: 组件radioGroup增加gap属性用于设置item间隔 
+
+fix: 修复H5全局导入
+
+## 3.3.39(2024-11-04)
+fix: 修复相册组件
+
+## 3.3.38(2024-11-04)
+fix: 修复视频预览报错 #510
+
+add: album组件增加stop参数支持阻止事件冒泡
+
+## 3.3.37(2024-10-21)
+fix: 修复因为修改组件名称前缀,导致h5打包后$parent方法内找不到父组件的问题
+
+fix: 修复datetime-picker选择2000年以前日期出错
+
+## 3.3.36(2024-10-09)
+fix: toast 自动关闭
+
+feat: 增加微信小程序用户昵称审核完毕回调及修改 ts 定义文件
+
+## 3.3.35(2024-10-08)
+feat: modal和picker支持v-model:show双向绑定
+
+feat: 支持checkbox使用slot自定义label后自带点击事件 #522
+
+feat: swipe-action支持自动关闭特性及初始化打开状态
+
+## 3.3.34(2024-09-23)
+feat: 支持toast设置duration值为-1时不自动关闭
+
+## 3.3.33(2024-09-18)
+fix: 修复test.date('008')等验证结果不准确
+
+## 3.3.32(2024-09-09)
+fix: u-keyboard名称冲突warning
+
+## 3.3.31(2024-08-31)
+feat: qrcode初步支持nvue
+
+## 3.3.30(2024-08-30)
+fix: slider兼容step为字符串类型
+
+## 3.3.29(2024-08-30)
+fix: 修复tabs组件current参数为字符串处理逻辑
+
+## 3.3.28(2024-08-26)
+fix: list组件滑动偏移量不一样取绝对值导致iOS下拉偏移量计算错误
+
+## 3.3.27(2024-08-22)
+fix: 修复up-datetime-picker组件toolbarRightSlot定义缺失
+
+fix: 修复FormItem的rules更新错误的问题
+
+## 3.3.26(2024-08-22)
+fix: 批量注册全局组件优化
+
+## 3.3.25(2024-08-21)
+fix: 修复slider在app-vue下样式问题
+
+## 3.3.24(2024-08-19)
+fix: 修复时间选择器hasInput模式小程序不生效
+
+feat: 支持H5导入所有组件
+
+## 3.3.23(2024-08-17)
+feat: swipe-action增加closeAll方法
+
+fix: 兼容tabs在某些场景下index小于0时自动设置为0
+
+add: 通用mixin新增navTo页面跳转方法
+
+## 3.3.21(2024-08-15)
+improvement: 优化二维码组件loading及支持预览与长按事件 #351
+
+fix: 修复swipe-action自动关闭其它功能及组件卸载自动关闭
+
+## 3.3.20(2024-08-15)
+refactor: props默认值文件移至组件文件夹内便于查找
+## 3.3.19(2024-08-14)
+fix: 修复2被rpx兼容处理只在数字值生效
+
+add: 增加swiper自定义插槽示例
+
+## 3.3.18(2024-08-13)
+feat: 新增支持datetime-picker工具栏插槽及picker插槽支持修复
+## 3.3.17(2024-08-12)
+feat: swiper组件增加默认slot便于自定义
+
+feat: grid新增间隔参数
+
+feat: picker新增toolbar-right和toolbar-bottom插槽
+
+## 3.3.16(2024-08-12)
+fix: 解决swiper中title换行后多余的内容未被遮挡问题
+
+fix: 修复迷你导航适配异形屏
+
+## 3.3.15(2024-08-09)
+fix: 修复默认单位设置为rpx时一些组件高度间距异常
+
+fix: 修复日历在rpx单位下布局异常
+
+feat: code-input支持App端展示输入光标
+
+## 3.3.14(2024-08-09)
+add: 增加box组件
+
+add: 增加card卡片组件
+
+
+## 3.3.13(2024-08-08)
+feat: input支持调用原生组件的focus和blur方法
+
+improvement: grid-item条件编译优化
+
+add: 新增迷你导航组件
+
+## 3.3.12(2024-08-06)
+improvement: $u挂载时机调整便于打包分离chunk
+
+fix: steps新增itemStyle属性名称冲突
+
+## 3.3.11(2024-08-05)
+feat: 新增支持upload组件的deletable/maxCount/accept变更监听 #333
+
+feat: 新增支持tabs在swiper中使用
+
+feat: 新增FormItem支持独立设置验证规则rules
+
+fix: 修复index-list未设置$slots.header时索引高亮失效
+
+## 3.3.10(2024-08-02)
+fix: 修复index-list偶发的滑动最后一个索引报错top不存在
+
+fix: 修复gird在QQ、抖音小程序下布局
+
+feat: 优化step支持自定义样式prop
+
+feat: action-sheet组件支持v-model:show双向绑定
+
+fix: 小程序下steps和grid都统一采用grid布局
+
+fix: 修复支付宝小程序下input类型为数字时双向绑定失效
+
+feat : form 表单 validate 校验不通过后 error增加字段prop信息  #304
+
+fix: form组件异步校异常验问题 #393
+
+## 3.3.9(2024-08-01)
+fix: 优化获取nvue元素
+
+feat: modal新增contentTextAlign设置文案对齐方式
+
+fix: 修复NVUE下tabbar文字不显示  #458
+
+feat: loading-page增加zIndex属性
+
+fix: 相册在宽度较小时换行问题
+
+feat: album相册增加自适应自动换行模式
+
+feat: album相册增加图片尺寸单位prop
+
+fix: 修复calendar日历月份居中
+
+## 3.3.8(2024-07-31)
+feat: slider支持进度条任意位置触发按钮拖动
+
+fix: 修复app-vue下modal标题不居中
+
+fix: #459 TS setConfig 声明异常
+
+feat: tabs组件增加longPress长按事件
+
+feat: 新增showRight属性控制collapse右侧图标显隐
+
+fix: 优化nvue下css警告
+
+## 3.3.7(2024-07-29)
+feat: 支持IndexList组件支持在弹窗等场景下使用及联动优化
+
+feat: popup组件支持v-model:show双向绑定
+
+feat: 优化tabs的current双向绑定
+
+fix: checkbox独立使用时checked赋初始值可以,但是手动切换时值没有做双向绑定! #455
+
+feat: slider组件支持区间双滑块
+
+fix: toast 支持自定义图标?可传入了决对路径的 icon也没有用 #409
+
+feat: form-item校验失败时 增加class方便自定义显示错误的展示方式 #394
+
+fix: up-cell的required配置不生效 #395
+
+fix: 横向滚动组件,微信小程序编译后会有警告 #415
+
+fix: u-picker内部对默认值defaultIndex的监听 #425
+
+feat: toast 组件支持遮掩层穿透  #417
+
+fix: 兼容vue的slot编译bug #423
+
+fix: upload 微信小程序 点击预览视频报错 #424
+
+fix: u-number-box 组件修改【integer, decimalLength, min, max 】props时没有触发绑定值更新 #429
+
+feat: Tabs组件能否支持自定义插槽 #439
+
+feat: ActionSheet 可以配置最大高度吗, 我当做select使用了。 #445
+
+fix: cursor-pointer优化
+
+feat: 新版slider组件兼容NVUE改造
+
+feat: 新增slider组件手动实现以支持样式自定义
+
+perf:补充TS声明提示信息
+
+修复:ActionSheet 操作菜单cancelText属性为空DOM节点还存在并且可以点击问题
+
+fix: 去除预留的beforeDestroy兼容容易在某些sdk下不识别条件编译
+
+## 3.3.6(2024-07-23)
+feat: u-album组件添加radius,shape参数,定义参考当前u-image参数
+
+fix: 修复了calendar组件title和日期title未垂直居中的问题
+
+fix: update:modelValue缺失emit定义
+
+## 3.3.5(2024-07-10)
+picker组件支持hasInput模式
+
+## 3.3.4(2024-07-07)
+fix: input组件双向绑定问题 #419
+
+lazy-load完善emit
+
+优化通用小程序分享
+
+## 3.3.2(2024-06-27)
+fix: 在Nvue环境中编译,出现大量警告 #406
+## 3.3.1(2024-06-27)
+u-button组件报错,找不到button mixins #407
+## 3.3.0(2024-06-27)
+feat: checkbox支持label设置slot
+
+feat: modal增加customClass
+
+feat: navbar、popup、tabs、text支持customClass
+
+fix: cell组建缺少flex布局
+
+fix: 修复微信小程序真机调试时快速输入出现文本回退问题
+
+feat: tag增加默认slot
+
+公共mixin改造为按需导入语法
+
+refactor: 组件props混入mixin改造为按需导入语法
+
+fix: u-tabbar 安卓手机点击按钮变蓝问题 #396
+
+feat: upload组建增加extension属性
+
+fix: upload组件参数mode添加left
+
+fix: 修复阴影在非nvue时白色背景色不显示
+
+## 3.2.24(2024-06-11)
+fix: 修复时间选择器confirm事件触发时机导致2次才会触发v-model更新
+## 3.2.23(2024-05-30)
+fix: #378 H5 u-input 在表单中初始值为空也会触发一次 formValidate(this,"change")事件导致进入页面直接校验了一次
+
+fix: #373 搜索组件up-search的@clear事件无效
+
+fix: #372 ActionSheet 组件的取消按钮触发区域太小
+
+## 3.2.22(2024-05-13)
+上传组件支持微信小程序预览视频
+
+修复折叠面板右侧箭头不显示
+
+修复uxp2px
+
+## 3.2.21(2024-05-10)
+fix: loading-icon修复flex布局
+## 3.2.20(2024-05-10)
+修复瀑布流大小写#355
+## 3.2.19(2024-05-10)
+去除意外的文件引入
+## 3.2.18(2024-05-09)
+fix: 349 popup 组件设置 zIndex 属性后,组件渲染异常#
+feat: 搜索框增加adjustPosition属性
+fix: #331增加u-action-sheet__cancel
+优化mixin兼容性
+feat: #326 up-list增加下拉刷新功能
+fix: #319 优化up-tabs参数与定义匹配
+fix: index-list组件微信小程序端使用自定义导航栏异常
+fix: #285 pickerimmediateChange 写死为true
+fix: #111 u-scroll-list组件,隐藏指示器后报错, 提示找不到ref
+list增加微信小程序防抖配置
+
+## 3.2.17(2024-05-08)
+fix: 支付宝小程序二维码渲染
+## 3.2.16(2024-05-06)
+修复tabs中,当前激活样式的undefined bug
+
+fix: #341u-code 倒计时没结束前退出,再次进入结束后退出界面,再次进入重新开始倒计时bug
+
+受到uni-app内置text样式影响修复
+
+## 3.2.15(2024-04-28)
+优化时间选择器hasInput模式初始化值
+## 3.2.14(2024-04-24)
+去除pleaseSetTranspileDependencies
+
+http采用useStore
+
+## 3.2.13(2024-04-22)
+修复modal标题样式
+
+优化日期选择器hasInput模式宽度
+
+## 3.2.12(2024-04-22)
+修复color应用
+## 3.2.11(2024-04-18)
+修复import化带来的问题
+## 3.2.10(2024-04-17)
+完善input清空事件App端失效的兼容性
+
+修复日历组件二次打开后当前月份显示不正确
+
+## 3.2.9(2024-04-16)
+组件内uni.$u用法改为import引入
+
+规范化及兼容性增强
+
+## 3.2.8(2024-04-15)
+修复up-tag语法错
+## 3.2.7(2024-04-15)
+修复下拉菜单背景色在支付宝小程序无效
+
+setConfig改为浅拷贝解决无法用import导入代替uni.$u.props设置
+
+## 3.2.6(2024-04-14)
+修复某些情况下滑动单元格默认右侧按钮是展开的问题
+## 3.2.5(2024-04-13)
+调整分段器尺寸及修复窗口大小改变时重新计算尺寸
+
+多个组件支持cursor-pointer增强PC端体验
+
+## 3.2.4(2024-04-12)
+初步支持typescript
+## 3.2.3(2024-04-12)
+fix: 修复square属性在小程序下无效问题
+
+fix:修复lastIndex异常导致的column异常问题
+
+fix: alipayapp picker style
+
+feat(button): 添加用户同意隐私协议事件回调
+
+fix: input switch password
+
+fix: 修复u-code组件keepRuning失效问题
+
+feat: form-item添加labelPosition属性
+
+新增dropdown组件
+
+分段器支持内部current值
+
+优化cell和action-sheet视觉大小
+
+修复tabs文字换行
+
+## 3.2.2(2024-04-11)
+修复换行符问题
+## 3.2.1(2024-04-11)
+修复演示H5二维码
+
+fix: #270 ReadMore 展开阅读更多内容变化兼容
+
+fix: #238Calendar组件maxDate修改为不能小于minDate
+
+checkbox支持独立使用
+
+修复popup中在微信小程序中真机调试滚动失效
+
+## 3.2.0(2024-04-10)
+修复轮播图在nvue显示
+修复疑似u-slider名称被占用导致slider在App下不显示
+解决微信小程序提示 Some selectors are not allowed in component wxss
+示例中u-前缀统一为up-
+增加瀑布流与图片懒加载组件
+fix: #308修复tag组件缺失iconColor参数
+fix: #297使用grid布局解决目前编译为抖音小程序无法开启virtualHost
+## 3.1.52(2024-04-07)
+工具类方法调用import化改造
+新增up-copy复制组件
+## 3.1.51(2024-04-07)
+优化时间选择器自带输入框格式化显示
+防止按钮文字换行
+修复订单列表模板滑动
+增加u-qrcode二维码组件
+## 3.1.49(2024-03-27)
+日期时间组件支持自带输入框
+fix: popup弹窗滚动穿透问题
+fix: 修复小程序numberbox bug
+## 3.1.48(2024-03-18)
+fix:[plugin:uni:pre-css] Unbalanced delimiter found in string
+## 3.1.47(2024-03-18)
+fix: setConfig设置组件默认参数无效问题
+fix: 修复自定义图标无效问题
+feat: 增加u-form-item单独设置规则变量
+fix:#293小程序是自定义导航栏的时候即传了customNavHeight的时候会出现跳转偏移的情况
+
+## 3.1.46(2024-01-29)
+beforeUnmount
+## 3.1.45(2024-01-24)
+fix: #262ext组件为超链接的情况下size属性不生效
+fix: #263最新版本3.1.42中微信小程序u-swipe-action-item报错
+fix: #224最新版本3.1.42中微信小程序u-swipe-action-item报错
+fix: #263支持支付宝小程序
+fix: #261u-input在直接修改v-model的绑定值时,每隔一次会无法出发change事件
+优化折叠面板兼容微信小程序
+## 3.1.42(2024-01-15)
+修复u-number-box默认值0时在小程序不显示值
+优化u-code的timer判断
+优化支付宝小程序下textarea字数统计兼容
+优化u-calendar
+## 3.1.41(2023-11-18)
+#215优化u-cell图标容器间距问题
+## 3.1.40(2023-11-16)
+修复u-slider双向绑定
+## 3.1.39(2023-11-10)
+修复头条小程序不支持env(safe-area-inset-bottom)
+优化#201u-grid 指定列数导致闪烁
+#193IndexList 索引列表 高度错误
+其他优化
+## 3.1.38(2023-10-08)
+修复u-slider
+## 3.1.37(2023-09-13)
+完善emits定义及修复code-input双向数据绑定
+## 3.1.36(2023-08-08)
+修复富文本事件名称大小写
+## 3.1.35(2023-08-02)
+修复编译到支付宝小程序u-form报错
+## 3.1.34(2023-07-27)
+修复App打包uni.$u.mpMixin方式sdk暂时不支持导致报错
+## 3.1.33(2023-07-13)
+修复弹窗进入动画、模板页面样式等
+## 3.1.31(2023-07-11)
+修复dayjs引用
+## 3.0.8(2022-07-12)
+修复u-tag默认宽度撑满容器
+## 3.0.7(2022-07-12)
+修复u-navbar自定义插槽演示示例
+## 3.0.6(2022-07-11)
+修复u-image缺少emits申明
+## 3.0.5(2022-07-11)
+修复u-upload缺少emits申明
+## 3.0.4(2022-07-10)
+修复u-textarea/u-input/u-datetime-picker/u-number-box/u-radio-group/u-switch/u-rate在vue3下数据绑定
+## 3.0.3(2022-07-09)
+启用自建演示二维码
+## 3.0.2(2022-07-09)
+修复dayjs/clipboard等导致打包报错
+## 3.0.1(2022-07-09)
+增加插件市场地址
+## 3.0.0(2022-07-09)
+# uview-plus(vue3)初步发布

+ 85 - 0
uni_modules/uview-plus/components/u--form/u--form.vue

@@ -0,0 +1,85 @@
+<template>
+	<uvForm
+		ref="uForm"
+		:model="model"
+		:rules="rules"
+		:errorType="errorType"
+		:borderBottom="borderBottom"
+		:labelPosition="labelPosition"
+		:labelWidth="labelWidth"
+		:labelAlign="labelAlign"
+		:labelStyle="labelStyle"
+		:customStyle="customStyle"
+	>
+		<slot />
+	</uvForm>
+</template>
+
+<script>
+	/**
+	 * 此组件存在的理由是,在nvue下,u-form被uni-app官方占用了,u-form在nvue中相当于form组件
+	 * 所以在nvue下,取名为u--form,内部其实还是u-form.vue,只不过做一层中转
+	 */
+	import uvForm from '../u-form/u-form.vue';
+	import { props } from '../u-form/props.js';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	export default {
+		// #ifdef MP-WEIXIN
+		name: 'u-form',
+		// #endif
+		// #ifndef MP-WEIXIN
+		name: 'u--form',
+		// #endif
+		mixins: [mpMixin, props, mixin],
+		components: {
+			uvForm
+		},
+		created() {
+			this.children = []
+		},
+		methods: {
+			// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则
+			setRules(rules) {
+				this.$refs.uForm.setRules(rules)
+			},
+			/**
+			 * 校验全部数据
+			 * @param {Object} options
+			 * @param {Boolean} options.showErrorMsg -是否显示校验信息,
+			 */
+			validate(options) {
+				/**
+				 * 在微信小程序中,通过this.$parent拿到的父组件是u--form,而不是其内嵌的u-form
+				 * 导致在u-form组件中,拿不到对应的children数组,从而校验无效,所以这里每次调用u-form组件中的
+				 * 对应方法的时候,在小程序中都先将u--form的children赋值给u-form中的children
+				 */
+				// #ifdef MP-WEIXIN
+				this.setMpData()
+				// #endif
+				return this.$refs.uForm.validate(options)
+			},
+			validateField(value, callback) {
+				// #ifdef MP-WEIXIN
+				this.setMpData()
+				// #endif
+				return this.$refs.uForm.validateField(value, callback)
+			},
+			resetFields() {
+				// #ifdef MP-WEIXIN
+				this.setMpData()
+				// #endif
+				return this.$refs.uForm.resetFields()
+			},
+			clearValidate(props) {
+				// #ifdef MP-WEIXIN
+				this.setMpData()
+				// #endif
+				return this.$refs.uForm.clearValidate(props)
+			},
+			setMpData() {
+				this.$refs.uForm.children = this.children
+			}
+		},
+	}
+</script>

+ 50 - 0
uni_modules/uview-plus/components/u--image/u--image.vue

@@ -0,0 +1,50 @@
+<template>
+	<uvImage 
+		:src="src"
+		:mode="mode"
+		:width="width"
+		:height="height"
+		:shape="shape"
+		:radius="radius"
+		:lazyLoad="lazyLoad"
+		:showMenuByLongpress="showMenuByLongpress"
+		:loadingIcon="loadingIcon"
+		:errorIcon="errorIcon"
+		:showLoading="showLoading"
+		:showError="showError"
+		:fade="fade"
+		:webp="webp"
+		:duration="duration"
+		:bgColor="bgColor"
+		:customStyle="customStyle"
+		@click="$emit('click')"
+		@error="$emit('error')"
+		@load="$emit('load')"
+	>
+		<template v-slot:loading>
+			<slot name="loading"></slot>
+		</template>
+		<template v-slot:error>
+			<slot name="error"></slot>
+		</template>
+	</uvImage>
+</template>
+
+<script>
+	/**
+	 * 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件
+	 * 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转
+	 */
+	import uvImage from '../u-image/u-image.vue';
+	import { props } from '../u-image/props.js';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	export default {
+		name: 'u--image',
+		mixins: [mpMixin, props, mixin],
+		components: {
+			uvImage
+		},
+		emits: ['click', 'error', 'load']
+	}
+</script>

+ 74 - 0
uni_modules/uview-plus/components/u--input/u--input.vue

@@ -0,0 +1,74 @@
+<template>
+	<uvInput 
+		<!-- #ifdef VUE2 -->
+		:value="value"
+		@input="e => $emit('input', e)"
+		<!-- #endif -->
+		<!-- #ifdef VUE3 -->
+		:modelValue="modelValue"
+		@update:modelValue="e => $emit('update:modelValue', e)"
+		<!-- #endif -->
+		:type="type"
+		:fixed="fixed"
+		:disabled="disabled"
+		:disabledColor="disabledColor"
+		:clearable="clearable"
+		:password="password"
+		:maxlength="maxlength"
+		:placeholder="placeholder"
+		:placeholderClass="placeholderClass"
+		:placeholderStyle="placeholderStyle"
+		:showWordLimit="showWordLimit"
+		:confirmType="confirmType"
+		:confirmHold="confirmHold"
+		:holdKeyboard="holdKeyboard"
+		:focus="focus"
+		:autoBlur="autoBlur"
+		:disableDefaultPadding="disableDefaultPadding"
+		:cursor="cursor"
+		:cursorSpacing="cursorSpacing"
+		:selectionStart="selectionStart"
+		:selectionEnd="selectionEnd"
+		:adjustPosition="adjustPosition"
+		:inputAlign="inputAlign"
+		:fontSize="fontSize"
+		:color="color"
+		:prefixIcon="prefixIcon"
+		:suffixIcon="suffixIcon"
+		:suffixIconStyle="suffixIconStyle"
+		:prefixIconStyle="prefixIconStyle"
+		:border="border"
+		:readonly="readonly"
+		:shape="shape"
+		:customStyle="customStyle"
+		:formatter="formatter"
+		:ignoreCompositionEvent="ignoreCompositionEvent"
+	>
+		<!-- #ifdef MP -->
+		<slot name="prefix"></slot>
+		<slot name="suffix"></slot>
+		<!-- #endif -->
+		<!-- #ifndef MP -->
+		<slot name="prefix" slot="prefix"></slot>
+		<slot name="suffix" slot="suffix"></slot>
+		<!-- #endif -->
+	</uvInput>
+</template>
+
+<script>
+	/**
+	 * 此组件存在的理由是,在nvue下,u-input被uni-app官方占用了,u-input在nvue中相当于input组件
+	 * 所以在nvue下,取名为u--input,内部其实还是u-input.vue,只不过做一层中转
+	 */
+	import uvInput from '../u-input/u-input.vue';
+	import { props } from '../u-input/props.js';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	export default {
+		name: 'u--input',
+		mixins: [mpMixin, props, mixin],
+		components: {
+			uvInput
+		},
+	}
+</script>

+ 45 - 0
uni_modules/uview-plus/components/u--text/u--text.vue

@@ -0,0 +1,45 @@
+<template>
+    <uvText
+        :type="type"
+        :show="show"
+        :text="text"
+        :prefixIcon="prefixIcon"
+        :suffixIcon="suffixIcon"
+        :mode="mode"
+        :href="href"
+        :format="format"
+        :call="call"
+        :openType="openType"
+        :bold="bold"
+        :block="block"
+        :lines="lines"
+        :color="color"
+		:decoration="decoration"
+        :size="size"
+        :iconStyle="iconStyle"
+        :margin="margin"
+        :lineHeight="lineHeight"
+        :align="align"
+        :wordWrap="wordWrap"
+        :customStyle="customStyle"
+    ></uvText>
+</template>
+
+<script>
+/**
+ * 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件
+ * 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转
+ * 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法
+ */
+import uvText from "../u-text/u-text.vue";
+import { props } from "../u-text/props.js";
+import { mpMixin } from '../../libs/mixin/mpMixin.js'
+import { mixin } from '../../libs/mixin/mixin.js'
+export default {
+    name: "u--text",
+    mixins: [mpMixin, mixin, props,],
+    components: {
+        uvText,
+    },
+};
+</script>

+ 47 - 0
uni_modules/uview-plus/components/u--textarea/u--textarea.vue

@@ -0,0 +1,47 @@
+<template>
+	<uvTextarea
+		:value="value"
+		:modelValue="modelValue"
+		:placeholder="placeholder"
+		:height="height"
+		:confirmType="confirmType"
+		:disabled="disabled"
+		:count="count"
+		:focus="focus"
+		:autoHeight="autoHeight"
+		:fixed="fixed"
+		:cursorSpacing="cursorSpacing"
+		:cursor="cursor"
+		:showConfirmBar="showConfirmBar"
+		:selectionStart="selectionStart"
+		:selectionEnd="selectionEnd"
+		:adjustPosition="adjustPosition"
+		:disableDefaultPadding="disableDefaultPadding"
+		:holdKeyboard="holdKeyboard"
+		:maxlength="maxlength"
+		:border="border"
+		:customStyle="customStyle"
+		:formatter="formatter"
+		:ignoreCompositionEvent="ignoreCompositionEvent"
+		@input="e => $emit('input', e)"
+		@update:modelValue="e => $emit('update:modelValue', e)"
+	></uvTextarea>
+</template>
+
+<script>
+	/**
+	 * 此组件存在的理由是,在nvue下,u--textarea被uni-app官方占用了,u-textarea在nvue中相当于textarea组件
+	 * 所以在nvue下,取名为u--textarea,内部其实还是u-textarea.vue,只不过做一层中转
+	 */
+	import uvTextarea from '../u-textarea/u-textarea.vue';
+	import { props } from '../u-textarea/props.js';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	export default {
+		name: 'u--textarea',
+		mixins: [mpMixin, props, mixin],
+		components: {
+			uvTextarea
+		},
+	}
+</script>

+ 109 - 0
uni_modules/uview-plus/components/u-action-sheet-data/u-action-sheet-data.vue

@@ -0,0 +1,109 @@
+<template>
+	<view class="u-action-sheet-data">
+		<view class="u-action-sheet-data__trigger">
+			<slot name="trigger"></slot>
+			<up-input
+				v-if="!$slots['trigger']"
+				:modelValue="current"
+				disabled
+				disabledColor="#ffffff"
+				:placeholder="title"
+				border="none"
+			></up-input>
+			<view @click="show = true"
+				class="u-action-sheet-data__trigger__cover"></view>
+		</view>
+		<up-action-sheet
+			:show="show"
+			:actions="options"
+			:title="title"
+			safeAreaInsetBottom
+			:description="description"
+			@close="show = false"
+			@select="select"
+		>
+		</up-action-sheet>
+	</view>
+</template>
+
+<script>
+export default {
+    props: {
+		modelValue: {
+			type: [String, Number],
+			default: ''
+		},
+		title: {
+			type: String,
+			default: ''
+		},
+		description: {
+			type: String,
+			default: ''
+		},
+		options: {
+			type: Array,
+			default: () => {
+				return []
+			}
+		},
+		valueKey: {
+			type: String,
+			default: 'value'
+		},
+		labelKey: {
+			type: String,
+			default: 'name'
+		}
+    },
+    data() {
+        return {
+			show: false,
+			current: '',
+        }
+    },
+    created() {
+		if (this.modelValue) {
+			this.options.forEach((ele) => {
+				if (ele[this.valueKey] == this.modelValue) {
+					this.current = ele[this.labelKey]
+				}
+			})
+		}
+    },
+    emits: ['update:modelValue'],
+	watch: {
+		modelValue() {
+			this.options.forEach((ele) => {
+				if (ele[this.valueKey] == this.modelValue) {
+					this.current = ele[this.labelKey]
+				}
+			})
+		}
+	},
+    methods: {
+        hideKeyboard() {
+            uni.hideKeyboard()
+        },
+        select(e) {
+            this.$emit('update:modelValue', e[this.valueKey])
+			this.current = e[this.labelKey]
+        },
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+	.u-action-sheet-data {
+		&__trigger {
+			position: relative;
+			&__cover {
+				position: absolute;
+				top: 0;
+				left: 0;
+				right: 0;
+				bottom: 0;
+			}
+		}
+	}
+</style>

+ 26 - 0
uni_modules/uview-plus/components/u-action-sheet/actionSheet.js

@@ -0,0 +1,26 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:44:35
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/actionSheet.js
+ */
+export default {
+    // action-sheet组件
+    actionSheet: {
+        show: false,
+        title: '',
+        description: '',
+        actions: [],
+        index: '',
+        cancelText: '',
+        closeOnClickAction: true,
+        safeAreaInsetBottom: true,
+        openType: '',
+        closeOnClickOverlay: true,
+        round: 0,
+        wrapMaxHeight: '600px'
+    }
+}

+ 62 - 0
uni_modules/uview-plus/components/u-action-sheet/props.js

@@ -0,0 +1,62 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+
+export const props = defineMixin({
+    props: {
+        // 操作菜单是否展示 (默认false)
+        show: {
+            type: Boolean,
+            default: () => defProps.actionSheet.show
+        },
+        // 标题
+        title: {
+            type: String,
+            default: () => defProps.actionSheet.title
+        },
+        // 选项上方的描述信息
+        description: {
+            type: String,
+            default: () => defProps.actionSheet.description
+        },
+        // 数据
+        actions: {
+            type: Array,
+            default: () => defProps.actionSheet.actions
+        },
+        // 取消按钮的文字,不为空时显示按钮
+        cancelText: {
+            type: String,
+            default: () => defProps.actionSheet.cancelText
+        },
+        // 点击某个菜单项时是否关闭弹窗
+        closeOnClickAction: {
+            type: Boolean,
+            default: () => defProps.actionSheet.closeOnClickAction
+        },
+        // 处理底部安全区(默认true)
+        safeAreaInsetBottom: {
+            type: Boolean,
+            default: () => defProps.actionSheet.safeAreaInsetBottom
+        },
+        // 小程序的打开方式
+        openType: {
+            type: String,
+            default: () => defProps.actionSheet.openType
+        },
+        // 点击遮罩是否允许关闭 (默认true)
+        closeOnClickOverlay: {
+            type: Boolean,
+            default: () => defProps.actionSheet.closeOnClickOverlay
+        },
+        // 圆角值
+        round: {
+            type: [Boolean, String, Number],
+            default: () => defProps.actionSheet.round
+        },
+        // 选项区域最大高度
+        wrapMaxHeight: {
+            type: [String],
+            default: () => defProps.actionSheet.wrapMaxHeight
+        },
+    }
+})

+ 282 - 0
uni_modules/uview-plus/components/u-action-sheet/u-action-sheet.vue

@@ -0,0 +1,282 @@
+
+<template>
+	<u-popup
+	    :show="show"
+	    mode="bottom"
+	    @close="closeHandler"
+	    :safeAreaInsetBottom="safeAreaInsetBottom"
+	    :round="round"
+	>
+		<view class="u-action-sheet">
+			<view
+			    class="u-action-sheet__header"
+			    v-if="title"
+			>
+				<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
+				<view
+				    class="u-action-sheet__header__icon-wrap"
+				    @tap.stop="cancel"
+				>
+					<u-icon
+					    name="close"
+					    size="17"
+					    color="#c8c9cc"
+					    bold
+					></u-icon>
+				</view>
+			</view>
+			<text
+			    class="u-action-sheet__description"
+				:style="[{
+					marginTop: `${title && description ? 0 : '18px'}`
+				}]"
+			    v-if="description"
+			>{{description}}</text>
+			<slot>
+				<u-line v-if="description"></u-line>
+				<scroll-view scroll-y class="u-action-sheet__item-wrap" :style="{maxHeight: wrapMaxHeight}">
+					<view :key="index" v-for="(item, index) in actions">
+						<!-- #ifdef MP -->
+						<button
+						    class="u-reset-button"
+						    :openType="item.openType"
+						    @getuserinfo="onGetUserInfo"
+						    @contact="onContact"
+						    @getphonenumber="onGetPhoneNumber"
+						    @error="onError"
+						    @launchapp="onLaunchApp"
+						    @opensetting="onOpenSetting"
+						    :lang="lang"
+						    :session-from="sessionFrom"
+						    :send-message-title="sendMessageTitle"
+						    :send-message-path="sendMessagePath"
+						    :send-message-img="sendMessageImg"
+						    :show-message-card="showMessageCard"
+						    :app-parameter="appParameter"
+						    @tap="selectHandler(index)"
+						    :hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
+						>
+							<!-- #endif -->
+							<view
+							    class="u-action-sheet__item-wrap__item"
+							    @tap.stop="selectHandler(index)"
+							    :hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
+							    :hover-stay-time="150"
+							>
+								<template v-if="!item.loading">
+									<text
+									    class="u-action-sheet__item-wrap__item__name"
+									    :style="[itemStyle(index)]"
+									>{{ item.name }}</text>
+									<text
+									    v-if="item.subname"
+									    class="u-action-sheet__item-wrap__item__subname"
+									>{{ item.subname }}</text>
+								</template>
+								<u-loading-icon
+								    v-else
+								    custom-class="van-action-sheet__loading"
+								    size="18"
+								    mode="circle"
+								/>
+							</view>
+							<!-- #ifdef MP -->
+						</button>
+						<!-- #endif -->
+						<u-line v-if="index !== actions.length - 1"></u-line>
+					</view>
+				</scroll-view>
+			</slot>
+			<u-gap
+			    bgColor="#eaeaec"
+			    height="6"
+			    v-if="cancelText"
+			></u-gap>
+			<view class="u-action-sheet__item-wrap__item u-action-sheet__cancel"
+				hover-class="u-action-sheet--hover" @tap="cancel" v-if="cancelText">
+				<text
+				    @touchmove.stop.prevent
+				    :hover-stay-time="150"
+				    class="u-action-sheet__cancel-text"
+				>{{cancelText}}</text>
+			</view>
+		</view>
+	</u-popup>
+</template>
+
+<script>
+	import { openType } from '../../libs/mixin/openType'
+	import { buttonMixin } from '../../libs/mixin/button'
+	import { props } from './props';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	import { addUnit } from '../../libs/function/index';
+	/**
+	 * ActionSheet 操作菜单
+	 * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
+	 * @tutorial https://ijry.github.io/uview-plus/components/actionSheet.html
+	 * 
+	 * @property {Boolean}			show				操作菜单是否展示 (默认 false )
+	 * @property {String}			title				操作菜单标题
+	 * @property {String}			description			选项上方的描述信息
+	 * @property {Array<Object>}	actions				按钮的文字数组,见官方文档示例
+	 * @property {String}			cancelText			取消按钮的提示文字,不为空时显示按钮
+	 * @property {Boolean}			closeOnClickAction	点击某个菜单项时是否关闭弹窗 (默认 true )
+	 * @property {Boolean}			safeAreaInsetBottom	处理底部安全区 (默认 true )
+	 * @property {String}			openType			小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error )
+	 * @property {Boolean}			closeOnClickOverlay	点击遮罩是否允许关闭  (默认 true )
+	 * @property {Number|String}	round				圆角值,默认无圆角  (默认 0 )
+	 * @property {String}			lang				指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文
+	 * @property {String}			sessionFrom			会话来源,openType="contact"时有效
+	 * @property {String}			sendMessageTitle	会话内消息卡片标题,openType="contact"时有效
+	 * @property {String}			sendMessagePath		会话内消息卡片点击跳转小程序路径,openType="contact"时有效
+	 * @property {String}			sendMessageImg		会话内消息卡片图片,openType="contact"时有效
+	 * @property {Boolean}			showMessageCard		是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false )
+	 * @property {String}			appParameter		打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效
+	 * 
+	 * @event {Function} select			点击ActionSheet列表项时触发 
+	 * @event {Function} close			点击取消按钮时触发
+	 * @event {Function} getuserinfo	用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
+	 * @event {Function} contact		客服消息回调,openType="contact"时有效
+	 * @event {Function} getphonenumber	获取用户手机号回调,openType="getPhoneNumber"时有效
+	 * @event {Function} error			当使用开放能力时,发生错误的回调,openType="error"时有效
+	 * @event {Function} launchapp		打开 APP 成功的回调,openType="launchApp"时有效
+	 * @event {Function} opensetting	在打开授权设置页后回调,openType="openSetting"时有效
+	 * @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
+	 */
+	export default {
+		name: "u-action-sheet",
+		// 一些props参数和methods方法,通过mixin混入,因为其他文件也会用到
+		mixins: [openType, buttonMixin, mixin, props],
+		data() {
+			return {
+
+			}
+		},
+		computed: {
+			// 操作项目的样式
+			itemStyle() {
+				return (index) => {
+					let style = {};
+					if (this.actions[index].color) style.color = this.actions[index].color
+					if (this.actions[index].fontSize) style.fontSize = addUnit(this.actions[index].fontSize)
+					// 选项被禁用的样式
+					if (this.actions[index].disabled) style.color = '#c0c4cc'
+					return style;
+				}
+			},
+		},
+		emits: ["close", "select", "update:show"],
+		methods: {
+			closeHandler() {
+				// 允许点击遮罩关闭时,才发出close事件
+				if(this.closeOnClickOverlay) {
+					this.$emit('update:show', false)
+					this.$emit('close')
+				}
+			},
+			// 点击取消按钮
+			cancel() {
+				this.$emit('update:show', false)
+				this.$emit('close')
+			},
+			selectHandler(index) {
+				const item = this.actions[index]
+				if (item && !item.disabled && !item.loading) {
+					this.$emit('select', item)
+					if (this.closeOnClickAction) {
+						this.$emit('update:show', false)
+						this.$emit('close')
+					}
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$u-action-sheet-reset-button-width:100% !default;
+	$u-action-sheet-title-font-size: 16px !default;
+	$u-action-sheet-title-padding: 12px 30px !default;
+	$u-action-sheet-title-color: $u-main-color !default;
+	$u-action-sheet-header-icon-wrap-right:15px !default;
+	$u-action-sheet-header-icon-wrap-top:15px !default;
+	$u-action-sheet-description-font-size:13px !default;
+	$u-action-sheet-description-color:14px !default;
+	$u-action-sheet-description-margin: 18px 15px !default;
+	$u-action-sheet-item-wrap-item-padding:17px !default;
+	$u-action-sheet-item-wrap-name-font-size:16px !default;
+	$u-action-sheet-item-wrap-subname-font-size:13px !default;
+	$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
+	$u-action-sheet-item-wrap-subname-margin-top:10px !default;
+	$u-action-sheet-cancel-text-font-size:16px !default;
+	$u-action-sheet-cancel-text-color:$u-content-color !default;
+	$u-action-sheet-cancel-text-font-size:15px !default;
+	$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
+
+	.u-reset-button {
+		width: $u-action-sheet-reset-button-width;
+	}
+
+	.u-action-sheet {
+		text-align: center;
+		&__header {
+			position: relative;
+			padding: $u-action-sheet-title-padding;
+			&__title {
+				font-size: $u-action-sheet-title-font-size;
+				color: $u-action-sheet-title-color;
+				font-weight: bold;
+				text-align: center;
+			}
+
+			&__icon-wrap {
+				position: absolute;
+				right: $u-action-sheet-header-icon-wrap-right;
+				top: $u-action-sheet-header-icon-wrap-top;
+			}
+		}
+
+		&__description {
+			font-size: $u-action-sheet-description-font-size;
+			color: $u-tips-color;
+			margin: $u-action-sheet-description-margin;
+			text-align: center;
+		}
+
+		&__item-wrap {
+
+			&__item {
+				padding: $u-action-sheet-item-wrap-item-padding;
+				@include flex;
+				align-items: center;
+				justify-content: center;
+				flex-direction: column;
+
+				&__name {
+					font-size: $u-action-sheet-item-wrap-name-font-size;
+					color: $u-main-color;
+					text-align: center;
+				}
+
+				&__subname {
+					font-size: $u-action-sheet-item-wrap-subname-font-size;
+					color: $u-action-sheet-item-wrap-subname-color;
+					margin-top: $u-action-sheet-item-wrap-subname-margin-top;
+					text-align: center;
+				}
+			}
+		}
+
+		&__cancel-text {
+			font-size: $u-action-sheet-cancel-text-font-size;
+			color: $u-action-sheet-cancel-text-color;
+			text-align: center;
+			// padding: $u-action-sheet-cancel-text-font-size;
+		}
+
+		&--hover {
+			background-color: $u-action-sheet-cancel-text-hover-background-color;
+		}
+	}
+</style>

+ 28 - 0
uni_modules/uview-plus/components/u-album/album.js

@@ -0,0 +1,28 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:47:24
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/album.js
+ */
+export default {
+    // album 组件
+    album: {
+        urls: [],
+        keyName: '',
+        singleSize: 180,
+        multipleSize: 70,
+        space: 6,
+        singleMode: 'scaleToFill',
+        multipleMode: 'aspectFill',
+        maxCount: 9,
+        previewFullImage: true,
+        rowCount: 3,
+        showMore: true,
+        autoWrap: false,
+        unit: 'px',
+        stop: true,
+    }
+}

+ 86 - 0
uni_modules/uview-plus/components/u-album/props.js

@@ -0,0 +1,86 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+export const props = defineMixin({
+    props: {
+        // 图片地址,Array<String>|Array<Object>形式
+        urls: {
+            type: Array,
+            default: () => defProps.album.urls
+        },
+        // 指定从数组的对象元素中读取哪个属性作为图片地址
+        keyName: {
+            type: String,
+            default: () => defProps.album.keyName
+        },
+        // 单图时,图片长边的长度
+        singleSize: {
+            type: [String, Number],
+            default: () => defProps.album.singleSize
+        },
+        // 多图时,图片边长
+        multipleSize: {
+            type: [String, Number],
+            default: () => defProps.album.multipleSize
+        },
+        // 多图时,图片水平和垂直之间的间隔
+        space: {
+            type: [String, Number],
+            default: () => defProps.album.space
+        },
+        // 单图时,图片缩放裁剪的模式
+        singleMode: {
+            type: String,
+            default: () => defProps.album.singleMode
+        },
+        // 多图时,图片缩放裁剪的模式
+        multipleMode: {
+            type: String,
+            default: () => defProps.album.multipleMode
+        },
+        // 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
+        maxCount: {
+            type: [String, Number],
+            default: () => defProps.album.maxCount
+        },
+        // 是否可以预览图片
+        previewFullImage: {
+            type: Boolean,
+            default: () => defProps.album.previewFullImage
+        },
+        // 每行展示图片数量,如设置,singleSize和multipleSize将会无效
+        rowCount: {
+            type: [String, Number],
+            default: () => defProps.album.rowCount
+        },
+        // 超出maxCount时是否显示查看更多的提示
+        showMore: {
+            type: Boolean,
+            default: () => defProps.album.showMore
+        },
+        // 图片形状,circle-圆形,square-方形
+        shape: {
+            type: String,
+            default: () => defProps.image.shape
+        },
+        // 圆角,单位任意
+        radius: {
+            type: [String, Number],
+            default: () => defProps.image.radius
+        },
+        // 自适应换行
+        autoWrap: {
+            type: Boolean,
+            default: () => defProps.album.autoWrap
+        },
+        // 单位
+        unit: {
+            type: [String],
+            default: () => defProps.album.unit
+        },
+        // 阻止点击冒泡
+        stop: {
+            type: Boolean,
+            default: () => defProps.album.stop
+        }
+    }
+})

+ 300 - 0
uni_modules/uview-plus/components/u-album/u-album.vue

@@ -0,0 +1,300 @@
+<template>
+    <view class="u-album">
+        <view
+            class="u-album__row"
+            ref="u-album__row"
+            v-for="(arr, index) in showUrls"
+            :forComputedUse="albumWidth"
+            :key="index"
+            :style="{flexWrap: autoWrap ? 'wrap' : 'nowrap'}"
+        >
+            <view
+                class="u-album__row__wrapper"
+                v-for="(item, index1) in arr"
+                :key="index1"
+                :style="[imageStyle(index + 1, index1 + 1)]"
+                @tap="onPreviewTap($event, getSrc(item))"
+            >
+                <image
+                    :src="getSrc(item)"
+                    :mode="
+                        urls.length === 1
+                            ? imageHeight > 0
+                                ? singleMode
+                                : 'widthFix'
+                            : multipleMode
+                    "
+                    :style="[
+                        {
+                            width: imageWidth,
+                            height: imageHeight,
+                            borderRadius: shape == 'circle' ? '10000px' : addUnit(radius)
+                        }
+                    ]"
+                ></image>
+                <view
+                    v-if="
+                        showMore &&
+                        urls.length > rowCount * showUrls.length &&
+                        index === showUrls.length - 1 &&
+                        index1 === showUrls[showUrls.length - 1].length - 1
+                    "
+                    class="u-album__row__wrapper__text"
+                    :style="{
+					    borderRadius: shape == 'circle' ? '50%' : addUnit(radius),
+				    }"
+                >
+                    <up-text
+                        :text="`+${urls.length - maxCount}`"
+                        color="#fff"
+                        :size="multipleSize * 0.3"
+                        align="center"
+                        customStyle="justify-content: center"
+                    ></up-text>
+                </view>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import { props } from './props';
+import { mpMixin } from '../../libs/mixin/mpMixin';
+import { mixin } from '../../libs/mixin/mixin';
+import { addUnit, sleep } from '../../libs/function/index';
+import test from '../../libs/function/test';
+// #ifdef APP-NVUE
+// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
+const dom = uni.requireNativePlugin('dom')
+// #endif
+
+/**
+ * Album 相册
+ * @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
+ * @tutorial https://ijry.github.io/uview-plus/components/album.html
+ *
+ * @property {Array}           urls             图片地址列表 Array<String>|Array<Object>形式
+ * @property {String}          keyName          指定从数组的对象元素中读取哪个属性作为图片地址
+ * @property {String | Number} singleSize       单图时,图片长边的长度  (默认 180 )
+ * @property {String | Number} multipleSize     多图时,图片边长 (默认 70 )
+ * @property {String | Number} space            多图时,图片水平和垂直之间的间隔 (默认 6 )
+ * @property {String}          singleMode       单图时,图片缩放裁剪的模式 (默认 'scaleToFill' )
+ * @property {String}          multipleMode     多图时,图片缩放裁剪的模式 (默认 'aspectFill' )
+ * @property {String | Number} maxCount         取消按钮的提示文字 (默认 9 )
+ * @property {Boolean}         previewFullImage 是否可以预览图片 (默认 true )
+ * @property {String | Number} rowCount         每行展示图片数量,如设置,singleSize和multipleSize将会无效	(默认 3 )
+ * @property {Boolean}         showMore         超出maxCount时是否显示查看更多的提示 (默认 true )
+ * @property {String}          shape            图片形状,circle-圆形,square-方形 (默认 'square' )
+ * @property {String | Number} radius           圆角值,单位任意,如果为数值,则为px单位 (默认 0 )
+ * @property {Boolean}         autoWrap         自适应换行模式,不受rowCount限制,图片会自动换行 (默认 false )
+ * @property {String}          unit             图片单位 (默认 px )
+ * @event    {Function}        albumWidth       某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送  (回调参数 width )
+ * @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
+ */
+export default {
+    name: 'u-album',
+    mixins: [mpMixin, mixin, props],
+    data() {
+        return {
+            // 单图的宽度
+            singleWidth: 0,
+            // 单图的高度
+            singleHeight: 0,
+            // 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比
+            singlePercent: 0.6
+        }
+    },
+    watch: {
+        urls: {
+            immediate: true,
+            handler(newVal) {
+                if (newVal.length === 1) {
+                    this.getImageRect()
+                }
+            }
+        }
+    },
+	emits: ["albumWidth"],
+    computed: {
+        imageStyle() {
+            return (index1, index2) => {
+                const { space, rowCount, multipleSize, urls } = this,
+                    rowLen = this.showUrls.length,
+                    allLen = this.urls.length
+                const style = {
+                    marginRight: addUnit(space),
+                    marginBottom: addUnit(space)
+                }
+                // 如果为最后一行,则每个图片都无需下边框
+                if (index1 === rowLen && !this.autoWrap) style.marginBottom = 0
+                // 每行的最右边一张和总长度的最后一张无需右边框
+                if (!this.autoWrap) {
+                    if (
+                        index2 === rowCount ||
+                        (index1 === rowLen &&
+                            index2 === this.showUrls[index1 - 1].length)
+                    )
+                        style.marginRight = 0
+                }
+                return style
+            }
+        },
+        // 将数组划分为二维数组
+        showUrls() {
+            if (this.autoWrap) {
+                return [ this.urls.slice(0, this.maxCount) ];
+            } else {
+                const arr = []
+                this.urls.map((item, index) => {
+                    // 限制最大展示数量
+                    if (index + 1 <= this.maxCount) {
+                        // 计算该元素为第几个素组内
+                        const itemIndex = Math.floor(index / this.rowCount)
+                        // 判断对应的索引是否存在
+                        if (!arr[itemIndex]) {
+                            arr[itemIndex] = []
+                        }
+                        arr[itemIndex].push(item)
+                    }
+                })
+                return arr
+            }
+        },
+        imageWidth() {
+            return addUnit(
+                this.urls.length === 1 ? this.singleWidth : this.multipleSize, this.unit
+            )
+        },
+        imageHeight() {
+            return addUnit(
+                this.urls.length === 1 ? this.singleHeight : this.multipleSize, this.unit
+            )
+        },
+        // 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
+        // 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送
+        albumWidth() {
+            let width = 0
+            if (this.urls.length === 1) {
+                width = this.singleWidth
+            } else {
+                width =
+                    this.showUrls[0].length * this.multipleSize +
+                    this.space * (this.showUrls[0].length - 1)
+            }
+            this.$emit('albumWidth', width)
+            return width
+        }
+    },
+    emits: ['preview', 'albumWidth'],
+    methods: {
+        addUnit,
+        // 预览图片
+        onPreviewTap(e, url) {
+            const urls = this.urls.map((item) => {
+                return this.getSrc(item)
+            })
+            if (this.previewFullImage) {
+                uni.previewImage({
+                    current: url,
+                    urls
+                })
+                // 是否阻止事件传播
+                this.stop && this.preventEvent(e)
+            } else {
+                this.$emit('preview', {
+                    urls,
+                    currentIndex: urls.indexOf(url)
+                })
+            }
+        },
+        // 获取图片的路径
+        getSrc(item) {
+            return test.object(item)
+                ? (this.keyName && item[this.keyName]) || item.src
+                : item
+        },
+        // 单图时,获取图片的尺寸
+        // 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
+        // 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
+        getImageRect() {
+            const src = this.getSrc(this.urls[0])
+            uni.getImageInfo({
+                src,
+                success: (res) => {
+                    let singleSize = this.singleSize;
+                    // 单位
+                    let unit = '';
+                    if (Number.isNaN(Number(this.singleSize))) {
+                        // 大小中有字符 则记录字符
+                        unit = this.singleSize.replace(/\d+/g, ''); // 单位
+                        singleSize = Number(this.singleSize.replace(/\D+/g, ''), 10); // 具体值
+                    }
+
+                    // 判断图片横向还是竖向展示方式
+                    const isHorizotal = res.width >= res.height
+                    this.singleWidth = isHorizotal
+                        ? singleSize
+                        : (res.width / res.height) * singleSize
+                    this.singleHeight = !isHorizotal
+                        ? singleSize
+                        : (res.height / res.width) * this.singleWidth
+
+                    // 如果有单位统一设置单位
+                    if(unit != null && unit !== ''){
+                        this.singleWidth = this.singleWidth + unit
+                        this.singleHeight = this.singleHeight + unit
+                    }
+                },
+                fail: () => {
+                    this.getComponentWidth()
+                }
+            })
+        },
+        // 获取组件的宽度
+        async getComponentWidth() {
+            // 延时一定时间,以获取dom尺寸
+            await sleep(30)
+            // #ifndef APP-NVUE
+            this.$uGetRect('.u-album__row').then((size) => {
+                this.singleWidth = size.width * this.singlePercent
+            })
+            // #endif
+
+            // #ifdef APP-NVUE
+            // 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组
+            const ref = this.$refs['u-album__row'][0]
+            ref &&
+                dom.getComponentRect(ref, (res) => {
+                    this.singleWidth = res.size.width * this.singlePercent
+                })
+            // #endif
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.u-album {
+    @include flex(column);
+
+    &__row {
+        @include flex(row);
+
+        &__wrapper {
+            position: relative;
+
+            &__text {
+                position: absolute;
+                top: 0;
+                left: 0;
+                right: 0;
+                bottom: 0;
+                background-color: rgba(0, 0, 0, 0.3);
+                @include flex(row);
+                justify-content: center;
+                align-items: center;
+            }
+        }
+    }
+}
+</style>

+ 22 - 0
uni_modules/uview-plus/components/u-alert/alert.js

@@ -0,0 +1,22 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:48:53
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/alert.js
+ */
+export default {
+    // alert警告组件
+    alert: {
+        title: '',
+        type: 'warning',
+        description: '',
+        closable: false,
+        showIcon: false,
+        effect: 'light',
+        center: false,
+        fontSize: 14
+    }
+}

+ 46 - 0
uni_modules/uview-plus/components/u-alert/props.js

@@ -0,0 +1,46 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+export const props = defineMixin({
+    props: {
+        // 显示文字
+        title: {
+            type: String,
+            default: () => defProps.alert.title
+        },
+        // 主题,success/warning/info/error
+        type: {
+            type: String,
+            default: () => defProps.alert.type
+        },
+        // 辅助性文字
+        description: {
+            type: String,
+            default: () => defProps.alert.description
+        },
+        // 是否可关闭
+        closable: {
+            type: Boolean,
+            default: () => defProps.alert.closable
+        },
+        // 是否显示图标
+        showIcon: {
+            type: Boolean,
+            default: () => defProps.alert.showIcon
+        },
+        // 浅或深色调,light-浅色,dark-深色
+        effect: {
+            type: String,
+            default: () => defProps.alert.effect
+        },
+        // 文字是否居中
+        center: {
+            type: Boolean,
+            default: () => defProps.alert.center
+        },
+        // 字体大小
+        fontSize: {
+            type: [String, Number],
+            default: () => defProps.alert.fontSize
+        }
+    }
+})

+ 250 - 0
uni_modules/uview-plus/components/u-alert/u-alert.vue

@@ -0,0 +1,250 @@
+<template>
+	<u-transition
+	    mode="fade"
+	    :show="show"
+	>
+		<view
+		    class="u-alert"
+		    :class="[`u-alert--${type}--${effect}`]"
+		    @tap.stop="clickHandler"
+		    :style="[addStyle(customStyle)]"
+		>
+			<view
+			    class="u-alert__icon"
+			    v-if="showIcon"
+			>
+				<u-icon
+				    :name="iconName"
+				    size="18"
+				    :color="iconColor"
+				></u-icon>
+			</view>
+			<view
+			    class="u-alert__content"
+			    :style="[{
+					paddingRight: closable ? '20px' : 0
+				}]"
+			>
+				<text
+				    class="u-alert__content__title"
+				    v-if="title"
+					:style="[{
+						fontSize: addUnit(fontSize),
+						textAlign: center ? 'center' : 'left'
+					}]"
+				    :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
+				>{{ title }}</text>
+				<text
+				    class="u-alert__content__desc"
+					v-if="description"
+					:style="[{
+						fontSize: addUnit(fontSize),
+						textAlign: center ? 'center' : 'left'
+					}]"
+				    :class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
+				>{{ description }}</text>
+			</view>
+			<view
+			    class="u-alert__close"
+			    v-if="closable"
+			    @tap.stop="closeHandler"
+			>
+				<u-icon
+				    name="close"
+				    :color="iconColor"
+				    size="15"
+				></u-icon>
+			</view>
+		</view>
+	</u-transition>
+</template>
+
+<script>
+	import { props } from './props';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	import { addUnit, addStyle } from '../../libs/function/index';
+	/**
+	 * Alert  警告提示
+	 * @description 警告提示,展现需要关注的信息。
+	 * @tutorial https://ijry.github.io/uview-plus/components/alertTips.html
+	 * 
+	 * @property {String}			title       显示的文字 
+	 * @property {String}			type        使用预设的颜色  (默认 'warning' )
+	 * @property {String}			description 辅助性文字,颜色比title浅一点,字号也小一点,可选  
+	 * @property {Boolean}			closable    关闭按钮(默认为叉号icon图标)  (默认 false )
+	 * @property {Boolean}			showIcon    是否显示左边的辅助图标   ( 默认 false )
+	 * @property {String}			effect      多图时,图片缩放裁剪的模式  (默认 'light' )
+	 * @property {Boolean}			center		文字是否居中  (默认 false )
+	 * @property {String | Number}	fontSize    字体大小  (默认 14 )
+	 * @property {Object}			customStyle	定义需要用到的外部样式
+	 * @event    {Function}        click       点击组件时触发
+	 * @event    {Function}        close       点击关闭按钮时触发
+	 * @example  <u-alert :title="title"  type = "warning" :closable="closable" :description = "description"></u-alert>
+	 */
+	export default {
+		name: 'u-alert',
+		mixins: [mpMixin, mixin, props],
+		data() {
+			return {
+				show: true
+			}
+		},
+		computed: {
+			iconColor() {
+				return this.effect === 'light' ? this.type : '#fff'
+			},
+			// 不同主题对应不同的图标
+			iconName() {
+				switch (this.type) {
+					case 'success':
+						return 'checkmark-circle-fill';
+						break;
+					case 'error':
+						return 'close-circle-fill';
+						break;
+					case 'warning':
+						return 'error-circle-fill';
+						break;
+					case 'info':
+						return 'info-circle-fill';
+						break;
+					case 'primary':
+						return 'more-circle-fill';
+						break;
+					default: 
+						return 'error-circle-fill';
+				}
+			}
+		},
+		emits: ["click","close"],
+		methods: {
+			addUnit,
+			addStyle,
+			// 点击内容
+			clickHandler() {
+				this.$emit('click')
+			},
+			// 点击关闭按钮
+			closeHandler() {
+				this.show = false   
+				this.$emit('close')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+
+	.u-alert {
+		position: relative;
+		background-color: $u-primary;
+		padding: 8px 10px;
+		@include flex(row);
+		align-items: center;
+		border-top-left-radius: 4px;
+		border-top-right-radius: 4px;
+		border-bottom-left-radius: 4px;
+		border-bottom-right-radius: 4px;
+
+		&--primary--dark {
+			background-color: $u-primary;
+		}
+
+		&--primary--light {
+			background-color: #ecf5ff;
+		}
+
+		&--error--dark {
+			background-color: $u-error;
+		}
+
+		&--error--light {
+			background-color: #FEF0F0;
+		}
+
+		&--success--dark {
+			background-color: $u-success;
+		}
+
+		&--success--light {
+			background-color: #f5fff0;
+		}
+
+		&--warning--dark {
+			background-color: $u-warning;
+		}
+
+		&--warning--light {
+			background-color: #FDF6EC;
+		}
+
+		&--info--dark {
+			background-color: $u-info;
+		}
+
+		&--info--light {
+			background-color: #f4f4f5;
+		}
+
+		&__icon {
+			margin-right: 5px;
+		}
+
+		&__content {
+			@include flex(column);
+			flex: 1;
+
+			&__title {
+				color: $u-main-color;
+				font-size: 14px;
+				font-weight: bold;
+				color: #fff;
+				margin-bottom: 2px;
+			}
+
+			&__desc {
+				color: $u-main-color;
+				font-size: 14px;
+				flex-wrap: wrap;
+				color: #fff;
+			}
+		}
+
+		&__title--dark,
+		&__desc--dark {
+			color: #FFFFFF;
+		}
+
+		&__text--primary--light,
+		&__text--primary--light {
+			color: $u-primary;
+		}
+
+		&__text--success--light,
+		&__text--success--light {
+			color: $u-success;
+		}
+
+		&__text--warning--light,
+		&__text--warning--light {
+			color: $u-warning;
+		}
+
+		&__text--error--light,
+		&__text--error--light {
+			color: $u-error;
+		}
+
+		&__text--info--light,
+		&__text--info--light {
+			color: $u-info;
+		}
+
+		&__close {
+			position: absolute;
+			top: 11px;
+			right: 10px;
+		}
+	}
+</style>

+ 23 - 0
uni_modules/uview-plus/components/u-avatar-group/avatarGroup.js

@@ -0,0 +1,23 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:49:55
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/avatarGroup.js
+ */
+export default {
+    // avatarGroup 组件
+    avatarGroup: {
+        urls: [],
+        maxCount: 5,
+        shape: 'circle',
+        mode: 'scaleToFill',
+        showMore: true,
+        size: 40,
+        keyName: '',
+        gap: 0.5,
+		extraValue: 0
+    }
+}

+ 54 - 0
uni_modules/uview-plus/components/u-avatar-group/props.js

@@ -0,0 +1,54 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+export const props = defineMixin({
+    props: {
+        // 头像图片组
+        urls: {
+            type: Array,
+            default: () => defProps.avatarGroup.urls
+        },
+        // 最多展示的头像数量
+        maxCount: {
+            type: [String, Number],
+            default: () => defProps.avatarGroup.maxCount
+        },
+        // 头像形状
+        shape: {
+            type: String,
+            default: () => defProps.avatarGroup.shape
+        },
+        // 图片裁剪模式
+        mode: {
+            type: String,
+            default: () => defProps.avatarGroup.mode
+        },
+        // 超出maxCount时是否显示查看更多的提示
+        showMore: {
+            type: Boolean,
+            default: () => defProps.avatarGroup.showMore
+        },
+        // 头像大小
+        size: {
+            type: [String, Number],
+            default: () => defProps.avatarGroup.size
+        },
+        // 指定从数组的对象元素中读取哪个属性作为图片地址
+        keyName: {
+            type: String,
+            default: () => defProps.avatarGroup.keyName
+        },
+		// 头像之间的遮挡比例
+        gap: {
+            type: [String, Number],
+            validator(value) {
+                return value >= 0 && value <= 1
+            },
+            default: () => defProps.avatarGroup.gap
+        },
+		// 需额外显示的值
+		extraValue: {
+			type: [Number, String],
+			default: () => defProps.avatarGroup.extraValue
+		}
+    }
+})

+ 109 - 0
uni_modules/uview-plus/components/u-avatar-group/u-avatar-group.vue

@@ -0,0 +1,109 @@
+<template>
+	<view class="u-avatar-group">
+		<view
+		    class="u-avatar-group__item"
+		    v-for="(item, index) in showUrl"
+		    :key="index"
+		    :style="{
+				marginLeft: index === 0 ? 0 : addUnit(-size * gap)
+			}"
+		>
+			<u-avatar
+			    :size="size"
+			    :shape="shape"
+			    :mode="mode"
+			    :src="testObject(item) ? keyName && item[keyName] || item.url : item"
+			></u-avatar>
+			<view
+			    class="u-avatar-group__item__show-more"
+			    v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
+				@tap="clickHandler"
+			>
+				<up-text
+				    color="#ffffff"
+				    :size="size * 0.4"
+				    :text="`+${extraValue || urls.length - showUrl.length}`"
+					align="center"
+					customStyle="justify-content: center"
+				></up-text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { props } from './props';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	import { addUnit } from '../../libs/function/index';
+	import test from '../../libs/function/test';
+	/**
+	 * AvatarGroup  头像组
+	 * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
+	 * @tutorial https://ijry.github.io/uview-plus/components/avatar.html
+	 * 
+	 * @property {Array}           urls     头像图片组 (默认 [] )
+	 * @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
+	 * @property {String}          shape    头像形状( 'circle' (默认) | 'square' )
+	 * @property {String}          mode     图片裁剪模式(默认 'scaleToFill' )
+	 * @property {Boolean}         showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
+	 * @property {String | Number} size      头像大小 (默认 40 )
+	 * @property {String}          keyName  指定从数组的对象元素中读取哪个属性作为图片地址 
+	 * @property {String | Number} gap      头像之间的遮挡比例(0.4代表遮挡40%)  (默认 0.5 )
+	 * @property {String | Number} extraValue  需额外显示的值
+	 * @event    {Function}        showMore 头像组更多点击
+	 * @example  <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=>
+	 */
+	export default {
+		name: 'u-avatar-group',
+		mixins: [mpMixin, mixin, props],
+		data() {
+			return {
+
+			}
+		},
+		computed: {
+			showUrl() {
+				return this.urls.slice(0, this.maxCount)
+			}
+		},
+		emits: ["showMore"],
+		methods: {
+			addUnit,
+			testObject: test.object,
+			clickHandler() {
+				this.$emit('showMore')
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+
+	.u-avatar-group {
+		@include flex;
+
+		&__item {
+			margin-left: -10px;
+			position: relative;
+
+			&--no-indent {
+				// 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持
+				margin-left: 0;
+			}
+
+			&__show-more {
+				position: absolute;
+				top: 0;
+				bottom: 0;
+				left: 0;
+				right: 0;
+				background-color: rgba(0, 0, 0, 0.3);
+				@include flex;
+				align-items: center;
+				justify-content: center;
+				border-radius: 100px;
+			}
+		}
+	}
+</style>

+ 28 - 0
uni_modules/uview-plus/components/u-avatar/avatar.js

@@ -0,0 +1,28 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:49:22
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/avatar.js
+ */
+export default {
+    // avatar 组件
+    avatar: {
+        src: '',
+        shape: 'circle',
+        size: 40,
+        mode: 'scaleToFill',
+        text: '',
+        bgColor: '#c0c4cc',
+        color: '#ffffff',
+        fontSize: 18,
+        icon: '',
+        mpAvatar: false,
+        randomBgColor: false,
+        defaultUrl: '',
+        colorIndex: '',
+        name: ''
+    }
+}

+ 81 - 0
uni_modules/uview-plus/components/u-avatar/props.js

@@ -0,0 +1,81 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+import test from '../../libs/function/test';
+export const props = defineMixin({
+    props: {
+        // 头像图片路径(不能为相对路径)
+        src: {
+            type: String,
+            default: () => defProps.avatar.src
+        },
+        // 头像形状,circle-圆形,square-方形
+        shape: {
+            type: String,
+            default: () => defProps.avatar.shape
+        },
+        // 头像尺寸
+        size: {
+            type: [String, Number],
+            default: () => defProps.avatar.size
+        },
+        // 裁剪模式
+        mode: {
+            type: String,
+            default: () => defProps.avatar.mode
+        },
+        // 显示的文字
+        text: {
+            type: String,
+            default: () => defProps.avatar.text
+        },
+        // 背景色
+        bgColor: {
+            type: String,
+            default: () => defProps.avatar.bgColor
+        },
+        // 文字颜色
+        color: {
+            type: String,
+            default: () => defProps.avatar.color
+        },
+        // 文字大小
+        fontSize: {
+            type: [String, Number],
+            default: () => defProps.avatar.fontSize
+        },
+        // 显示的图标
+        icon: {
+            type: String,
+            default: () => defProps.avatar.icon
+        },
+        // 显示小程序头像,只对百度,微信,QQ小程序有效
+        mpAvatar: {
+            type: Boolean,
+            default: () => defProps.avatar.mpAvatar
+        },
+        // 是否使用随机背景色
+        randomBgColor: {
+            type: Boolean,
+            default: () => defProps.avatar.randomBgColor
+        },
+        // 加载失败的默认头像(组件有内置默认图片)
+        defaultUrl: {
+            type: String,
+            default: () => defProps.avatar.defaultUrl
+        },
+        // 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
+        colorIndex: {
+            type: [String, Number],
+            // 校验参数规则,索引在0-19之间
+            validator(n) {
+                return test.range(n, [0, 19]) || n === ''
+            },
+            default: () => defProps.avatar.colorIndex
+        },
+        // 组件标识符
+        name: {
+            type: String,
+            default: () => defProps.avatar.name
+        }
+    }
+})

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 61 - 0
uni_modules/uview-plus/components/u-avatar/u-avatar.vue


+ 27 - 0
uni_modules/uview-plus/components/u-back-top/backtop.js

@@ -0,0 +1,27 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:50:18
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/backtop.js
+ */
+export default {
+    // backtop组件
+    backtop: {
+        mode: 'circle',
+        icon: 'arrow-upward',
+        text: '',
+        duration: 100,
+        scrollTop: 0,
+        top: 400,
+        bottom: 100,
+        right: 20,
+        zIndex: 9,
+        iconStyle: {
+            color: '#909399',
+            fontSize: '19px'
+        }
+    }
+}

+ 56 - 0
uni_modules/uview-plus/components/u-back-top/props.js

@@ -0,0 +1,56 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+export const props = defineMixin({
+    props: {
+        // 返回顶部的形状,circle-圆形,square-方形
+        mode: {
+            type: String,
+            default: () => defProps.backtop.mode
+        },
+        // 自定义图标
+        icon: {
+            type: String,
+            default: () => defProps.backtop.icon
+        },
+        // 提示文字
+        text: {
+            type: String,
+            default: () => defProps.backtop.text
+        },
+        // 返回顶部滚动时间
+        duration: {
+            type: [String, Number],
+            default: () => defProps.backtop.duration
+        },
+        // 滚动距离
+        scrollTop: {
+            type: [String, Number],
+            default: () => defProps.backtop.scrollTop
+        },
+        // 距离顶部多少距离显示,单位px
+        top: {
+            type: [String, Number],
+            default: () => defProps.backtop.top
+        },
+        // 返回顶部按钮到底部的距离,单位px
+        bottom: {
+            type: [String, Number],
+            default: () => defProps.backtop.bottom
+        },
+        // 返回顶部按钮到右边的距离,单位px
+        right: {
+            type: [String, Number],
+            default: () => defProps.backtop.right
+        },
+        // 层级
+        zIndex: {
+            type: [String, Number],
+            default: () => defProps.backtop.zIndex
+        },
+        // 图标的样式,对象形式
+        iconStyle: {
+            type: Object,
+            default: () => defProps.backtop.iconStyle
+        }
+    }
+})

+ 132 - 0
uni_modules/uview-plus/components/u-back-top/u-back-top.vue

@@ -0,0 +1,132 @@
+<template>
+	<u-transition
+	    mode="fade"
+	    :customStyle="backTopStyle"
+	    :show="show"
+	>
+		<view
+		    class="u-back-top"
+			:style="[contentStyle]"
+		    v-if="!$slots.default && !$slots.$default"
+			@click="backToTop"
+		>
+			<u-icon
+			    :name="icon"
+			    :custom-style="iconStyle"
+			></u-icon>
+			<text
+			    v-if="text"
+			    class="u-back-top__text"
+			>{{text}}</text>
+		</view>
+		<slot v-else />
+	</u-transition>
+</template>
+
+<script>
+	import { props } from './props';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	import { addUnit, addStyle, getPx, deepMerge, error } from '../../libs/function/index';
+	// #ifdef APP-NVUE
+	const dom = weex.requireModule('dom')
+	// #endif
+	/**
+	 * backTop 返回顶部
+	 * @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
+	 * @tutorial https://uview-plus.jiangruyi.com/components/backTop.html
+	 * 
+	 * @property {String}			mode  		返回顶部的形状,circle-圆形,square-方形 (默认 'circle' )
+	 * @property {String} 			icon 		自定义图标 (默认 'arrow-upward' ) 见官方文档示例
+	 * @property {String} 			text 		提示文字 
+	 * @property {String | Number}  duration	返回顶部滚动时间 (默认 100)
+	 * @property {String | Number}  scrollTop	滚动距离 (默认 0 )
+	 * @property {String | Number}  top  		距离顶部多少距离显示,单位px (默认 400 )
+	 * @property {String | Number}  bottom  	返回顶部按钮到底部的距离,单位px (默认 100 )
+	 * @property {String | Number}  right  		返回顶部按钮到右边的距离,单位px (默认 20 )
+	 * @property {String | Number}  zIndex 		层级   (默认 9 )
+	 * @property {Object<Object>}  	iconStyle 	图标的样式,对象形式   (默认 {color: '#909399',fontSize: '19px'})
+	 * @property {Object}			customStyle	定义需要用到的外部样式
+	 * 
+	 * @example <u-back-top :scrollTop="scrollTop"></u-back-top>
+	 */
+	export default {
+		name: 'u-back-top',
+		mixins: [mpMixin, mixin, props],
+		computed: {
+			backTopStyle() {
+				// 动画组件样式
+				const style = {
+					bottom: addUnit(this.bottom),
+					right: addUnit(this.right),
+					width: '40px',
+					height: '40px',
+					position: 'fixed',
+					zIndex: 10,
+				}
+				return style
+			},
+			show() {
+				return getPx(this.scrollTop) > getPx(this.top)
+			},
+			contentStyle() {
+				const style = {}
+				let radius = 0
+				// 是否圆形
+				if(this.mode === 'circle') {
+					radius = '100px'
+				} else {
+					radius = '4px'
+				}
+				// 为了兼容安卓nvue,只能这么分开写
+				style.borderTopLeftRadius = radius
+				style.borderTopRightRadius = radius
+				style.borderBottomLeftRadius = radius
+				style.borderBottomRightRadius = radius
+				return deepMerge(style, addStyle(this.customStyle))
+			}
+		},
+		emits: ["click"],
+		methods: {
+			backToTop() {
+				// #ifdef APP-NVUE
+				if (!this.$parent.$refs['u-back-top']) {
+					error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`)
+				}
+				dom.scrollToElement(this.$parent.$refs['u-back-top'], {
+					offset: 0
+				})
+				// #endif
+				
+				// #ifndef APP-NVUE
+				uni.pageScrollTo({
+					scrollTop: 0,
+					duration: this.duration
+				});
+				// #endif
+				this.$emit('click')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+     $u-back-top-flex:1 !default;
+     $u-back-top-height:100% !default;
+     $u-back-top-background-color:#E1E1E1 !default;
+     $u-back-top-tips-font-size:12px !default;
+	.u-back-top {
+		@include flex;
+		flex-direction: column;
+		align-items: center;
+		flex:$u-back-top-flex;
+		height: $u-back-top-height;
+		justify-content: center;
+		background-color: $u-back-top-background-color;
+
+		&__tips {
+			font-size:$u-back-top-tips-font-size;
+			transform: scale(0.8);
+		}
+	}
+</style>

+ 27 - 0
uni_modules/uview-plus/components/u-badge/badge.js

@@ -0,0 +1,27 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-23 19:51:50
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/badge.js
+ */
+export default {
+    // 徽标数组件
+    badge: {
+        isDot: false,
+        value: '',
+        show: true,
+        max: 999,
+        type: 'error',
+        showZero: false,
+        bgColor: null,
+        color: null,
+        shape: 'circle',
+        numberType: 'overflow',
+        offset: [],
+        inverted: false,
+        absolute: false
+    }
+}

+ 79 - 0
uni_modules/uview-plus/components/u-badge/props.js

@@ -0,0 +1,79 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+export const props = defineMixin({
+    props: {
+        // 是否显示圆点
+        isDot: {
+            type: Boolean,
+            default: () => defProps.badge.isDot
+        },
+        // 显示的内容
+        value: {
+            type: [Number, String],
+            default: () => defProps.badge.value
+        },
+        // 显示的内容
+        modelValue: {
+            type: [Number, String],
+            default: () => defProps.badge.modelValue
+        },
+        // 是否显示
+        show: {
+            type: Boolean,
+            default: () => defProps.badge.show
+        },
+        // 最大值,超过最大值会显示 '{max}+'
+        max: {
+            type: [Number, String],
+            default: () => defProps.badge.max
+        },
+        // 主题类型,error|warning|success|primary
+        type: {
+            type: String,
+            default: () => defProps.badge.type
+        },
+        // 当数值为 0 时,是否展示 Badge
+        showZero: {
+            type: Boolean,
+            default: () => defProps.badge.showZero
+        },
+        // 背景颜色,优先级比type高,如设置,type参数会失效
+        bgColor: {
+            type: [String, null],
+            default: () => defProps.badge.bgColor
+        },
+        // 字体颜色
+        color: {
+            type: [String, null],
+            default: () => defProps.badge.color
+        },
+        // 徽标形状,circle-四角均为圆角,horn-左下角为直角
+        shape: {
+            type: String,
+            default: () => defProps.badge.shape
+        },
+        // 设置数字的显示方式,overflow|ellipsis|limit
+        // overflow会根据max字段判断,超出显示`${max}+`
+        // ellipsis会根据max判断,超出显示`${max}...`
+        // limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
+        numberType: {
+            type: String,
+            default: () => defProps.badge.numberType
+        },
+        // 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
+        offset: {
+            type: Array,
+            default: () => defProps.badge.offset
+        },
+        // 是否反转背景和字体颜色
+        inverted: {
+            type: Boolean,
+            default: () => defProps.badge.inverted
+        },
+        // 是否绝对定位
+        absolute: {
+            type: Boolean,
+            default: () => defProps.badge.absolute
+        }
+    }
+})

+ 176 - 0
uni_modules/uview-plus/components/u-badge/u-badge.vue

@@ -0,0 +1,176 @@
+<template>
+	<text
+		v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
+		:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]"
+		:style="[addStyle(customStyle), badgeStyle]"
+		class="u-badge"
+	>{{ isDot ? '' :showValue }}</text>
+</template>
+
+<script>
+	import { props } from './props';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	import { addStyle, addUnit } from '../../libs/function/index';
+	/**
+	 * badge 徽标数
+	 * @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
+	 * @tutorial https://uview-plus.jiangruyi.com/components/badge.html
+	 * 
+	 * @property {Boolean} 			isDot 		是否显示圆点 (默认 false )
+	 * @property {String | Number} 	value 		显示的内容
+	 * @property {Boolean} 			show 		是否显示 (默认 true )
+	 * @property {String | Number} 	max 		最大值,超过最大值会显示 '{max}+'  (默认999)
+	 * @property {String} 			type 		主题类型,error|warning|success|primary (默认 'error' )
+	 * @property {Boolean} 			showZero	当数值为 0 时,是否展示 Badge (默认 false )
+	 * @property {String} 			bgColor 	背景颜色,优先级比type高,如设置,type参数会失效
+	 * @property {String} 			color 		字体颜色 (默认 '#ffffff' )
+	 * @property {String} 			shape 		徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' )
+	 * @property {String} 			numberType	设置数字的显示方式,overflow|ellipsis|limit  (默认 'overflow' )
+	 * @property {Array}} 			offset		设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
+	 * @property {Boolean} 			inverted	是否反转背景和字体颜色(默认 false )
+	 * @property {Boolean} 			absolute	是否绝对定位(默认 false )
+	 * @property {Object}			customStyle	定义需要用到的外部样式
+	 * @example <u-badge :type="type" :count="count"></u-badge>
+	 */
+	export default {
+		name: 'u-badge',
+		mixins: [mpMixin, props, mixin],
+		computed: {
+			// 是否将badge中心与父组件右上角重合
+			boxStyle() {
+				let style = {};
+				return style;
+			},
+			// 整个组件的样式
+			badgeStyle() {
+				const style = {}
+				if(this.color) {
+					style.color = this.color
+				}
+				if (this.bgColor && !this.inverted) {
+					style.backgroundColor = this.bgColor
+				}
+				if (this.absolute) {
+					style.position = 'absolute'
+					// 如果有设置offset参数
+					if(this.offset.length) {
+						// top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top
+						const top = this.offset[0]
+						const right = this.offset[1] || top
+						style.top = addUnit(top)
+						style.right = addUnit(right)
+					}
+				}
+				return style
+			},
+			showValue() {
+				switch (this.numberType) {
+					case "overflow":
+						return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
+						break;
+					case "ellipsis":
+						return Number(this.value) > Number(this.max) ? "..." : this.value
+						break;
+					case "limit":
+						return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
+							Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
+								1e3 * 100) / 100 + "k" : this.value
+						break;
+					default:
+						return Number(this.value)
+				}
+			},
+		},
+		methods: {
+			addStyle
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+
+	$u-badge-primary: $u-primary !default;
+	$u-badge-error: $u-error !default;
+	$u-badge-success: $u-success !default;
+	$u-badge-info: $u-info !default;
+	$u-badge-warning: $u-warning !default;
+	$u-badge-dot-radius: 100px !default;
+	$u-badge-dot-size: 8px !default;
+	$u-badge-dot-right: 4px !default;
+	$u-badge-dot-top: 0 !default;
+	$u-badge-text-font-size: 11px !default;
+	$u-badge-text-right: 10px !default;
+	$u-badge-text-padding: 2px 5px !default;
+	$u-badge-text-align: center !default;
+	$u-badge-text-color: #FFFFFF !default;
+
+	.u-badge {
+		border-top-right-radius: $u-badge-dot-radius;
+		border-top-left-radius: $u-badge-dot-radius;
+		border-bottom-left-radius: $u-badge-dot-radius;
+		border-bottom-right-radius: $u-badge-dot-radius;
+		@include flex;
+		line-height: $u-badge-text-font-size;
+		text-align: $u-badge-text-align;
+		font-size: $u-badge-text-font-size;
+		color: $u-badge-text-color;
+
+		&--dot {
+			height: $u-badge-dot-size;
+			width: $u-badge-dot-size;
+		}
+		
+		&--inverted {
+			font-size: 13px;
+		}
+		
+		&--not-dot {
+			padding: $u-badge-text-padding;
+		}
+
+		&--horn {
+			border-bottom-left-radius: 0;
+		}
+
+		&--primary {
+			background-color: $u-badge-primary;
+		}
+		
+		&--primary--inverted {
+			color: $u-badge-primary;
+		}
+
+		&--error {
+			background-color: $u-badge-error;
+		}
+		
+		&--error--inverted {
+			color: $u-badge-error;
+		}
+
+		&--success {
+			background-color: $u-badge-success;
+		}
+		
+		&--success--inverted {
+			color: $u-badge-success;
+		}
+
+		&--info {
+			background-color: $u-badge-info;
+		}
+		
+		&--info--inverted {
+			color: $u-badge-info;
+		}
+
+		&--warning {
+			background-color: $u-badge-warning;
+		}
+		
+		&--warning--inverted {
+			color: $u-badge-warning;
+		}
+	}
+</style>

+ 27 - 0
uni_modules/uview-plus/components/u-box/props.js

@@ -0,0 +1,27 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+
+export const propsBox = defineMixin({
+    props: {
+        // 背景色
+        bgColors: {
+            type: [Array],
+            default: ['#EEFCFF', '#FCF8FF', '#FDF8F2']
+        },
+        // 高度
+        height: {
+            type: [String],
+            default: "160px"
+        },
+        // 圆角
+        borderRadius: {
+            type: [String],
+            default: "6px"
+        },
+        // 间隔
+        gap: {
+            type: [String],
+            default: "15px"
+        },
+    }
+})

+ 91 - 0
uni_modules/uview-plus/components/u-box/u-box.vue

@@ -0,0 +1,91 @@
+<template>
+	<view class="u-box" :style="[{height: height}, addStyle(customStyle)]">
+        <view class="u-box__left" :style="{borderRadius: borderRadius, backgroundColor: bgColors[0]}">
+            <slot name="left">左</slot>
+        </view>
+        <view class="u-box__gap" :style="{width: gap, height: height}"></view>
+        <view class="u-box__right">
+            <view class="u-box__right-top" :style="{borderRadius: borderRadius, backgroundColor: bgColors[1]}">
+                <slot name="rightTop">右上</slot>
+            </view>
+            <view class="u-box__right-gap" :style="{height: gap}"></view>
+            <view class="u-box__right-bottom" :style="{borderRadius: borderRadius, backgroundColor: bgColors[2]}">
+                <slot name="rightBottom">右下</slot>
+            </view>
+        </view>
+	</view>
+</template>
+
+<script>
+	import { propsBox } from './props';
+	import { mpMixin } from '../../libs/mixin/mpMixin';
+	import { mixin } from '../../libs/mixin/mixin';
+	import { addStyle } from '../../libs/function/index';
+	import test from '../../libs/function/test';
+	/**
+	 * box 盒子
+	 * @description box盒子一般为左边一个盒子,右侧两个等高的半盒组成,常用于App首页座位重点突出。
+	 * @tutorial https://uview-plus.jiangruyi.com/components/box.html
+	 * @property {Array}	bgColors			背景色
+	 * @property {String}	height			    高度
+     * @property {String}	borderRadius		圆角
+	 * @property {Object}   customStyle		    定义需要用到的外部样式
+	 * 
+	 * @event {Function}			click			点击cell列表时触发
+	 * @example <up-box colors=['blue', 'red', 'yellow'] height="200px"></up-box>
+	 */
+	export default {
+		name: 'up-box',
+		data() {
+			return {
+			}
+		},
+		mixins: [mpMixin, mixin, propsBox],
+		computed: {
+		},
+		emits: [],
+		methods: {
+			addStyle,
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+
+	.u-box {
+        /* #ifndef APP-NVUE */
+        /* #endif */
+        @include flex();
+        flex: 1;
+
+		&__left {
+            @include flex();
+            justify-content: center;
+            align-items: center;
+            flex: 1;
+        }
+        &__gap {
+            @include flex();
+            flex-direction: column;
+        }
+        &__right {
+            @include flex();
+            flex-direction: column;
+            flex: 1;
+        }
+
+        &__right-top {
+            @include flex();
+            flex: 1;
+            justify-content: center;
+            align-items: center;
+        }
+
+        &__right-bottom {
+            @include flex();
+            flex: 1;
+            justify-content: center;
+            align-items: center;
+        }
+	}
+</style>

+ 43 - 0
uni_modules/uview-plus/components/u-button/button.js

@@ -0,0 +1,43 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:51:27
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/button.js
+ */
+export default {
+    // button组件
+    button: {
+        hairline: false,
+        type: 'info',
+        size: 'normal',
+        shape: 'square',
+        plain: false,
+        disabled: false,
+        loading: false,
+        loadingText: '',
+        loadingMode: 'spinner',
+        loadingSize: 15,
+        openType: '',
+        formType: '',
+        appParameter: '',
+        hoverStopPropagation: true,
+        lang: 'en',
+        sessionFrom: '',
+        sendMessageTitle: '',
+        sendMessagePath: '',
+        sendMessageImg: '',
+        showMessageCard: false,
+        dataName: '',
+        throttleTime: 0,
+        hoverStartTime: 0,
+        hoverStayTime: 200,
+        text: '',
+        icon: '',
+        iconColor: '',
+        color: '',
+        stop: true,
+    }
+}

+ 46 - 0
uni_modules/uview-plus/components/u-button/nvue.scss

@@ -0,0 +1,46 @@
+$u-button-active-opacity:0.75 !default;
+$u-button-loading-text-margin-left:4px !default;
+$u-button-text-color: #FFFFFF !default;
+$u-button-text-plain-error-color:$u-error !default;
+$u-button-text-plain-warning-color:$u-warning !default;
+$u-button-text-plain-success-color:$u-success !default;
+$u-button-text-plain-info-color:$u-info !default;
+$u-button-text-plain-primary-color:$u-primary !default;
+.u-button {
+	&--active {
+		opacity: $u-button-active-opacity;
+	}
+	
+	&--active--plain {
+		background-color: rgb(217, 217, 217);
+	}
+	
+	&__loading-text {
+		margin-left:$u-button-loading-text-margin-left;
+	}
+	
+	&__text,
+	&__loading-text {
+		color:$u-button-text-color;
+	}
+	
+	&__text--plain--error {
+		color:$u-button-text-plain-error-color;
+	}
+	
+	&__text--plain--warning {
+		color:$u-button-text-plain-warning-color;
+	}
+	
+	&__text--plain--success{
+		color:$u-button-text-plain-success-color;
+	}
+	
+	&__text--plain--info {
+		color:$u-button-text-plain-info-color;
+	}
+	
+	&__text--plain--primary {
+		color:$u-button-text-plain-primary-color;
+	}
+}

+ 159 - 0
uni_modules/uview-plus/components/u-button/props.js

@@ -0,0 +1,159 @@
+import { defineMixin } from '../../libs/vue'
+import defProps from '../../libs/config/props.js'
+export const props = defineMixin({
+    props: {
+        // 是否细边框
+        hairline: {
+            type: Boolean,
+            default: () => defProps.button.hairline
+        },
+        // 按钮的预置样式,info,primary,error,warning,success
+        type: {
+            type: String,
+            default: () => defProps.button.type
+        },
+        // 按钮尺寸,large,normal,small,mini
+        size: {
+            type: String,
+            default: () => defProps.button.size
+        },
+        // 按钮形状,circle(两边为半圆),square(带圆角)
+        shape: {
+            type: String,
+            default: () => defProps.button.shape
+        },
+        // 按钮是否镂空
+        plain: {
+            type: Boolean,
+            default: () => defProps.button.plain
+        },
+        // 是否禁止状态
+        disabled: {
+            type: Boolean,
+            default: () => defProps.button.disabled
+        },
+        // 是否加载中
+        loading: {
+            type: Boolean,
+            default: () => defProps.button.loading
+        },
+        // 加载中提示文字
+        loadingText: {
+            type: [String, Number],
+            default: () => defProps.button.loadingText
+        },
+        // 加载状态图标类型
+        loadingMode: {
+            type: String,
+            default: () => defProps.button.loadingMode
+        },
+        // 加载图标大小
+        loadingSize: {
+            type: [String, Number],
+            default: () => defProps.button.loadingSize
+        },
+        // 开放能力,具体请看uniapp稳定关于button组件部分说明
+        // https://uniapp.dcloud.io/component/button
+        openType: {
+            type: String,
+            default: () => defProps.button.openType
+        },
+        // 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
+        // 取值为submit(提交表单),reset(重置表单)
+        formType: {
+            type: String,
+            default: () => defProps.button.formType
+        },
+        // 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
+        // 只微信小程序、QQ小程序有效
+        appParameter: {
+            type: String,
+            default: () => defProps.button.appParameter
+        },
+        // 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
+        hoverStopPropagation: {
+            type: Boolean,
+            default: () => defProps.button.hoverStopPropagation
+        },
+        // 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
+        lang: {
+            type: String,
+            default: () => defProps.button.lang
+        },
+        // 会话来源,open-type="contact"时有效。只微信小程序有效
+        sessionFrom: {
+            type: String,
+            default: () => defProps.button.sessionFrom
+        },
+        // 会话内消息卡片标题,open-type="contact"时有效
+        // 默认当前标题,只微信小程序有效
+        sendMessageTitle: {
+            type: String,
+            default: () => defProps.button.sendMessageTitle
+        },
+        // 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
+        // 默认当前分享路径,只微信小程序有效
+        sendMessagePath: {
+            type: String,
+            default: () => defProps.button.sendMessagePath
+        },
+        // 会话内消息卡片图片,open-type="contact"时有效
+        // 默认当前页面截图,只微信小程序有效
+        sendMessageImg: {
+            type: String,
+            default: () => defProps.button.sendMessageImg
+        },
+        // 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
+        // 用户点击后可以快速发送小程序消息,open-type="contact"时有效
+        showMessageCard: {
+            type: Boolean,
+            default: () => defProps.button.showMessageCard
+        },
+        // 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
+        dataName: {
+            type: String,
+            default: () => defProps.button.dataName
+        },
+        // 节流,一定时间内只能触发一次
+        throttleTime: {
+            type: [String, Number],
+            default: () => defProps.button.throttleTime
+        },
+        // 按住后多久出现点击态,单位毫秒
+        hoverStartTime: {
+            type: [String, Number],
+            default: () => defProps.button.hoverStartTime
+        },
+        // 手指松开后点击态保留时间,单位毫秒
+        hoverStayTime: {
+            type: [String, Number],
+            default: () => defProps.button.hoverStayTime
+        },
+        // 按钮文字,之所以通过props传入,是因为slot传入的话
+        // nvue中无法控制文字的样式
+        text: {
+            type: [String, Number],
+            default: () => defProps.button.text
+        },
+        // 按钮图标
+        icon: {
+            type: String,
+            default: () => defProps.button.icon
+        },
+        // 按钮图标
+        iconColor: {
+            type: String,
+            default: () => defProps.button.icon
+        },
+        // 按钮颜色,支持传入linear-gradient渐变色
+        color: {
+            type: String,
+            default: () => defProps.button.color
+        },
+        // 停止冒泡
+        stop: {
+            type: Boolean,
+            default: () => defProps.button.stop
+        },
+    }
+})

+ 503 - 0
uni_modules/uview-plus/components/u-button/u-button.vue

@@ -0,0 +1,503 @@
+<template>
+    <!-- #ifndef APP-NVUE -->
+    <button
+        :hover-start-time="Number(hoverStartTime)"
+        :hover-stay-time="Number(hoverStayTime)"
+        :form-type="formType"
+        :open-type="openType"
+        :app-parameter="appParameter"
+        :hover-stop-propagation="hoverStopPropagation"
+        :send-message-title="sendMessageTitle"
+        :send-message-path="sendMessagePath"
+        :lang="lang"
+        :data-name="dataName"
+        :session-from="sessionFrom"
+        :send-message-img="sendMessageImg"
+        :show-message-card="showMessageCard"
+        @getphonenumber="getphonenumber"
+        @getuserinfo="getuserinfo"
+        @error="error"
+        @opensetting="opensetting"
+        @launchapp="launchapp"
+        @agreeprivacyauthorization="agreeprivacyauthorization"
+        :hover-class="!disabled && !loading ? 'u-button--active' : ''"
+        class="u-button u-reset-button"
+        :style="[baseColor, addStyle(customStyle)]"
+        @tap="clickHandler"
+        :class="bemClass"
+    >
+        <template v-if="loading">
+            <u-loading-icon
+                :mode="loadingMode"
+                :size="loadingSize * 1.15"
+                :color="loadingColor"
+            ></u-loading-icon>
+            <text
+                class="u-button__loading-text"
+                :style="[{ fontSize: textSize + 'px' }]"
+                >{{ loadingText || text }}</text
+            >
+        </template>
+        <template v-else>
+            <u-icon
+                v-if="icon"
+                :name="icon"
+                :color="iconColorCom"
+                :size="textSize * 1.35"
+                :customStyle="{ marginRight: '2px' }"
+            ></u-icon>
+            <slot>
+                <text
+                    class="u-button__text"
+                    :style="[{ fontSize: textSize + 'px' }]"
+                    >{{ text }}</text
+                >
+            </slot>
+        </template>
+    </button>
+    <!-- #endif -->
+
+    <!-- #ifdef APP-NVUE -->
+    <view
+        :hover-start-time="Number(hoverStartTime)"
+        :hover-stay-time="Number(hoverStayTime)"
+        class="u-button"
+        :hover-class="
+            !disabled && !loading && !color && (plain || type === 'info')
+                ? 'u-button--active--plain'
+                : !disabled && !loading && !plain
+                ? 'u-button--active'
+                : ''
+        "
+        @tap="clickHandler"
+        :class="bemClass"
+        :style="[baseColor, addStyle(customStyle)]"
+    >
+        <template v-if="loading">
+            <u-loading-icon
+                :mode="loadingMode"
+                :size="loadingSize * 1.15"
+                :color="loadingColor"
+            ></u-loading-icon>
+            <text
+                class="u-button__loading-text"
+                :style="[nvueTextStyle]"
+                :class="[plain && `u-button__text--plain--${type}`]"
+                >{{ loadingText || text }}</text
+            >
+        </template>
+        <template v-else>
+            <u-icon
+                v-if="icon"
+                :name="icon"
+                :color="iconColorCom"
+                :size="textSize * 1.35"
+            ></u-icon>
+            <text
+                class="u-button__text"
+                :style="[
+                    {
+                        marginLeft: icon ? '2px' : 0,
+                    },
+                    nvueTextStyle,
+                ]"
+                :class="[plain && `u-button__text--plain--${type}`]"
+                >{{ text }}</text
+            >
+        </template>
+    </view>
+    <!-- #endif -->
+</template>
+
+<script lang="ts">
+import { buttonMixin } from "../../libs/mixin/button";
+import { openType } from "../../libs/mixin/openType";
+import { mpMixin } from '../../libs/mixin/mpMixin';
+import { mixin } from '../../libs/mixin/mixin';
+import { props } from "./props";
+import { addStyle } from '../../libs/function/index';
+import { throttle } from '../../libs/function/throttle';
+import color from '../../libs/config/color';
+/**
+ * button 按钮
+ * @description Button 按钮
+ * @tutorial https://ijry.github.io/uview-plus/components/button.html
+ *
+ * @property {Boolean}			hairline				是否显示按钮的细边框 (默认 true )
+ * @property {String}			type					按钮的预置样式,info,primary,error,warning,success (默认 'info' )
+ * @property {String}			size					按钮尺寸,large,normal,mini (默认 normal)
+ * @property {String}			shape					按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' )
+ * @property {Boolean}			plain					按钮是否镂空,背景色透明 (默认 false)
+ * @property {Boolean}			disabled				是否禁用 (默认 false)
+ * @property {Boolean}			loading					按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false)
+ * @property {String | Number}	loadingText				加载中提示文字
+ * @property {String}			loadingMode				加载状态图标类型 (默认 'spinner' )
+ * @property {String | Number}	loadingSize				加载图标大小 (默认 15 )
+ * @property {String}			openType				开放能力,具体请看uniapp稳定关于button组件部分说明
+ * @property {String}			formType				用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
+ * @property {String}			appParameter			打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效)
+ * @property {Boolean}			hoverStopPropagation	指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true )
+ * @property {String}			lang					指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en )
+ * @property {String}			sessionFrom				会话来源,openType="contact"时有效
+ * @property {String}			sendMessageTitle		会话内消息卡片标题,openType="contact"时有效
+ * @property {String}			sendMessagePath			会话内消息卡片点击跳转小程序路径,openType="contact"时有效
+ * @property {String}			sendMessageImg			会话内消息卡片图片,openType="contact"时有效
+ * @property {Boolean}			showMessageCard			是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false)
+ * @property {String}			dataName				额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
+ * @property {String | Number}	throttleTime			节流,一定时间内只能触发一次 (默认 0 )
+ * @property {String | Number}	hoverStartTime			按住后多久出现点击态,单位毫秒 (默认 0 )
+ * @property {String | Number}	hoverStayTime			手指松开后点击态保留时间,单位毫秒 (默认 200 )
+ * @property {String | Number}	text					按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式)
+ * @property {String}			icon					按钮图标
+ * @property {String}			iconColor				按钮图标颜色
+ * @property {String}			color					按钮颜色,支持传入linear-gradient渐变色
+ * @property {Object}			customStyle				定义需要用到的外部样式
+ *
+ * @event {Function}	click			非禁止并且非加载中,才能点击
+ * @event {Function}	getphonenumber	open-type="getPhoneNumber"时有效
+ * @event {Function}	getuserinfo		用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
+ * @event {Function}	error			当使用开放能力时,发生错误的回调
+ * @event {Function}	opensetting		在打开授权设置页并关闭后回调
+ * @event {Function}	launchapp		打开 APP 成功的回调
+ * @event {Function}	agreeprivacyauthorization	用户同意隐私协议事件回调
+ * @example <u-button>月落</u-button>
+ */
+export default {
+    name: "u-button",
+    // #ifdef MP
+    mixins: [mpMixin, mixin, buttonMixin, openType, props],
+    // #endif
+    // #ifndef MP
+    mixins: [mpMixin, mixin, props],
+    // #endif
+    data() {
+        return {};
+    },
+    computed: {
+        // 生成bem风格的类名
+        bemClass() {
+            // this.bem为一个computed变量,在mixin中
+            if (!this.color) {
+                return this.bem(
+                    "button",
+                    ["type", "shape", "size"],
+                    ["disabled", "plain", "hairline"]
+                );
+            } else {
+                // 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式
+                return this.bem(
+                    "button",
+                    ["shape", "size"],
+                    ["disabled", "plain", "hairline"]
+                );
+            }
+        },
+        loadingColor() {
+            if (this.plain) {
+                // 如果有设置color值,则用color值,否则使用type主题颜色
+                return this.color
+                    ? this.color
+                    : color[`u-${this.type}`];
+            }
+            if (this.type === "info") {
+                return "#c9c9c9";
+            }
+            return "rgb(200, 200, 200)";
+        },
+        iconColorCom() {
+            // 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
+            // u-icon的color能接受一个主题颜色的值
+			if (this.iconColor) return this.iconColor;
+			if (this.plain) {
+                return this.color ? this.color : this.type;
+            } else {
+                return this.type === "info" ? "#000000" : "#ffffff";
+            }
+        },
+        baseColor() {
+            let style = {};
+            if (this.color) {
+                // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
+                style.color = this.plain ? this.color : "white";
+                if (!this.plain) {
+                    // 非镂空,背景色使用自定义的颜色
+                    style["background-color"] = this.color;
+                }
+                if (this.color.indexOf("gradient") !== -1) {
+                    // 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色
+                    // weex文档说明可以写borderWidth的形式,为什么这里需要分开写?
+                    // 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效
+                    style.borderTopWidth = 0;
+                    style.borderRightWidth = 0;
+                    style.borderBottomWidth = 0;
+                    style.borderLeftWidth = 0;
+                    if (!this.plain) {
+                        style.backgroundImage = this.color;
+                    }
+                } else {
+                    // 非渐变色,则设置边框相关的属性
+                    style.borderColor = this.color;
+                    style.borderWidth = "1px";
+                    style.borderStyle = "solid";
+                }
+            }
+            return style;
+        },
+        // nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
+        nvueTextStyle() {
+            let style = {};
+            // 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
+            if (this.type === "info") {
+                style.color = "#323233";
+            }
+            if (this.color) {
+                style.color = this.plain ? this.color : "white";
+            }
+            style.fontSize = this.textSize + "px";
+            return style;
+        },
+        // 字体大小
+        textSize() {
+            let fontSize = 14,
+                { size } = this;
+            if (size === "large") fontSize = 16;
+            if (size === "normal") fontSize = 14;
+            if (size === "small") fontSize = 12;
+            if (size === "mini") fontSize = 10;
+            return fontSize;
+        },
+    },
+	emits: ['click', 'getphonenumber', 'getuserinfo',
+		'error', 'opensetting', 'launchapp', 'agreeprivacyauthorization'],
+    methods: {
+        addStyle,
+        clickHandler(e: any) {
+            // 非禁止并且非加载中,才能点击
+            if (!this.disabled && !this.loading) {
+				// 进行节流控制,每this.throttle毫秒内,只在开始处执行
+				throttle(() => {
+					this.$emit("click", e);
+				}, this.throttleTime);
+            }
+            // 是否阻止事件传播
+            this.stop && this.preventEvent(e)
+        },
+        // 下面为对接uniapp官方按钮开放能力事件回调的对接
+        getphonenumber(res: any) {
+            this.$emit("getphonenumber", res);
+        },
+        getuserinfo(res: any) {
+            this.$emit("getuserinfo", res);
+        },
+        error(res: any) {
+            this.$emit("error", res);
+        },
+        opensetting(res: any) {
+            this.$emit("opensetting", res);
+        },
+        launchapp(res: any) {
+            this.$emit("launchapp", res);
+        },
+        agreeprivacyauthorization(res) {
+            this.$emit("agreeprivacyauthorization", res);
+        },
+    },
+};
+</script>
+
+<style lang="scss" scoped>
+/* #ifndef APP-NVUE */
+@import "./vue.scss";
+/* #endif */
+
+/* #ifdef APP-NVUE */
+@import "./nvue.scss";
+/* #endif */
+
+$u-button-u-button-height: 40px !default;
+$u-button-text-font-size: 15px !default;
+$u-button-loading-text-font-size: 15px !default;
+$u-button-loading-text-margin-left: 4px !default;
+$u-button-large-width: 100% !default;
+$u-button-large-height: 50px !default;
+$u-button-normal-padding: 0 12px !default;
+$u-button-large-padding: 0 15px !default;
+$u-button-normal-font-size: 14px !default;
+$u-button-small-min-width: 60px !default;
+$u-button-small-height: 30px !default;
+$u-button-small-padding: 0px 8px !default;
+$u-button-mini-padding: 0px 8px !default;
+$u-button-small-font-size: 12px !default;
+$u-button-mini-height: 22px !default;
+$u-button-mini-font-size: 10px !default;
+$u-button-mini-min-width: 50px !default;
+$u-button-disabled-opacity: 0.5 !default;
+$u-button-info-color: #323233 !default;
+$u-button-info-background-color: #fff !default;
+$u-button-info-border-color: #ebedf0 !default;
+$u-button-info-border-width: 1px !default;
+$u-button-info-border-style: solid !default;
+$u-button-success-color: #fff !default;
+$u-button-success-background-color: $u-success !default;
+$u-button-success-border-color: $u-button-success-background-color !default;
+$u-button-success-border-width: 1px !default;
+$u-button-success-border-style: solid !default;
+$u-button-primary-color: #fff !default;
+$u-button-primary-background-color: $u-primary !default;
+$u-button-primary-border-color: $u-button-primary-background-color !default;
+$u-button-primary-border-width: 1px !default;
+$u-button-primary-border-style: solid !default;
+$u-button-error-color: #fff !default;
+$u-button-error-background-color: $u-error !default;
+$u-button-error-border-color: $u-button-error-background-color !default;
+$u-button-error-border-width: 1px !default;
+$u-button-error-border-style: solid !default;
+$u-button-warning-color: #fff !default;
+$u-button-warning-background-color: $u-warning !default;
+$u-button-warning-border-color: $u-button-warning-background-color !default;
+$u-button-warning-border-width: 1px !default;
+$u-button-warning-border-style: solid !default;
+$u-button-block-width: 100% !default;
+$u-button-circle-border-top-right-radius: 100px !default;
+$u-button-circle-border-top-left-radius: 100px !default;
+$u-button-circle-border-bottom-left-radius: 100px !default;
+$u-button-circle-border-bottom-right-radius: 100px !default;
+$u-button-square-border-top-right-radius: 3px !default;
+$u-button-square-border-top-left-radius: 3px !default;
+$u-button-square-border-bottom-left-radius: 3px !default;
+$u-button-square-border-bottom-right-radius: 3px !default;
+$u-button-icon-min-width: 1em !default;
+$u-button-plain-background-color: #fff !default;
+$u-button-hairline-border-width: 0.5px !default;
+
+.u-button {
+    height: $u-button-u-button-height;
+    position: relative;
+    align-items: center;
+    justify-content: center;
+    @include flex;
+    /* #ifndef APP-NVUE */
+    box-sizing: border-box;
+    /* #endif */
+    flex-direction: row;
+
+    &__text {
+        font-size: $u-button-text-font-size;
+    }
+
+    &__loading-text {
+        font-size: $u-button-loading-text-font-size;
+        margin-left: $u-button-loading-text-margin-left;
+    }
+
+    &--large {
+        /* #ifndef APP-NVUE */
+        width: $u-button-large-width;
+        /* #endif */
+        height: $u-button-large-height;
+        padding: $u-button-large-padding;
+    }
+
+    &--normal {
+        padding: $u-button-normal-padding;
+        font-size: $u-button-normal-font-size;
+    }
+
+    &--small {
+        /* #ifndef APP-NVUE */
+        min-width: $u-button-small-min-width;
+        /* #endif */
+        height: $u-button-small-height;
+        padding: $u-button-small-padding;
+        font-size: $u-button-small-font-size;
+    }
+
+    &--mini {
+        height: $u-button-mini-height;
+        font-size: $u-button-mini-font-size;
+        /* #ifndef APP-NVUE */
+        min-width: $u-button-mini-min-width;
+        /* #endif */
+        padding: $u-button-mini-padding;
+    }
+
+    &--disabled {
+        opacity: $u-button-disabled-opacity;
+    }
+
+    &--info {
+        color: $u-button-info-color;
+        background-color: $u-button-info-background-color;
+        border-color: $u-button-info-border-color;
+        border-width: $u-button-info-border-width;
+        border-style: $u-button-info-border-style;
+    }
+
+    &--success {
+        color: $u-button-success-color;
+        background-color: $u-button-success-background-color;
+        border-color: $u-button-success-border-color;
+        border-width: $u-button-success-border-width;
+        border-style: $u-button-success-border-style;
+    }
+
+    &--primary {
+        color: $u-button-primary-color;
+        background-color: $u-button-primary-background-color;
+        border-color: $u-button-primary-border-color;
+        border-width: $u-button-primary-border-width;
+        border-style: $u-button-primary-border-style;
+    }
+
+    &--error {
+        color: $u-button-error-color;
+        background-color: $u-button-error-background-color;
+        border-color: $u-button-error-border-color;
+        border-width: $u-button-error-border-width;
+        border-style: $u-button-error-border-style;
+    }
+
+    &--warning {
+        color: $u-button-warning-color;
+        background-color: $u-button-warning-background-color;
+        border-color: $u-button-warning-border-color;
+        border-width: $u-button-warning-border-width;
+        border-style: $u-button-warning-border-style;
+    }
+
+    &--block {
+        @include flex;
+        width: $u-button-block-width;
+    }
+
+    &--circle {
+        border-top-right-radius: $u-button-circle-border-top-right-radius;
+        border-top-left-radius: $u-button-circle-border-top-left-radius;
+        border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
+        border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
+    }
+
+    &--square {
+        border-bottom-left-radius: $u-button-square-border-top-right-radius;
+        border-bottom-right-radius: $u-button-square-border-top-left-radius;
+        border-top-left-radius: $u-button-square-border-bottom-left-radius;
+        border-top-right-radius: $u-button-square-border-bottom-right-radius;
+    }
+
+    &__icon {
+        /* #ifndef APP-NVUE */
+        min-width: $u-button-icon-min-width;
+        line-height: inherit !important;
+        vertical-align: top;
+        /* #endif */
+    }
+
+    &--plain {
+        background-color: $u-button-plain-background-color;
+    }
+
+    &--hairline {
+        border-width: $u-button-hairline-border-width !important;
+    }
+}
+</style>

+ 81 - 0
uni_modules/uview-plus/components/u-button/vue.scss

@@ -0,0 +1,81 @@
+// nvue下hover-class无效
+$u-button-before-top:50% !default;
+$u-button-before-left:50% !default;
+$u-button-before-width:100% !default;
+$u-button-before-height:100% !default;
+$u-button-before-transform:translate(-50%, -50%) !default;
+$u-button-before-opacity:0 !default;
+$u-button-before-background-color:#000 !default;
+$u-button-before-border-color:#000 !default;
+$u-button-active-before-opacity:.15 !default;
+$u-button-icon-margin-left:4px !default;
+$u-button-plain-u-button-info-color:$u-info;
+$u-button-plain-u-button-success-color:$u-success;
+$u-button-plain-u-button-error-color:$u-error;
+$u-button-plain-u-button-warning-color:$u-warning;
+
+.u-button {
+	width: 100%;
+	white-space: nowrap;
+	
+	&__text {
+		white-space: nowrap;
+		line-height: 1;
+	}
+	
+	&:before {
+		position: absolute;
+		top:$u-button-before-top;
+		left:$u-button-before-left;
+		width:$u-button-before-width;
+		height:$u-button-before-height;
+		border: inherit;
+		border-radius: inherit;
+		transform:$u-button-before-transform;
+		opacity:$u-button-before-opacity;
+		content: " ";
+		background-color:$u-button-before-background-color;
+		border-color:$u-button-before-border-color;
+	}
+	
+	&--active {
+		&:before {
+			opacity: .15
+		}
+	}
+	
+	&__icon+&__text:not(:empty),
+	&__loading-text {
+		margin-left:$u-button-icon-margin-left;
+	}
+	
+	&--plain {
+		&.u-button--primary {
+			color: $u-primary;
+		}
+	}
+	
+	&--plain {
+		&.u-button--info {
+			color:$u-button-plain-u-button-info-color;
+		}
+	}
+	
+	&--plain {
+		&.u-button--success {
+			color:$u-button-plain-u-button-success-color;
+		}
+	}
+	
+	&--plain {
+		&.u-button--error {
+			color:$u-button-plain-u-button-error-color;
+		}
+	}
+	
+	&--plain {
+		&.u-button--warning {
+			color:$u-button-plain-u-button-warning-color;
+		}
+	}
+}

+ 45 - 0
uni_modules/uview-plus/components/u-calendar/calendar.js

@@ -0,0 +1,45 @@
+/*
+ * @Author       : LQ
+ * @Description  :
+ * @version      : 1.0
+ * @Date         : 2021-08-20 16:44:21
+ * @LastAuthor   : LQ
+ * @lastTime     : 2021-08-20 16:52:43
+ * @FilePath     : /u-view2.0/uview-ui/libs/config/props/calendar.js
+ */
+export default {
+    // calendar 组件
+    calendar: {
+        title: '日期选择',
+        showTitle: true,
+        showSubtitle: true,
+        mode: 'single',
+        startText: '开始',
+        endText: '结束',
+        customList: [],
+        color: '#3c9cff',
+        minDate: 0,
+        maxDate: 0,
+        defaultDate: null,
+        maxCount: Number.MAX_SAFE_INTEGER, // Infinity
+        rowHeight: 56,
+        formatter: null,
+        showLunar: false,
+        showMark: true,
+        confirmText: '确定',
+        confirmDisabledText: '确定',
+        show: false,
+        closeOnClickOverlay: false,
+        readonly: false,
+        showConfirm: true,
+        maxRange: Number.MAX_SAFE_INTEGER, // Infinity
+        rangePrompt: '',
+        showRangePrompt: true,
+        allowSameDay: false,
+		round: 0,
+		monthNum: 3,
+        weekText: ['一', '二', '三', '四', '五', '六', '日'],
+        forbidDays: [],
+        forbidDaysToast: '该日期已禁用',
+    }
+}

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.