Skip to content

Clock Face 时钟表盘组件

Clock Face 是一个基于 Canvas 的时钟表盘组件,支持自定义扇形区域、刻度样式和中心文字。

基础用法

安装

bash
npm install vue3-xm

导入

js
import { ClockFace } from "vue3-xm";

使用示例

基础时钟

基础时钟表盘

一个简单的时钟表盘,包含基本的刻度和一个扇形区域。

查看代码
vue
<template>
    <div class="demo-container">
        <h3>基础时钟表盘</h3>
        <p>一个简单的时钟表盘,包含基本的刻度和一个扇形区域。</p>

        <div class="demo-wrapper">
            <ClockFace
                :size="300"
                center-text="Clock"
                :center-text-style="centerTextStyle"
                :sectors="sectors"
                @sector-hover="handleSectorHover"
            />
        </div>

        <div v-if="hoveredSector" class="hover-info">
            <p>
                <strong>悬停区域:</strong> {{ formatTime(hoveredSector.sector.from) }} -
                {{ formatTime(hoveredSector.sector.to) }}
            </p>
        </div>
    </div>
</template>

<script setup>
import { ref } from "vue";
import { ClockFace } from "vue3-xm";

const hoveredSector = ref(null);

const centerTextStyle = {
    fontSize: 20,
    fontFamily: "Arial, sans-serif",
    color: "#333",
    fontWeight: "bold",
    textAlign: "center",
    textBaseline: "middle",
};

const sectors = [
    {
        from: { h: 9, m: 0, s: 0 },
        to: { h: 12, m: 0, s: 0 },
        color: "rgba(255, 99, 132, 0.4)",
        startPos: 30,
        endPos: 70,
    },
];

const handleSectorHover = (data) => {
    hoveredSector.value = data;
};

const formatTime = (time) => {
    const h = time.h === 0 ? 12 : time.h;
    const m = time.m.toString().padStart(2, "0");
    const s = time.s.toString().padStart(2, "0");
    return `${h}:${m}:${s}`;
};
</script>

<style scoped>
.demo-container {
    padding: 20px;
    border: 1px solid #e1e4e8;
    border-radius: 8px;
    margin: 20px 0;
}

.demo-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px;
    background: #f8f9fa;
    border-radius: 6px;
    margin: 20px 0;
}

.hover-info {
    padding: 12px;
    background: #e3f2fd;
    border-left: 4px solid #2196f3;
    border-radius: 4px;
    margin-top: 16px;
}

.hover-info p {
    margin: 0;
    color: #1976d2;
}
</style>

高级配置

高级配置时钟

展示多个扇形区域、自定义样式和交互效果的时钟表盘。

查看代码
vue
<template>
    <div class="demo-container">
        <h3>高级配置时钟</h3>
        <p>展示多个扇形区域、自定义样式和交互效果的时钟表盘。</p>

        <div class="demo-wrapper">
            <ClockFace
                :size="400"
                center-text="Work Schedule"
                :center-text-style="centerTextStyle"
                :sectors="sectors"
                :border-color="borderColor"
                :border-width="3"
                :background-color="backgroundColor"
                :major-tick-color="majorTickColor"
                :major-tick-width="3"
                :major-tick-len="25"
                :minor-tick-color="minorTickColor"
                :minor-tick-width="1"
                :minor-tick-len="12"
                @sector-hover="handleSectorHover"
            />
        </div>

        <div class="controls">
            <div class="control-group">
                <label>背景颜色:</label>
                <select v-model="backgroundColor">
                    <option value="transparent">透明</option>
                    <option value="#ffffff">白色</option>
                    <option value="#f0f0f0">浅灰</option>
                    <option value="#e3f2fd">浅蓝</option>
                </select>
            </div>

            <div class="control-group">
                <label>边框颜色:</label>
                <input type="color" v-model="borderColor" />
            </div>

            <div class="control-group">
                <label>主刻度颜色:</label>
                <input type="color" v-model="majorTickColor" />
            </div>

            <div class="control-group">
                <label>次刻度颜色:</label>
                <input type="color" v-model="minorTickColor" />
            </div>
        </div>

        <div v-if="hoveredSector" class="hover-info">
            <p>
                <strong>{{ hoveredSector.sector.label }}:</strong> {{ formatTime(hoveredSector.sector.from) }} -
                {{ formatTime(hoveredSector.sector.to) }}
            </p>
            <p><strong>描述:</strong> {{ hoveredSector.sector.description }}</p>
        </div>
    </div>
