新增部分图标
This commit is contained in:
parent
2d96d453ab
commit
b72ce523f1
|
|
@ -0,0 +1,166 @@
|
||||||
|
<template>
|
||||||
|
<view>
|
||||||
|
<view class="box-rds cankao">
|
||||||
|
<view class="top_title">
|
||||||
|
参考
|
||||||
|
</view>
|
||||||
|
<view class="flx jcsb lt_title">
|
||||||
|
<view class="flx ac">
|
||||||
|
<view class="little-circle color0">
|
||||||
|
</view>
|
||||||
|
<view class="wz">
|
||||||
|
偏低
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flx ac">
|
||||||
|
<view class="little-circle color1">
|
||||||
|
</view>
|
||||||
|
<view class="wz">
|
||||||
|
正常
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flx ac">
|
||||||
|
<view class="little-circle color2">
|
||||||
|
</view>
|
||||||
|
<view class="wz">
|
||||||
|
偏高
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="ck_tb">
|
||||||
|
<view :class="'flx jcsb ac'" v-for="(v,index) in cankaoData" :key="index">
|
||||||
|
<view class="tb_tt">
|
||||||
|
{{v.name}}
|
||||||
|
</view>
|
||||||
|
<view class=" zzt">
|
||||||
|
<view class="flx fd_row">
|
||||||
|
<view v-if="idx1 > 0" :class="'zzt-body color'+(idx1 - 1)" v-for="(vv,idx1) in v.data" :key="idx1" :style="'flex:'+ ((vv - v.data[idx1-1])/v.max)">
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="flx fd_row ">
|
||||||
|
<view v-if="idx1 > 0" :class="'flx '+ (idx1 == 1?'jcsb': 'jc-end')" v-for="(vv,idx1) in v.data" :key="idx1" :style="'flex:'+ (((vv - v.data[idx1-1])/v.max) + v.adjustment[idx1-1])">
|
||||||
|
<view class="font-small">
|
||||||
|
{{ idx1 == 1?v.data[idx1-1]:''}}
|
||||||
|
</view>
|
||||||
|
<view class="font-small">
|
||||||
|
{{vv}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name:"cankao",
|
||||||
|
props:{
|
||||||
|
cankaoData:Array,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped="scss">
|
||||||
|
.body-style {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
.color0{
|
||||||
|
background-color: #a6e6aa;
|
||||||
|
}
|
||||||
|
.color1{
|
||||||
|
background-color: #29cf6f;
|
||||||
|
}
|
||||||
|
.color2{
|
||||||
|
background-color: #fb8646;
|
||||||
|
}
|
||||||
|
.little-circle{
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 20rpx;
|
||||||
|
height: 20rpx;
|
||||||
|
|
||||||
|
}
|
||||||
|
.box-rds {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin: 20rpx;
|
||||||
|
|
||||||
|
}
|
||||||
|
.cankao{
|
||||||
|
.top_title{
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
.lt_title{
|
||||||
|
padding:20rpx 60rpx;
|
||||||
|
}
|
||||||
|
.wz{
|
||||||
|
font-size: 24rpx;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
color: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.ck_tb{
|
||||||
|
.tb_tt{
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
.zzt{
|
||||||
|
padding: 20rpx 0;
|
||||||
|
width: 60%;
|
||||||
|
.zzt-body{
|
||||||
|
height: 10rpx;
|
||||||
|
margin: 2rpx;
|
||||||
|
}
|
||||||
|
.zzt-body:nth-child(1){
|
||||||
|
border-top-left-radius: 10rpx;
|
||||||
|
border-bottom-left-radius: 10rpx;;
|
||||||
|
}
|
||||||
|
.zzt-body:nth-child(3){
|
||||||
|
border-top-right-radius: 10rpx;
|
||||||
|
border-bottom-right-radius: 10rpx;;
|
||||||
|
}
|
||||||
|
.font-small{
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flx{
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
}
|
||||||
|
.jc-end{
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
.jc-start{
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
.ac{
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.jc{
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.jcsb{
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.fd_row{
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -35,6 +35,13 @@
|
||||||
{
|
{
|
||||||
"path": "pages/login/explain",
|
"path": "pages/login/explain",
|
||||||
"style": {}
|
"style": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path" : "pages/index/echarts",
|
||||||
|
"style" :
|
||||||
|
{
|
||||||
|
"navigationBarTitleText" : ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// "tabBar": {
|
// "tabBar": {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,609 @@
|
||||||
|
<template>
|
||||||
|
<view class="body-style">
|
||||||
|
<tm-nav-bar left-icon="arrow-left" :title="dataConfig[type].name" @clickLeft="back" />
|
||||||
|
<view class="flx jcsb ac" style="height: 40rpx;background-color: #fff;padding: 20rpx;">
|
||||||
|
<view class="" style="font-size: 40rpx;font-weight: bold;">
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<view class="" style="color: #b8b8b8;font-size: 24rpx;">
|
||||||
|
{{time}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view style="height: 40rpx;background-color: #fff;">
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<!-- <view class="title flx ac" style="justify-content: center;">
|
||||||
|
<view class="title-data">
|
||||||
|
{{dataConfig[type].title}}
|
||||||
|
</view>
|
||||||
|
<view class="title-unit">
|
||||||
|
{{dataConfig[type].unit}}
|
||||||
|
</view>
|
||||||
|
</view> -->
|
||||||
|
<view style=" height:600rpx;background-color: #fff;"><l-echart ref="chartRef" @finished="init"></l-echart></view>
|
||||||
|
|
||||||
|
<cankao v-if="dataConfig[type].cankaoData" :cankaoData="dataConfig[type].cankaoData" ></cankao>
|
||||||
|
<view class="box-rds " @click="goPath">
|
||||||
|
<view class="flx jcsb ac">
|
||||||
|
<view class="" style="font-size: 26rpx;">
|
||||||
|
全部数据
|
||||||
|
</view>
|
||||||
|
<view style="color: #b8b8b8;">></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="" style="height: 20rpx;">
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
|
||||||
|
import { mapGetters } from "vuex";
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
time: new Date().toISOString().substring(0, 10),
|
||||||
|
type:'',
|
||||||
|
desc:'',
|
||||||
|
dataConfig:{
|
||||||
|
bloodGlucose:{
|
||||||
|
title:'123123',
|
||||||
|
name:'血糖',
|
||||||
|
color:"#fb8544",
|
||||||
|
unit:'毫摩尔/升',
|
||||||
|
cankaoData:[
|
||||||
|
{
|
||||||
|
name:'空腹/餐前',
|
||||||
|
data:[
|
||||||
|
0,3.9,6.1,15
|
||||||
|
],
|
||||||
|
adjustment:[
|
||||||
|
0.05,
|
||||||
|
0.00,
|
||||||
|
-0.05
|
||||||
|
],
|
||||||
|
max:15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'餐后1小时',
|
||||||
|
data:[
|
||||||
|
0,6.7,9.4,15
|
||||||
|
],
|
||||||
|
adjustment:[
|
||||||
|
0.04,
|
||||||
|
0.00,
|
||||||
|
-0.04
|
||||||
|
],
|
||||||
|
max:15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name:'餐后2小时',
|
||||||
|
data:[
|
||||||
|
0,4.4,7.8,15
|
||||||
|
],
|
||||||
|
adjustment:[
|
||||||
|
0.04,
|
||||||
|
0.00,
|
||||||
|
-0.04
|
||||||
|
],
|
||||||
|
max:15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
bloodOxygen:{
|
||||||
|
title:'123123',
|
||||||
|
name:'血氧',
|
||||||
|
color:"#bf32fc",
|
||||||
|
unit:'%',
|
||||||
|
cankaoData:false,
|
||||||
|
|
||||||
|
},
|
||||||
|
bodyTemperature:{
|
||||||
|
title:'bodyTemperature',
|
||||||
|
name:'体温',
|
||||||
|
color:"#bf32fc",
|
||||||
|
unit:'℃',
|
||||||
|
cankaoData:false,
|
||||||
|
},
|
||||||
|
|
||||||
|
pulseReat:{
|
||||||
|
title:'123123',
|
||||||
|
name:'心率',
|
||||||
|
color:"#fd5656",
|
||||||
|
unit:'次/分',
|
||||||
|
cankaoData:false,
|
||||||
|
|
||||||
|
},
|
||||||
|
bloodLiquid:{
|
||||||
|
title:'123123',
|
||||||
|
name:'尿酸',
|
||||||
|
color:"#f00",
|
||||||
|
unit:'微摩尔/升',
|
||||||
|
cankaoData:[
|
||||||
|
{
|
||||||
|
name:'尿酸',
|
||||||
|
data:[
|
||||||
|
0,150,420,1000
|
||||||
|
],
|
||||||
|
adjustment:[
|
||||||
|
0.06,
|
||||||
|
0.00,
|
||||||
|
-0.06
|
||||||
|
],
|
||||||
|
max:1000
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
option:{
|
||||||
|
xAxis: {
|
||||||
|
splitLine:{
|
||||||
|
show:false
|
||||||
|
},
|
||||||
|
type:'value',
|
||||||
|
max:4,
|
||||||
|
min:0,
|
||||||
|
axisLabel: {
|
||||||
|
show: true,
|
||||||
|
|
||||||
|
splitNumber:2,
|
||||||
|
formatter: function(value, index) {
|
||||||
|
let arr = ['12am', '6am', '12pm', '6pm', '12am']
|
||||||
|
return arr[ Math.floor(index)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
yAxis: {
|
||||||
|
splitLine:{
|
||||||
|
show:true,
|
||||||
|
lineStyle: {
|
||||||
|
// 使用深浅的间隔色
|
||||||
|
color: ["#ccc"],
|
||||||
|
type:"dashed"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false // 设置y轴线不显示
|
||||||
|
},
|
||||||
|
axisLabel: {},
|
||||||
|
position:"right",
|
||||||
|
splitNumber:3
|
||||||
|
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
symbolSize: 5,
|
||||||
|
data:
|
||||||
|
[
|
||||||
|
|
||||||
|
// [0.5, 3.5],
|
||||||
|
// [1.2, 2.4],
|
||||||
|
// [1.4, 2.8],
|
||||||
|
// [2.7, 2.4],
|
||||||
|
// [3.4, 6],
|
||||||
|
],
|
||||||
|
markLine: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
yAxis: 2.5, // 在 y 值为 100 的位置添加水平参考线
|
||||||
|
}
|
||||||
|
],
|
||||||
|
lineStyle:{
|
||||||
|
color:'#ccc',
|
||||||
|
cap:"butt"
|
||||||
|
},
|
||||||
|
label:{
|
||||||
|
color:'#ccc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
type: 'scatter',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
option2: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
|
},
|
||||||
|
confine: true
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['热度', '正面', '负面']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 15,
|
||||||
|
top: 40,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#999999'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666666',
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
axisTick: { show: false },
|
||||||
|
data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#999999'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666666'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '热度',
|
||||||
|
type: 'bar',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'inside'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [300, 270, 340, 344, 300, 320, 310],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '正面',
|
||||||
|
type: 'bar',
|
||||||
|
stack: '总量',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [120, 102, 141, 174, 190, 250, 220]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '负面',
|
||||||
|
type: 'bar',
|
||||||
|
stack: '总量',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'left'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [-20, -32, -21, -34, -90, -130, -110]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(e) {
|
||||||
|
this.type = e.type
|
||||||
|
this.desc = e.desc || ''
|
||||||
|
// this.getDataList()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
getActiceDevice: "api/getActiceDevice"
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async init() {
|
||||||
|
this.chart = await this.$refs.chartRef.init(echarts);
|
||||||
|
let option = await this.getDataList();
|
||||||
|
this.chart.setOption(option)
|
||||||
|
|
||||||
|
},
|
||||||
|
back() {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1
|
||||||
|
})
|
||||||
|
},
|
||||||
|
goPath(){
|
||||||
|
uni.navigateTo({
|
||||||
|
url:'./detail?type='+this.type +(this.desc == ''?'':'&desc='+this.desc)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
makeHour(hours){
|
||||||
|
|
||||||
|
return Math.floor(hours/6); // 使用%运算符取余,确保结果是0-4的范围
|
||||||
|
},
|
||||||
|
makeMinute(minute){
|
||||||
|
return minute/60;
|
||||||
|
},
|
||||||
|
makeFloatHoursMinutes(hours, minutes) {
|
||||||
|
|
||||||
|
let total = hours * 3600 + minutes * 60;
|
||||||
|
let floatData = total / 86400 * 4
|
||||||
|
return floatData.toFixed(2);
|
||||||
|
},
|
||||||
|
async getDataList(){
|
||||||
|
let res = await this.$store.dispatch('api/getDeviceListDays', {
|
||||||
|
type: (this.type == 'step'?'step_split':this.type),
|
||||||
|
// type: (this.type),
|
||||||
|
device_real_time: this.time,
|
||||||
|
device_id:this.getActiceDevice.device_id
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.makeOptionConfig(res.data);
|
||||||
|
},
|
||||||
|
makeOptionConfig(data){
|
||||||
|
let echartsData = [];
|
||||||
|
let sum = 0;
|
||||||
|
let max = 0;
|
||||||
|
let min = 0;
|
||||||
|
let avg = 0;
|
||||||
|
let len = 0;
|
||||||
|
switch(this.type){
|
||||||
|
|
||||||
|
case 'bodyTemperature':
|
||||||
|
data.map((v,i) => {
|
||||||
|
let timeArr = v.hour_minute.split(':');
|
||||||
|
let dataMsg = parseFloat(v.data_msg);
|
||||||
|
let floatData = this.makeFloatHoursMinutes(timeArr[0],timeArr[1])
|
||||||
|
echartsData.push({value:[floatData,dataMsg],itemStyle: {color: this.dataConfig[this.type].color}})
|
||||||
|
sum += dataMsg
|
||||||
|
if(max == 0 || max < dataMsg){
|
||||||
|
max = dataMsg
|
||||||
|
}
|
||||||
|
if(min == 0 || max > dataMsg){
|
||||||
|
min = dataMsg
|
||||||
|
}
|
||||||
|
})
|
||||||
|
avg = sum / data.length
|
||||||
|
avg = parseFloat(avg.toFixed(2))
|
||||||
|
this.option.series[0].data = echartsData
|
||||||
|
this.option.series[0].markLine.data[0].yAxis = avg
|
||||||
|
this.option.series[0].markLine.lineStyle.color = this.dataConfig[this.type].color
|
||||||
|
this.option.series[0].markLine.label.color = this.dataConfig[this.type].color
|
||||||
|
this.option.yAxis.min = 32;
|
||||||
|
this.option.yAxis.max = max + 4;
|
||||||
|
this.option.title = {
|
||||||
|
text :min + '-' + max,
|
||||||
|
subtext: '毫摩尔/升',
|
||||||
|
left: 'center'
|
||||||
|
};
|
||||||
|
this.dataConfig.bodyTemperature.title = min + '-' + max
|
||||||
|
break;
|
||||||
|
case 'bloodOxygen':
|
||||||
|
data.map((v,i) => {
|
||||||
|
let timeArr = v.hour_minute.split(':');
|
||||||
|
let dataMsg = parseFloat(v.data_msg);
|
||||||
|
let floatData = this.makeFloatHoursMinutes(timeArr[0],timeArr[1])
|
||||||
|
echartsData.push({value:[floatData,dataMsg],itemStyle: {color: this.dataConfig[this.type].color}})
|
||||||
|
sum += dataMsg
|
||||||
|
if(max == 0 || max < dataMsg){
|
||||||
|
max = dataMsg
|
||||||
|
}
|
||||||
|
if(min == 0 || max > dataMsg){
|
||||||
|
min = dataMsg
|
||||||
|
}
|
||||||
|
})
|
||||||
|
avg = sum / data.length
|
||||||
|
avg = parseFloat(avg.toFixed(2))
|
||||||
|
this.option.series[0].data = echartsData
|
||||||
|
this.option.series[0].markLine.data[0].yAxis = avg
|
||||||
|
this.option.series[0].markLine.lineStyle.color = this.dataConfig[this.type].color
|
||||||
|
this.option.series[0].markLine.label.color = this.dataConfig[this.type].color
|
||||||
|
this.option.title = {
|
||||||
|
text :min + '-' + max,
|
||||||
|
subtext: '毫摩尔/升',
|
||||||
|
left: 'center'
|
||||||
|
};
|
||||||
|
this.dataConfig.bodyTemperature.title = min + '-' + max
|
||||||
|
break;
|
||||||
|
case 'bloodGlucose':
|
||||||
|
data.map((v,i) => {
|
||||||
|
let timeArr = v.hour_minute.split(':');
|
||||||
|
let floatData = this.makeFloatHoursMinutes(timeArr[0],timeArr[1])
|
||||||
|
echartsData.push({value:[floatData,v.data_msg],itemStyle: {color: this.dataConfig[this.type].color}})
|
||||||
|
sum += v.data_msg
|
||||||
|
if(max == 0 || max < v.data_msg){
|
||||||
|
max = v.data_msg
|
||||||
|
}
|
||||||
|
if(min == 0 || max > v.data_msg){
|
||||||
|
min = v.data_msg
|
||||||
|
}
|
||||||
|
})
|
||||||
|
avg = sum / data.length
|
||||||
|
avg = parseFloat(avg.toFixed(2))
|
||||||
|
this.option.series[0].data = echartsData
|
||||||
|
this.option.series[0].markLine.data[0].yAxis = avg
|
||||||
|
this.option.series[0].markLine.lineStyle.color = this.dataConfig[this.type].color
|
||||||
|
this.option.series[0].markLine.label.color = this.dataConfig[this.type].color
|
||||||
|
this.option.title = {
|
||||||
|
text :min + '-' + max,
|
||||||
|
subtext: '毫摩尔/升',
|
||||||
|
left: 'center'
|
||||||
|
};
|
||||||
|
this.dataConfig.bloodGlucose.title = min + '-' + max
|
||||||
|
break;
|
||||||
|
|
||||||
|
data.map((v,i) => {
|
||||||
|
|
||||||
|
let dataMsg = v.data_msg;
|
||||||
|
let timeArr = v.hour_minute.split(':');
|
||||||
|
for(let i = 0;i<5;i++){
|
||||||
|
let real_data = dataMsg[i]
|
||||||
|
if(real_data <= 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += 1;
|
||||||
|
let floatData = this.makeFloatHoursMinutes(timeArr[0],parseInt( timeArr[1]) + i)
|
||||||
|
echartsData.push({value:[floatData,real_data],itemStyle: {color: this.dataConfig[this.type].color}})
|
||||||
|
sum += real_data
|
||||||
|
if(max == 0 || max < real_data){
|
||||||
|
max = real_data
|
||||||
|
}
|
||||||
|
if(min == 0 || max > real_data){
|
||||||
|
min = real_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
avg = sum / len
|
||||||
|
avg = parseFloat(avg.toFixed(2))
|
||||||
|
this.option.series[0].data = echartsData
|
||||||
|
this.option.series[0].markLine.data[0].yAxis = avg
|
||||||
|
this.option.series[0].markLine.lineStyle.color = this.dataConfig[this.type].color
|
||||||
|
this.option.series[0].markLine.label.color = this.dataConfig[this.type].color
|
||||||
|
this.option.title = {
|
||||||
|
text :min + '-' + max,
|
||||||
|
subtext: '%',
|
||||||
|
left: 'center'
|
||||||
|
};
|
||||||
|
this.dataConfig.bloodGlucose.title = min + '-' + max
|
||||||
|
this.option.yAxis.axisLabel.formatter = '{value}%';
|
||||||
|
this.option.yAxis.splitNumber = 3;
|
||||||
|
this.option.yAxis.min = 95;
|
||||||
|
this.option.yAxis.max = 100;
|
||||||
|
break;
|
||||||
|
case 'pulseReat':
|
||||||
|
data.map((v,i) => {
|
||||||
|
|
||||||
|
let dataMsg = v.data_msg;
|
||||||
|
let timeArr = v.hour_minute.split(':');
|
||||||
|
for(let i = 0;i<1;i++){
|
||||||
|
let real_data = dataMsg[i]
|
||||||
|
if(real_data <= 0){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len += 1;
|
||||||
|
|
||||||
|
let floatData = this.makeFloatHoursMinutes(timeArr[0],parseInt( timeArr[1]) + i)
|
||||||
|
|
||||||
|
echartsData.push({value:[floatData,real_data],itemStyle: {color: this.dataConfig[this.type].color}})
|
||||||
|
sum += real_data
|
||||||
|
if(max == 0 || max < real_data){
|
||||||
|
max = real_data
|
||||||
|
}
|
||||||
|
if(min == 0 || max > real_data){
|
||||||
|
min = real_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
avg = sum / len
|
||||||
|
avg = parseFloat(avg.toFixed(2))
|
||||||
|
this.option.series[0].data = echartsData
|
||||||
|
this.option.series[0].markLine.data[0].yAxis = avg
|
||||||
|
this.option.series[0].markLine.lineStyle.color = this.dataConfig[this.type].color
|
||||||
|
this.option.series[0].markLine.label.color = this.dataConfig[this.type].color
|
||||||
|
this.option.title = {
|
||||||
|
text :min + '-' + max,
|
||||||
|
subtext: '次/分',
|
||||||
|
left: 'center'
|
||||||
|
};
|
||||||
|
this.dataConfig.bloodGlucose.title = min + '-' + max
|
||||||
|
// this.option.yAxis.axisLabel.formatter = '{value}%';
|
||||||
|
this.option.yAxis.splitNumber = 3;
|
||||||
|
this.option.yAxis.min = 30;
|
||||||
|
this.option.yAxis.max = 90;
|
||||||
|
break;
|
||||||
|
case 'bloodLiquid':
|
||||||
|
|
||||||
|
data.map((v,i) => {
|
||||||
|
let dataMsg = v.data_msg;
|
||||||
|
let real_data = dataMsg.uricAcidVal/10
|
||||||
|
let timeArr = v.hour_minute.split(':');
|
||||||
|
let floatData = this.makeFloatHoursMinutes(timeArr[0],timeArr[1])
|
||||||
|
echartsData.push({value:[floatData,real_data],itemStyle: {color: this.dataConfig[this.type].color}})
|
||||||
|
sum += real_data
|
||||||
|
if(max == 0 || max < real_data){
|
||||||
|
max = real_data
|
||||||
|
}
|
||||||
|
if(min == 0 || max > real_data){
|
||||||
|
min = real_data
|
||||||
|
}
|
||||||
|
len += 1;
|
||||||
|
|
||||||
|
})
|
||||||
|
avg = sum / len
|
||||||
|
avg = parseFloat(avg.toFixed(2))
|
||||||
|
this.option.series[0].data = echartsData
|
||||||
|
this.option.series[0].markLine.data[0].yAxis = avg
|
||||||
|
this.option.series[0].markLine.lineStyle.color = this.dataConfig[this.type].color
|
||||||
|
this.option.series[0].markLine.label.color = this.dataConfig[this.type].color
|
||||||
|
// this.option.series[0].type = 'this.dataConfig[this.type].color'
|
||||||
|
this.option.title = {
|
||||||
|
text :min + '-' + max,
|
||||||
|
subtext: '微摩尔/升',
|
||||||
|
left: 'center',
|
||||||
|
textStyle:{
|
||||||
|
fontWeight:"lighter",
|
||||||
|
fontSize:24
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.dataConfig.bloodGlucose.title = min + '-' + max
|
||||||
|
this.option.yAxis.axisLabel.formatter = function(v,i){
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
this.option.yAxis.splitNumber = 3;
|
||||||
|
this.option.yAxis.min = 0;
|
||||||
|
this.option.yAxis.max = 330;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this.option;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped="scss">
|
||||||
|
.body-style {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
}
|
||||||
|
.box-rds {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 40rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
margin: 20rpx;
|
||||||
|
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
background-color: #fff;
|
||||||
|
.title-data{
|
||||||
|
font-size: 60rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flx{
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
}
|
||||||
|
.jc-end{
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
.jc-start{
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
.ac{
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.jc{
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.jcsb{
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.fd_row{
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
<!-- <image src="../../static/icon/血糖.png" mode="widthFix"></image> -->
|
<!-- <image src="../../static/icon/血糖.png" mode="widthFix"></image> -->
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="content-item" @click="toPage('/pages/index/detail?type=bloodGlucose')">
|
<view class="content-item" @click="toPage('/pages/index/echarts?type=bloodGlucose')">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
{{getNameByKey('bloodGlucose')}}
|
{{getNameByKey('bloodGlucose')}}
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
<image src="../../static/icon/xuetang.png" mode="widthFix"></image>
|
<image src="../../static/icon/xuetang.png" mode="widthFix"></image>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="content-item" @click="toPage('/pages/index/detail?type=bloodOxygen')">
|
<view class="content-item" @click="toPage('/pages/index/echarts?type=bloodOxygen')">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
{{getNameByKey('bloodOxygen')}}
|
{{getNameByKey('bloodOxygen')}}
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -112,7 +112,7 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content-item" @click="toPage('/pages/index/detail?type=bodyTemperature')">
|
<view class="content-item" @click="toPage('/pages/index/echarts?type=bodyTemperature')">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
{{getNameByKey('bodyTemperature')}}
|
{{getNameByKey('bodyTemperature')}}
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content-item" @click="toPage('/pages/index/detail?type=pulseReat')">
|
<view class="content-item" @click="toPage('/pages/index/echarts?type=pulseReat')">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
{{getNameByKey('pulseReat')}}
|
{{getNameByKey('pulseReat')}}
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -224,7 +224,7 @@
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="content-item" @click="toPage('/pages/index/detail?type=bloodLiquid&desc=uricAcidVal')">
|
<view class="content-item" @click="toPage('/pages/index/echarts?type=bloodLiquid&desc=uricAcidVal')">
|
||||||
<view class="title">
|
<view class="title">
|
||||||
尿酸
|
尿酸
|
||||||
</view>
|
</view>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
## 0.9.3(2024-07-17)
|
||||||
|
- feat: 鸿蒙 canvas 事件缺失,待官方修复,如何在鸿蒙使用请看文档`常见问题 vue3`
|
||||||
|
- fiex: 修复 h5 非模拟器的情况下显示不全的问题
|
||||||
|
## 0.9.2(2024-07-12)
|
||||||
|
- chore: 删除多余文件
|
||||||
|
## 0.9.1(2024-07-12)
|
||||||
|
- fix: 修复 安卓5不显示图表问题
|
||||||
|
## 0.9.0(2024-06-13)
|
||||||
|
- chore: 合并nvue和uvue
|
||||||
|
## 0.8.9(2024-05-19)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.8.8(2024-05-13)
|
||||||
|
- chore: 更新文档和uvue示例
|
||||||
|
## 0.8.7(2024-04-26)
|
||||||
|
- fix: uniapp x需要HBX 4.13以上
|
||||||
|
## 0.8.6(2024-04-10)
|
||||||
|
- feat: 支持 uniapp x ios
|
||||||
|
## 0.8.5(2024-04-03)
|
||||||
|
- fix: 修复 nvue `reset`传值不生效问题
|
||||||
|
- feat: 支持 uniapp x web
|
||||||
|
## 0.8.4(2024-01-27)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.8.3(2024-01-21)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.8.2(2024-01-21)
|
||||||
|
- feat: 支持 `uvue`
|
||||||
|
## 0.8.1(2023-08-24)
|
||||||
|
- fix: app 的`touch`事件为`object` 导致无法显示 `tooltip`
|
||||||
|
## 0.8.0(2023-08-22)
|
||||||
|
- fix: 离屏 报错问题
|
||||||
|
- fix: 微信小程序PC无法使用事件
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.7.9(2023-07-29)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.7.8(2023-07-29)
|
||||||
|
- fix: 离屏 报错问题
|
||||||
|
## 0.7.7(2023-07-27)
|
||||||
|
- chore: 更新文档
|
||||||
|
- chore: lime-echart 里的示例使用自定tooltips
|
||||||
|
- feat: 对支持离屏的使用离屏创建(微信、字节、支付宝)
|
||||||
|
## 0.7.6(2023-06-30)
|
||||||
|
- fix: vue3 报`width`的错
|
||||||
|
## 0.7.5(2023-05-25)
|
||||||
|
- chore: 更新文档 和 demo, 使用`lime-echart`这个标签即可查看示例
|
||||||
|
## 0.7.4(2023-05-22)
|
||||||
|
- chore: 增加关于钉钉小程序上传时提示安全问题的说明及修改建议
|
||||||
|
## 0.7.3(2023-05-16)
|
||||||
|
- chore: 更新 vue3 非微信小程序平台可能缺少`wx`的说明
|
||||||
|
## 0.7.2(2023-05-16)
|
||||||
|
- chore: 更新 vue3 非微信小程序平台的可以缺少`wx`的说明
|
||||||
|
## 0.7.1(2023-04-26)
|
||||||
|
- chore: 更新demo,使用`lime-echart`这个标签即可查看示例
|
||||||
|
- chore:微信小程序的`tooltip`文字有阴影,怀疑是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
|
||||||
|
## 0.7.0(2023-04-24)
|
||||||
|
- fix: 修复`setAttribute is not a function`
|
||||||
|
## 0.6.9(2023-04-15)
|
||||||
|
- chore: 更新文档,vue3请使用echarts esm的包
|
||||||
|
## 0.6.8(2023-03-22)
|
||||||
|
- feat: mac pc无法使用canvas 2d
|
||||||
|
## 0.6.7(2023-03-17)
|
||||||
|
- feat: 更新文档
|
||||||
|
## 0.6.6(2023-03-17)
|
||||||
|
- feat: 微信小程序PC已经支持canvas 2d,故去掉判断PC
|
||||||
|
## 0.6.5(2022-11-03)
|
||||||
|
- fix: 某些手机touches为对象,导致无法交互。
|
||||||
|
## 0.6.4(2022-10-28)
|
||||||
|
- fix: 优化点击事件的触发条件
|
||||||
|
## 0.6.3(2022-10-26)
|
||||||
|
- fix: 修复 dataZoom 拖动问题
|
||||||
|
## 0.6.2(2022-10-23)
|
||||||
|
- fix: 修复 飞书小程序 尺寸问题
|
||||||
|
## 0.6.1(2022-10-19)
|
||||||
|
- fix: 修复 PC mousewheel 事件 鼠标位置不准确的BUG,不兼容火狐!
|
||||||
|
- feat: showLoading 增加传参
|
||||||
|
## 0.6.0(2022-09-16)
|
||||||
|
- feat: 增加PC的mousewheel事件
|
||||||
|
## 0.5.4(2022-09-16)
|
||||||
|
- fix: 修复 nvue 动态数据不显示问题
|
||||||
|
## 0.5.3(2022-09-16)
|
||||||
|
- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.5.2(2022-09-16)
|
||||||
|
- feat: 增加enableHover属性, 在PC端时当鼠标进入显示tooltip,不必按下。
|
||||||
|
## 0.5.1(2022-09-16)
|
||||||
|
- fix: 修复nvue报错
|
||||||
|
## 0.5.0(2022-09-15)
|
||||||
|
- feat: init(echarts, theme?:string, opts?:{}, callback: function(chart))
|
||||||
|
## 0.4.8(2022-09-11)
|
||||||
|
- feat: 增加 @finished
|
||||||
|
## 0.4.7(2022-08-24)
|
||||||
|
- chore: 去掉 stylus
|
||||||
|
## 0.4.6(2022-08-24)
|
||||||
|
- feat: 增加 beforeDelay
|
||||||
|
## 0.4.5(2022-08-12)
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.4.4(2022-08-12)
|
||||||
|
- fix: 修复 resize 无参数时报错
|
||||||
|
## 0.4.3(2022-08-07)
|
||||||
|
# 评论有说本插件对新手不友好,让我做不好就不要发出来。 还有的说跟官网一样,发出来做什么,给我整无语了。
|
||||||
|
# 所以在此提醒一下准备要下载的你,如果你从未使用过 echarts 请不要下载 或 谨慎下载。
|
||||||
|
# 如果你确认要下载,麻烦看完文档。还有请注意插件是让echarts在uniapp能运行,API 配置请自行去官网查阅!
|
||||||
|
# 如果你不会echarts 但又需要图表,市场上有个很优秀的图表插件 uchart 你可以去使用这款插件,uchart的作者人很好,也热情。
|
||||||
|
# 每个人都有自己的本职工作,如果你能力强可以自行兼容,如果使用了他人的插件也麻烦尊重他人的成果和劳动时间。谢谢。
|
||||||
|
# 为了心情愉悦,本人已经使用插件屏蔽差评。
|
||||||
|
- chore: 更新文档
|
||||||
|
## 0.4.2(2022-07-20)
|
||||||
|
- feat: 增加 resize
|
||||||
|
## 0.4.1(2022-06-07)
|
||||||
|
- fix: 修复 canvasToTempFilePath 不生效问题
|
||||||
|
## 0.4.0(2022-06-04)
|
||||||
|
- chore 为了词云 增加一个canvas 标签
|
||||||
|
- 词云下载地址[echart-wordcloud](https://ext.dcloud.net.cn/plugin?id=8430)
|
||||||
|
## 0.3.9(2022-06-02)
|
||||||
|
- chore: 更新文档
|
||||||
|
- tips: lines 不支持 `trailLength`
|
||||||
|
## 0.3.8(2022-05-31)
|
||||||
|
- fix: 修复 因mouse事件冲突tooltip跳动问题
|
||||||
|
## 0.3.7(2022-05-26)
|
||||||
|
- chore: 更新文档
|
||||||
|
- chore: 设置默认宽高300px
|
||||||
|
- fix: 修复 vue3 微信小程序 拖影BUG
|
||||||
|
- chore: 支持PC
|
||||||
|
## 0.3.5(2022-04-28)
|
||||||
|
- chore: 更新使用方式
|
||||||
|
- 🔔 必须使用hbuilderx 3.4.8-alpha以上
|
||||||
|
## 0.3.4(2021-08-03)
|
||||||
|
- chore: 增加 setOption的参数值
|
||||||
|
## 0.3.3(2021-07-22)
|
||||||
|
- fix: 修复 径向渐变报错的问题
|
||||||
|
## 0.3.2(2021-07-09)
|
||||||
|
- chore: 统一命名规范,无须主动引入组件
|
||||||
|
## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
|
||||||
|
## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.3.1(2021-06-21)
|
||||||
|
- fix: 修复 app-nvue ios is-enable 无效的问题
|
||||||
|
## [代码示例站点1](https://limeui.qcoon.cn/#/echart-example)
|
||||||
|
## [代码示例站点2](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.3.0(2021-06-14)
|
||||||
|
- fix: 修复 头条系小程序 2d 报 JSON.stringify 的问题
|
||||||
|
- 目前 头条系小程序 2d 无法在开发工具上预览,划动图表页面无法滚动,axisLabel 字体颜色无法更改,建议使用非2d。
|
||||||
|
## 0.2.9(2021-06-06)
|
||||||
|
- fix: 修复 头条系小程序 2d 放大的BUG
|
||||||
|
- 头条系小程序 2d 无法在开发工具上预览,也存在划动图表页面无法滚动的问题。
|
||||||
|
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.2.8(2021-05-19)
|
||||||
|
- fix: 修复 微信小程序 PC 显示过大的问题
|
||||||
|
## 0.2.7(2021-05-19)
|
||||||
|
- fix: 修复 微信小程序 PC 不显示问题
|
||||||
|
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.2.6(2021-05-14)
|
||||||
|
- feat: 支持 `image`
|
||||||
|
- feat: props 增加 `ec.clear`,更新时是否先删除图表样式
|
||||||
|
- feat: props 增加 `isDisableScroll` ,触摸图表时是否禁止页面滚动
|
||||||
|
- feat: props 增加 `webviewStyles` ,webview 的样式, 仅nvue有效
|
||||||
|
## 0.2.5(2021-05-13)
|
||||||
|
- docs: 插件用到了css 预编译器 [stylus](https://ext.dcloud.net.cn/plugin?name=compile-stylus) 请安装它
|
||||||
|
## 0.2.4(2021-05-12)
|
||||||
|
- fix: 修复 百度平台 多个图表ctx 和 渐变色 bug
|
||||||
|
- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.2.3(2021-05-10)
|
||||||
|
- feat: 增加 `canvasToTempFilePath` 方法,用于生成图片
|
||||||
|
```js
|
||||||
|
this.$refs.chart.canvasToTempFilePath({success: (res) => {
|
||||||
|
console.log('tempFilePath:', res.tempFilePath)
|
||||||
|
}})
|
||||||
|
```
|
||||||
|
## 0.2.2(2021-05-10)
|
||||||
|
- feat: 增加 `dispose` 方法,用于销毁实例
|
||||||
|
- feat: 增加 `isClickable` 是否派发点击
|
||||||
|
- feat: 实验性的支持 `nvue` 使用要慎重考虑
|
||||||
|
- ## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.2.1(2021-05-06)
|
||||||
|
- fix:修复 微信小程序 json 报错
|
||||||
|
- chore: `reset` 更改为 `setChart`
|
||||||
|
- feat: 增加 `isEnable` 开启初始化 启用这个后 无须再使用`init`方法
|
||||||
|
```html
|
||||||
|
<l-echart ref="chart" is-enable />
|
||||||
|
```
|
||||||
|
```js
|
||||||
|
// 显示加载
|
||||||
|
this.$refs.chart.showLoading()
|
||||||
|
// 使用实例回调
|
||||||
|
this.$refs.chart.setChart(chart => ...code)
|
||||||
|
// 直接设置图表配置
|
||||||
|
this.$refs.chart.setOption(data)
|
||||||
|
```
|
||||||
|
## 0.2.0(2021-05-05)
|
||||||
|
- fix:修复 头条 百度 偏移的问题
|
||||||
|
- docs: 更新文档
|
||||||
|
## [代码示例:http://liangei.gitee.io/limeui/#/echart-example](http://liangei.gitee.io/limeui/#/echart-example)
|
||||||
|
## 0.1.0(2021-05-02)
|
||||||
|
- chore: 第一次上传,基本全端兼容,使用方法与官网一致。
|
||||||
|
- 已知BUG:非2d 无法使用背景色,已反馈官方
|
||||||
|
- 已知BUG:头条 百度 有许些偏移
|
||||||
|
- 后期计划:兼容nvue
|
||||||
|
|
@ -0,0 +1,391 @@
|
||||||
|
const cacheChart = {}
|
||||||
|
const fontSizeReg = /([\d\.]+)px/;
|
||||||
|
class EventEmit {
|
||||||
|
constructor() {
|
||||||
|
this.__events = {};
|
||||||
|
}
|
||||||
|
on(type, listener) {
|
||||||
|
if (!type || !listener) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const events = this.__events[type] || [];
|
||||||
|
events.push(listener);
|
||||||
|
this.__events[type] = events;
|
||||||
|
}
|
||||||
|
emit(type, e) {
|
||||||
|
if (type.constructor === Object) {
|
||||||
|
e = type;
|
||||||
|
type = e && e.type;
|
||||||
|
}
|
||||||
|
if (!type) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const events = this.__events[type];
|
||||||
|
if (!events || !events.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
events.forEach((listener) => {
|
||||||
|
listener.call(this, e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
off(type, listener) {
|
||||||
|
const __events = this.__events;
|
||||||
|
const events = __events[type];
|
||||||
|
if (!events || !events.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!listener) {
|
||||||
|
delete __events[type];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0, len = events.length; i < len; i++) {
|
||||||
|
if (events[i] === listener) {
|
||||||
|
events.splice(i, 1);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Image {
|
||||||
|
constructor() {
|
||||||
|
this.currentSrc = null
|
||||||
|
this.naturalHeight = 0
|
||||||
|
this.naturalWidth = 0
|
||||||
|
this.width = 0
|
||||||
|
this.height = 0
|
||||||
|
this.tagName = 'IMG'
|
||||||
|
}
|
||||||
|
set src(src) {
|
||||||
|
this.currentSrc = src
|
||||||
|
uni.getImageInfo({
|
||||||
|
src,
|
||||||
|
success: (res) => {
|
||||||
|
this.naturalWidth = this.width = res.width
|
||||||
|
this.naturalHeight = this.height = res.height
|
||||||
|
this.onload()
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
this.onerror()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
get src() {
|
||||||
|
return this.currentSrc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class OffscreenCanvas {
|
||||||
|
constructor(ctx, com, canvasId) {
|
||||||
|
this.tagName = 'canvas'
|
||||||
|
this.com = com
|
||||||
|
this.canvasId = canvasId
|
||||||
|
this.ctx = ctx
|
||||||
|
}
|
||||||
|
set width(w) {
|
||||||
|
this.com.offscreenWidth = w
|
||||||
|
}
|
||||||
|
set height(h) {
|
||||||
|
this.com.offscreenHeight = h
|
||||||
|
}
|
||||||
|
get width() {
|
||||||
|
return this.com.offscreenWidth || 0
|
||||||
|
}
|
||||||
|
get height() {
|
||||||
|
return this.com.offscreenHeight || 0
|
||||||
|
}
|
||||||
|
getContext(type) {
|
||||||
|
return this.ctx
|
||||||
|
}
|
||||||
|
getImageData() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.com.$nextTick(() => {
|
||||||
|
uni.canvasGetImageData({
|
||||||
|
x:0,
|
||||||
|
y:0,
|
||||||
|
width: this.com.offscreenWidth,
|
||||||
|
height: this.com.offscreenHeight,
|
||||||
|
canvasId: this.canvasId,
|
||||||
|
success: (res) => {
|
||||||
|
resolve(res)
|
||||||
|
},
|
||||||
|
fail: (err) => {
|
||||||
|
reject(err)
|
||||||
|
},
|
||||||
|
}, this.com)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class Canvas {
|
||||||
|
constructor(ctx, com, isNew, canvasNode={}) {
|
||||||
|
cacheChart[com.canvasId] = {ctx}
|
||||||
|
this.canvasId = com.canvasId;
|
||||||
|
this.chart = null;
|
||||||
|
this.isNew = isNew
|
||||||
|
this.tagName = 'canvas'
|
||||||
|
this.canvasNode = canvasNode;
|
||||||
|
this.com = com;
|
||||||
|
if (!isNew) {
|
||||||
|
this._initStyle(ctx)
|
||||||
|
}
|
||||||
|
this._initEvent();
|
||||||
|
this._ee = new EventEmit()
|
||||||
|
}
|
||||||
|
getContext(type) {
|
||||||
|
if (type === '2d') {
|
||||||
|
return this.ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAttribute(key, value) {
|
||||||
|
if(key === 'aria-label') {
|
||||||
|
this.com['ariaLabel'] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setChart(chart) {
|
||||||
|
this.chart = chart;
|
||||||
|
}
|
||||||
|
createOffscreenCanvas(param){
|
||||||
|
if(!this.children) {
|
||||||
|
this.com.isOffscreenCanvas = true
|
||||||
|
this.com.offscreenWidth = param.width||300
|
||||||
|
this.com.offscreenHeight = param.height||300
|
||||||
|
const com = this.com
|
||||||
|
const canvasId = this.com.offscreenCanvasId
|
||||||
|
const context = uni.createCanvasContext(canvasId, this.com)
|
||||||
|
this._initStyle(context)
|
||||||
|
this.children = new OffscreenCanvas(context, com, canvasId)
|
||||||
|
}
|
||||||
|
return this.children
|
||||||
|
}
|
||||||
|
appendChild(child) {
|
||||||
|
console.log('child', child)
|
||||||
|
}
|
||||||
|
dispatchEvent(type, e) {
|
||||||
|
if(typeof type == 'object') {
|
||||||
|
this._ee.emit(type.type, type);
|
||||||
|
} else {
|
||||||
|
this._ee.emit(type, e);
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
attachEvent() {
|
||||||
|
}
|
||||||
|
detachEvent() {
|
||||||
|
}
|
||||||
|
addEventListener(type, listener) {
|
||||||
|
this._ee.on(type, listener)
|
||||||
|
}
|
||||||
|
removeEventListener(type, listener) {
|
||||||
|
this._ee.off(type, listener)
|
||||||
|
}
|
||||||
|
_initCanvas(zrender, ctx) {
|
||||||
|
// zrender.util.getContext = function() {
|
||||||
|
// return ctx;
|
||||||
|
// };
|
||||||
|
// zrender.util.$override('measureText', function(text, font) {
|
||||||
|
// ctx.font = font || '12px sans-serif';
|
||||||
|
// return ctx.measureText(text, font);
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
_initStyle(ctx, child) {
|
||||||
|
const styles = [
|
||||||
|
'fillStyle',
|
||||||
|
'strokeStyle',
|
||||||
|
'fontSize',
|
||||||
|
'globalAlpha',
|
||||||
|
'opacity',
|
||||||
|
'textAlign',
|
||||||
|
'textBaseline',
|
||||||
|
'shadow',
|
||||||
|
'lineWidth',
|
||||||
|
'lineCap',
|
||||||
|
'lineJoin',
|
||||||
|
'lineDash',
|
||||||
|
'miterLimit',
|
||||||
|
// #ifdef H5
|
||||||
|
'font',
|
||||||
|
// #endif
|
||||||
|
];
|
||||||
|
const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
|
||||||
|
styles.forEach(style => {
|
||||||
|
Object.defineProperty(ctx, style, {
|
||||||
|
set: value => {
|
||||||
|
// #ifdef H5
|
||||||
|
if (style === 'font' && fontSizeReg.test(value)) {
|
||||||
|
const match = fontSizeReg.exec(value);
|
||||||
|
ctx.setFontSize(match[1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
if (style === 'opacity') {
|
||||||
|
ctx.setGlobalAlpha(value)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (style !== 'fillStyle' && style !== 'strokeStyle' || value !== 'none' && value !== null) {
|
||||||
|
// #ifdef H5 || APP-PLUS || MP-BAIDU
|
||||||
|
if(typeof value == 'object') {
|
||||||
|
if (value.hasOwnProperty('colorStop') || value.hasOwnProperty('colors')) {
|
||||||
|
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
if(colorReg.test(value)) {
|
||||||
|
value = value.replace(colorReg, '#$1$1$2$2$3$3')
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
if(!this.isNew && !child) {
|
||||||
|
ctx.uniDrawImage = ctx.drawImage
|
||||||
|
ctx.drawImage = (...a) => {
|
||||||
|
a[0] = a[0].src
|
||||||
|
ctx.uniDrawImage(...a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!ctx.createRadialGradient) {
|
||||||
|
ctx.createRadialGradient = function() {
|
||||||
|
return ctx.createCircularGradient(...[...arguments].slice(-3))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 字节不支持
|
||||||
|
if (!ctx.strokeText) {
|
||||||
|
ctx.strokeText = (...a) => {
|
||||||
|
ctx.fillText(...a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 钉钉不支持
|
||||||
|
if (!ctx.measureText) {
|
||||||
|
const strLen = (str) => {
|
||||||
|
let len = 0;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
|
||||||
|
len++;
|
||||||
|
} else {
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
ctx.measureText = (text, font) => {
|
||||||
|
let fontSize = ctx?.state?.fontSize || 12;
|
||||||
|
if (font) {
|
||||||
|
fontSize = parseInt(font.match(/([\d\.]+)px/)[1])
|
||||||
|
}
|
||||||
|
fontSize /= 2;
|
||||||
|
let isBold = fontSize >= 16;
|
||||||
|
const widthFactor = isBold ? 1.3 : 1;
|
||||||
|
return {
|
||||||
|
width: strLen(text) * fontSize * widthFactor
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_initEvent(e) {
|
||||||
|
this.event = {};
|
||||||
|
const eventNames = [{
|
||||||
|
wxName: 'touchStart',
|
||||||
|
ecName: 'mousedown'
|
||||||
|
}, {
|
||||||
|
wxName: 'touchMove',
|
||||||
|
ecName: 'mousemove'
|
||||||
|
}, {
|
||||||
|
wxName: 'touchEnd',
|
||||||
|
ecName: 'mouseup'
|
||||||
|
}, {
|
||||||
|
wxName: 'touchEnd',
|
||||||
|
ecName: 'click'
|
||||||
|
}];
|
||||||
|
|
||||||
|
eventNames.forEach(name => {
|
||||||
|
this.event[name.wxName] = e => {
|
||||||
|
const touch = e.touches[0];
|
||||||
|
this.chart.getZr().handler.dispatch(name.ecName, {
|
||||||
|
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
|
||||||
|
zrY: name.wxName === 'tap' ? touch.clientY : touch.y
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
set width(w) {
|
||||||
|
this.canvasNode.width = w
|
||||||
|
}
|
||||||
|
set height(h) {
|
||||||
|
this.canvasNode.height = h
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() {
|
||||||
|
return this.canvasNode.width || 0
|
||||||
|
}
|
||||||
|
get height() {
|
||||||
|
return this.canvasNode.height || 0
|
||||||
|
}
|
||||||
|
get ctx() {
|
||||||
|
return cacheChart[this.canvasId]['ctx'] || null
|
||||||
|
}
|
||||||
|
set chart(chart) {
|
||||||
|
cacheChart[this.canvasId]['chart'] = chart
|
||||||
|
}
|
||||||
|
get chart() {
|
||||||
|
return cacheChart[this.canvasId]['chart'] || null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dispatch(name, {x,y, wheelDelta}) {
|
||||||
|
this.dispatch(name, {
|
||||||
|
zrX: x,
|
||||||
|
zrY: y,
|
||||||
|
zrDelta: wheelDelta,
|
||||||
|
preventDefault: () => {},
|
||||||
|
stopPropagation: () =>{}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function setCanvasCreator(echarts, {canvas, node}) {
|
||||||
|
// echarts.setCanvasCreator(() => canvas);
|
||||||
|
if(echarts && !echarts.registerPreprocessor) {
|
||||||
|
return console.warn('echarts 版本不对或未传入echarts,vue3请使用esm格式')
|
||||||
|
}
|
||||||
|
echarts.registerPreprocessor(option => {
|
||||||
|
if (option && option.series) {
|
||||||
|
if (option.series.length > 0) {
|
||||||
|
option.series.forEach(series => {
|
||||||
|
series.progressive = 0;
|
||||||
|
});
|
||||||
|
} else if (typeof option.series === 'object') {
|
||||||
|
option.series.progressive = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
function loadImage(src, onload, onerror) {
|
||||||
|
let img = null
|
||||||
|
if(node && node.createImage) {
|
||||||
|
img = node.createImage()
|
||||||
|
img.onload = onload.bind(img);
|
||||||
|
img.onerror = onerror.bind(img);
|
||||||
|
img.src = src;
|
||||||
|
return img
|
||||||
|
} else {
|
||||||
|
img = new Image()
|
||||||
|
img.onload = onload.bind(img)
|
||||||
|
img.onerror = onerror.bind(img);
|
||||||
|
img.src = src
|
||||||
|
return img
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(echarts.setPlatformAPI) {
|
||||||
|
echarts.setPlatformAPI({
|
||||||
|
loadImage: canvas.setChart ? loadImage : null,
|
||||||
|
createCanvas(){
|
||||||
|
const key = 'createOffscreenCanvas'
|
||||||
|
return uni.canIUse(key) && uni[key] ? uni[key]({type: '2d'}) : canvas
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
<template>
|
||||||
|
<!-- #ifdef APP -->
|
||||||
|
<web-view class="lime-echart" ref="chartRef" @load="loaded" :style="[customStyle]"
|
||||||
|
:webview-styles="[webviewStyles]" src="/uni_modules/lime-echart/static/uvue.html?v=10112">
|
||||||
|
</web-view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<div class="lime-echart" ref="chartRef"></div>
|
||||||
|
<!-- #endif -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="uts" setup>
|
||||||
|
// @ts-nocheck
|
||||||
|
import { Echarts } from './uvue';
|
||||||
|
type EchartsResolve = (value : Echarts) => void
|
||||||
|
defineOptions({
|
||||||
|
name: 'l-echart'
|
||||||
|
})
|
||||||
|
const emits = defineEmits(['finished'])
|
||||||
|
const props = defineProps({
|
||||||
|
// #ifdef APP
|
||||||
|
webviewStyles: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
customStyle: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
webviewStyles: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
customStyle: {
|
||||||
|
type: [String, Object]
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
isDisableScroll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isClickable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
enableHover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
beforeDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 30
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const finished = ref(false)
|
||||||
|
const map = [] as EchartsResolve[]
|
||||||
|
const callbackMap = [] as EchartsResolve[]
|
||||||
|
// let context = null as UniWebViewElement | null
|
||||||
|
let chart = null as Echarts | null
|
||||||
|
let chartRef = ref<UniWebViewElement | null>(null)
|
||||||
|
|
||||||
|
const trigger = () => {
|
||||||
|
// #ifdef APP
|
||||||
|
if (finished.value) {
|
||||||
|
if (chart == null) {
|
||||||
|
chart = new Echarts(chartRef.value!)
|
||||||
|
}
|
||||||
|
while (map.length > 0) {
|
||||||
|
const resolve = map.pop() as EchartsResolve
|
||||||
|
resolve(chart!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
while (map.length > 0) {
|
||||||
|
if(chart != null){
|
||||||
|
const resolve = map.pop() as EchartsResolve
|
||||||
|
resolve(chart!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
if(chart != null){
|
||||||
|
while(callbackMap.length > 0){
|
||||||
|
const callback = callbackMap.pop() as EchartsResolve
|
||||||
|
callback(chart!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #ifdef APP
|
||||||
|
const loaded = (event : UniWebViewLoadEvent) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
finished.value = true
|
||||||
|
trigger()
|
||||||
|
emits('finished')
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
|
||||||
|
const _next = () : boolean => {
|
||||||
|
if (chart == null) {
|
||||||
|
console.warn(`组件还未初始化,请先使用 init`)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const setOption = (option : UTSJSONObject) => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.setOption(option);
|
||||||
|
}
|
||||||
|
const showLoading = () => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.showLoading();
|
||||||
|
}
|
||||||
|
const hideLoading = () => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.hideLoading();
|
||||||
|
}
|
||||||
|
const clear = () => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.clear();
|
||||||
|
}
|
||||||
|
const dispose = () => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.dispose();
|
||||||
|
}
|
||||||
|
const resize = (size : UTSJSONObject) => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.resize(size);
|
||||||
|
}
|
||||||
|
const canvasToTempFilePath = (opt : UTSJSONObject) => {
|
||||||
|
if (_next()) return
|
||||||
|
chart!.canvasToTempFilePath(opt);
|
||||||
|
}
|
||||||
|
// function init() : Promise<Echarts> {
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// map.push(resolve)
|
||||||
|
// trigger()
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// #ifdef APP
|
||||||
|
function init(callback : ((chart : Echarts) => void) | null) : Promise<Echarts> {
|
||||||
|
// if (chart !== null && callback != null) {
|
||||||
|
// callback(chart!)
|
||||||
|
// } else {
|
||||||
|
// console.warn('echarts 未加载完成,您可以延时一下')
|
||||||
|
// }
|
||||||
|
if(callback!=null){
|
||||||
|
callbackMap.push(callback)
|
||||||
|
}
|
||||||
|
return new Promise<Echarts>((resolve) => {
|
||||||
|
map.push(resolve)
|
||||||
|
trigger()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
const touchstart = (e) => {
|
||||||
|
if(chart == null) return
|
||||||
|
const handler = chart.getZr().handler;
|
||||||
|
const rect = chart.getZr().dom.getBoundingClientRect()
|
||||||
|
handler.dispatch('mousedown', {
|
||||||
|
zrX: e.touches[0].clientX - rect.left,
|
||||||
|
zrY: e.touches[0].clientY - rect.top
|
||||||
|
})
|
||||||
|
handler.dispatch('click', {
|
||||||
|
zrX: e.touches[0].clientX - rect.left,
|
||||||
|
zrY: e.touches[0].clientY - rect.top
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const touchmove = (e) => {
|
||||||
|
if(chart == null) return
|
||||||
|
const handler = chart.getZr().handler;
|
||||||
|
const rect = chart.getZr().dom.getBoundingClientRect()
|
||||||
|
handler.dispatch('mousemove', {
|
||||||
|
zrX: e.touches[0].clientX - rect.left,
|
||||||
|
zrY: e.touches[0].clientY - rect.top
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const mouseup = (e) => {
|
||||||
|
if(chart == null) return
|
||||||
|
const handler = chart.getZr().handler;
|
||||||
|
handler.dispatch('mousemove', {
|
||||||
|
zrX: 999999999,
|
||||||
|
zrY: 999999999
|
||||||
|
})
|
||||||
|
handler.dispatch('mouseup', {
|
||||||
|
zrX: 999999999,
|
||||||
|
zrY: 999999999
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function init(echarts: any, ...args: any[]): Promise<Echarts>{
|
||||||
|
if(echarts == null){
|
||||||
|
console.error('请确保已经引入了 ECharts 库');
|
||||||
|
return Promise.reject('请确保已经引入了 ECharts 库');
|
||||||
|
}
|
||||||
|
let theme:string|null=null
|
||||||
|
let opts={}
|
||||||
|
let callback:Function|null=null;
|
||||||
|
|
||||||
|
args.forEach(item =>{
|
||||||
|
if(typeof item === 'function') {
|
||||||
|
callback = item
|
||||||
|
} else if(['string'].includes(typeof item)){
|
||||||
|
theme = item
|
||||||
|
} else if(typeof item === 'object'){
|
||||||
|
opts = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
chart = echarts.init(chartRef.value, theme, opts)
|
||||||
|
window.addEventListener('touchstart', touchstart)
|
||||||
|
window.addEventListener('touchmove', touchmove)
|
||||||
|
window.addEventListener('touchend', mouseup)
|
||||||
|
|
||||||
|
if(callback!=null && typeof callback == 'function'){
|
||||||
|
callbackMap.push(callback)
|
||||||
|
}
|
||||||
|
return new Promise<Echarts>((resolve) => {
|
||||||
|
map.push(resolve)
|
||||||
|
trigger()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(()=>{
|
||||||
|
finished.value = true
|
||||||
|
trigger()
|
||||||
|
emits('finished')
|
||||||
|
})
|
||||||
|
onUnmounted(()=>{
|
||||||
|
window.removeEventListener('touchstart', touchstart)
|
||||||
|
window.removeEventListener('touchmove', touchmove)
|
||||||
|
window.removeEventListener('touchend', mouseup)
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
init,
|
||||||
|
setOption,
|
||||||
|
showLoading,
|
||||||
|
hideLoading,
|
||||||
|
clear,
|
||||||
|
dispose,
|
||||||
|
resize,
|
||||||
|
canvasToTempFilePath
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.lime-echart {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,514 @@
|
||||||
|
<template>
|
||||||
|
<view class="lime-echart" :style="customStyle" v-if="canvasId" ref="limeEchart" :aria-label="ariaLabel">
|
||||||
|
<!-- #ifndef APP-NVUE -->
|
||||||
|
<canvas
|
||||||
|
class="lime-echart__canvas"
|
||||||
|
v-if="use2dCanvas"
|
||||||
|
type="2d"
|
||||||
|
:id="canvasId"
|
||||||
|
:style="canvasStyle"
|
||||||
|
:disable-scroll="isDisableScroll"
|
||||||
|
@touchstart="touchStart"
|
||||||
|
@touchmove="touchMove"
|
||||||
|
@touchend="touchEnd"
|
||||||
|
/>
|
||||||
|
<canvas
|
||||||
|
class="lime-echart__canvas"
|
||||||
|
v-else
|
||||||
|
:width="nodeWidth"
|
||||||
|
:height="nodeHeight"
|
||||||
|
:style="canvasStyle"
|
||||||
|
:canvas-id="canvasId"
|
||||||
|
:id="canvasId"
|
||||||
|
:disable-scroll="isDisableScroll"
|
||||||
|
@touchstart="touchStart"
|
||||||
|
@touchmove="touchMove"
|
||||||
|
@touchend="touchEnd"
|
||||||
|
/>
|
||||||
|
<view class="lime-echart__mask"
|
||||||
|
v-if="isPC"
|
||||||
|
@mousedown="touchStart"
|
||||||
|
@mousemove="touchMove"
|
||||||
|
@mouseup="touchEnd"
|
||||||
|
@touchstart="touchStart"
|
||||||
|
@touchmove="touchMove"
|
||||||
|
@touchend="touchEnd">
|
||||||
|
</view>
|
||||||
|
<canvas v-if="isOffscreenCanvas" :style="offscreenStyle" :canvas-id="offscreenCanvasId"></canvas>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifdef APP-NVUE -->
|
||||||
|
<web-view
|
||||||
|
class="lime-echart__canvas"
|
||||||
|
:id="canvasId"
|
||||||
|
:style="canvasStyle"
|
||||||
|
:webview-styles="webviewStyles"
|
||||||
|
ref="webview"
|
||||||
|
src="/uni_modules/lime-echart/static/uvue.html?v=1"
|
||||||
|
@pagefinish="finished = true"
|
||||||
|
@onPostMessage="onMessage"
|
||||||
|
></web-view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
import {Canvas, setCanvasCreator, dispatch} from './canvas';
|
||||||
|
import {wrapTouch, convertTouchesToArray, devicePixelRatio ,sleep, canIUseCanvas2d, getRect} from './utils';
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
import { base64ToPath, sleep } from './utils';
|
||||||
|
import {Echarts} from './nvue'
|
||||||
|
// #endif
|
||||||
|
const charts = {}
|
||||||
|
const echartsObj = {}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LimeChart 图表
|
||||||
|
* @description 全端兼容的eCharts
|
||||||
|
* @tutorial https://ext.dcloud.net.cn/plugin?id=4899
|
||||||
|
|
||||||
|
* @property {String} customStyle 自定义样式
|
||||||
|
* @property {String} type 指定 canvas 类型
|
||||||
|
* @value 2d 使用canvas 2d,部分小程序支持
|
||||||
|
* @value '' 使用原生canvas,会有层级问题
|
||||||
|
* @value bottom right 不缩放图片,只显示图片的右下边区域
|
||||||
|
* @property {Boolean} isDisableScroll
|
||||||
|
* @property {number} beforeDelay = [30] 延迟初始化 (毫秒)
|
||||||
|
* @property {Boolean} enableHover PC端使用鼠标悬浮
|
||||||
|
|
||||||
|
* @event {Function} finished 加载完成触发
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'lime-echart',
|
||||||
|
props: {
|
||||||
|
// #ifdef MP-WEIXIN || MP-TOUTIAO
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: '2d'
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
webviewStyles: Object,
|
||||||
|
// hybrid: Boolean,
|
||||||
|
// #endif
|
||||||
|
customStyle: String,
|
||||||
|
isDisableScroll: Boolean,
|
||||||
|
isClickable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
enableHover: Boolean,
|
||||||
|
beforeDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||||
|
use2dCanvas: true,
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||||
|
use2dCanvas: false,
|
||||||
|
// #endif
|
||||||
|
ariaLabel: '图表',
|
||||||
|
width: null,
|
||||||
|
height: null,
|
||||||
|
nodeWidth: null,
|
||||||
|
nodeHeight: null,
|
||||||
|
// canvasNode: null,
|
||||||
|
config: {},
|
||||||
|
inited: false,
|
||||||
|
finished: false,
|
||||||
|
file: '',
|
||||||
|
platform: '',
|
||||||
|
isPC: false,
|
||||||
|
isDown: false,
|
||||||
|
isOffscreenCanvas: false,
|
||||||
|
offscreenWidth: 0,
|
||||||
|
offscreenHeight: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
canvasId() {
|
||||||
|
return `lime-echart${this._ && this._.uid || this._uid}`
|
||||||
|
},
|
||||||
|
offscreenCanvasId() {
|
||||||
|
return `${this.canvasId}_offscreen`
|
||||||
|
},
|
||||||
|
offscreenStyle() {
|
||||||
|
return `width:${this.offscreenWidth}px;height: ${this.offscreenHeight}px; position: fixed; left: 99999px; background: red`
|
||||||
|
},
|
||||||
|
canvasStyle() {
|
||||||
|
return this.width && this.height ? ('width:' + this.width + 'px;height:' + this.height + 'px') : ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// #ifndef VUE3
|
||||||
|
beforeDestroy() {
|
||||||
|
this.clear()
|
||||||
|
this.dispose()
|
||||||
|
// #ifdef H5
|
||||||
|
if(this.isPC) {
|
||||||
|
document.removeEventListener('mousewheel', this.mousewheel)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE3
|
||||||
|
beforeUnmount() {
|
||||||
|
this.clear()
|
||||||
|
this.dispose()
|
||||||
|
// #ifdef H5
|
||||||
|
if(this.isPC) {
|
||||||
|
document.removeEventListener('mousewheel', this.mousewheel)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
created() {
|
||||||
|
// #ifdef H5
|
||||||
|
if(!('ontouchstart' in window)) {
|
||||||
|
this.isPC = true
|
||||||
|
document.addEventListener('mousewheel', this.mousewheel)
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN || MP-TOUTIAO || MP-ALIPAY
|
||||||
|
const { platform } = uni.getSystemInfoSync();
|
||||||
|
this.isPC = /windows/i.test(platform)
|
||||||
|
// #endif
|
||||||
|
this.use2dCanvas = this.type === '2d' && canIUseCanvas2d()
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.$emit('finished')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
onMessage(e) {
|
||||||
|
const detail = e?.detail?.data[0] || null;
|
||||||
|
const data = detail?.data
|
||||||
|
const key = detail?.event
|
||||||
|
const options = data?.options
|
||||||
|
const event = data?.event
|
||||||
|
const file = detail?.file
|
||||||
|
if (key == 'log' && data) {
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
if(event) {
|
||||||
|
this.chart.dispatchAction(event.replace(/"/g,''), options)
|
||||||
|
}
|
||||||
|
if(file) {
|
||||||
|
thie.file = file
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
setChart(callback) {
|
||||||
|
if(!this.chart) {
|
||||||
|
console.warn(`组件还未初始化,请先使用 init`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(typeof callback === 'function' && this.chart) {
|
||||||
|
callback(this.chart);
|
||||||
|
}
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
if(typeof callback === 'function') {
|
||||||
|
this.$refs.webview.evalJs(`setChart(${JSON.stringify(callback.toString())}, ${JSON.stringify(this.chart.options)})`);
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
setOption() {
|
||||||
|
if (!this.chart || !this.chart.setOption) {
|
||||||
|
console.warn(`组件还未初始化,请先使用 init`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.chart.setOption(...arguments);
|
||||||
|
},
|
||||||
|
showLoading() {
|
||||||
|
if(this.chart) {
|
||||||
|
this.chart.showLoading(...arguments)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hideLoading() {
|
||||||
|
if(this.chart) {
|
||||||
|
this.chart.hideLoading()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear() {
|
||||||
|
if(this.chart) {
|
||||||
|
this.chart.clear()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dispose() {
|
||||||
|
if(this.chart) {
|
||||||
|
this.chart.dispose()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resize(size) {
|
||||||
|
if(size && size.width && size.height) {
|
||||||
|
this.height = size.height
|
||||||
|
this.width = size.width
|
||||||
|
if(this.chart) {this.chart.resize(size)}
|
||||||
|
} else {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
uni.createSelectorQuery()
|
||||||
|
.in(this)
|
||||||
|
.select(`.lime-echart`)
|
||||||
|
.boundingClientRect()
|
||||||
|
.exec(res => {
|
||||||
|
if (res) {
|
||||||
|
let { width, height } = res[0];
|
||||||
|
this.width = width = width || 300;
|
||||||
|
this.height = height = height || 300;
|
||||||
|
this.chart.resize({width, height})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
canvasToTempFilePath(args = {}) {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
const { use2dCanvas, canvasId } = this;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const copyArgs = Object.assign({
|
||||||
|
canvasId,
|
||||||
|
success: resolve,
|
||||||
|
fail: reject
|
||||||
|
}, args);
|
||||||
|
if (use2dCanvas) {
|
||||||
|
delete copyArgs.canvasId;
|
||||||
|
copyArgs.canvas = this.canvasNode;
|
||||||
|
}
|
||||||
|
uni.canvasToTempFilePath(copyArgs, this);
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
this.file = ''
|
||||||
|
this.$refs.webview.evalJs(`canvasToTempFilePath()`);
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.$watch('file', async (file) => {
|
||||||
|
if(file) {
|
||||||
|
const tempFilePath = await base64ToPath(file)
|
||||||
|
resolve(args.success({tempFilePath}))
|
||||||
|
} else {
|
||||||
|
reject(args.fail({error: ``}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
async init(echarts, ...args) {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
if(args && args.length == 0 && !echarts) {
|
||||||
|
console.error('缺少参数:init(echarts, theme?:string, opts?: object, callback?: function)')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
let theme=null,opts={},callback;
|
||||||
|
|
||||||
|
Array.from(arguments).forEach(item => {
|
||||||
|
if(typeof item === 'function') {
|
||||||
|
callback = item
|
||||||
|
}
|
||||||
|
if(['string'].includes(typeof item)) {
|
||||||
|
theme = item
|
||||||
|
}
|
||||||
|
if(typeof item === 'object') {
|
||||||
|
opts = item
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if(this.beforeDelay) {
|
||||||
|
await sleep(this.beforeDelay)
|
||||||
|
}
|
||||||
|
let config = await this.getContext();
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
setCanvasCreator(echarts, config)
|
||||||
|
try {
|
||||||
|
this.chart = echarts.init(config.canvas, theme, Object.assign({}, config, opts))
|
||||||
|
if(typeof callback === 'function') {
|
||||||
|
callback(this.chart)
|
||||||
|
} else {
|
||||||
|
return this.chart
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e.messges)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
this.chart = new Echarts(this.$refs.webview)
|
||||||
|
this.$refs.webview.evalJs(`init(null, null, ${JSON.stringify(opts)}, ${theme})`)
|
||||||
|
if(callback) {
|
||||||
|
callback(this.chart)
|
||||||
|
} else {
|
||||||
|
return this.chart
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
getContext() {
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
if(this.finished) {
|
||||||
|
return Promise.resolve(this.finished)
|
||||||
|
}
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.$watch('finished', (val) => {
|
||||||
|
if(val) {
|
||||||
|
resolve(this.finished)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
return getRect(`#${this.canvasId}`, {context: this, type: this.use2dCanvas ? 'fields': 'boundingClientRect'}).then(res => {
|
||||||
|
if(res) {
|
||||||
|
let dpr = devicePixelRatio
|
||||||
|
let {width, height, node} = res
|
||||||
|
let canvas;
|
||||||
|
this.width = width = width || 300;
|
||||||
|
this.height = height = height || 300;
|
||||||
|
if(node) {
|
||||||
|
const ctx = node.getContext('2d');
|
||||||
|
canvas = new Canvas(ctx, this, true, node);
|
||||||
|
this.canvasNode = node
|
||||||
|
} else {
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
dpr = !this.isPC ? devicePixelRatio : 1// 1.25
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-ALIPAY || MP-TOUTIAO
|
||||||
|
dpr = this.isPC ? devicePixelRatio : 1
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY || MP-LARK
|
||||||
|
dpr = devicePixelRatio
|
||||||
|
// #endif
|
||||||
|
// #ifdef WEB
|
||||||
|
dpr = 1
|
||||||
|
// #endif
|
||||||
|
this.rect = res
|
||||||
|
this.nodeWidth = width * dpr;
|
||||||
|
this.nodeHeight = height * dpr;
|
||||||
|
const ctx = uni.createCanvasContext(this.canvasId, this);
|
||||||
|
canvas = new Canvas(ctx, this, false);
|
||||||
|
}
|
||||||
|
return { canvas, width, height, devicePixelRatio: dpr, node };
|
||||||
|
} else {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
getRelative(e, touches) {
|
||||||
|
let { clientX, clientY } = e
|
||||||
|
if(!(clientX && clientY) && touches && touches[0]) {
|
||||||
|
clientX = touches[0].clientX
|
||||||
|
clientY = touches[0].clientY
|
||||||
|
}
|
||||||
|
return {x: clientX - this.rect.left, y: clientY - this.rect.top, wheelDelta: e.wheelDelta || 0}
|
||||||
|
},
|
||||||
|
getTouch(e, touches) {
|
||||||
|
const {x} = touches && touches[0] || {}
|
||||||
|
return x ? touches[0] : this.getRelative(e, touches);
|
||||||
|
},
|
||||||
|
touchStart(e) {
|
||||||
|
this.isDown = true
|
||||||
|
const next = () => {
|
||||||
|
const touches = convertTouchesToArray(e.touches)
|
||||||
|
if(this.chart) {
|
||||||
|
const touch = this.getTouch(e, touches)
|
||||||
|
this.startX = touch.x
|
||||||
|
this.startY = touch.y
|
||||||
|
this.startT = new Date()
|
||||||
|
const handler = this.chart.getZr().handler;
|
||||||
|
dispatch.call(handler, 'mousedown', touch)
|
||||||
|
dispatch.call(handler, 'mousemove', touch)
|
||||||
|
handler.processGesture(wrapTouch(e), 'start');
|
||||||
|
clearTimeout(this.endTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(this.isPC) {
|
||||||
|
getRect(`#${this.canvasId}`, {context: this}).then(res => {
|
||||||
|
this.rect = res
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
},
|
||||||
|
touchMove(e) {
|
||||||
|
if(this.isPC && this.enableHover && !this.isDown) {this.isDown = true}
|
||||||
|
const touches = convertTouchesToArray(e.touches)
|
||||||
|
if (this.chart && this.isDown) {
|
||||||
|
const handler = this.chart.getZr().handler;
|
||||||
|
dispatch.call(handler, 'mousemove', this.getTouch(e, touches))
|
||||||
|
handler.processGesture(wrapTouch(e), 'change');
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
touchEnd(e) {
|
||||||
|
this.isDown = false
|
||||||
|
if (this.chart) {
|
||||||
|
const touches = convertTouchesToArray(e.changedTouches)
|
||||||
|
const {x} = touches && touches[0] || {}
|
||||||
|
const touch = (x ? touches[0] : this.getRelative(e, touches)) || {};
|
||||||
|
const handler = this.chart.getZr().handler;
|
||||||
|
const isClick = Math.abs(touch.x - this.startX) < 10 && new Date() - this.startT < 200;
|
||||||
|
dispatch.call(handler, 'mouseup', touch)
|
||||||
|
handler.processGesture(wrapTouch(e), 'end');
|
||||||
|
if(isClick) {
|
||||||
|
dispatch.call(handler, 'click', touch)
|
||||||
|
} else {
|
||||||
|
this.endTimer = setTimeout(() => {
|
||||||
|
dispatch.call(handler, 'mousemove', {x: 999999999,y: 999999999});
|
||||||
|
dispatch.call(handler, 'mouseup', {x: 999999999,y: 999999999});
|
||||||
|
},50)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
mousewheel(e){
|
||||||
|
if(this.chart) {
|
||||||
|
dispatch.call(this.chart.getZr().handler, 'mousewheel', this.getTouch(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.lime-echart {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
flex: 1;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
.lime-echart__canvas {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
/* #endif */
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
flex: 1;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
.lime-echart__mask {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
export class Echarts {
|
||||||
|
eventMap = new Map()
|
||||||
|
constructor(webview) {
|
||||||
|
this.webview = webview
|
||||||
|
this.options = null
|
||||||
|
}
|
||||||
|
setOption() {
|
||||||
|
this.options = arguments
|
||||||
|
this.webview.evalJs(`setOption(${JSON.stringify(arguments)})`);
|
||||||
|
}
|
||||||
|
getOption() {
|
||||||
|
return this.options
|
||||||
|
}
|
||||||
|
showLoading() {
|
||||||
|
this.webview.evalJs(`showLoading(${JSON.stringify(arguments)})`);
|
||||||
|
}
|
||||||
|
hideLoading() {
|
||||||
|
this.webview.evalJs(`hideLoading()`);
|
||||||
|
}
|
||||||
|
clear() {
|
||||||
|
this.webview.evalJs(`clear()`);
|
||||||
|
}
|
||||||
|
dispose() {
|
||||||
|
this.webview.evalJs(`dispose()`);
|
||||||
|
}
|
||||||
|
resize(size) {
|
||||||
|
if(size) {
|
||||||
|
this.webview.evalJs(`resize(${JSON.stringify(size)})`);
|
||||||
|
} else {
|
||||||
|
this.webview.evalJs(`resize()`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
on(type, ...args) {
|
||||||
|
const query = args[0]
|
||||||
|
const useQuery = query && typeof query != 'function'
|
||||||
|
const param = useQuery ? [type, query] : [type]
|
||||||
|
const key = `${type}${useQuery ? JSON.stringify(query): '' }`
|
||||||
|
const callback = useQuery ? args[1]: args[0]
|
||||||
|
if(typeof callback == 'function'){
|
||||||
|
this.eventMap.set(key, callback)
|
||||||
|
}
|
||||||
|
this.webview.evalJs(`on(${JSON.stringify(param)})`);
|
||||||
|
console.warn('nvue 暂不支持事件')
|
||||||
|
}
|
||||||
|
dispatchAction(type, options){
|
||||||
|
const handler = this.eventMap.get(type)
|
||||||
|
if(handler){
|
||||||
|
handler(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
// 计算版本
|
||||||
|
export function compareVersion(v1, v2) {
|
||||||
|
v1 = v1.split('.')
|
||||||
|
v2 = v2.split('.')
|
||||||
|
const len = Math.max(v1.length, v2.length)
|
||||||
|
while (v1.length < len) {
|
||||||
|
v1.push('0')
|
||||||
|
}
|
||||||
|
while (v2.length < len) {
|
||||||
|
v2.push('0')
|
||||||
|
}
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
const num1 = parseInt(v1[i], 10)
|
||||||
|
const num2 = parseInt(v2[i], 10)
|
||||||
|
|
||||||
|
if (num1 > num2) {
|
||||||
|
return 1
|
||||||
|
} else if (num1 < num2) {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
const systemInfo = uni.getSystemInfoSync();
|
||||||
|
|
||||||
|
function gte(version) {
|
||||||
|
// 截止 2023-03-22 mac pc小程序不支持 canvas 2d
|
||||||
|
let {
|
||||||
|
SDKVersion,
|
||||||
|
platform
|
||||||
|
} = systemInfo;
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
SDKVersion = my.SDKVersion
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
return platform !== 'mac' && compareVersion(SDKVersion, version) >= 0;
|
||||||
|
// #endif
|
||||||
|
return compareVersion(SDKVersion, version) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function canIUseCanvas2d() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
return gte('2.9.0');
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
return gte('2.7.0');
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
return gte('1.78.0');
|
||||||
|
// #endif
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertTouchesToArray(touches) {
|
||||||
|
// 如果 touches 是一个数组,则直接返回它
|
||||||
|
if (Array.isArray(touches)) {
|
||||||
|
return touches;
|
||||||
|
}
|
||||||
|
// 如果touches是一个对象,则转换为数组
|
||||||
|
if (typeof touches === 'object' && touches !== null) {
|
||||||
|
return Object.values(touches);
|
||||||
|
}
|
||||||
|
// 对于其他类型,直接返回它
|
||||||
|
return touches;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wrapTouch(event) {
|
||||||
|
for (let i = 0; i < event.touches.length; ++i) {
|
||||||
|
const touch = event.touches[i];
|
||||||
|
touch.offsetX = touch.x;
|
||||||
|
touch.offsetY = touch.y;
|
||||||
|
}
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
export const devicePixelRatio = uni.getSystemInfoSync().pixelRatio
|
||||||
|
// #endif
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
export function base64ToPath(base64) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
|
||||||
|
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||||
|
bitmap.loadBase64Data(base64, () => {
|
||||||
|
if (!format) {
|
||||||
|
reject(new Error('ERROR_BASE64SRC_PARSE'))
|
||||||
|
}
|
||||||
|
const time = new Date().getTime();
|
||||||
|
const filePath = `_doc/uniapp_temp/${time}.${format}`
|
||||||
|
|
||||||
|
bitmap.save(filePath, {},
|
||||||
|
() => {
|
||||||
|
bitmap.clear()
|
||||||
|
resolve(filePath)
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
bitmap.clear()
|
||||||
|
console.error(`${JSON.stringify(error)}`)
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
}, (error) => {
|
||||||
|
bitmap.clear()
|
||||||
|
console.error(`${JSON.stringify(error)}`)
|
||||||
|
reject(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
|
||||||
|
export function sleep(time) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve(true)
|
||||||
|
}, time)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getRect(selector, options = {}) {
|
||||||
|
const typeDefault = 'boundingClientRect'
|
||||||
|
const {
|
||||||
|
context,
|
||||||
|
type = typeDefault
|
||||||
|
} = options
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const dom = uni.createSelectorQuery().in(context).select(selector);
|
||||||
|
const result = (rect) => {
|
||||||
|
if (rect) {
|
||||||
|
resolve(rect)
|
||||||
|
} else {
|
||||||
|
reject()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == typeDefault) {
|
||||||
|
dom[type](result).exec()
|
||||||
|
} else {
|
||||||
|
dom[type]({
|
||||||
|
node: true,
|
||||||
|
size: true,
|
||||||
|
rect: true
|
||||||
|
}, result).exec()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
// @ts-nocheck
|
||||||
|
// #ifdef APP
|
||||||
|
type EchartsEventHandler = (event: UTSJSONObject)=>void
|
||||||
|
// type EchartsTempResolve = (obj : UTSJSONObject) => void
|
||||||
|
// type EchartsTempOptions = UTSJSONObject
|
||||||
|
export class Echarts {
|
||||||
|
options: UTSJSONObject = {} as UTSJSONObject
|
||||||
|
context: UniWebViewElement
|
||||||
|
eventMap: Map<string, EchartsEventHandler> = new Map()
|
||||||
|
private temp: UTSJSONObject[] = []
|
||||||
|
constructor(context: UniWebViewElement){
|
||||||
|
this.context = context
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
init(){
|
||||||
|
this.context.evalJS(`init(null, null, ${JSON.stringify({})})`)
|
||||||
|
|
||||||
|
this.context.addEventListener('message', (e : UniWebViewMessageEvent) => {
|
||||||
|
// event.stopPropagation()
|
||||||
|
// event.preventDefault()
|
||||||
|
|
||||||
|
const detail = e.detail.data[0]
|
||||||
|
const file = detail.getString('file')
|
||||||
|
const data = detail.get('data')
|
||||||
|
const key = detail.getString('event')
|
||||||
|
const options = typeof data == 'object' ? (data as UTSJSONObject).getJSON('options'): null
|
||||||
|
const event = typeof data == 'object' ? (data as UTSJSONObject).getString('event'): null
|
||||||
|
if (key == 'log' && data != null) {
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
if (event != null && options != null) {
|
||||||
|
this.dispatchAction(event.replace(/"/g,''), options)
|
||||||
|
}
|
||||||
|
if(file != null){
|
||||||
|
while (this.temp.length > 0) {
|
||||||
|
const opt = this.temp.pop()
|
||||||
|
const success = opt?.get('success')
|
||||||
|
if(typeof success == 'function'){
|
||||||
|
success as (res: UTSJSONObject) => void
|
||||||
|
success({tempFilePath: file})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
setOption(option: UTSJSONObject){
|
||||||
|
this.options = option;
|
||||||
|
this.context.evalJS(`setOption(${JSON.stringify([option])})`)
|
||||||
|
}
|
||||||
|
setOption(option: UTSJSONObject, notMerge: boolean = false, lazyUpdate: boolean = false){
|
||||||
|
this.options = option;
|
||||||
|
this.context.evalJS(`setOption(${JSON.stringify([option, notMerge, lazyUpdate])})`)
|
||||||
|
}
|
||||||
|
setOption(option: UTSJSONObject, notMerge: UTSJSONObject){
|
||||||
|
this.options = option;
|
||||||
|
this.context.evalJS(`setOption(${JSON.stringify([option, notMerge])})`)
|
||||||
|
}
|
||||||
|
getOption(): UTSJSONObject {
|
||||||
|
return this.options
|
||||||
|
}
|
||||||
|
showLoading(){
|
||||||
|
this.context.evalJS(`showLoading(${JSON.stringify([] as any[])})`);
|
||||||
|
}
|
||||||
|
showLoading(type: string, opts: UTSJSONObject){
|
||||||
|
this.context.evalJS(`showLoading(${JSON.stringify([type, opts])})`);
|
||||||
|
}
|
||||||
|
hideLoading(){
|
||||||
|
this.context.evalJS(`hideLoading()`);
|
||||||
|
}
|
||||||
|
clear(){
|
||||||
|
this.context.evalJS(`clear()`);
|
||||||
|
}
|
||||||
|
dispose(){
|
||||||
|
this.context.evalJS(`dispose()`);
|
||||||
|
}
|
||||||
|
resize(size:UTSJSONObject){
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.context.evalJS(`resize(${JSON.stringify(size)})`);
|
||||||
|
},0)
|
||||||
|
}
|
||||||
|
resize(){
|
||||||
|
setTimeout(()=>{
|
||||||
|
this.context.evalJS(`resize()`);
|
||||||
|
},10)
|
||||||
|
|
||||||
|
}
|
||||||
|
on(type:string, query: any, callback: EchartsEventHandler) {
|
||||||
|
const key = `${type}${JSON.stringify(query)}`
|
||||||
|
if(typeof callback == 'function'){
|
||||||
|
this.eventMap.set(key, callback)
|
||||||
|
}
|
||||||
|
this.context.evalJS(`on(${JSON.stringify([type, query])})`);
|
||||||
|
console.warn('uvue 暂不支持事件')
|
||||||
|
}
|
||||||
|
on(type:string, callback: EchartsEventHandler) {
|
||||||
|
const key = `${type}`
|
||||||
|
if(typeof callback == 'function'){
|
||||||
|
this.eventMap.set(key, callback)
|
||||||
|
}
|
||||||
|
this.context.evalJS(`on(${JSON.stringify([type])})`);
|
||||||
|
console.warn('uvue 暂不支持事件')
|
||||||
|
}
|
||||||
|
dispatchAction(type:string, options: UTSJSONObject){
|
||||||
|
const handler = this.eventMap.get(type)
|
||||||
|
if(handler!=null){
|
||||||
|
handler(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvasToTempFilePath(opt: UTSJSONObject){
|
||||||
|
// this.context.evalJS(`on(${JSON.stringify(opt)})`);
|
||||||
|
this.context.evalJS(`canvasToTempFilePath(${JSON.stringify(opt)})`);
|
||||||
|
this.temp.push(opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP
|
||||||
|
export class Echarts {
|
||||||
|
constructor() {}
|
||||||
|
setOption(option: UTSJSONObject): void
|
||||||
|
isDisposed(): boolean;
|
||||||
|
clear(): void;
|
||||||
|
resize(size:UTSJSONObject): void;
|
||||||
|
resize(): void;
|
||||||
|
canvasToTempFilePath(opt : UTSJSONObject): void;
|
||||||
|
dispose(): void;
|
||||||
|
showLoading(cfg?: UTSJSONObject): void;
|
||||||
|
showLoading(name?: string, cfg?: UTSJSONObject): void;
|
||||||
|
hideLoading(): void;
|
||||||
|
getZr(): any
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
<template>
|
||||||
|
<view style="width: 100%; height: 408px;">
|
||||||
|
<l-echart ref="chartRef" @finished="init"></l-echart>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showTip: false,
|
||||||
|
option: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
// shadowBlur: 0,
|
||||||
|
textStyle: {
|
||||||
|
textShadowBlur: 0
|
||||||
|
},
|
||||||
|
renderMode: 'richText',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '邮件营销',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [120, 132, 101, 134, 90, 230, 210]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '联盟广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [220, 182, 191, 234, 290, 330, 310]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '视频广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [150, 232, 201, 154, 190, 330, 410]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '直接访问',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [320, 332, 301, 334, 390, 330, 320]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索引擎',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
console.log('lime echarts nvue')
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
const chartRef = this.$refs['chartRef']
|
||||||
|
chartRef.init(chart => {
|
||||||
|
chart.setOption(this.option);
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
// shadowBlur: 0,
|
||||||
|
textStyle: {
|
||||||
|
textShadowBlur: 0
|
||||||
|
},
|
||||||
|
renderMode: 'richText',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '邮件营销',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [120, 132, 101, 134, 90, 230, 210]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '联盟广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [220, 182, 191, 234, 290, 330, 310]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '视频广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [150, 232, 201, 154, 190, 330, 410]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '直接访问',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [320, 332, 301, 334, 390, 330, 320]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索引擎',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chart.setOption(option);
|
||||||
|
},1000)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
// this.$refs.chart.canvasToTempFilePath({
|
||||||
|
// success(res) {
|
||||||
|
// console.log('res::::', res)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
<template>
|
||||||
|
<view style="width: 100%; height: 408px;background-color: aqua;">
|
||||||
|
<l-echart ref="chartRef" @finished="init"></l-echart>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="uts" setup>
|
||||||
|
// @ts-nocheck
|
||||||
|
// #ifdef H5
|
||||||
|
import * as echarts from 'echarts/dist/echarts.esm.js'
|
||||||
|
// #endif
|
||||||
|
const chartRef = ref<LEchartComponentPublicInstance|null>(null)
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
// shadowBlur: 0,
|
||||||
|
textStyle: {
|
||||||
|
textShadowBlur: 0
|
||||||
|
},
|
||||||
|
renderMode: 'richText',
|
||||||
|
},
|
||||||
|
// formatter: async (params: any) => {
|
||||||
|
// console.log('params', params)
|
||||||
|
// return 1
|
||||||
|
// },
|
||||||
|
legend: {
|
||||||
|
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '邮件营销',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [120, 132, 101, 134, 90, 230, 210]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '联盟广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [220, 182, 191, 234, 290, 330, 310]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '视频广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [150, 232, 201, 154, 190, 330, 410]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '直接访问',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [320, 332, 301, 334, 390, 330, 320]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索引擎',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = async () =>{
|
||||||
|
if(chartRef.value== null) return
|
||||||
|
// #ifdef APP
|
||||||
|
const chart = await chartRef.value!.init(null)
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
const chart = await chartRef.value!.init(echarts, null)
|
||||||
|
// #endif
|
||||||
|
chart.setOption(option)
|
||||||
|
chart.on('mouseover', function (params) {
|
||||||
|
console.log('params', params);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// setTimeout(()=> {
|
||||||
|
// const option1 = {
|
||||||
|
// tooltip: {
|
||||||
|
// trigger: 'axis',
|
||||||
|
// // shadowBlur: 0,
|
||||||
|
// textStyle: {
|
||||||
|
// textShadowBlur: 0
|
||||||
|
// },
|
||||||
|
// renderMode: 'richText',
|
||||||
|
// },
|
||||||
|
// legend: {
|
||||||
|
// data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||||
|
// },
|
||||||
|
// grid: {
|
||||||
|
// left: '3%',
|
||||||
|
// right: '4%',
|
||||||
|
// bottom: '3%',
|
||||||
|
// containLabel: true
|
||||||
|
// },
|
||||||
|
// xAxis: {
|
||||||
|
// type: 'category',
|
||||||
|
// boundaryGap: false,
|
||||||
|
// data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
// },
|
||||||
|
// yAxis: {
|
||||||
|
// type: 'value'
|
||||||
|
// },
|
||||||
|
// series: [
|
||||||
|
// {
|
||||||
|
// name: '邮件营销',
|
||||||
|
// type: 'line',
|
||||||
|
// stack: '总量',
|
||||||
|
// data: [820, 132, 101, 134, 90, 230, 210]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '联盟广告',
|
||||||
|
// type: 'line',
|
||||||
|
// stack: '总量',
|
||||||
|
// data: [220, 182, 191, 234, 290, 330, 310]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '视频广告',
|
||||||
|
// type: 'line',
|
||||||
|
// stack: '总量',
|
||||||
|
// data: [950, 232, 201, 154, 190, 330, 410]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '直接访问',
|
||||||
|
// type: 'line',
|
||||||
|
// stack: '总量',
|
||||||
|
// data: [320, 332, 301, 334, 390, 330, 320]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '搜索引擎',
|
||||||
|
// type: 'line',
|
||||||
|
// stack: '总量',
|
||||||
|
// data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// chart.setOption(option1)
|
||||||
|
// },1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
<template>
|
||||||
|
<view >
|
||||||
|
<view style="height: 750rpx; position: relative">
|
||||||
|
<l-echart ref="chart" @finished="init"></l-echart>
|
||||||
|
<view class="customTooltips" :style="{left: position[0] + 'px',top: position[1] + 'px'}" v-if="params.length && position.length && showTip">
|
||||||
|
<view>这是个自定的tooltips</view>
|
||||||
|
<view>{{params[0]['axisValue']}}</view>
|
||||||
|
<view v-for="item in params">
|
||||||
|
<view>
|
||||||
|
<text>{{item.seriesName}}</text>
|
||||||
|
<text>{{item.value}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// nvue 不需要引入
|
||||||
|
// #ifdef VUE2
|
||||||
|
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min';
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE3
|
||||||
|
// #ifdef MP
|
||||||
|
// 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require
|
||||||
|
const echarts = require('../../static/echarts.min');
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP
|
||||||
|
// 由于 vue3 使用vite 不支持umd格式的包,故引入npm的包
|
||||||
|
import * as echarts from 'echarts/dist/echarts.esm';
|
||||||
|
console.log('wx', wx.getSystemInfoSync().uniPlatform)
|
||||||
|
// #endif
|
||||||
|
// #endif
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showTip: false,
|
||||||
|
position: [],
|
||||||
|
params: [],
|
||||||
|
option: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
// shadowBlur: 0,
|
||||||
|
textStyle: {
|
||||||
|
textShadowBlur : 0
|
||||||
|
},
|
||||||
|
renderMode: 'richText',
|
||||||
|
position: (point, params, dom, rect, size) => {
|
||||||
|
// 假设自定义的tooltips尺寸
|
||||||
|
const box = [170, 170]
|
||||||
|
// 偏移
|
||||||
|
const offsetX = point[0] < size.viewSize[0] / 2 ? 20 : -box[0] - 20;
|
||||||
|
const offsetY = point[1] < size.viewSize[1] / 2 ? 20 : -box[1] - 20;
|
||||||
|
const x = point[0] + offsetX;
|
||||||
|
const y = point[1] + offsetY;
|
||||||
|
|
||||||
|
this.position = [x, y]
|
||||||
|
this.params = params
|
||||||
|
},
|
||||||
|
formatter: (params, ticket, callback) => {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '邮件营销',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [120, 132, 101, 134, 90, 230, 210]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '联盟广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [220, 182, 191, 234, 290, 330, 310]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '视频广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [150, 232, 201, 154, 190, 330, 410]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '直接访问',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [320, 332, 301, 334, 390, 330, 320]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索引擎',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
// init(echarts, theme?:string, opts?:{}, chart => {})
|
||||||
|
// echarts 必填, 非nvue必填,nvue不用填
|
||||||
|
// theme 可选,应用的主题,目前只支持名称,如:'dark'
|
||||||
|
// opts = { // 可选
|
||||||
|
// locale?: string // 从 `5.0.0` 开始支持
|
||||||
|
// }
|
||||||
|
// chart => {} , callback 返回图表实例
|
||||||
|
// setTimeout(()=>{
|
||||||
|
// this.$refs.chart.init(echarts, chart => {
|
||||||
|
// chart.setOption(this.option);
|
||||||
|
// });
|
||||||
|
// },300)
|
||||||
|
this.$refs.chart.init(echarts, chart => {
|
||||||
|
chart.setOption(this.option);
|
||||||
|
|
||||||
|
// 监听tooltip显示事件
|
||||||
|
chart.on('showTip', (params) => {
|
||||||
|
this.showTip = true
|
||||||
|
console.log('showTip::')
|
||||||
|
});
|
||||||
|
chart.on('hideTip', (params) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.showTip = false
|
||||||
|
},300)
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
// shadowBlur: 0,
|
||||||
|
textStyle: {
|
||||||
|
textShadowBlur: 0
|
||||||
|
},
|
||||||
|
renderMode: 'richText',
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '邮件营销',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [1120, 132, 101, 134, 90, 230, 210]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '联盟广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [220, 182, 191, 234, 290, 330, 310]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '视频广告',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [150, 632, 201, 154, 190, 330, 410]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '直接访问',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [820, 332, 301, 334, 390, 330, 320]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '搜索引擎',
|
||||||
|
type: 'line',
|
||||||
|
stack: '总量',
|
||||||
|
data: [820, 932, 901, 934, 1290, 1330, 1320]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chart.setOption(option);
|
||||||
|
},1000)
|
||||||
|
|
||||||
|
});
|
||||||
|
},
|
||||||
|
save() {
|
||||||
|
this.$refs.chart.canvasToTempFilePath({
|
||||||
|
success(res) {
|
||||||
|
console.log('res::::', res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.customTooltips {
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 20rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
{
|
||||||
|
"id": "lime-echart",
|
||||||
|
"displayName": "echarts",
|
||||||
|
"version": "0.9.3",
|
||||||
|
"description": "echarts 全端兼容,一款使echarts图表能跑在uniapp各端中的插件, 支持uniapp(包含鸿蒙)/uniappx(web,ios,安卓)",
|
||||||
|
"keywords": [
|
||||||
|
"echarts",
|
||||||
|
"canvas",
|
||||||
|
"图表",
|
||||||
|
"可视化"
|
||||||
|
],
|
||||||
|
"repository": "https://gitee.com/liangei/lime-echart",
|
||||||
|
"engines": {
|
||||||
|
"HBuilderX": "^3.6.4"
|
||||||
|
},
|
||||||
|
"dcloudext": {
|
||||||
|
"sale": {
|
||||||
|
"regular": {
|
||||||
|
"price": "0.00"
|
||||||
|
},
|
||||||
|
"sourcecode": {
|
||||||
|
"price": "0.00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"qq": ""
|
||||||
|
},
|
||||||
|
"declaration": {
|
||||||
|
"ads": "无",
|
||||||
|
"data": "无",
|
||||||
|
"permissions": "无"
|
||||||
|
},
|
||||||
|
"npmurl": "",
|
||||||
|
"type": "component-vue"
|
||||||
|
},
|
||||||
|
"uni_modules": {
|
||||||
|
"dependencies": [],
|
||||||
|
"encrypt": [],
|
||||||
|
"platforms": {
|
||||||
|
"cloud": {
|
||||||
|
"tcb": "y",
|
||||||
|
"aliyun": "y",
|
||||||
|
"alipay": "n"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"App": {
|
||||||
|
"app-vue": "y",
|
||||||
|
"app-nvue": "y",
|
||||||
|
"app-uvue": "y"
|
||||||
|
},
|
||||||
|
"H5-mobile": {
|
||||||
|
"Safari": "y",
|
||||||
|
"Android Browser": "y",
|
||||||
|
"微信浏览器(Android)": "y",
|
||||||
|
"QQ浏览器(Android)": "y"
|
||||||
|
},
|
||||||
|
"H5-pc": {
|
||||||
|
"Chrome": "u",
|
||||||
|
"IE": "u",
|
||||||
|
"Edge": "u",
|
||||||
|
"Firefox": "u",
|
||||||
|
"Safari": "u"
|
||||||
|
},
|
||||||
|
"小程序": {
|
||||||
|
"微信": "y",
|
||||||
|
"阿里": "y",
|
||||||
|
"百度": "y",
|
||||||
|
"字节跳动": "y",
|
||||||
|
"QQ": "y",
|
||||||
|
"钉钉": "u",
|
||||||
|
"快手": "u",
|
||||||
|
"飞书": "u",
|
||||||
|
"京东": "u"
|
||||||
|
},
|
||||||
|
"快应用": {
|
||||||
|
"华为": "u",
|
||||||
|
"联盟": "u"
|
||||||
|
},
|
||||||
|
"Vue": {
|
||||||
|
"vue2": "y",
|
||||||
|
"vue3": "y"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"echarts": "^5.4.1",
|
||||||
|
"zrender": "^5.4.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
lockfileVersion: 5.4
|
||||||
|
|
||||||
|
specifiers:
|
||||||
|
echarts: ^5.4.1
|
||||||
|
zrender: ^5.4.3
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
echarts: registry.npmmirror.com/echarts/5.4.1
|
||||||
|
zrender: registry.npmmirror.com/zrender/5.4.3
|
||||||
|
|
||||||
|
packages:
|
||||||
|
|
||||||
|
registry.npmmirror.com/echarts/5.4.1:
|
||||||
|
resolution: {integrity: sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/echarts/-/echarts-5.4.1.tgz}
|
||||||
|
name: echarts
|
||||||
|
version: 5.4.1
|
||||||
|
dependencies:
|
||||||
|
tslib: registry.npmmirror.com/tslib/2.3.0
|
||||||
|
zrender: registry.npmmirror.com/zrender/5.4.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
registry.npmmirror.com/tslib/2.3.0:
|
||||||
|
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz}
|
||||||
|
name: tslib
|
||||||
|
version: 2.3.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
registry.npmmirror.com/zrender/5.4.1:
|
||||||
|
resolution: {integrity: sha512-M4Z05BHWtajY2241EmMPHglDQAJ1UyHQcYsxDNzD9XLSkPDqMq4bB28v9Pb4mvHnVQ0GxyTklZ/69xCFP6RXBA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/zrender/-/zrender-5.4.1.tgz}
|
||||||
|
name: zrender
|
||||||
|
version: 5.4.1
|
||||||
|
dependencies:
|
||||||
|
tslib: registry.npmmirror.com/tslib/2.3.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
registry.npmmirror.com/zrender/5.4.3:
|
||||||
|
resolution: {integrity: sha512-DRUM4ZLnoaT0PBVvGBDO9oWIDBKFdAVieNWxWwK0niYzJCMwGchRk21/hsE+RKkIveH3XHCyvXcJDkgLVvfizQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/zrender/-/zrender-5.4.3.tgz}
|
||||||
|
name: zrender
|
||||||
|
version: 5.4.3
|
||||||
|
dependencies:
|
||||||
|
tslib: registry.npmmirror.com/tslib/2.3.0
|
||||||
|
dev: false
|
||||||
|
|
@ -0,0 +1,403 @@
|
||||||
|
# echarts 图表 <span style="font-size:16px;">👑👑👑👑👑 <span style="background:#ff9d00;padding:2px 4px;color:#fff;font-size:10px;border-radius: 3px;">全端</span></span>
|
||||||
|
> 一个基于 JavaScript 的开源可视化图表库 [查看更多 站点1](https://limeui.qcoon.cn/#/echart) | [查看更多 站点2](http://liangei.gitee.io/limeui/#/echart) <br>
|
||||||
|
> 基于 echarts 做了兼容处理,更多示例请访问 [uni示例 站点1](https://limeui.qcoon.cn/#/echart-example) | [uni示例 站点2](http://liangei.gitee.io/limeui/#/echart-example) | [官方示例](https://echarts.apache.org/examples/zh/index.html) <br>
|
||||||
|
> Q群:1046793420 <br>
|
||||||
|
|
||||||
|
## 平台兼容
|
||||||
|
|
||||||
|
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
|
||||||
|
| --- | ---------- | ------------ | ---------- | ---------- | --------- | ---- |
|
||||||
|
| √ | √ | √ | √ | √ | √ | √ |
|
||||||
|
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
- 第一步:在市场导入 [百度图表](https://ext.dcloud.net.cn/plugin?id=4899)
|
||||||
|
- 第二步:选择插件依赖:<br>
|
||||||
|
1、可以选插件内的`echarts`包或自定义包,自定义包[下载地址](https://echarts.apache.org/zh/builder.html)<br>
|
||||||
|
2、或者使用`npm`安装`echarts`
|
||||||
|
|
||||||
|
**注意**
|
||||||
|
* 🔔 echarts 5.3.0及以上
|
||||||
|
* 🔔 如果是 `cli` 项目请下载插件到`src`目录下的`uni_modules`,没有这个目录就创建一个
|
||||||
|
|
||||||
|
|
||||||
|
## 代码演示
|
||||||
|
|
||||||
|
### Vue2
|
||||||
|
- 引入依赖,可以是插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html),也可以是`npm`包
|
||||||
|
|
||||||
|
```html
|
||||||
|
<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef" @finished="init"></l-echart></view>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 插件内的 三选一
|
||||||
|
import * as echarts from '@/uni_modules/lime-echart/static/echarts.min'
|
||||||
|
// 自定义的 三选一 下载后放入项目的路径
|
||||||
|
import * as echarts from 'xxx/echarts.min'
|
||||||
|
// npm包 三选一 需要在控制台 输入命令:npm install echarts
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
option: {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
|
},
|
||||||
|
confine: true
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['热度', '正面', '负面']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 15,
|
||||||
|
top: 40,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#999999'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666666'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
axisTick: { show: false },
|
||||||
|
data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#999999'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666666'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '热度',
|
||||||
|
type: 'bar',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'inside'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [300, 270, 340, 344, 300, 320, 310],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '正面',
|
||||||
|
type: 'bar',
|
||||||
|
stack: '总量',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [120, 102, 141, 174, 190, 250, 220]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '负面',
|
||||||
|
type: 'bar',
|
||||||
|
stack: '总量',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'left'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [-20, -32, -21, -34, -90, -130, -110]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// 组件能被调用必须是组件的节点已经被渲染到页面上
|
||||||
|
methods: {
|
||||||
|
async init() {
|
||||||
|
// chart 图表实例不能存在data里
|
||||||
|
const chart = await this.$refs.chartRef.init(echarts);
|
||||||
|
chart.setOption(this.option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Vue3
|
||||||
|
- 小程序可以使用`require`引入插件内提供或自己下载的[自定义包](https://echarts.apache.org/zh/builder.html)
|
||||||
|
- `require`仅支持相对路径,不支持路径别名
|
||||||
|
- 非小程序使用 `npm` 包
|
||||||
|
|
||||||
|
|
||||||
|
```html
|
||||||
|
<view style="width:750rpx; height:750rpx"><l-echart ref="chartRef"></l-echart></view>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 小程序 二选一
|
||||||
|
// 插件内的 二选一
|
||||||
|
const echarts = require('../../uni_modules/lime-echart/static/echarts.min');
|
||||||
|
// 自定义的 二选一 下载后放入项目的路径
|
||||||
|
const echarts = require('xxx/xxx/echarts');
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// 非小程序
|
||||||
|
// 需要在控制台 输入命令:npm install echarts
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
|
||||||
|
const chartRef = ref(null)
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
|
},
|
||||||
|
confine: true
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['热度', '正面', '负面']
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 15,
|
||||||
|
top: 40,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#999999'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666666'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
axisTick: { show: false },
|
||||||
|
data: ['汽车之家', '今日头条', '百度贴吧', '一点资讯', '微信', '微博', '知乎'],
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#999999'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#666666'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '热度',
|
||||||
|
type: 'bar',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'inside'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [300, 270, 340, 344, 300, 320, 310],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '正面',
|
||||||
|
type: 'bar',
|
||||||
|
stack: '总量',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [120, 102, 141, 174, 190, 250, 220]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '负面',
|
||||||
|
type: 'bar',
|
||||||
|
stack: '总量',
|
||||||
|
label: {
|
||||||
|
normal: {
|
||||||
|
show: true,
|
||||||
|
position: 'left'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: [-20, -32, -21, -34, -90, -130, -110]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
onMounted( ()=>{
|
||||||
|
// 组件能被调用必须是组件的节点已经被渲染到页面上
|
||||||
|
setTimeout(async()=>{
|
||||||
|
if(!chartRef.value) return
|
||||||
|
const myChart = await chartRef.value.init(echarts)
|
||||||
|
myChart.setOption(option)
|
||||||
|
},300)
|
||||||
|
})
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Uvue
|
||||||
|
- Uvue和Nvue不需要引入`echarts`,因为它们的实现方式是`webview`
|
||||||
|
- uniapp x需要HBX 4.13以上
|
||||||
|
|
||||||
|
```html
|
||||||
|
<view style="width: 100%; height: 408px;">
|
||||||
|
<l-echart ref="chartRef" @finished="init"></l-echart>
|
||||||
|
</view>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// @ts-nocheck
|
||||||
|
// #ifdef H5
|
||||||
|
import * as echarts from 'echarts/dist/echarts.esm.js'
|
||||||
|
// #endif
|
||||||
|
const chartRef = ref<LEchartComponentPublicInstance|null>(null);
|
||||||
|
const init = async () => {
|
||||||
|
if(chartRef.value== null) return
|
||||||
|
// #ifdef APP
|
||||||
|
const chart = await chartRef.value!.init(null)
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
const chart = await chartRef.value!.init(echarts, null)
|
||||||
|
// #endif
|
||||||
|
chart.setOption(option)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 数据更新
|
||||||
|
- 1、使用 `ref` 可获取`setOption`设置更新
|
||||||
|
- 2、也可以拿到图表实例`chart`设置`myChart.setOption(data)`
|
||||||
|
|
||||||
|
```js
|
||||||
|
// ref
|
||||||
|
this.$refs.chart.setOption(data)
|
||||||
|
|
||||||
|
// 图表实例
|
||||||
|
myChart.setOption(data)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 图表大小
|
||||||
|
- 在有些场景下,我们希望当容器大小改变时,图表的大小也相应地改变。
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 默认获取容器尺寸
|
||||||
|
this.$refs.chart.resize()
|
||||||
|
// 指定尺寸
|
||||||
|
this.$refs.chart.resize({width: 375, height: 375})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 自定义Tooltips
|
||||||
|
- uvue\nvue 不支持
|
||||||
|
由于除H5之外都不存在dom,但又有tooltips个性化的需求,代码就不贴了,看示例吧
|
||||||
|
```
|
||||||
|
代码位于/uni_modules/lime-echart/component/lime-echart
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 插件标签
|
||||||
|
- 默认 l-echart 为 component
|
||||||
|
- 默认 lime-echart 为 demo
|
||||||
|
```html
|
||||||
|
// 在任意地方使用可查看domo, 代码位于/uni_modules/lime-echart/component/lime-echart
|
||||||
|
<lime-echart></lime-echart>
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 常见问题
|
||||||
|
- 钉钉小程序 由于没有`measureText`,模拟的`measureText`又无法得到当前字体的`fontWeight`,故可能存在估计不精细的问题
|
||||||
|
- 微信小程序 `2d` 只支持 真机调试2.0
|
||||||
|
- 微信开发工具会出现 `canvas` 不跟随页面的情况,真机不影响
|
||||||
|
- 微信开发工具会出现 `canvas` 层级过高的问题,真机一般不受影响,可以先测只有两个元素的页面看是否会有层级问题。
|
||||||
|
- toolbox 不支持 `saveImage`
|
||||||
|
- echarts 5.3.0 的 lines 不支持 trailLength,故需设置为 `0`
|
||||||
|
- dataZoom H5不要设置 `showDetail`
|
||||||
|
- 如果微信小程序的`tooltip`文字有阴影,可能是微信的锅,临时解决方法是`tooltip.shadowBlur = 0`
|
||||||
|
- 如果钉钉小程序上传时报安全问题`Uint8Clamped`,可以向钉钉反馈是安全代码扫描把Uint8Clamped数组错误识别了,也可以在 echarts 文件修改`Uint8Clamped`
|
||||||
|
```js
|
||||||
|
// 找到这段代码把代码中`Uint8Clamped`改成`Uint8_Clamped`,再把下划线去掉,不过直接去掉`Uint8Clamped`也是可行的
|
||||||
|
// ["Int8","Uint8","Uint8Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e+"Array]"]
|
||||||
|
// 改成如下
|
||||||
|
["Int8","Uint8","Uint8_Clamped","Int16","Uint16","Int32","Uint32","Float32","Float64"],(function(t,e){return t["[object "+e.replace('_','')+"Array]"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### vue3
|
||||||
|
如果您是使用 **vite + vue3** 非微信小程序可能会遇到`echarts`文件缺少`wx`判断导致无法使用或缺少`tooltip`<br>
|
||||||
|
|
||||||
|
方式一:可以在`echarts.min.js`文件开头增加以下内容,参考插件内的echart.min.js的做法
|
||||||
|
|
||||||
|
```js
|
||||||
|
let global = null //有些环境缺失这个导致完法运行,比如鸿蒙
|
||||||
|
let wx = uni
|
||||||
|
```
|
||||||
|
|
||||||
|
方式二:在`vite.config.js`的`define`设置环境
|
||||||
|
|
||||||
|
```js
|
||||||
|
// 或者在`vite.config.js`的`define`设置环境
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import uni from '@dcloudio/vite-plugin-uni';
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [uni()],
|
||||||
|
define: {
|
||||||
|
global: null,//有些环境缺失这个导致完法运行,比如鸿蒙
|
||||||
|
wx: process.env.UNI_PLATFORM == 'mp-weixin' ? 'wx' : '"uni"'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Props
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --------------- | -------- | ------- | ------------ | ----- |
|
||||||
|
| custom-style | 自定义样式 | `string` | - | - |
|
||||||
|
| type | 指定 canvas 类型 | `string` | `2d` | |
|
||||||
|
| is-disable-scroll | 触摸图表时是否禁止页面滚动 | `boolean` | `false` | |
|
||||||
|
| beforeDelay | 延迟初始化 (毫秒) | `number` | `30` | |
|
||||||
|
| enableHover | PC端使用鼠标悬浮 | `boolean` | `false` | |
|
||||||
|
|
||||||
|
## 事件
|
||||||
|
|
||||||
|
| 参数 | 说明 |
|
||||||
|
| --------------- | --------------- |
|
||||||
|
| init(echarts, chart => {}) | 初始化调用函数,第一个参数是传入`echarts`,第二个参数是回调函数,回调函数的参数是 `chart` 实例 |
|
||||||
|
| setChart(chart => {}) | 已经初始化后,请使用这个方法,是个回调函数,参数是 `chart` 实例 |
|
||||||
|
| setOption(data) | [图表配置项](https://echarts.apache.org/zh/option.html#title),用于更新 ,传递是数据 `option` |
|
||||||
|
| clear() | 清空当前实例,会移除实例中所有的组件和图表。 |
|
||||||
|
| dispose() | 销毁实例 |
|
||||||
|
| showLoading() | 显示加载 |
|
||||||
|
| hideLoading() | 隐藏加载 |
|
||||||
|
| [canvasToTempFilePath](https://uniapp.dcloud.io/api/canvas/canvasToTempFilePath.html#canvastotempfilepath)(opt) | 用于生成图片,与官方使用方法一致,但不需要传`canvasId` |
|
||||||
|
|
||||||
|
|
||||||
|
## 打赏
|
||||||
|
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
|
||||||
|

|
||||||
|

|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,173 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||||
|
<title></title>
|
||||||
|
<style type="text/css">
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
.canvas {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow-y: hidden;
|
||||||
|
background-color: transparent;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="canvas" id="limeChart"></div>
|
||||||
|
<script type="text/javascript" src="./uni.webview.1.5.5.js"></script>
|
||||||
|
<script type="text/javascript" src="./echarts.min.js"></script>
|
||||||
|
<script type="text/javascript" src="./ecStat.min.js"></script>
|
||||||
|
<!-- <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts-liquidfill@latest/dist/echarts-liquidfill.min.js"></script> -->
|
||||||
|
<script>
|
||||||
|
let chart = null;
|
||||||
|
let cache = [];
|
||||||
|
console.log = function() {
|
||||||
|
emit('log', {
|
||||||
|
log: arguments,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function emit(event, data) {
|
||||||
|
postMessage({
|
||||||
|
event,
|
||||||
|
data
|
||||||
|
})
|
||||||
|
cache = []
|
||||||
|
}
|
||||||
|
|
||||||
|
function postMessage(data) {
|
||||||
|
uni.webView.postMessage({
|
||||||
|
data
|
||||||
|
})
|
||||||
|
// window.__uniapp_x_.postMessage(JSON.stringify(data))
|
||||||
|
};
|
||||||
|
|
||||||
|
function stringify(key, value) {
|
||||||
|
if (typeof value === 'object' && value !== null) {
|
||||||
|
if (cache.indexOf(value) !== -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cache.push(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse(name, callback, options) {
|
||||||
|
const optionNameReg = /[\w]+\.setOption\(([\w]+\.)?([\w]+)\)/
|
||||||
|
if (optionNameReg.test(callback)) {
|
||||||
|
const optionNames = callback.match(optionNameReg)
|
||||||
|
if (optionNames[1]) {
|
||||||
|
const _this = optionNames[1].split('.')[0]
|
||||||
|
window[_this] = {}
|
||||||
|
window[_this][optionNames[2]] = options
|
||||||
|
return optionNames[2]
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function init(callback, options, opts, theme) {
|
||||||
|
if (!chart) {
|
||||||
|
chart = echarts.init(document.getElementById('limeChart'), theme, opts)
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
chart.setOption(options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function on(data) {
|
||||||
|
if (chart && data.length > 0) {
|
||||||
|
const [type, query] = data
|
||||||
|
const key = `${type}${JSON.stringify(query||'')}`
|
||||||
|
if (query) {
|
||||||
|
chart.on(type, query, function(options) {
|
||||||
|
var obj = {};
|
||||||
|
Object.keys(options).forEach(function(key) {
|
||||||
|
if (key != 'event') {
|
||||||
|
obj[key] = options[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit(key, {
|
||||||
|
event: key,
|
||||||
|
options: obj,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
chart.on(type, function(options) {
|
||||||
|
var obj = {};
|
||||||
|
Object.keys(options).forEach(function(key) {
|
||||||
|
if (key != 'event') {
|
||||||
|
obj[key] = options[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit(key, {
|
||||||
|
event: key,
|
||||||
|
options: obj,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function setChart(callback, options) {
|
||||||
|
if (!callback) return
|
||||||
|
if (chart && callback && options) {
|
||||||
|
var r = null
|
||||||
|
const name = parse('r', callback, options)
|
||||||
|
if (name) this[name] = options
|
||||||
|
eval(`r = ${callback};`)
|
||||||
|
if (r) {
|
||||||
|
r(chart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOption(data) {
|
||||||
|
if (chart) chart.setOption(data[0], data[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLoading(data) {
|
||||||
|
if (chart) chart.showLoading(data[0], data[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideLoading() {
|
||||||
|
if (chart) chart.hideLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
if (chart) chart.clear()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function dispose() {
|
||||||
|
if (chart) chart.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize(size) {
|
||||||
|
if (chart) chart.resize(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
function canvasToTempFilePath(opt) {
|
||||||
|
if (chart) {
|
||||||
|
delete opt.success
|
||||||
|
const src = chart.getDataURL(opt)
|
||||||
|
postMessage({
|
||||||
|
// event: 'file',
|
||||||
|
file: src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Reference in New Issue