123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- <template>
- <view class="progress_box" :style="{ 'background-color': pageBg }">
- <!-- #ifdef MP-ALIPAY -->
- <canvas :id="id" :style="{ width: width + 'px', height: width + 'px' }" :disable-scroll="isMove"
- @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"></canvas>
- <!-- #endif -->
- <!-- #ifndef MP-ALIPAY -->
- <canvas :canvas-id="id" :style="{ width: width + 'px', height: width + 'px' }" :disable-scroll="isMove"
- @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"></canvas>
- <!-- #endif -->
- <view class="p_ps_show" v-if="!$slots.default">
- <view class="ps_text plan" :style="{'color': colorEnd}">
- <text v-if="false">{{circleTotal}}</text>
- <text>{{centerTxt}}</text>
- </view>
- <!-- <view class="ps_text his" v-if="isTwoVal">
- <text>{{twoVal}}</text>
- <text>Puffs</text>
- </view> -->
- </view>
- <view v-else class="p_ps_show">
- <slot></slot>
- </view>
- </view>
- </template>
- <script>
- function isInArea(e, r) {
- return Math.pow(e.x - r.x, 2) + Math.pow(e.y - r.y, 2) <= Math.pow(r.r + 10, 2);
- }
- function isInCtrl(e, r) {
- if (isInArea(e, r)) {
- return true;
- } else {
- return false;
- }
- }
- export default {
- props: {
- id: {
- default: 'canvas'
- },
- val: {
- default: 0
- },
- twoVal: {
- default: 0
- },
- isTwoVal: {
- default: true
- },
- // 步进值
- step: {
- default: 5
- },
- // 宽度
- width: {
- default: 220
- },
- // 圆的宽度
- border: {
- default: 35
- },
- colorSatrt: {
- default: '#FFD2E0'
- },
- // 圆的颜色
- colorEnd: {
- default: '#ff0163'
- },
- // 圆的外层的颜色
- colorButton: {
- default: '#ffffff'
- },
- // 背景色
- pageBg: {
- default: '#ffffff'
- },
- // 一圈的值
- circle: {
- default: 300
- },
- oneCircle: {
- default: false
- }
- },
- data() {
- return {
- oldTouches: {},
- valData: 0,
- circleNum: 0,
- centerColor: '',
- valPoint: {},
- centerPoint: {},
- isMove: false,
- centerTxt:'滑动解锁'
- };
- },
- mounted() {
- this.circleNum = Math.floor(this.val / this.circle)
- this.valData = this.val % this.circle
- const gradientList = this.gradient(this.colorSatrt, this.colorEnd, 3)
- this.centerColor = gradientList ? gradientList[1] : '#ff8cb6'
- this.setDrawCircle(this.valData)
- },
- computed: {
- circleTotal() {
- return this.circleNum * this.circle + this.valData
- }
- },
- watch: {
- val(val) {
- this.circleNum = Math.floor(val / this.circle)
- this.valData = val % this.circle
- this.setDrawCircle(this.valData)
- }
- },
- methods: {
- setDrawCircle(val) {
- this.valData = val
- this.drawCircle(this.valData, this.width, this.border, this.colorSatrt, this.colorEnd, this.colorButton);
- },
- drawCircle(val = 0, width, border, colorSatrt, colorEnd, colorButton) {
- let radius = width / 2 - 20; //半径
- let centerPoint = {
- //坐标
- x: width / 2,
- y: width / 2,
- r: radius
- };
- this.centerPoint = centerPoint;
- let ctx = uni.createCanvasContext(this.id, this);
- if (this.circleNum <= 0) {
- // 圆的颜色
- ctx.setStrokeStyle(colorSatrt);
- // 开始绘制圆形
- ctx.beginPath();
- // 设置圆的宽度
- ctx.setLineWidth(border + 4);
- // 绘制一个圆形
- ctx.arc(centerPoint.x, centerPoint.y, radius, 0, 2 * Math.PI, false);
- ctx.stroke();
- ctx.closePath();
- }
- const circleb = (this.circle / 2)
- const overOneRound = this.circleNum >= 1
- let arcVal = val
- let orign = [centerPoint.x, centerPoint.y]
- if (overOneRound) {
- arcVal = this.circle
- ctx.save()
- ctx.translate(centerPoint.x, centerPoint.y)
- ctx.rotate(val / this.circle * 2 * Math.PI)
- orign = [0, 0]
- }
- // 绘制渐变
- ctx.beginPath();
- // 设置圆的宽度
- ctx.setLineWidth(border + 4);
- ctx.setLineCap('round')
- let b = ctx.createLinearGradient(0, 0, 0, orign[1] + radius); //创建渐变对象 渐变开始点和渐变结束点
- b.addColorStop(0, colorSatrt); //渐变开始值
- b.addColorStop(1, this.centerColor); //渐变结束值
- ctx.strokeStyle = b; //使用渐变对象作为圆环的颜色
- ctx.arc(orign[0], orign[1], radius, 1.5 * Math.PI, (1.5 + arcVal / circleb) * Math.PI, false);
- ctx.stroke();
- ctx.closePath();
- if (arcVal > circleb) {
- ctx.beginPath();
- ctx.setLineCap('round')
- ctx.setLineWidth(border + 4);
- let g = ctx.createLinearGradient(0, orign[1] + radius, 0, 0);
- g.addColorStop(0, this.centerColor);
- g.addColorStop(1, colorEnd);
- ctx.strokeStyle = g;
- ctx.arc(orign[0], orign[1], radius, 0.5 * Math.PI, (0.5 + (arcVal - circleb) / circleb) * Math.PI,
- false);
- ctx.stroke();
- ctx.closePath();
- }
- if (overOneRound) {
- ctx.restore()
- }
- //画控制点
- let valRadius = border + 1; //点的半径
- // 点的半径
- let valRadian = 0;
- val -= circleb - circleb / 2
- let valPoint = {
- x: centerPoint.x + radius * Math.cos((val / circleb) * Math.PI),
- y: centerPoint.y + radius * Math.sin((val / circleb) * Math.PI),
- r: valRadius,
- v: val,
- s: 0.75 + valRadian,
- e: 2.25 - valRadian,
- t: 1.5 - 2 * valRadian,
- n: val
- };
- // console.log(valPoint)
- // console.log('centerPoint',centerPoint)
- this.valPoint = valPoint;
- // 点最外层
- ctx.beginPath();
- ctx.setFillStyle(colorButton);
- ctx.arc(valPoint.x, valPoint.y, valPoint.r, 0, 2 * Math.PI, false);
- ctx.fill()
- // 点内部的颜色
- ctx.beginPath();
- ctx.setFillStyle(colorEnd);
- ctx.arc(valPoint.x, valPoint.y, valPoint.r - 2, 0, 2 * Math.PI, false);
- ctx.fill();
- ctx.closePath();
- // 绘制箭头
- ctx.translate(valPoint.x, valPoint.y)
- ctx.rotate(val / this.circle * 2 * Math.PI)
- ctx.beginPath();
- ctx.setLineCap('round')
- ctx.setLineWidth(3)
- ctx.setStrokeStyle('#FF99C1')
- ctx.moveTo(0, 4);
- ctx.lineTo(-5, -2);
- ctx.stroke()
- ctx.moveTo(0, 4);
- ctx.lineTo(5, -2);
- ctx.stroke()
- ctx.closePath();
- ctx.setTransform(1, 0, 0, 1, 0, 0)
- ctx.draw();
- },
- // 获取两个颜色之间渐变的色值
- gradient(startColor, endColor, step) {
- function rgbToHex(r, g, b) {
- let hex = ((r << 16) | (g << 8) | b).toString(16);
- return "#" + new Array(Math.abs(hex.length - 7)).join("0") + hex;
- }
- function hexToRgb(hex) {
- let rgb = [];
- for (let i = 1; i < 7; i += 2) {
- rgb.push(parseInt("0x" + hex.slice(i, i + 2)));
- }
- return rgb;
- }
- //将hex转换为rgb
- let sColor = hexToRgb(startColor);
- let eColor = hexToRgb(endColor);
- //计算R\G\B每一步的差值
- let rStep = (eColor[0] - sColor[0]) / step;
- let gStep = (eColor[1] - sColor[1]) / step;
- let bStep = (eColor[2] - sColor[2]) / step;
- let gradientColorArr = [];
- for (let i = 0; i < step; i++) {
- //计算每一步的hex值
- gradientColorArr.push(rgbToHex(parseInt(rStep * i + sColor[0]), parseInt(gStep * i + sColor[1]),
- parseInt(bStep * i + sColor[2])));
- }
- return gradientColorArr;
- },
- touchStart(e) {
- let touches = e.mp.changedTouches[0] || e.changedTouches[0];
- this.oldTouches = {
- x: touches.x,
- y: touches.y
- };
- if (isInCtrl(touches, this.valPoint)) {
- this.isMove = true;
- }
- },
- touchMove(e) {
- const oldTouches = this.oldTouches;
- const touches = e.mp.changedTouches[0] || e.changedTouches[0];
- if (this.isMove === true) {
- let angle = Math.atan2(this.centerPoint.y - touches.y, this.centerPoint.x - touches.x) / Math.PI;
- let degrees = angle * 180 - 90 // -180 ~ 180
- // 判断是加还是减
- let numVal = 0
- if (degrees >= 0 && degrees <= 180) {
- numVal = Math.round(degrees * ((this.circle / 2) / 180))
- } else {
- numVal = Math.round((360 + degrees) * ((this.circle / 2) / 180))
- }
- if (numVal < this.circle / 30 && this.valData > this.circle - this.circle / 30) {
- this.circleNum += 1
- } else if ((numVal - this.valData) >= (this.circle / 2)) {
- this.circleNum -= 1
- }
- this.valData = numVal
- if (this.circleNum < 0) {
- this.circleNum = 0
- this.valData = 0
- }
- if (this.oneCircle && this.circleNum > 0) {
- this.circleNum = 1
- this.valData = 0
- }
- this.setDrawCircle(this.valData)
- }
- },
- touchEnd(e) {
- if (this.isMove) {
- this.$emit('change', this.circleTotal);
- if(this.circleTotal < 290) {
- this.centerTxt = '解锁失败';
- let that = this;
- setTimeout(function() {
- that.centerTxt = '滑动解锁';
- that.setDrawCircle(0)
- },500);
- }else {
- this.centerTxt = '解锁成功';
- }
- }
- this.isMove = false;
- }
- }
- };
- </script>
- <style scoped lang="scss">
- .progress_box {
- position: relative;
- .p_ps_show {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- display: flex;
- flex-direction: column;
- align-items: center;
- .ps_text {
- display: flex;
- flex-direction: column;
- align-items: center;
- font-size: 60rpx;
- padding: 0 20rpx;
- &.plan {
- border-bottom: solid 0rpx #acacac;
- padding-bottom: 8rpx;
- }
- &.his {
- color: #acacac;
- }
- text {
- &:first-child {
- font-weight: bold;
- }
- &:last-child {
- font-size: 30rpx;
- }
- }
- }
- }
- }
- </style>
|