<template> <view> <view class="qiun-columns"> <uCharts id="ucharts" :val="opts.val" :min="opts.min" :max="opts.max" :step="opts.step" :width="opts.width" :height="opts.height" :border="opts.border" :title="opts.title" :showUnit="opts.showUnit" :unit="opts.unit" :showDecimal="opts.showDecimal" :colorSatrt="opts.colorSatrt" :colorEnd="opts.colorEnd" :colorButton="opts.colorButton" :pageBg="opts.pageBg" :circleBg="opts.circleBg" :pointBg="opts.pointBg" :setUpUrl="opts.setUpUrl" @change="change" ref="ucharts" /> </view> <button class="qiun-button" @tap="changeData()">更新圖表</button> <!-- 下面是簡單調用的例子,除了id和val其餘的均可以不給 --> <view class="qiun-columns"> <uCharts id="ucharts2" :val="simple" title="PM2.5" colorSatrt="#5ACECE" :showUnit="showUnit" colorEnd="#8CCE42"/> </view> </view> </template> <script> import uCharts from '@/components/u-charts/bar.vue'; var _self; export default { data() { return { simple:18, showUnit:false, opts:{ val:15.8, min:10, max:40, step:1, width:220, height:220, border:35, title:'室內溫度',//傳null爲不顯示最上面標題 showUnit:true,//是否顯示單位 unit:'℃', showDecimal:true,//是否小數 colorSatrt:'#FFC2B3', colorEnd:'#FF3B1D', colorButton:'#565656',//底部按鈕顏色 pageBg:'#F4F5F6',//組件頁面背景色,若是父組件像本示例設置了padding,你懂的哈 circleBg:'#FFFFFF',//中間圓心文字塊的背景色 pointBg:'#FFFFFF'//控制點背景色 // setUpUrl:'../../page/testurl'//設置那個按鈕跳轉的地方 } }; }, components: { uCharts }, onLoad() { _self = this; this.getServerData(); }, methods: { change(val){ console.log(val) }, getServerData() { }, changeData() { //做爲調用組件內方法的示例,您自由想象發揮哈 this.$refs.ucharts.changeData(28.35); } } }; </script> <style> .qiun-columns { display: flex; flex-direction: column !important; padding: 40upx; } </style>
<template> <view class="progress_box" :style="{'background-color': pageBg}"> <canvas :canvas-id="id" :style="{'width':width+'px','height':height+'px'}" disable-scroll=true @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"></canvas> <view class="progress_txt" :style="{'width':centerRadius+'px','height':centerRadius+'px','background-color': circleBg}"> <view class="progress_info_top" v-if="title">{{title}}</view> <view class="progress_info_center"> <view class="progress_info_center_a"> {{ integer }} </view> <view class="progress_info_center_c"> <view class="progress_info_center_c1"><text class="c1_text" v-if="showUnit">{{unit}}</text></view> <view class="progress_info_center_c2"><text class="c1_text" v-if="showDecimal">.{{ decimal }}</text></view> </view> </view> <view class="progress_info_bottom" @tap="goSetUp">設置</view> </view> </view> </template> <script> function isInAngleRange(angle, startAngle, endAngle) { function adjust(angle) { while (angle < 0) { angle += 2 * Math.PI; } while (angle > 2 * Math.PI) { angle -= 2 * Math.PI; } return angle; } angle = adjust(angle); startAngle = adjust(startAngle); endAngle = adjust(endAngle); if (startAngle > endAngle) { endAngle += 2 * Math.PI; if (angle < startAngle) { angle += 2 * Math.PI; } } return angle >= startAngle && angle <= endAngle; } function isInArea(e, r) { return Math.pow(e.x - r.x, 2) + Math.pow(e.y - r.y, 2) <= Math.pow(r.r, 2); } function isInUp(e,r) { if(isInArea(e,r)){ let angle = Math.atan2(r.y - e.y, e.x - r.x); angle = -angle; if (isInAngleRange(angle, 0.5*Math.PI, 0.75*Math.PI)) { return true; }else{ return false; } }else{ return false; } } function isInDown(e,r) { if(isInArea(e,r)){ let angle = Math.atan2(r.y - e.y, e.x - r.x); angle = -angle; if (isInAngleRange(angle, 0.25*Math.PI, 0.5*Math.PI)) { return true; }else{ return false; } }else{ return false; } } function isInCtrl(e,r) { if(isInArea(e,r)){ return true; }else{ return false; } } export default { props:{ id:{ default:'ucharts' }, val:{ default:0 }, min:{ default:-10 }, max:{ default:30 }, step:{ default:1 }, width:{ default:220 }, height:{ default:220 }, border:{ default:35 }, title:{ default:null }, unit:{ default:'℃' }, showUnit:{ default:'true' }, showDecimal:{ default:'true' }, colorSatrt:{ default:'#FFC2B3' }, colorEnd:{ default:'#FF3B1D' }, colorButton:{ default:'#565656' }, pageBg:{ default:'#F4F5F6' }, circleBg:{ default:'#FFFFFF' }, pointBg:{ default:'#FFFFFF' }, setUpUrl:{ default:'../../page/initUrl' } }, data() { return { valData:0, valPoint:{}, centerPoint:{}, insideRadius:{}, startPoint:{}, endPoint:{}, isMove:false } }, computed: { integer:function() { if(this.valData<this.min){ return this.min }; if(this.valData>this.max){ return this.max }; return parseInt(this.valData); }, decimal:function() { if(this.valData<this.min){ return 0 }; if(this.valData>this.max){ return 0 }; return Math.abs(parseInt(this.valData*10)-parseInt(this.valData)*10); }, centerRadius:function() { return Math.min(this.width/2-this.border,this.height/2-this.border)*2 * 0.9; } }, mounted: function() { this.valData=this.val; this.drawCircle(this.val,this.min,this.max,this.width,this.height,this.border,this.colorSatrt,this.colorEnd,this.colorButton,this.pointBg); }, methods: { drawCircle:function(val,min,max,width,height,border,colorSatrt,colorEnd,colorButton,pointBg) { let radius=Math.min(width/2-border/2,height/2-border/2); let centerPoint={ x:width/2, y:height/2, r:radius+border/2 }; this.centerPoint=centerPoint; this.insideRadius={ x:width/2, y:height/2, r:radius-border/2 } let ctx = uni.createCanvasContext(this.id, this); ctx.setLineWidth(border); ctx.setStrokeStyle(colorButton); ctx.setLineCap('butt'); //畫按鈕背景 ctx.beginPath(); ctx.arc(centerPoint.x, centerPoint.y, radius , 0.25 * Math.PI, 0.75 * Math.PI, false); ctx.stroke(); //畫按鈕 ctx.setLineWidth(1); ctx.setStrokeStyle("#FFFFFF"); ctx.beginPath(); ctx.moveTo(centerPoint.x, height); ctx.lineTo(centerPoint.x, height-border); ctx.stroke(); ctx.setLineWidth(3); ctx.beginPath(); let upPoint={ x:centerPoint.x+(radius)*Math.cos(0.625* Math.PI), y:centerPoint.x+(radius)*Math.sin(0.625* Math.PI) }; let downPoint={ x:centerPoint.x+(radius)*Math.cos(0.375* Math.PI), y:centerPoint.x+(radius)*Math.sin(0.375* Math.PI) }; let xLength=border*0.6/2; ctx.moveTo(upPoint.x-xLength, upPoint.y); ctx.lineTo(upPoint.x+xLength, upPoint.y); ctx.moveTo(upPoint.x, upPoint.y-xLength); ctx.lineTo(upPoint.x, upPoint.y+xLength); ctx.moveTo(downPoint.x-xLength, downPoint.y); ctx.lineTo(downPoint.x+xLength, downPoint.y); ctx.stroke(); //變色背景條 ctx.setLineWidth(border); let gradient = ctx.createLinearGradient(centerPoint.x-radius-border, centerPoint.y, centerPoint.x+radius+border, centerPoint.y); gradient.addColorStop('0', colorSatrt); gradient.addColorStop('1.0', colorEnd); ctx.setStrokeStyle(gradient); ctx.beginPath(); ctx.arc(centerPoint.x, centerPoint.y, radius , 0.75 * Math.PI, 0.25 * Math.PI, false); ctx.stroke(); //畫控制點 ctx.beginPath(); ctx.setFillStyle(pointBg); //控制點陰影效果,不須要能夠刪掉 ctx.setShadow(2, 2, 2, '#888888') if(val<min) val=min; if(val>max) val=max; let progress = (val- min) / (max - min) ; //控制點半徑 let valRadius=border * 0.45; //控制點弧度 let valRadian= valRadius / (Math.PI * radius); progress = (1.5-2*valRadian) * progress + 0.75+valRadian; if (progress >= 2) { progress = progress % 2; } let valPoint={ x:centerPoint.x+(radius)*Math.cos(progress* Math.PI), y:centerPoint.x+(radius)*Math.sin(progress* Math.PI), r:valRadius, v:val, s:0.75+valRadian, e:2.25-valRadian, t:1.5-2*valRadian, n:progress, }; this.valPoint=valPoint; ctx.arc(valPoint.x, valPoint.y, valPoint.r, 0, 2 * Math.PI, false); ctx.closePath(); ctx.fill(); ctx.draw(); }, touchStart:function(e) { let touches = e.mp.changedTouches[0] || e.changedTouches[0]; if(isInCtrl(touches,this.valPoint)){ this.isMove=true; touches.val=this.valPoint; this.startPoint=touches; } }, touchMove:function(e) { let touches = e.mp.changedTouches[0] || e.changedTouches[0]; if(this.isMove === true){ //這兩句是判斷是否在進度條內,加上體驗很差,你能夠試一下&& isInArea(touches,this.insideRadius) === false && isInArea(touches,this.centerPoint) === true let angle = Math.atan2(this.centerPoint.y - touches.y, touches.x - this.centerPoint.x); angle = -angle; let newRadian = angle/Math.PI; if(newRadian<0){ newRadian = 2 + newRadian; } if(newRadian < this.startPoint.val.e - 1.7){ newRadian += 2; } let progress = (newRadian - this.startPoint.val.s)/this.startPoint.val.t; progress = (this.max - this.min)*progress; let nweVal = this.min + progress; if(nweVal>this.max) nweVal = this.max; if(nweVal<this.min) nweVal = this.min; nweVal=(parseInt(nweVal*10)*0.1).toFixed(1); this.valData = nweVal; this.drawCircle(nweVal,this.min,this.max,this.width,this.height,this.border,this.colorSatrt,this.colorEnd,this.colorButton,this.pointBg); } }, touchEnd:function(e) { let touches = e.mp.changedTouches[0] || e.changedTouches[0]; if(isInUp(touches,this.centerPoint) === true && this.isMove === false){ this.valData+=this.step; if(this.valData>this.max) this.valData = this.max; this.drawCircle(this.valData,this.min,this.max,this.width,this.height,this.border,this.colorSatrt,this.colorEnd,this.colorButton,this.pointBg); } if(isInDown(touches,this.centerPoint) === true && this.isMove === false){ this.valData-=this.step; if(this.valData<this.min) this.valData = this.min; this.drawCircle(this.valData,this.min,this.max,this.width,this.height,this.border,this.colorSatrt,this.colorEnd,this.colorButton,this.pointBg); } if(this.isMove){ this.$emit('change',this.valData) // let _this=this; // uni.request({ // url: 'https://www.ucharts.cn/data.json', // data:{ // val:this.valData // }, // success: function(res) { // console.log("發送新數據["+_this.valData+"]成功!") // }, // fail: () => { // _self.tips="網絡錯誤,小程序端請檢查合法域名"; // }, // }); // this.isMove = false; } }, goSetUp:function() { console.log(this.setUpUrl); uni.showToast({ title: '跳轉界面', duration: 2000 }); }, changeData:function(val) { this.valData=val; this.drawCircle(val,this.min,this.max,this.width,this.height,this.border,this.colorSatrt,this.colorEnd,this.colorButton,this.pointBg); }, } }; </script> <style> .progress_box { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; text-align: center; } .progress_txt { position: absolute; font-size: 28upx; border-radius: 50%; flex-direction: column !important; display: flex; align-items: center; justify-content: center; text-align: center; box-shadow:0 0 6upx 4upx #DEDEDE; } .progress_info_top { font-size: 32upx; letter-spacing: 2upx; color: #000000; } .progress_info_center { display: flex; flex-direction: row !important; color: #000000; } .progress_info_center_a { font-size: 80upx; height: 100upx; line-height: 100upx; font-weight: bold; letter-spacing: 2upx; } .progress_info_center_c { position: relative; height: 100upx; display: flex; flex-direction: column !important; align-items: center; justify-content: center; } .progress_info_center_c1 { display: flex; height: 50upx; align-items: center ; } .c1_text{ height: 28upx; font-size: 28upx; letter-spacing: 2upx; } .progress_info_center_c2 { display: flex; height: 50upx; align-items:flex-start; } .c2_text{ height: 50upx; font-size: 28upx; letter-spacing: 2upx; } .progress_info_bottom { font-size: 32upx; letter-spacing: 2upx; color: #666666; } </style>
page { background: #F4F5F6; width: 750upx; overflow-x: hidden; } .qiun-padding { padding: 2%; width: 96%; } .qiun-wrap { display: flex; flex-wrap: wrap; } .qiun-rows { display: flex; flex-direction: row !important; } .qiun-columns { display: flex; flex-direction: column !important; } .qiun-common-mt { margin-top: 10upx; } .qiun-common-border-bottom { border-bottom: 1px solid #E9E9E9; } .qiun-bg-white { background: #FFFFFF; } .qiun-title-bar { width: 96%; padding: 10upx 2%; flex-wrap: nowrap; } .qiun-title-dot-light { border-left: 10upx solid #0ea391; padding-left: 10upx; font-size: 32upx; color: #000000 } .qiun-textarea { height: 400upx; font-size: 34upx; box-sizing: border-box; line-height: 50upx; width: 100%; background-color: #FFFFFF; } .qiun-text-tips { font-size: 28upx; color: #dc2626; line-height: 40upx; padding: 6upx; } .qiun-button { background: #2fc25b; color: #FFFFFF; margin: 20upx; } /* 通用樣式 */ .qiun-charts { width: 750upx; height: 500upx; background-color: #FFFFFF; } .charts { width: 750upx; height: 500upx; background-color: #FFFFFF; } /* 橫屏樣式 */ .qiun-charts-rotate { width: 700upx; height: 1100upx; background-color: #FFFFFF; padding: 25upx; } .charts-rotate { width: 700upx; height: 1100upx; background-color: #FFFFFF; } /* 圓弧進度樣式 */ .qiun-charts3 { width: 750upx; height: 250upx; background-color: #FFFFFF; position: relative; } .charts3 { position: absolute; width: 250upx; height: 250upx; background-color: #FFFFFF; }