</template>

<script setup>
import { ref } from "vue";
import { ClockFace } from "vue3-xm";

const hoveredSector = ref(null);
const backgroundColor = ref("transparent");
const borderColor = ref("#2c3e50");
const majorTickColor = ref("#34495e");
const minorTickColor = ref("#7f8c8d");

const centerTextStyle = {
    fontSize: 16,
    fontFamily: "Arial, sans-serif",
    color: "#2c3e50",
    fontWeight: "bold",
    textAlign: "center",
    textBaseline: "middle",
};

const sectors = [
    {
        from: { h: 9, m: 0, s: 0 },
        to: { h: 12, m: 0, s: 0 },
        color: "rgba(255, 99, 132, 0.5)",
        startPos: 25,
        endPos: 65,
        label: "上午工作",
        description: "处理重要任务和会议",
    },
    {
        from: { h: 13, m: 0, s: 0 },
        to: { h: 17, m: 0, s: 0 },
        color: "rgba(54, 162, 235, 0.5)",
        startPos: 25,
        endPos: 65,
        label: "下午工作",
        description: "项目开发和协作",
    },
    {
        from: { h: 12, m: 0, s: 0 },
        to: { h: 13, m: 0, s: 0 },
        color: "rgba(255, 206, 86, 0.5)",
        startPos: 65,
        endPos: 85,
        label: "午休时间",
        description: "休息和用餐",
    },
    {
        from: { h: 19, m: 0, s: 0 },
        to: { h: 22, m: 0, s: 0 },
        color: "rgba(75, 192, 192, 0.5)",
        startPos: 65,
        endPos: 85,
        label: "个人时间",
        description: "学习和娱乐",
    },
];

const handleSectorHover = (data) => {
    hoveredSector.value = data;
};

const formatTime = (time) => {
    const h = time.h === 0 ? 12 : time.h;
    const m = time.m.toString().padStart(2, "0");
    const s = time.s.toString().padStart(2, "0");
    return `${h}:${m}:${s}`;
};
</script>

<style scoped>
.demo-container {
    padding: 20px;
    border: 1px solid #e1e4e8;
    border-radius: 8px;
    margin: 20px 0;
}

.demo-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 30px;
    background: #f8f9fa;
    border-radius: 6px;
    margin: 20px 0;
}

.controls {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    padding: 20px;
    background: #ffffff;
    border: 1px solid #e1e4e8;
    border-radius: 6px;
    margin: 20px 0;
}

