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();
- },
- });
|