新增部分图标
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",
|
||||
"style": {}
|
||||
},
|
||||
{
|
||||
"path" : "pages/index/echarts",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : ""
|
||||
}
|
||||
}
|
||||
],
|
||||
// "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> -->
|
||||
</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">
|
||||
{{getNameByKey('bloodGlucose')}}
|
||||
</view>
|
||||
|
|
@ -67,7 +67,7 @@
|
|||
<image src="../../static/icon/xuetang.png" mode="widthFix"></image>
|
||||
</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">
|
||||
{{getNameByKey('bloodOxygen')}}
|
||||
</view>
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
</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">
|
||||
{{getNameByKey('bodyTemperature')}}
|
||||
</view>
|
||||
|
|
@ -134,7 +134,7 @@
|
|||
</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">
|
||||
{{getNameByKey('pulseReat')}}
|
||||
</view>
|
||||
|
|
@ -224,7 +224,7 @@
|
|||
</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>
|
||||
|
|
|
|||
|
|
@ -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