.control-group {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.control-group label {
    font-weight: 500;
    color: #333;
    font-size: 14px;
}

.control-group select,
.control-group input {
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
}

.control-group input[type="color"] {
    height: 40px;
    cursor: pointer;
}

.hover-info {
    padding: 16px;
    background: #e8f5e8;
    border-left: 4px solid #4caf50;
    border-radius: 4px;
    margin-top: 16px;
}

.hover-info p {
    margin: 4px 0;
    color: #2e7d32;
}

.hover-info p:first-child {
    font-size: 16px;
}
</style>

日历任务安排

月历任务表盘

展示整个月的任务安排,每天一个时钟表盘,测试多表盘性能。

2025年8月

周日
周一
周二
周三
周四
周五
周六
27
28
29
30
31
15个任务
23个任务
33个任务
42个任务
52个任务
62个任务
72个任务
82个任务
91个任务
101个任务
113个任务
123个任务
133个任务
143个任务
153个任务
162个任务
172个任务
184个任务
194个任务
204个任务
214个任务
224个任务
233个任务
243个任务
255个任务
265个任务
275个任务
285个任务
292个任务
301个任务
311个任务
1
2
3
4
5
6

本月统计

总任务数92
工作日数31
平均每日任务3.0
总工作时间80h

性能测试: 当前渲染 42 个时钟表盘

渲染时间: 0ms

查看代码
vue
<template>
    <div class="demo-container">
        <h3>月历任务表盘</h3>
        <p>展示整个月的任务安排,每天一个时钟表盘,测试多表盘性能。</p>

        <!-- 月份选择器 -->
        <div class="month-selector">
            <button @click="previousMonth" class="nav-btn">← 上个月</button>
            <div class="current-month">
                <h4>{{ formatMonth(currentDate) }}</h4>
                <input type="month" v-model="currentMonthStr" @change="onMonthChange" class="month-input" />
            </div>
            <button @click="nextMonth" class="nav-btn">下个月 →</button>
        </div>

        <!-- 月历网格 -->
        <div class="calendar-grid">
            <!-- 星期标题 -->
            <div class="weekday-header">
                <div v-for="day in weekDays" :key="day" class="weekday">{{ day }}</div>
            </div>

            <!-- 日期表盘网格 -->
            <div class="calendar-days">
                <div
                    v-for="day in calendarDays"
                    :key="`${day.date}-${day.isCurrentMonth}`"
                    class="day-container"
                    :class="{
                        'other-month': !day.isCurrentMonth,
                        today: day.isToday,
                        'has-tasks': day.tasks.length > 0,
                    }"
                >
                    <div class="day-header">
                        <span class="day-number">{{ day.dayNumber }}</span>
                        <span class="task-count" v-if="day.tasks.length > 0">{{ day.tasks.length }}个任务</span>
                    </div>

                    <!-- 每天的时钟表盘 -->
                    <div class="clock-container">
                        <ClockFace
                            :size="120"
                            :center-text="day.tasks.length > 0 ? day.tasks.length.toString() : ''"
                            :center-text-style="miniClockTextStyle"
                            :sectors="day.tasks"
                            :border-color="day.isToday ? '#e74c3c' : '#95a5a6'"
                            :border-width="day.isToday ? 2 : 1"
                            :background-color="day.isCurrentMonth ? '#ffffff' : '#f8f9fa'"
                            :major-tick-color="'#bdc3c7'"
                            :major-tick-width="1"
                            :major-tick-len="8"
                            :minor-tick-color="'#ecf0f1'"
                            :minor-tick-width="0.5"
                            :minor-tick-len="4"
                            @sector-hover="(data) => handleSectorHover(data, day.date)"
                        />
                    </div>
                </div>
            </div>
        </div>

        <!-- 悬停任务详情 -->
        <div v-if="hoveredTask" class="task-detail">
            <h4>{{ hoveredTask.sector.title }}</h4>
            <p><strong>日期:</strong> {{ hoveredTask.date }}</p>
            <p>
                <strong>时间:</strong> {{ formatTime(hoveredTask.sector.from) }} -
                {{ formatTime(hoveredTask.sector.to) }}
            </p>
            <p><strong>类型:</strong> {{ hoveredTask.sector.type }}</p>
            <p><strong>描述:</strong> {{ hoveredTask.sector.description }}</p>
            <p v-if="hoveredTask.sector.location"><strong>地点:</strong> {{ hoveredTask.sector.location }}</p>
        </div>

        <!-- 月度统计 -->
        <div class="month-stats">
            <div class="stat-card">
                <h4>本月统计</h4>
                <div class="stats-grid">
                    <div class="stat-item">
                        <span class="stat-label">总任务数</span>
                        <span class="stat-value">{{ monthStats.totalTasks }}</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">工作日数</span>
                        <span class="stat-value">{{ monthStats.workDays }}</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">平均每日任务</span>
                        <span class="stat-value">{{ monthStats.avgTasksPerDay }}</span>
                    </div>
                    <div class="stat-item">
                        <span class="stat-label">总工作时间</span>
                        <span class="stat-value">{{ monthStats.totalWorkHours }}h</span>
                    </div>
                </div>
            </div>
        </div>

        <!-- 性能监控 -->
        <div class="performance-info">
            <p><strong>性能测试:</strong> 当前渲染 {{ calendarDays.length }} 个时钟表盘</p>
            <p><strong>渲染时间:</strong> {{ renderTime }}ms</p>
        </div>
    </div>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick } from "vue";
