| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 | import { BLUE, WHITE } from '../common/color';import { VantComponent } from '../common/component';import { getSystemInfoSync } from '../common/utils';import { isObj } from '../common/validator';import { canIUseCanvas2d } from '../common/version';import { adaptor } from './canvas';function format(rate) {    return Math.min(Math.max(rate, 0), 100);}const PERIMETER = 2 * Math.PI;const BEGIN_ANGLE = -Math.PI / 2;const STEP = 1;VantComponent({    props: {        text: String,        lineCap: {            type: String,            value: 'round',        },        value: {            type: Number,            value: 0,            observer: 'reRender',        },        speed: {            type: Number,            value: 50,        },        size: {            type: Number,            value: 100,            observer() {                this.drawCircle(this.currentValue);            },        },        fill: String,        layerColor: {            type: String,            value: WHITE,        },        color: {            type: null,            value: BLUE,            observer() {                this.setHoverColor().then(() => {                    this.drawCircle(this.currentValue);                });            },        },        type: {            type: String,            value: '',        },        strokeWidth: {            type: Number,            value: 4,        },        clockwise: {            type: Boolean,            value: true,        },    },    data: {        hoverColor: BLUE,    },    methods: {        getContext() {            const { type, size } = this.data;            if (type === '' || !canIUseCanvas2d()) {                const ctx = wx.createCanvasContext('van-circle', this);                return Promise.resolve(ctx);            }            const dpr = getSystemInfoSync().pixelRatio;            return new Promise((resolve) => {                wx.createSelectorQuery()                    .in(this)                    .select('#van-circle')                    .node()                    .exec((res) => {                    const canvas = res[0].node;                    const ctx = canvas.getContext(type);                    if (!this.inited) {                        this.inited = true;                        canvas.width = size * dpr;                        canvas.height = size * dpr;                        ctx.scale(dpr, dpr);                    }                    resolve(adaptor(ctx));                });            });        },        setHoverColor() {            const { color, size } = this.data;            if (isObj(color)) {                return this.getContext().then((context) => {                    if (!context)                        return;                    const LinearColor = context.createLinearGradient(size, 0, 0, 0);                    Object.keys(color)                        .sort((a, b) => parseFloat(a) - parseFloat(b))                        .map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key]));                    this.hoverColor = LinearColor;                });            }            this.hoverColor = color;            return Promise.resolve();        },        presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) {            const { strokeWidth, lineCap, clockwise, size } = this.data;            const position = size / 2;            const radius = position - strokeWidth / 2;            context.setStrokeStyle(strokeStyle);            context.setLineWidth(strokeWidth);            context.setLineCap(lineCap);            context.beginPath();            context.arc(position, position, radius, beginAngle, endAngle, !clockwise);            context.stroke();            if (fill) {                context.setFillStyle(fill);                context.fill();            }        },        renderLayerCircle(context) {            const { layerColor, fill } = this.data;            this.presetCanvas(context, layerColor, 0, PERIMETER, fill);        },        renderHoverCircle(context, formatValue) {            const { clockwise } = this.data;            // 结束角度            const progress = PERIMETER * (formatValue / 100);            const endAngle = clockwise                ? BEGIN_ANGLE + progress                : 3 * Math.PI - (BEGIN_ANGLE + progress);            this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle);        },        drawCircle(currentValue) {            const { size } = this.data;            this.getContext().then((context) => {                if (!context)                    return;                context.clearRect(0, 0, size, size);                this.renderLayerCircle(context);                const formatValue = format(currentValue);                if (formatValue !== 0) {                    this.renderHoverCircle(context, formatValue);                }                context.draw();            });        },        reRender() {            // tofector 动画暂时没有想到好的解决方案            const { value, speed } = this.data;            if (speed <= 0 || speed > 1000) {                this.drawCircle(value);                return;            }            this.clearMockInterval();            this.currentValue = this.currentValue || 0;            const run = () => {                this.interval = setTimeout(() => {                    if (this.currentValue !== value) {                        if (Math.abs(this.currentValue - value) < STEP) {                            this.currentValue = value;                        }                        else if (this.currentValue < value) {                            this.currentValue += STEP;                        }                        else {                            this.currentValue -= STEP;                        }                        this.drawCircle(this.currentValue);                        run();                    }                    else {                        this.clearMockInterval();                    }                }, 1000 / speed);            };            run();        },        clearMockInterval() {            if (this.interval) {                clearTimeout(this.interval);                this.interval = null;            }        },    },    mounted() {        this.currentValue = this.data.value;        this.setHoverColor().then(() => {            this.drawCircle(this.currentValue);        });    },    destroyed() {        this.clearMockInterval();    },});
 |