123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import { createVNode as _createVNode } from "vue";
- import { watch, computed, defineComponent } from "vue";
- import { raf, cancelRaf } from "@vant/use";
- import { isObject, truthProp, numericProp, getSizeStyle, makeStringProp, makeNumberProp, makeNumericProp, createNamespace } from "../utils/index.mjs";
- const [name, bem] = createNamespace("circle");
- let uid = 0;
- const format = (rate) => Math.min(Math.max(+rate, 0), 100);
- function getPath(clockwise, viewBoxSize) {
- const sweepFlag = clockwise ? 1 : 0;
- return `M ${viewBoxSize / 2} ${viewBoxSize / 2} m 0, -500 a 500, 500 0 1, ${sweepFlag} 0, 1000 a 500, 500 0 1, ${sweepFlag} 0, -1000`;
- }
- const circleProps = {
- text: String,
- size: numericProp,
- fill: makeStringProp("none"),
- rate: makeNumericProp(100),
- speed: makeNumericProp(0),
- color: [String, Object],
- clockwise: truthProp,
- layerColor: String,
- currentRate: makeNumberProp(0),
- strokeWidth: makeNumericProp(40),
- strokeLinecap: String,
- startPosition: makeStringProp("top")
- };
- var stdin_default = defineComponent({
- name,
- props: circleProps,
- emits: ["update:currentRate"],
- setup(props, {
- emit,
- slots
- }) {
- const id = `van-circle-${uid++}`;
- const viewBoxSize = computed(() => +props.strokeWidth + 1e3);
- const path = computed(() => getPath(props.clockwise, viewBoxSize.value));
- const svgStyle = computed(() => {
- const ROTATE_ANGLE_MAP = {
- top: 0,
- right: 90,
- bottom: 180,
- left: 270
- };
- const angleValue = ROTATE_ANGLE_MAP[props.startPosition];
- if (angleValue) {
- return {
- transform: `rotate(${angleValue}deg)`
- };
- }
- });
- watch(() => props.rate, (rate) => {
- let rafId;
- const startTime = Date.now();
- const startRate = props.currentRate;
- const endRate = format(rate);
- const duration = Math.abs((startRate - endRate) * 1e3 / +props.speed);
- const animate = () => {
- const now = Date.now();
- const progress = Math.min((now - startTime) / duration, 1);
- const rate2 = progress * (endRate - startRate) + startRate;
- emit("update:currentRate", format(parseFloat(rate2.toFixed(1))));
- if (endRate > startRate ? rate2 < endRate : rate2 > endRate) {
- rafId = raf(animate);
- }
- };
- if (props.speed) {
- if (rafId) {
- cancelRaf(rafId);
- }
- rafId = raf(animate);
- } else {
- emit("update:currentRate", endRate);
- }
- }, {
- immediate: true
- });
- const renderHover = () => {
- const PERIMETER = 3140;
- const {
- strokeWidth,
- currentRate,
- strokeLinecap
- } = props;
- const offset = PERIMETER * currentRate / 100;
- const color = isObject(props.color) ? `url(#${id})` : props.color;
- const style = {
- stroke: color,
- strokeWidth: `${+strokeWidth + 1}px`,
- strokeLinecap,
- strokeDasharray: `${offset}px ${PERIMETER}px`
- };
- return _createVNode("path", {
- "d": path.value,
- "style": style,
- "class": bem("hover"),
- "stroke": color
- }, null);
- };
- const renderLayer = () => {
- const style = {
- fill: props.fill,
- stroke: props.layerColor,
- strokeWidth: `${props.strokeWidth}px`
- };
- return _createVNode("path", {
- "class": bem("layer"),
- "style": style,
- "d": path.value
- }, null);
- };
- const renderGradient = () => {
- const {
- color
- } = props;
- if (!isObject(color)) {
- return;
- }
- const Stops = Object.keys(color).sort((a, b) => parseFloat(a) - parseFloat(b)).map((key, index) => _createVNode("stop", {
- "key": index,
- "offset": key,
- "stop-color": color[key]
- }, null));
- return _createVNode("defs", null, [_createVNode("linearGradient", {
- "id": id,
- "x1": "100%",
- "y1": "0%",
- "x2": "0%",
- "y2": "0%"
- }, [Stops])]);
- };
- const renderText = () => {
- if (slots.default) {
- return slots.default();
- }
- if (props.text) {
- return _createVNode("div", {
- "class": bem("text")
- }, [props.text]);
- }
- };
- return () => _createVNode("div", {
- "class": bem(),
- "style": getSizeStyle(props.size)
- }, [_createVNode("svg", {
- "viewBox": `0 0 ${viewBoxSize.value} ${viewBoxSize.value}`,
- "style": svgStyle.value
- }, [renderGradient(), renderLayer(), renderHover()]), renderText()]);
- }
- });
- export {
- stdin_default as default
- };
|