import { ClockFace } from "vue3-xm";

const currentDate = ref(new Date());
const hoveredTask = ref(null);
const renderTime = ref(0);

// 星期标题
const weekDays = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];

// 格式化当前月份为字符串
const currentMonthStr = computed({
    get: () => {
        const year = currentDate.value.getFullYear();
        const month = (currentDate.value.getMonth() + 1).toString().padStart(2, "0");
        return `${year}-${month}`;
    },
    set: (value) => {
        const [year, month] = value.split("-");
        currentDate.value = new Date(parseInt(year), parseInt(month) - 1, 1);
    },
});

// 生成随机任务数据
const generateRandomTasks = (date) => {
    const tasks = [];
    const taskTypes = [
        {
            type: "工作",
            color: "rgba(231, 76, 60, 0.6)",
            titles: ["项目开发", "团队会议", "代码评审", "客户拜访", "文档编写"],
        },
        { type: "学习", color: "rgba(52, 73, 94, 0.6)", titles: ["英语学习", "培训课程", "技术研究", "读书时间"] },
        { type: "健身", color: "rgba(52, 152, 219, 0.6)", titles: ["晨练", "瑜伽练习", "健身房", "跑步"] },
        { type: "休闲", color: "rgba(142, 68, 173, 0.6)", titles: ["朋友聚餐", "看电影", "阅读", "购物"] },
    ];

    // 根据日期生成一定的随机性,但保持一致性
    const seed = date.getDate() + date.getMonth() * 31;
    const random = ((seed * 9301 + 49297) % 233280) / 233280;

    // 周末和工作日不同的任务密度
    const isWeekend = date.getDay() === 0 || date.getDay() === 6;
    const taskCount = isWeekend ? Math.floor(random * 3) + 1 : Math.floor(random * 4) + 2;

    for (let i = 0; i < taskCount; i++) {
        const typeIndex = Math.floor((random * (i + 1)) % taskTypes.length);
        const type = taskTypes[typeIndex];
        const titleIndex = Math.floor((random * (i + 2)) % type.titles.length);

        const startHour = Math.floor((random * (i + 3)) % 12) + 8; // 8-19点
        const duration = Math.floor((random * (i + 4)) % 3) + 1; // 1-3小时

        tasks.push({
            from: { h: startHour, m: 0, s: 0 },
            to: { h: startHour + duration, m: 0, s: 0 },
            color: type.color,
            title: type.titles[titleIndex],
            type: type.type,
            description: `${type.titles[titleIndex]}相关活动`,
            location: type.type === "工作" ? "办公室" : type.type === "健身" ? "健身房" : "其他",
        });
    }

    return tasks.sort((a, b) => a.from.h - b.from.h);
};

// 生成月历数据
const calendarDays = computed(() => {
    const startTime = performance.now();

    const year = currentDate.value.getFullYear();
    const month = currentDate.value.getMonth();

    // 获取当月第一天和最后一天
    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);

    // 获取日历网格的开始日期(包含上月的一些日期)
    const startDate = new Date(firstDay);
    startDate.setDate(startDate.getDate() - firstDay.getDay());

    // 获取日历网格的结束日期(包含下月的一些日期)
    const endDate = new Date(startDate);
    endDate.setDate(endDate.getDate() + 41); // 6周 = 42天

    const days = [];
    const today = new Date();

    for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
        const currentD = new Date(d);
        const isCurrentMonth = currentD.getMonth() === month;
        const isToday = currentD.toDateString() === today.toDateString();

        days.push({
            date: currentD.toISOString().split("T")[0],
            dayNumber: currentD.getDate(),
            isCurrentMonth,
            isToday,
            tasks: isCurrentMonth ? generateRandomTasks(currentD) : [],
        });
    }

    nextTick(() => {
        renderTime.value = Math.round(performance.now() - startTime);
    });

    return days;
});

