<!--
    Basic circular progress bar that uses SVG and stroke offset to produce the effect. Stroke
    color is derived from currentColor. Sizes to container and maintains a 1:1 aspect.

    <px-progress-circle stroke-width="4" progress=".5" :style="{color: green}" />

-->
<template>
    <div :class="bem()">
        <svg
            width="100%"
            height="100%"
            :viewBox="`0 0 ${width} ${width}`"
            version="1.1"
            xmlns="http://www.w3.org/2000/svg"
            xmlns:xlink="http://www.w3.org/1999/xlink"
        >
            <circle
                v-if="backgroundVisible"
                :class="bem('bg')"
                stroke="currentColor"
                :stroke-width="calcStrokeWidth"
                :stroke-linecap="rounded ? 'round' : null"
                fill="transparent"
                :cx="width ? width / 2 : 0"
                :cy="width ? width / 2 : 0"
                :r="width ? Math.max(0, width / 2 - calcStrokeWidth / 2) : 0"
            ></circle>
            <circle
                :class="bem('fg')"
                stroke="currentColor"
                :stroke-width="calcStrokeWidth"
                :stroke-dasharray="strokeDashArray"
                :stroke-linecap="rounded ? 'round' : null"
                fill="transparent"
                :cx="width ? width / 2 : 0"
                :cy="width ? width / 2 : 0"
                :r="width ? Math.max(0, width / 2 - calcStrokeWidth / 2) : 0"
            ></circle>
        </svg>
    </div>
</template>

<script>
import PxBase from '../bases/PxBase.vue';
import PxBaseResize from '../bases/PxBaseResize.vue';
import tween from '../utils/tween.js';

export default {
    name: 'progress-circle',
    mixins: [PxBase, PxBaseResize],
    props: {
        // if stroke width is a string with a percentage it will be calculated as a percentage of the total width
        strokeWidth: { type: [Number, String], default: 10 },
        progress: { type: Number, default: 0 },
        rounded: { type: Boolean, default: false },
        backgroundVisible: { type: Boolean, default: false },
    },
    data() {
        return { width: 0, p: 0, animatedProgress: this.progress };
    },
    computed: {
        strokeDashArray() {
            let c = (this.width - this.calcStrokeWidth) * Math.PI;
            return `${c * Math.max(0, Math.min(1, this.animatedProgress))},${c}`;
        },
        calcStrokeWidth() {
            if (typeof this.strokeWidth === 'string' && this.strokeWidth.endsWith('%')) {
                return (parseFloat(this.strokeWidth) / 100) * this.width;
            }
            return this.strokeWidth;
        },
    },
    watch: {
        progress(nv) {
            if (this.progressTween) {
                this.progressTween.cancel();
            }

            this.progressTween = tween({
                from: this.animatedProgress,
                to: nv,
                dur: 1000,
                update: v => (this.animatedProgress = v),
            });
        },
    },

    methods: {
        resize() {
            this.width = this.$el.getBoundingClientRect()?.width;
        },
    },
};
</script>

<style lang="scss">
@use '../styles/px.scss' as *;
.progress-circle {
    width: 100%;
    height: 100%;

    @at-root {
        :root {
            --px-circle-progress-bg: currentColor;
            --px-circle-progress-bg-alpha: 0.1;
            --px-circle-progress-fg: currentColor;
            --px-circle-progress-alpha: 1;
        }
    }

    aspect-ratio: 1;
    font-size: 0;

    svg {
        width: 100%;
        height: 100%;
        display: block;
        transform: rotate(-90deg);
    }

    &__bg {
        stroke: var(--px-circle-progress-bg, currentColor);
        opacity: var(--px-circle-progress-bg-alpha, 0.2);
    }
    &__fg {
        stroke: var(--px-circle-progress-fg, currentColor);
        opacity: var(--px-circle-progress-fg-alpha, 1);
    }
}
</style>
