feat: revamp demo

This commit is contained in:
Justineo
2025-09-24 01:27:35 +08:00
committed by GU Yiling
parent 1da2bf7811
commit def0ad5bf5
47 changed files with 4180 additions and 1740 deletions

View File

@ -1,13 +1,13 @@
function random() {
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
function random(): number {
return Math.round(300 + Math.random() * 700) / 10;
}
export default function getData() {
return {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
export default function getData(): Option {
const option = {
textStyle: { ...DEMO_TEXT_STYLE },
dataset: {
dimensions: ["Product", "2015", "2016", "2017"],
source: [
@ -39,8 +39,8 @@ export default function getData() {
},
xAxis: { type: "category" },
yAxis: {},
// Declare several bar series, each will be mapped
// to a column of dataset.source by default.
series: [{ type: "bar" }, { type: "bar" }, { type: "bar" }],
};
} satisfies Option;
return option;
}

View File

@ -1,121 +0,0 @@
const data1 = [];
const symbolCount = 6;
for (let i = 0; i < 16; i++) {
data1.push([
Math.random() * 5,
Math.random() * 4,
Math.random() * 12,
Math.round(Math.random() * (symbolCount - 1)),
]);
}
const c1 = {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
legend: {
top: "3%",
data: ["scatter"],
},
tooltip: {
formatter: "{c}",
},
grid: {
top: "30%",
right: "18%",
bottom: "20%",
},
xAxis: {
type: "value",
splitLine: {
show: false,
},
},
yAxis: {
type: "value",
splitLine: {
show: false,
},
},
visualMap: [
{
realtime: false,
right: "2%",
bottom: "3%",
selectedMode: "multiple",
dimension: 2,
selected: [],
min: 0,
max: 18,
precision: 0,
splitNumber: 0,
calculable: true,
},
],
series: [
{
name: "scatter",
type: "scatter",
symbolSize: 30,
data: data1,
},
],
};
const c2 = {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
legend: {
top: "3%",
data: ["scatter"],
},
tooltip: {
formatter: "{c}",
},
grid: {
top: "30%",
right: "18%",
bottom: "20%",
},
xAxis: {
type: "value",
splitLine: {
show: false,
},
},
yAxis: {
type: "value",
splitLine: {
show: false,
},
},
visualMap: [
{
right: "2%",
bottom: "3%",
selectedMode: "multiple",
dimension: 2,
selected: [],
min: 0,
max: 18,
precision: 0,
splitNumber: 0,
calculable: true,
},
],
series: [
{
name: "scatter",
type: "scatter",
symbolSize: 30,
data: data1,
},
],
};
export default function getData() {
return [c1, c2];
}

78
demo/data/connect.ts Normal file
View File

@ -0,0 +1,78 @@
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
const POINT_COUNT = 16;
const SYMBOL_COUNT = 6;
function createScatterData(): Array<[number, number, number, number]> {
return Array.from({ length: POINT_COUNT }, () => [
Math.random() * 5,
Math.random() * 4,
Math.random() * 12,
Math.round(Math.random() * (SYMBOL_COUNT - 1)),
]);
}
const BASE_DATA = createScatterData();
function createOption(data: Array<[number, number, number, number]>): Option {
return {
textStyle: { ...DEMO_TEXT_STYLE },
legend: {
top: "3%",
data: ["scatter"],
},
tooltip: {
formatter: "{c}",
},
grid: {
top: "30%",
right: "18%",
bottom: "20%",
},
xAxis: {
type: "value",
splitLine: {
show: false,
},
},
yAxis: {
type: "value",
splitLine: {
show: false,
},
},
visualMap: [
{
realtime: false,
right: "2%",
bottom: "3%",
selectedMode: "multiple",
dimension: 2,
selected: [],
min: 0,
max: 18,
precision: 0,
splitNumber: 0,
calculable: true,
},
],
series: [
{
name: "scatter",
type: "scatter",
symbolSize: 30,
data,
},
],
} satisfies Option;
}
export default function getData(): [Option, Option] {
const options: [Option, Option] = [
createOption(BASE_DATA),
createOption(BASE_DATA),
];
return options;
}

View File

@ -1,56 +0,0 @@
export default function getData() {
return {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
legend: { top: 20 },
tooltip: {
trigger: "axis",
},
dataset: {
source: [
["product", "2012", "2013", "2014", "2015", "2016", "2017"],
["Milk Tea", 56.5, 82.1, 88.7, 70.1, 53.4, 85.1],
["Matcha Latte", 51.1, 51.4, 55.1, 53.3, 73.8, 68.7],
["Cheese Cocoa", 40.1, 62.2, 69.5, 36.4, 45.2, 32.5],
["Walnut Brownie", 25.2, 37.1, 41.2, 18, 33.9, 49.1],
],
},
xAxis: {
type: "category",
triggerEvent: true,
tooltip: { show: true, formatter: "" },
},
yAxis: {
triggerEvent: true,
tooltip: { show: true, formatter: "" },
},
series: [
{
type: "line",
smooth: true,
seriesLayoutBy: "row",
emphasis: { focus: "series" },
},
{
type: "line",
smooth: true,
seriesLayoutBy: "row",
emphasis: { focus: "series" },
},
{
type: "line",
smooth: true,
seriesLayoutBy: "row",
emphasis: { focus: "series" },
},
{
type: "line",
smooth: true,
seriesLayoutBy: "row",
emphasis: { focus: "series" },
},
],
};
}

38
demo/data/line.ts Normal file
View File

@ -0,0 +1,38 @@
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
export default function getData(): Option {
const option = {
textStyle: { ...DEMO_TEXT_STYLE },
legend: { top: 20 },
tooltip: {
trigger: "axis",
},
dataset: {
source: [
["product", "2012", "2013", "2014", "2015", "2016", "2017"],
["Milk Tea", 56.5, 82.1, 88.7, 70.1, 53.4, 85.1],
["Matcha Latte", 51.1, 51.4, 55.1, 53.3, 73.8, 68.7],
["Cheese Cocoa", 40.1, 62.2, 69.5, 36.4, 45.2, 32.5],
["Walnut Brownie", 25.2, 37.1, 41.2, 18, 33.9, 49.1],
],
},
xAxis: {
type: "category",
triggerEvent: true,
tooltip: { show: true },
},
yAxis: {
triggerEvent: true,
tooltip: { show: true },
},
series: Array.from({ length: 4 }, () => ({
type: "line",
smooth: true,
seriesLayoutBy: "row" as const,
emphasis: { focus: "series" as const },
})),
} satisfies Option;
return option;
}

View File

@ -1,33 +0,0 @@
import logo from "../assets/Vue-ECharts.svg?raw";
const d = logo.match(/\bd="([^"]+)"/)[1];
export default {
series: [
{
type: "liquidFill",
data: [0.7, 0.6, 0.55, 0.45],
amplitude: 6,
outline: {
show: false,
},
radius: "60%",
color: ["#4fc08d", "#44d64a", "#33c762", "#4acc80"],
backgroundStyle: {
color: "#fff",
borderColor: "#2c3e50",
borderWidth: 1,
},
shape: `path://${d}`,
label: {
formatter() {
return "";
},
},
itemStyle: {
shadowBlur: 12,
shadowColor: "rgba(0, 0, 0, 0.25)",
},
},
],
};

View File

@ -1,4 +1,14 @@
const data = [
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
interface CityDatum {
name: string;
value: number;
}
type ScatterPoint = { name: string; value: [number, number, number] };
const cityData: CityDatum[] = [
{ name: "海门", value: 9 },
{ name: "鄂尔多斯", value: 12 },
{ name: "招远", value: 12 },
@ -190,7 +200,7 @@ const data = [
{ name: "武汉", value: 273 },
{ name: "大庆", value: 279 },
];
const geoCoordMap = {
const geoCoordMap: Record<string, [number, number]> = {
: [121.15, 31.89],
: [109.781327, 39.608266],
: [120.38, 37.35],
@ -383,26 +393,28 @@ const geoCoordMap = {
: [125.03, 46.58],
};
function convertData(data) {
const res = [];
for (let i = 0; i < data.length; i++) {
const geoCoord = geoCoordMap[data[i].name];
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value),
});
function convertData(list: CityDatum[]): ScatterPoint[] {
const points: ScatterPoint[] = [];
for (const item of list) {
const geoCoord = geoCoordMap[item.name];
if (!geoCoord) {
continue;
}
points.push({
name: item.name,
value: [geoCoord[0], geoCoord[1], item.value],
});
}
return res;
return points;
}
export default function getData() {
return {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
export default function getData(): Option {
const sortedTopFive = [...cityData]
.sort((a, b) => b.value - a.value)
.slice(0, 6);
const option = {
textStyle: { ...DEMO_TEXT_STYLE },
backgroundColor: "#404a59",
title: {
text: "Air quality of major cities in China",
@ -448,11 +460,11 @@ export default function getData() {
name: "PM2.5",
type: "scatter",
coordinateSystem: "geo",
data: convertData(data),
symbolSize: (val) => val[2] / 10,
data: convertData(cityData),
symbolSize: (val: [number, number, number]) => val[2] / 10,
tooltip: {
formatter: function (val) {
return val.name + ": " + val.value[2];
formatter(value: ScatterPoint) {
return `${value.name}: ${value.value[2]}`;
},
},
itemStyle: {
@ -463,8 +475,8 @@ export default function getData() {
name: "Top 5",
type: "effectScatter",
coordinateSystem: "geo",
data: convertData(data.sort((a, b) => b.value - a.value).slice(0, 6)),
symbolSize: (val) => val[2] / 10,
data: convertData(sortedTopFive),
symbolSize: (val: [number, number, number]) => val[2] / 10,
showEffectOn: "render",
rippleEffect: {
brushType: "stroke",
@ -473,8 +485,8 @@ export default function getData() {
scale: true,
},
tooltip: {
formatter: function (val) {
return val.name + ": " + val.value[2];
formatter(value: ScatterPoint) {
return `${value.name}: ${value.value[2]}`;
},
},
label: {
@ -490,5 +502,7 @@ export default function getData() {
zlevel: 1,
},
],
};
} satisfies Option;
return option;
}

View File

@ -1,9 +1,9 @@
export default function getData() {
return {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
export default function getData(): Option {
const option = {
textStyle: { ...DEMO_TEXT_STYLE },
title: {
text: "Traffic Sources",
top: "5%",
@ -32,14 +32,9 @@ export default function getData() {
{ value: 135, name: "Video Ads" },
{ value: 1548, name: "Search Engines" },
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
},
},
],
};
} satisfies Option;
return option;
}

View File

@ -1,17 +1,17 @@
const data = [];
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
for (let i = 0; i <= 360; i++) {
const points: Array<[number, number]> = [];
for (let i = 0; i <= 360; i += 1) {
const t = (i / 180) * Math.PI;
const r = Math.sin(2 * t) * Math.cos(2 * t);
data.push([r, i]);
points.push([r, i]);
}
export default function getData() {
return {
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
export default function getData(): Option {
const option = {
textStyle: { ...DEMO_TEXT_STYLE },
title: {
text: "Dual Numeric Axis",
top: "5%",
@ -44,9 +44,11 @@ export default function getData() {
name: "line",
type: "line",
showSymbol: false,
data: data,
data: points,
},
],
animationDuration: 2000,
};
} satisfies Option;
return option;
}

View File

@ -1,8 +1,16 @@
import { ref, computed } from "vue";
import { defineStore } from "pinia";
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
interface Score {
name: string;
max: number;
value: number;
}
export const useScoreStore = defineStore("store", () => {
const scores = ref([
const scores = ref<Score[]>([
{ name: "Attack", max: 20, value: 19 },
{ name: "Defense", max: 20, value: 9 },
{ name: "Speed", max: 20, value: 18 },
@ -11,29 +19,23 @@ export const useScoreStore = defineStore("store", () => {
{ name: "Agility", max: 20, value: 20 },
]);
const metrics = computed(() => {
return scores.value.map(({ name }) => name);
});
const metrics = computed(() => scores.value.map(({ name }) => name));
function getRadarData(activeIndex: number) {
return {
function getRadarData(activeIndex: number): Option {
const option = {
title: {
text: "Player Ability",
top: "5%",
left: "5%",
},
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
textStyle: { ...DEMO_TEXT_STYLE },
radar: {
splitNumber: 4,
indicator: scores.value.map(({ name, max }, index) => {
if (index === activeIndex) {
return { name, max, color: "goldenrod" };
}
return { name, max };
}),
indicator: scores.value.map(({ name, max }, index) =>
index === activeIndex
? { name, max, color: "goldenrod" }
: { name, max },
),
},
series: [
{
@ -42,21 +44,28 @@ export const useScoreStore = defineStore("store", () => {
data: [{ value: scores.value.map(({ value }) => value) }],
},
],
};
} satisfies Option;
return option;
}
function increase(index: number, amount: number) {
function increase(index: number, amount: number): void {
const metric = scores.value[index];
metric.value = Math.max(Math.min(metric.value + amount, metric.max), 0);
if (!metric) {
return;
}
const next = Math.max(Math.min(metric.value + amount, metric.max), 0);
metric.value = next;
}
function isMax(index: number) {
const { value, max } = scores.value[index];
return value === max;
function isMax(index: number): boolean {
const metric = scores.value[index];
return metric ? metric.value === metric.max : false;
}
function isMin(index: number) {
return scores.value[index].value === 0;
function isMin(index: number): boolean {
const metric = scores.value[index];
return metric ? metric.value === 0 : false;
}
return {

View File

@ -1,7 +1,35 @@
import { graphic } from "echarts/core";
import type { Option } from "../../src/types";
import { DEMO_TEXT_STYLE } from "../constants";
const data = [
[
type ScatterDatum = [number, number, number, string, number];
type ScatterDataset = ScatterDatum[];
type SeriesColor = {
shadowColor: string;
gradient: graphic.RadialGradient;
};
const SERIES_CONFIG: Record<string, SeriesColor> = {
"1990": {
shadowColor: "rgba(120, 36, 50, 0.5)",
gradient: new graphic.RadialGradient(0.4, 0.3, 1, [
{ offset: 0, color: "rgb(251, 118, 123)" },
{ offset: 1, color: "rgb(204, 46, 72)" },
]),
},
"2015": {
shadowColor: "rgba(25, 100, 150, 0.5)",
gradient: new graphic.RadialGradient(0.4, 0.3, 1, [
{ offset: 0, color: "rgb(129, 227, 238)" },
{ offset: 1, color: "rgb(25, 183, 207)" },
]),
},
};
const dataset: Record<string, ScatterDataset> = {
"1990": [
[28604, 77, 17096869, "Australia", 1990],
[31163, 77.4, 27662440, "Canada", 1990],
[1516, 68, 1154605773, "China", 1990],
@ -22,7 +50,7 @@ const data = [
[26424, 75.7, 57110117, "United Kingdom", 1990],
[37062, 75.4, 252847810, "United States", 1990],
],
[
"2015": [
[44056, 81.8, 23968973, "Australia", 2015],
[43294, 81.7, 35939927, "Canada", 2015],
[13334, 76.9, 1376048943, "China", 2015],
@ -43,17 +71,41 @@ const data = [
[38225, 81.4, 64715810, "United Kingdom", 2015],
[53354, 79.1, 321773631, "United States", 2015],
],
];
};
export default function getData() {
return {
export default function getData(): Option {
const series = Object.entries(dataset).map(([year, data]) => {
const colors = SERIES_CONFIG[year];
return {
name: year,
data,
type: "scatter" as const,
symbolSize(value: ScatterDatum) {
return Math.sqrt(value[2]) / 5e2;
},
emphasis: {
label: {
show: true,
formatter({ data: datum }: { data: ScatterDatum }) {
return datum[3];
},
position: "top",
},
},
itemStyle: {
shadowBlur: 10,
shadowColor: colors.shadowColor,
shadowOffsetY: 5,
color: colors.gradient,
},
};
});
const option = {
grid: {
top: "25%",
},
textStyle: {
fontFamily: 'Inter, "Helvetica Neue", Arial, sans-serif',
fontWeight: 300,
},
textStyle: { ...DEMO_TEXT_STYLE },
title: {
text: "Life Expectancy vs. GDP by country",
top: "5%",
@ -62,7 +114,7 @@ export default function getData() {
legend: {
top: "6%",
right: "5%",
data: ["1990", "2015"],
data: Object.keys(dataset),
},
xAxis: {
splitLine: {
@ -79,71 +131,8 @@ export default function getData() {
},
scale: true,
},
series: [
{
name: "1990",
data: data[0],
type: "scatter",
symbolSize(data) {
return Math.sqrt(data[2]) / 5e2;
},
emphasis: {
label: {
show: true,
formatter({ data }) {
return data[3];
},
position: "top",
},
},
itemStyle: {
shadowBlur: 10,
shadowColor: "rgba(120, 36, 50, 0.5)",
shadowOffsetY: 5,
color: new graphic.RadialGradient(0.4, 0.3, 1, [
{
offset: 0,
color: "rgb(251, 118, 123)",
},
{
offset: 1,
color: "rgb(204, 46, 72)",
},
]),
},
},
{
name: "2015",
data: data[1],
type: "scatter",
symbolSize(data) {
return Math.sqrt(data[2]) / 5e2;
},
emphasis: {
label: {
show: true,
formatter({ data }) {
return data[3];
},
position: "top",
},
},
itemStyle: {
shadowBlur: 10,
shadowColor: "rgba(25, 100, 150, 0.5)",
shadowOffsetY: 5,
color: new graphic.RadialGradient(0.4, 0.3, 1, [
{
offset: 0,
color: "rgb(129, 227, 238)",
},
{
offset: 1,
color: "rgb(25, 183, 207)",
},
]),
},
},
],
};
series,
} satisfies Option;
return option;
}