// 月度统计
const monthStats = computed(() => {
    const currentMonthDays = calendarDays.value.filter((day) => day.isCurrentMonth);
    const totalTasks = currentMonthDays.reduce((sum, day) => sum + day.tasks.length, 0);
    const workDays = currentMonthDays.filter((day) => day.tasks.length > 0).length;
    const avgTasksPerDay = workDays > 0 ? (totalTasks / workDays).toFixed(1) : 0;

    const totalWorkHours = currentMonthDays.reduce((sum, day) => {
        return (
            sum +
            day.tasks
                .filter((task) => task.type === "工作")
                .reduce((taskSum, task) => {
                    return taskSum + (task.to.h - task.from.h);
                }, 0)
        );
    }, 0);

    return {
        totalTasks,
        workDays,
        avgTasksPerDay,
        totalWorkHours,
    };
});

// 小时钟样式
const miniClockTextStyle = {
    fontSize: 12,
    fontFamily: "Arial, sans-serif",
    color: "#2c3e50",
    fontWeight: "bold",
    textAlign: "center",
    textBaseline: "middle",
};

// 月份操作
const previousMonth = () => {
    const newDate = new Date(currentDate.value);
    newDate.setMonth(newDate.getMonth() - 1);
    currentDate.value = newDate;
};

const nextMonth = () => {
    const newDate = new Date(currentDate.value);
    newDate.setMonth(newDate.getMonth() + 1);
    currentDate.value = newDate;
};

const onMonthChange = () => {
    hoveredTask.value = null;
};

// 事件处理
const handleSectorHover = (data, date) => {
    if (data) {
        hoveredTask.value = {
            ...data,
            date: new Date(date).toLocaleDateString("zh-CN"),
        };
    } else {
        hoveredTask.value = null;
    }
};

// 格式化函数
const formatMonth = (date) => {
    const options = { year: "numeric", month: "long" };
    return date.toLocaleDateString("zh-CN", options);
};

const formatTime = (time) => {
    const h = time.h.toString().padStart(2, "0");
    const m = time.m.toString().padStart(2, "0");
    return `${h}:${m}`;
};

// 监听月份变化
watch(currentDate, () => {
    hoveredTask.value = null;
});

onMounted(() => {
    console.log("月历视图已加载,包含", calendarDays.value.length, "个时钟表盘");
});
</script>

<style scoped>
.demo-container {
    padding: 20px;
    border: 1px solid #e1e4e8;
    border-radius: 8px;
    margin: 20px 0;
    max-width: 1200px;
}

.month-selector {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 20px;
    margin-bottom: 30px;
    padding: 20px;
    background: #f8f9fa;
    border-radius: 8px;
}

.nav-btn {
    padding: 10px 20px;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 14px;
    transition: background-color 0.3s;
}

.nav-btn:hover {
    background: #2980b9;
}

.current-month {
    text-align: center;
}

.current-month h4 {
    margin: 0 0 10px 0;
    color: #2c3e50;
    font-size: 20px;
}

.month-input {
    padding: 8px;
    border: 1px solid #ddd;
    border-radius: 4px;
    font-size: 14px;
}

.calendar-grid {
    background: white;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.weekday-header {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    background: #34495e;
    color: white;
}

.weekday {
    padding: 15px;
    text-align: center;
    font-weight: bold;
    font-size: 14px;
}

.calendar-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    background: #ecf0f1;
}

.day-container {
    background: white;
    min-height: 160px;
    display: flex;
    flex-direction: column;
    transition: all 0.3s ease;
}

.day-container.other-month {
    background: #f8f9fa;
    opacity: 0.6;
}

.day-container.today {
    background: #fff5f5;
    box-shadow: inset 0 0 0 2px #e74c3c;
}

.day-container.has-tasks {
    background: #f0f8ff;
}

.day-container:hover {
    transform: scale(1.02);
    z-index: 10;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}

.day-header {
    padding: 8px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid #ecf0f1;
}

.day-number {
    font-weight: bold;
    font-size: 14px;
    color: #2c3e50;
}

