uniapp 开发智能温控开关 (环状图)

Posted neo-java

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uniapp 开发智能温控开关 (环状图)相关的知识,希望对你有一定的参考价值。

技术图片

  • index.vue
<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>

  • bar.vue

<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>


  • qiun.css

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;


以上是关于uniapp 开发智能温控开关 (环状图)的主要内容,如果未能解决你的问题,请参考以下文章

Google活动 | 智能家居开发者工作坊诚邀您参加

python测试开发django-148.ECharts 生成环状图(饼图)

uniapp骨架图使用不了

温控 开关

[教程]开机测试工具+HYBRID温控开关使用方法(影片)

新手怎么用uniapp制作图中小程序的样式?