.task-count {
    font-size: 10px;
    color: #7f8c8d;
    background: #ecf0f1;
    padding: 2px 6px;
    border-radius: 10px;
}

.clock-container {
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 5px;
}

.task-detail {
    position: fixed;
    top: 20px;
    right: 20px;
    background: white;
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 20px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
    z-index: 1000;
    min-width: 250px;
    max-width: 350px;
}

.task-detail h4 {
    margin: 0 0 10px 0;
    color: #2c3e50;
    font-size: 16px;
}

.task-detail p {
    margin: 5px 0;
    font-size: 14px;
    color: #34495e;
}

.month-stats {
    margin-top: 30px;
}

.stat-card {
    background: white;
    border: 1px solid #e1e4e8;
    border-radius: 8px;
    padding: 20px;
}

.stat-card h4 {
    margin: 0 0 20px 0;
    color: #2c3e50;
    font-size: 18px;
    text-align: center;
}

.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 20px;
}

.stat-item {
    text-align: center;
    padding: 15px;
    background: #f8f9fa;
    border-radius: 6px;
}

.stat-label {
    display: block;
    font-size: 12px;
    color: #7f8c8d;
    margin-bottom: 8px;
    font-weight: 500;
}

.stat-value {
    display: block;
    font-size: 24px;
    font-weight: bold;
    color: #3498db;
}

.performance-info {
    margin-top: 20px;
    padding: 15px;
    background: #e8f5e8;
    border-left: 4px solid #27ae60;
    border-radius: 4px;
    font-size: 14px;
    color: #2c3e50;
}

.performance-info p {
    margin: 2px 0;
}

@media (max-width: 1200px) {
    .calendar-days {
        grid-template-columns: repeat(7, 1fr);
    }

    .day-container {
        min-height: 140px;
    }

    .clock-container {
        padding: 3px;
    }
}

@media (max-width: 768px) {
    .month-selector {
        flex-direction: column;
        gap: 15px;
    }

    .day-container {
        min-height: 120px;
    }

    .stats-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .task-detail {
        position: static;
        margin-top: 20px;
    }
}

@media (max-width: 480px) {
    .calendar-days {
        gap: 0;
    }

    .day-container {
        min-height: 100px;
    }

    .weekday {
        padding: 10px 5px;
        font-size: 12px;
    }

    .day-header {
        padding: 5px;
        flex-direction: column;
        gap: 2px;
    }

    .day-number {
        font-size: 12px;
    }

    .task-count {
        font-size: 9px;
        padding: 1px 4px;
    }
}
</style>

API

Props

参数说明类型可选值默认值
size时钟大小number-300
centerText中心文字string-''
centerTextStyle中心文字样式object-见下方说明
sectors扇形区域数组array-见下方说明
startPos默认扇形内圈位置(百分比)number0-10070
endPos默认扇形外圈位置(百分比)number0-10010
borderColor边框颜色string-'#333'
borderWidth边框宽度number-4
backgroundColor背景颜色string-'transparent'
minorTickColor小刻度颜色string-'#666'
minorTickWidth小刻度宽度number-2
minorTickLen小刻度长度number-10
minorTickDistance小刻度距离边框距离number-0
majorTickColor大刻度颜色string-'#333'
majorTickWidth大刻度宽度number-4
majorTickLen大刻度长度number-20
majorTickDistance大刻度距离边框距离number-0

centerTextStyle 默认值

js
{
  fontSize: 16,
  fontFamily: 'Arial, sans-serif',
  color: '#333',
  fontWeight: 'normal',
  textAlign: 'center',
  textBaseline: 'middle'
}

sectors 数组项结构

参数说明类型是否必需
from开始时间object
to结束时间object
color扇形颜色string
startPos扇形内圈位置(百分比)number
endPos扇形外圈位置(百分比)number

时间对象结构

js
{
  h: 1,  // 小时 (0-11)
  m: 0,  // 分钟 (0-59)
  s: 0   // 秒钟 (0-59)
}

Events

事件名说明回调参数
sector-hover鼠标悬停在扇形区域时触发{ index: number, sector: object }null

Released under the MIT License.