@constela/runtime 2.0.10 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +3 -862
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -376,6 +376,7 @@ function createTypedStateStore(definitions) {
|
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
// src/expression/evaluator.ts
|
|
379
|
+
import { callGlobalFunction, GLOBAL_FUNCTIONS } from "@constela/core";
|
|
379
380
|
var SAFE_ARRAY_METHODS = /* @__PURE__ */ new Set([
|
|
380
381
|
"length",
|
|
381
382
|
"at",
|
|
@@ -436,272 +437,6 @@ var SAFE_DATE_INSTANCE_METHODS = /* @__PURE__ */ new Set([
|
|
|
436
437
|
"getSeconds",
|
|
437
438
|
"getMilliseconds"
|
|
438
439
|
]);
|
|
439
|
-
function getCalendarDays(year, month) {
|
|
440
|
-
if (typeof year !== "number" || typeof month !== "number") {
|
|
441
|
-
return void 0;
|
|
442
|
-
}
|
|
443
|
-
if (month < 0 || month > 11) {
|
|
444
|
-
return void 0;
|
|
445
|
-
}
|
|
446
|
-
const days = [];
|
|
447
|
-
const firstDayOfMonth = new Date(year, month, 1);
|
|
448
|
-
const dayOfWeek = firstDayOfMonth.getDay();
|
|
449
|
-
const lastDayOfMonth = new Date(year, month + 1, 0);
|
|
450
|
-
const daysInMonth = lastDayOfMonth.getDate();
|
|
451
|
-
const prevMonthDays = dayOfWeek;
|
|
452
|
-
const prevMonthLastDay = new Date(year, month, 0);
|
|
453
|
-
const prevMonthDaysCount = prevMonthLastDay.getDate();
|
|
454
|
-
const prevMonth = month === 0 ? 11 : month - 1;
|
|
455
|
-
const prevYear = month === 0 ? year - 1 : year;
|
|
456
|
-
for (let i = prevMonthDays - 1; i >= 0; i--) {
|
|
457
|
-
days.push({
|
|
458
|
-
date: prevMonthDaysCount - i,
|
|
459
|
-
month: prevMonth,
|
|
460
|
-
year: prevYear,
|
|
461
|
-
isCurrentMonth: false
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
for (let i = 1; i <= daysInMonth; i++) {
|
|
465
|
-
days.push({
|
|
466
|
-
date: i,
|
|
467
|
-
month,
|
|
468
|
-
year,
|
|
469
|
-
isCurrentMonth: true
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
const totalDaysSoFar = days.length;
|
|
473
|
-
const totalWeeksNeeded = Math.ceil(totalDaysSoFar / 7);
|
|
474
|
-
const targetDays = totalWeeksNeeded * 7;
|
|
475
|
-
const nextMonth = month === 11 ? 0 : month + 1;
|
|
476
|
-
const nextYear = month === 11 ? year + 1 : year;
|
|
477
|
-
const nextMonthDaysNeeded = targetDays - totalDaysSoFar;
|
|
478
|
-
for (let i = 1; i <= nextMonthDaysNeeded; i++) {
|
|
479
|
-
days.push({
|
|
480
|
-
date: i,
|
|
481
|
-
month: nextMonth,
|
|
482
|
-
year: nextYear,
|
|
483
|
-
isCurrentMonth: false
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
return days;
|
|
487
|
-
}
|
|
488
|
-
function getWeekDays(locale) {
|
|
489
|
-
const effectiveLocale = typeof locale === "string" ? locale : "en-US";
|
|
490
|
-
const baseSunday = new Date(2024, 0, 7);
|
|
491
|
-
const weekDays = [];
|
|
492
|
-
try {
|
|
493
|
-
const formatter = new Intl.DateTimeFormat(effectiveLocale || "en-US", { weekday: "short" });
|
|
494
|
-
for (let i = 0; i < 7; i++) {
|
|
495
|
-
const date = new Date(baseSunday);
|
|
496
|
-
date.setDate(baseSunday.getDate() + i);
|
|
497
|
-
weekDays.push(formatter.format(date));
|
|
498
|
-
}
|
|
499
|
-
return weekDays;
|
|
500
|
-
} catch {
|
|
501
|
-
const fallbackFormatter = new Intl.DateTimeFormat("en-US", { weekday: "short" });
|
|
502
|
-
for (let i = 0; i < 7; i++) {
|
|
503
|
-
const date = new Date(baseSunday);
|
|
504
|
-
date.setDate(baseSunday.getDate() + i);
|
|
505
|
-
weekDays.push(fallbackFormatter.format(date));
|
|
506
|
-
}
|
|
507
|
-
return weekDays;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
function getMonthName(month, locale) {
|
|
511
|
-
if (typeof month !== "number" || month < 0 || month > 11) {
|
|
512
|
-
return void 0;
|
|
513
|
-
}
|
|
514
|
-
const effectiveLocale = typeof locale === "string" ? locale : "en-US";
|
|
515
|
-
try {
|
|
516
|
-
const date = new Date(2024, month, 1);
|
|
517
|
-
const formatter = new Intl.DateTimeFormat(effectiveLocale, { month: "long" });
|
|
518
|
-
return formatter.format(date);
|
|
519
|
-
} catch {
|
|
520
|
-
const date = new Date(2024, month, 1);
|
|
521
|
-
const formatter = new Intl.DateTimeFormat("en-US", { month: "long" });
|
|
522
|
-
return formatter.format(date);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
function formatDateISO(year, month, date) {
|
|
526
|
-
if (typeof year !== "number" || typeof month !== "number" || typeof date !== "number") {
|
|
527
|
-
return void 0;
|
|
528
|
-
}
|
|
529
|
-
const y2 = String(year).padStart(4, "0");
|
|
530
|
-
const m2 = String(month + 1).padStart(2, "0");
|
|
531
|
-
const d2 = String(date).padStart(2, "0");
|
|
532
|
-
return `${y2}-${m2}-${d2}`;
|
|
533
|
-
}
|
|
534
|
-
function sortBy(items, key2, direction) {
|
|
535
|
-
if (!Array.isArray(items)) {
|
|
536
|
-
return void 0;
|
|
537
|
-
}
|
|
538
|
-
if (typeof key2 !== "string") {
|
|
539
|
-
return void 0;
|
|
540
|
-
}
|
|
541
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
542
|
-
if (forbiddenKeys.has(key2)) {
|
|
543
|
-
return void 0;
|
|
544
|
-
}
|
|
545
|
-
const dir = direction === "desc" ? "desc" : "asc";
|
|
546
|
-
const sorted = [...items];
|
|
547
|
-
sorted.sort((a, b2) => {
|
|
548
|
-
const aVal = a != null && typeof a === "object" ? a[key2] : void 0;
|
|
549
|
-
const bVal = b2 != null && typeof b2 === "object" ? b2[key2] : void 0;
|
|
550
|
-
if (aVal == null && bVal == null) return 0;
|
|
551
|
-
if (aVal == null) return 1;
|
|
552
|
-
if (bVal == null) return -1;
|
|
553
|
-
let comparison = 0;
|
|
554
|
-
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
555
|
-
comparison = aVal - bVal;
|
|
556
|
-
} else {
|
|
557
|
-
comparison = String(aVal).localeCompare(String(bVal));
|
|
558
|
-
}
|
|
559
|
-
return dir === "desc" ? -comparison : comparison;
|
|
560
|
-
});
|
|
561
|
-
return sorted;
|
|
562
|
-
}
|
|
563
|
-
function getPaginatedItems(items, page, pageSize) {
|
|
564
|
-
if (!Array.isArray(items)) {
|
|
565
|
-
return void 0;
|
|
566
|
-
}
|
|
567
|
-
if (typeof page !== "number" || page < 0) {
|
|
568
|
-
return void 0;
|
|
569
|
-
}
|
|
570
|
-
if (typeof pageSize !== "number" || pageSize <= 0) {
|
|
571
|
-
return void 0;
|
|
572
|
-
}
|
|
573
|
-
const start = page * pageSize;
|
|
574
|
-
const end = start + pageSize;
|
|
575
|
-
return items.slice(start, end);
|
|
576
|
-
}
|
|
577
|
-
function getTotalPages(itemCount, pageSize) {
|
|
578
|
-
if (typeof itemCount !== "number" || typeof pageSize !== "number") {
|
|
579
|
-
return 0;
|
|
580
|
-
}
|
|
581
|
-
if (itemCount < 0 || pageSize <= 0) {
|
|
582
|
-
return 0;
|
|
583
|
-
}
|
|
584
|
-
if (itemCount === 0) {
|
|
585
|
-
return 0;
|
|
586
|
-
}
|
|
587
|
-
return Math.ceil(itemCount / pageSize);
|
|
588
|
-
}
|
|
589
|
-
function getPageNumbers(currentPage, totalPages, maxVisible) {
|
|
590
|
-
if (typeof currentPage !== "number" || typeof totalPages !== "number" || typeof maxVisible !== "number") {
|
|
591
|
-
return [];
|
|
592
|
-
}
|
|
593
|
-
if (totalPages <= 0) {
|
|
594
|
-
return [];
|
|
595
|
-
}
|
|
596
|
-
if (currentPage < 0 || currentPage >= totalPages) {
|
|
597
|
-
return [];
|
|
598
|
-
}
|
|
599
|
-
if (totalPages <= maxVisible) {
|
|
600
|
-
return Array.from({ length: totalPages }, (_2, i) => i);
|
|
601
|
-
}
|
|
602
|
-
const result = [];
|
|
603
|
-
const firstPage = 0;
|
|
604
|
-
const lastPage = totalPages - 1;
|
|
605
|
-
result.push(firstPage);
|
|
606
|
-
const middleSlots = maxVisible - 2;
|
|
607
|
-
let middleStart = currentPage - Math.floor((middleSlots - 1) / 2);
|
|
608
|
-
let middleEnd = currentPage + Math.ceil((middleSlots - 1) / 2);
|
|
609
|
-
if (middleStart <= 1) {
|
|
610
|
-
middleStart = 1;
|
|
611
|
-
middleEnd = Math.min(middleSlots, lastPage - 1);
|
|
612
|
-
}
|
|
613
|
-
if (middleEnd >= lastPage - 1) {
|
|
614
|
-
middleEnd = lastPage - 1;
|
|
615
|
-
middleStart = Math.max(1, lastPage - middleSlots);
|
|
616
|
-
}
|
|
617
|
-
if (middleStart > 1) {
|
|
618
|
-
result.push(-1);
|
|
619
|
-
}
|
|
620
|
-
for (let i = middleStart; i <= middleEnd; i++) {
|
|
621
|
-
if (i > firstPage && i < lastPage) {
|
|
622
|
-
result.push(i);
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
if (middleEnd < lastPage - 1) {
|
|
626
|
-
result.push(-1);
|
|
627
|
-
}
|
|
628
|
-
result.push(lastPage);
|
|
629
|
-
return result;
|
|
630
|
-
}
|
|
631
|
-
function getVisibleRange(scrollTop, itemHeight, containerHeight, overscan) {
|
|
632
|
-
if (typeof scrollTop !== "number" || typeof itemHeight !== "number" || typeof containerHeight !== "number" || typeof overscan !== "number") {
|
|
633
|
-
return void 0;
|
|
634
|
-
}
|
|
635
|
-
if (scrollTop < 0 || itemHeight <= 0 || containerHeight <= 0) {
|
|
636
|
-
return void 0;
|
|
637
|
-
}
|
|
638
|
-
const firstVisible = Math.floor(scrollTop / itemHeight);
|
|
639
|
-
const visibleCount = Math.ceil(containerHeight / itemHeight);
|
|
640
|
-
const start = Math.max(0, firstVisible - overscan);
|
|
641
|
-
const end = firstVisible + visibleCount + overscan - 1;
|
|
642
|
-
return { start, end };
|
|
643
|
-
}
|
|
644
|
-
function getTotalHeight(itemCount, itemHeight) {
|
|
645
|
-
if (typeof itemCount !== "number" || typeof itemHeight !== "number") {
|
|
646
|
-
return 0;
|
|
647
|
-
}
|
|
648
|
-
if (itemCount < 0 || itemHeight <= 0) {
|
|
649
|
-
return 0;
|
|
650
|
-
}
|
|
651
|
-
return itemCount * itemHeight;
|
|
652
|
-
}
|
|
653
|
-
function formatDate(dateStr, format, locale) {
|
|
654
|
-
if (typeof dateStr !== "string" || !dateStr) {
|
|
655
|
-
return void 0;
|
|
656
|
-
}
|
|
657
|
-
const isoDateRegex = /^\d{4}-\d{2}-\d{2}$/;
|
|
658
|
-
if (!isoDateRegex.test(dateStr)) {
|
|
659
|
-
return void 0;
|
|
660
|
-
}
|
|
661
|
-
const [yearStr, monthStr, dayStr] = dateStr.split("-");
|
|
662
|
-
const year = parseInt(yearStr, 10);
|
|
663
|
-
const month = parseInt(monthStr, 10) - 1;
|
|
664
|
-
const day = parseInt(dayStr, 10);
|
|
665
|
-
const date = new Date(Date.UTC(year, month, day));
|
|
666
|
-
if (isNaN(date.getTime()) || date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) {
|
|
667
|
-
return void 0;
|
|
668
|
-
}
|
|
669
|
-
const effectiveFormat = typeof format === "string" ? format : "medium";
|
|
670
|
-
const effectiveLocale = typeof locale === "string" ? locale : "en-US";
|
|
671
|
-
if (effectiveFormat === "iso") {
|
|
672
|
-
return dateStr;
|
|
673
|
-
}
|
|
674
|
-
try {
|
|
675
|
-
let options;
|
|
676
|
-
switch (effectiveFormat) {
|
|
677
|
-
case "short":
|
|
678
|
-
if (effectiveLocale.startsWith("ja")) {
|
|
679
|
-
options = { year: "numeric", month: "2-digit", day: "2-digit", timeZone: "UTC" };
|
|
680
|
-
} else {
|
|
681
|
-
options = { year: "2-digit", month: "numeric", day: "numeric", timeZone: "UTC" };
|
|
682
|
-
}
|
|
683
|
-
break;
|
|
684
|
-
case "medium":
|
|
685
|
-
options = { year: "numeric", month: "short", day: "numeric", timeZone: "UTC" };
|
|
686
|
-
break;
|
|
687
|
-
case "long":
|
|
688
|
-
options = { year: "numeric", month: "long", day: "numeric", timeZone: "UTC" };
|
|
689
|
-
break;
|
|
690
|
-
default:
|
|
691
|
-
options = { year: "numeric", month: "short", day: "numeric", timeZone: "UTC" };
|
|
692
|
-
}
|
|
693
|
-
const formatter = new Intl.DateTimeFormat(effectiveLocale, options);
|
|
694
|
-
return formatter.format(date);
|
|
695
|
-
} catch {
|
|
696
|
-
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
697
|
-
year: "numeric",
|
|
698
|
-
month: "short",
|
|
699
|
-
day: "numeric",
|
|
700
|
-
timeZone: "UTC"
|
|
701
|
-
});
|
|
702
|
-
return formatter.format(date);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
440
|
function createLambdaFunction(lambda, ctx) {
|
|
706
441
|
return (item, index) => {
|
|
707
442
|
const lambdaLocals = {
|
|
@@ -943,51 +678,6 @@ function callDateInstanceMethod(target, method) {
|
|
|
943
678
|
return void 0;
|
|
944
679
|
}
|
|
945
680
|
}
|
|
946
|
-
var GLOBAL_FUNCTIONS = {
|
|
947
|
-
// Date helpers
|
|
948
|
-
getCalendarDays: (year, month) => getCalendarDays(year, month),
|
|
949
|
-
getWeekDays: (locale) => getWeekDays(locale),
|
|
950
|
-
getMonthName: (month, locale) => getMonthName(month, locale),
|
|
951
|
-
formatDate: (dateStr, format, locale) => formatDate(dateStr, format, locale),
|
|
952
|
-
formatDateISO: (year, month, date) => formatDateISO(year, month, date),
|
|
953
|
-
// DataTable helpers
|
|
954
|
-
sortBy: (items, key2, direction) => sortBy(items, key2, direction),
|
|
955
|
-
getPaginatedItems: (items, page, pageSize) => getPaginatedItems(items, page, pageSize),
|
|
956
|
-
getTotalPages: (itemCount, pageSize) => getTotalPages(itemCount, pageSize),
|
|
957
|
-
getPageNumbers: (currentPage, totalPages, maxVisible) => getPageNumbers(currentPage, totalPages, maxVisible),
|
|
958
|
-
// Virtual scroll helpers
|
|
959
|
-
getVisibleRange: (scrollTop, itemHeight, containerHeight, overscan) => getVisibleRange(scrollTop, itemHeight, containerHeight, overscan),
|
|
960
|
-
getTotalHeight: (itemCount, itemHeight) => getTotalHeight(itemCount, itemHeight),
|
|
961
|
-
// Chart helpers - Coordinate calculation
|
|
962
|
-
normalizeValue: (value, min, max) => normalizeValue(value, min, max),
|
|
963
|
-
scaleValue: (value, domainMin, domainMax, rangeMin, rangeMax) => scaleValue(value, domainMin, domainMax, rangeMin, rangeMax),
|
|
964
|
-
getBarDimensions: (data, index, width, height, gap, orientation) => getBarDimensions(data, index, width, height, gap, orientation),
|
|
965
|
-
// Chart helpers - Path generation
|
|
966
|
-
getLinePath: (points, curved) => getLinePath(points, curved),
|
|
967
|
-
getAreaPath: (points, baseline, curved) => getAreaPath(points, baseline, curved),
|
|
968
|
-
getArcPath: (cx, cy, radius, startAngle, endAngle) => getArcPath(cx, cy, radius, startAngle, endAngle),
|
|
969
|
-
// Chart helpers - Pie/Donut
|
|
970
|
-
getPieSlices: (data, valueKey) => getPieSlices(data, valueKey),
|
|
971
|
-
getDonutSlices: (data, valueKey, innerRadius) => getDonutSlices(data, valueKey, innerRadius),
|
|
972
|
-
// Chart helpers - Radar
|
|
973
|
-
getRadarPoints: (data, valueKey, cx, cy, radius, maxValue) => getRadarPoints(data, valueKey, cx, cy, radius, maxValue),
|
|
974
|
-
getRadarAxes: (labels, cx, cy, radius) => getRadarAxes(labels, cx, cy, radius),
|
|
975
|
-
// Chart helpers - Utilities
|
|
976
|
-
getChartBounds: (data, valueKey) => getChartBounds(data, valueKey),
|
|
977
|
-
scaleChartY: (value, boundsMin, boundsMax, height, paddingTop, paddingBottom) => scaleChartY(value, boundsMin, boundsMax, height, paddingTop, paddingBottom),
|
|
978
|
-
generateTicks: (min, max, count) => generateTicks(min, max, count),
|
|
979
|
-
// Chart helpers - Data aggregation
|
|
980
|
-
binData: (data, valueKey, binCount) => binData(data, valueKey, binCount),
|
|
981
|
-
aggregateData: (data, groupKey, valueKey, aggregation) => aggregateData(data, groupKey, valueKey, aggregation),
|
|
982
|
-
downsample: (data, targetCount, method) => downsample(data, targetCount, method)
|
|
983
|
-
};
|
|
984
|
-
function callGlobalFunction(method, args) {
|
|
985
|
-
const fn = GLOBAL_FUNCTIONS[method];
|
|
986
|
-
if (!fn) {
|
|
987
|
-
return void 0;
|
|
988
|
-
}
|
|
989
|
-
return fn(...args);
|
|
990
|
-
}
|
|
991
681
|
function evaluate(expr, ctx) {
|
|
992
682
|
switch (expr.expr) {
|
|
993
683
|
case "lit":
|
|
@@ -1030,20 +720,7 @@ function evaluate(expr, ctx) {
|
|
|
1030
720
|
Number,
|
|
1031
721
|
Boolean,
|
|
1032
722
|
console,
|
|
1033
|
-
|
|
1034
|
-
getCalendarDays,
|
|
1035
|
-
getWeekDays,
|
|
1036
|
-
getMonthName,
|
|
1037
|
-
formatDate,
|
|
1038
|
-
formatDateISO,
|
|
1039
|
-
// DataTable helper functions
|
|
1040
|
-
sortBy,
|
|
1041
|
-
getPaginatedItems,
|
|
1042
|
-
getTotalPages,
|
|
1043
|
-
getPageNumbers,
|
|
1044
|
-
// Virtual scroll helper functions
|
|
1045
|
-
getVisibleRange,
|
|
1046
|
-
getTotalHeight
|
|
723
|
+
...GLOBAL_FUNCTIONS
|
|
1047
724
|
};
|
|
1048
725
|
value = safeGlobals[varName];
|
|
1049
726
|
}
|
|
@@ -1054,7 +731,7 @@ function evaluate(expr, ctx) {
|
|
|
1054
731
|
if (typeof value === "function" && pathParts.length > 0) {
|
|
1055
732
|
let parent = ctx.locals[varName];
|
|
1056
733
|
if (parent === void 0) {
|
|
1057
|
-
const safeGlobals = { JSON, Math, Date, Object, Array, String, Number, Boolean, console,
|
|
734
|
+
const safeGlobals = { JSON, Math, Date, Object, Array, String, Number, Boolean, console, ...GLOBAL_FUNCTIONS };
|
|
1058
735
|
parent = safeGlobals[varName];
|
|
1059
736
|
}
|
|
1060
737
|
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
@@ -1312,542 +989,6 @@ function evaluateBinary(op, left, right, ctx) {
|
|
|
1312
989
|
throw new Error("Unknown binary operator: " + op);
|
|
1313
990
|
}
|
|
1314
991
|
}
|
|
1315
|
-
function normalizeValue(value, min, max) {
|
|
1316
|
-
if (typeof value !== "number" || typeof min !== "number" || typeof max !== "number") {
|
|
1317
|
-
return void 0;
|
|
1318
|
-
}
|
|
1319
|
-
if (max === min) {
|
|
1320
|
-
return 0;
|
|
1321
|
-
}
|
|
1322
|
-
return (value - min) / (max - min);
|
|
1323
|
-
}
|
|
1324
|
-
function scaleValue(value, domainMin, domainMax, rangeMin, rangeMax) {
|
|
1325
|
-
if (typeof value !== "number" || typeof domainMin !== "number" || typeof domainMax !== "number" || typeof rangeMin !== "number" || typeof rangeMax !== "number") {
|
|
1326
|
-
return void 0;
|
|
1327
|
-
}
|
|
1328
|
-
if (domainMax === domainMin) {
|
|
1329
|
-
return rangeMin;
|
|
1330
|
-
}
|
|
1331
|
-
const normalized = (value - domainMin) / (domainMax - domainMin);
|
|
1332
|
-
return rangeMin + normalized * (rangeMax - rangeMin);
|
|
1333
|
-
}
|
|
1334
|
-
function scaleChartY(value, boundsMin, boundsMax, height, paddingTop, paddingBottom) {
|
|
1335
|
-
if (typeof value !== "number" || typeof boundsMin !== "number" || typeof boundsMax !== "number" || typeof height !== "number" || typeof paddingTop !== "number" || typeof paddingBottom !== "number") {
|
|
1336
|
-
return void 0;
|
|
1337
|
-
}
|
|
1338
|
-
const drawableHeight = height - paddingTop - paddingBottom;
|
|
1339
|
-
if (drawableHeight <= 0) {
|
|
1340
|
-
return paddingTop;
|
|
1341
|
-
}
|
|
1342
|
-
if (boundsMax === boundsMin) {
|
|
1343
|
-
return paddingTop + drawableHeight / 2;
|
|
1344
|
-
}
|
|
1345
|
-
const normalized = (value - boundsMin) / (boundsMax - boundsMin);
|
|
1346
|
-
return paddingTop + drawableHeight * (1 - normalized);
|
|
1347
|
-
}
|
|
1348
|
-
function getBarDimensions(data, index, width, height, gap, orientation) {
|
|
1349
|
-
if (!Array.isArray(data) || data.length === 0) {
|
|
1350
|
-
return void 0;
|
|
1351
|
-
}
|
|
1352
|
-
if (typeof index !== "number" || index < 0 || index >= data.length) {
|
|
1353
|
-
return void 0;
|
|
1354
|
-
}
|
|
1355
|
-
if (typeof width !== "number" || typeof height !== "number" || typeof gap !== "number") {
|
|
1356
|
-
return void 0;
|
|
1357
|
-
}
|
|
1358
|
-
const isVertical = orientation === "vertical";
|
|
1359
|
-
const barCount = data.length;
|
|
1360
|
-
const values = data.map((d2) => typeof d2 === "number" ? d2 : 0);
|
|
1361
|
-
const maxValue = Math.max(...values);
|
|
1362
|
-
if (isVertical) {
|
|
1363
|
-
const totalGap = gap * (barCount + 1);
|
|
1364
|
-
const barWidth = (width - totalGap) / barCount;
|
|
1365
|
-
const barX = gap + index * (barWidth + gap);
|
|
1366
|
-
const value = values[index] ?? 0;
|
|
1367
|
-
const barHeight = maxValue > 0 ? value / maxValue * height : 0;
|
|
1368
|
-
const barY = height - barHeight;
|
|
1369
|
-
return {
|
|
1370
|
-
x: barX,
|
|
1371
|
-
y: barY,
|
|
1372
|
-
width: barWidth,
|
|
1373
|
-
height: barHeight
|
|
1374
|
-
};
|
|
1375
|
-
} else {
|
|
1376
|
-
const totalGap = gap * barCount;
|
|
1377
|
-
const barHeight = (height - totalGap) / barCount;
|
|
1378
|
-
const barY = gap + index * (barHeight + gap);
|
|
1379
|
-
const value = values[index] ?? 0;
|
|
1380
|
-
const barWidth = maxValue > 0 ? value / maxValue * width : 0;
|
|
1381
|
-
return {
|
|
1382
|
-
x: 0,
|
|
1383
|
-
y: barY,
|
|
1384
|
-
width: barWidth,
|
|
1385
|
-
height: barHeight
|
|
1386
|
-
};
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
function getCurvedPath(points) {
|
|
1390
|
-
if (points.length < 2) {
|
|
1391
|
-
return points.length === 1 ? `M${points[0].x},${points[0].y}` : "";
|
|
1392
|
-
}
|
|
1393
|
-
if (points.length === 2) {
|
|
1394
|
-
return `M${points[0].x},${points[0].y} L${points[1].x},${points[1].y}`;
|
|
1395
|
-
}
|
|
1396
|
-
const pathParts = [`M${points[0].x},${points[0].y}`];
|
|
1397
|
-
for (let i = 0; i < points.length - 1; i++) {
|
|
1398
|
-
const p0 = points[Math.max(0, i - 1)];
|
|
1399
|
-
const p1 = points[i];
|
|
1400
|
-
const p2 = points[i + 1];
|
|
1401
|
-
const p3 = points[Math.min(points.length - 1, i + 2)];
|
|
1402
|
-
const cp1x = p1.x + (p2.x - p0.x) / 6;
|
|
1403
|
-
const cp1y = p1.y + (p2.y - p0.y) / 6;
|
|
1404
|
-
const cp2x = p2.x - (p3.x - p1.x) / 6;
|
|
1405
|
-
const cp2y = p2.y - (p3.y - p1.y) / 6;
|
|
1406
|
-
pathParts.push(`C${cp1x},${cp1y} ${cp2x},${cp2y} ${p2.x},${p2.y}`);
|
|
1407
|
-
}
|
|
1408
|
-
return pathParts.join(" ");
|
|
1409
|
-
}
|
|
1410
|
-
function getLinePath(points, curved) {
|
|
1411
|
-
if (!Array.isArray(points)) {
|
|
1412
|
-
return void 0;
|
|
1413
|
-
}
|
|
1414
|
-
if (points.length === 0) {
|
|
1415
|
-
return "";
|
|
1416
|
-
}
|
|
1417
|
-
for (const point of points) {
|
|
1418
|
-
if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
|
|
1419
|
-
return void 0;
|
|
1420
|
-
}
|
|
1421
|
-
}
|
|
1422
|
-
const validPoints = points;
|
|
1423
|
-
if (validPoints.length === 1) {
|
|
1424
|
-
return `M${validPoints[0].x},${validPoints[0].y}`;
|
|
1425
|
-
}
|
|
1426
|
-
if (curved !== true) {
|
|
1427
|
-
const pathParts = validPoints.map((point, i) => {
|
|
1428
|
-
const command = i === 0 ? "M" : "L";
|
|
1429
|
-
return `${command}${point.x},${point.y}`;
|
|
1430
|
-
});
|
|
1431
|
-
return pathParts.join(" ");
|
|
1432
|
-
}
|
|
1433
|
-
return getCurvedPath(validPoints);
|
|
1434
|
-
}
|
|
1435
|
-
function getAreaPath(points, baseline, curved) {
|
|
1436
|
-
if (!Array.isArray(points)) {
|
|
1437
|
-
return void 0;
|
|
1438
|
-
}
|
|
1439
|
-
if (typeof baseline !== "number") {
|
|
1440
|
-
return void 0;
|
|
1441
|
-
}
|
|
1442
|
-
if (points.length === 0) {
|
|
1443
|
-
return "";
|
|
1444
|
-
}
|
|
1445
|
-
for (const point of points) {
|
|
1446
|
-
if (typeof point !== "object" || point === null || typeof point.x !== "number" || typeof point.y !== "number") {
|
|
1447
|
-
return void 0;
|
|
1448
|
-
}
|
|
1449
|
-
}
|
|
1450
|
-
const validPoints = points;
|
|
1451
|
-
let upperPath;
|
|
1452
|
-
if (curved === true && validPoints.length > 2) {
|
|
1453
|
-
upperPath = getCurvedPath(validPoints);
|
|
1454
|
-
} else {
|
|
1455
|
-
upperPath = validPoints.map((p2, i) => (i === 0 ? "M" : "L") + `${p2.x},${p2.y}`).join(" ");
|
|
1456
|
-
}
|
|
1457
|
-
const lastPoint = validPoints[validPoints.length - 1];
|
|
1458
|
-
const firstPoint = validPoints[0];
|
|
1459
|
-
return `${upperPath} L${lastPoint.x},${baseline} L${firstPoint.x},${baseline} Z`;
|
|
1460
|
-
}
|
|
1461
|
-
function getArcPath(cx, cy, radius, startAngle, endAngle) {
|
|
1462
|
-
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof startAngle !== "number" || typeof endAngle !== "number") {
|
|
1463
|
-
return void 0;
|
|
1464
|
-
}
|
|
1465
|
-
if (radius <= 0) {
|
|
1466
|
-
return void 0;
|
|
1467
|
-
}
|
|
1468
|
-
const x1 = cx + radius * Math.cos(startAngle);
|
|
1469
|
-
const y1 = cy + radius * Math.sin(startAngle);
|
|
1470
|
-
const x2 = cx + radius * Math.cos(endAngle);
|
|
1471
|
-
const y2 = cy + radius * Math.sin(endAngle);
|
|
1472
|
-
const angleDiff = endAngle - startAngle;
|
|
1473
|
-
const largeArcFlag = Math.abs(angleDiff) > Math.PI ? 1 : 0;
|
|
1474
|
-
return `M${x1},${y1} A${radius},${radius} 0 ${largeArcFlag},1 ${x2},${y2}`;
|
|
1475
|
-
}
|
|
1476
|
-
function getPieSlices(data, valueKey) {
|
|
1477
|
-
if (!Array.isArray(data)) {
|
|
1478
|
-
return void 0;
|
|
1479
|
-
}
|
|
1480
|
-
if (typeof valueKey !== "string") {
|
|
1481
|
-
return void 0;
|
|
1482
|
-
}
|
|
1483
|
-
if (data.length === 0) {
|
|
1484
|
-
return [];
|
|
1485
|
-
}
|
|
1486
|
-
const values = data.map((item) => {
|
|
1487
|
-
if (typeof item !== "object" || item === null) return 0;
|
|
1488
|
-
const val = item[valueKey];
|
|
1489
|
-
return typeof val === "number" ? val : 0;
|
|
1490
|
-
});
|
|
1491
|
-
const total = values.reduce((sum, val) => sum + val, 0);
|
|
1492
|
-
const slices = [];
|
|
1493
|
-
let currentAngle = 0;
|
|
1494
|
-
for (let i = 0; i < values.length; i++) {
|
|
1495
|
-
const value = values[i];
|
|
1496
|
-
const percentage = total > 0 ? value / total * 100 : 0;
|
|
1497
|
-
const angleSpan = total > 0 ? value / total * Math.PI * 2 : 0;
|
|
1498
|
-
slices.push({
|
|
1499
|
-
startAngle: currentAngle,
|
|
1500
|
-
endAngle: currentAngle + angleSpan,
|
|
1501
|
-
value,
|
|
1502
|
-
percentage
|
|
1503
|
-
});
|
|
1504
|
-
currentAngle += angleSpan;
|
|
1505
|
-
}
|
|
1506
|
-
return slices;
|
|
1507
|
-
}
|
|
1508
|
-
function getDonutSlices(data, valueKey, innerRadius) {
|
|
1509
|
-
if (typeof innerRadius !== "number" || innerRadius < 0) {
|
|
1510
|
-
return void 0;
|
|
1511
|
-
}
|
|
1512
|
-
const pieSlices = getPieSlices(data, valueKey);
|
|
1513
|
-
if (pieSlices === void 0) {
|
|
1514
|
-
return void 0;
|
|
1515
|
-
}
|
|
1516
|
-
const outerRadius = 100;
|
|
1517
|
-
return pieSlices.map((slice) => ({
|
|
1518
|
-
...slice,
|
|
1519
|
-
outerRadius,
|
|
1520
|
-
innerRadius
|
|
1521
|
-
}));
|
|
1522
|
-
}
|
|
1523
|
-
function getRadarPoints(data, valueKey, cx, cy, radius, maxValue) {
|
|
1524
|
-
if (!Array.isArray(data)) {
|
|
1525
|
-
return void 0;
|
|
1526
|
-
}
|
|
1527
|
-
if (typeof valueKey !== "string") {
|
|
1528
|
-
return void 0;
|
|
1529
|
-
}
|
|
1530
|
-
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number" || typeof maxValue !== "number") {
|
|
1531
|
-
return void 0;
|
|
1532
|
-
}
|
|
1533
|
-
if (maxValue <= 0) {
|
|
1534
|
-
return void 0;
|
|
1535
|
-
}
|
|
1536
|
-
if (data.length === 0) {
|
|
1537
|
-
return [];
|
|
1538
|
-
}
|
|
1539
|
-
const points = [];
|
|
1540
|
-
const angleStep = Math.PI * 2 / data.length;
|
|
1541
|
-
for (let i = 0; i < data.length; i++) {
|
|
1542
|
-
const item = data[i];
|
|
1543
|
-
const value = typeof item === "object" && item !== null ? item[valueKey] : 0;
|
|
1544
|
-
const numValue = typeof value === "number" ? value : 0;
|
|
1545
|
-
const scaledRadius = numValue / maxValue * radius;
|
|
1546
|
-
const angle = -Math.PI / 2 + i * angleStep;
|
|
1547
|
-
const x2 = cx + scaledRadius * Math.cos(angle);
|
|
1548
|
-
const y2 = cy + scaledRadius * Math.sin(angle);
|
|
1549
|
-
points.push({ x: x2, y: y2 });
|
|
1550
|
-
}
|
|
1551
|
-
return points;
|
|
1552
|
-
}
|
|
1553
|
-
function getRadarAxes(labels, cx, cy, radius) {
|
|
1554
|
-
if (!Array.isArray(labels)) {
|
|
1555
|
-
return void 0;
|
|
1556
|
-
}
|
|
1557
|
-
if (typeof cx !== "number" || typeof cy !== "number" || typeof radius !== "number") {
|
|
1558
|
-
return void 0;
|
|
1559
|
-
}
|
|
1560
|
-
if (radius < 0) {
|
|
1561
|
-
return void 0;
|
|
1562
|
-
}
|
|
1563
|
-
if (labels.length === 0) {
|
|
1564
|
-
return [];
|
|
1565
|
-
}
|
|
1566
|
-
const axes = [];
|
|
1567
|
-
const angleStep = Math.PI * 2 / labels.length;
|
|
1568
|
-
for (let i = 0; i < labels.length; i++) {
|
|
1569
|
-
const label = String(labels[i]);
|
|
1570
|
-
const angle = -Math.PI / 2 + i * angleStep;
|
|
1571
|
-
const x2 = cx + radius * Math.cos(angle);
|
|
1572
|
-
const y2 = cy + radius * Math.sin(angle);
|
|
1573
|
-
axes.push({
|
|
1574
|
-
x1: cx,
|
|
1575
|
-
y1: cy,
|
|
1576
|
-
x2,
|
|
1577
|
-
y2,
|
|
1578
|
-
label,
|
|
1579
|
-
angle
|
|
1580
|
-
});
|
|
1581
|
-
}
|
|
1582
|
-
return axes;
|
|
1583
|
-
}
|
|
1584
|
-
function getChartBounds(data, valueKey) {
|
|
1585
|
-
if (!Array.isArray(data) || data.length === 0) {
|
|
1586
|
-
return void 0;
|
|
1587
|
-
}
|
|
1588
|
-
if (typeof valueKey !== "string") {
|
|
1589
|
-
return void 0;
|
|
1590
|
-
}
|
|
1591
|
-
const values = [];
|
|
1592
|
-
for (const item of data) {
|
|
1593
|
-
if (typeof item !== "object" || item === null) {
|
|
1594
|
-
continue;
|
|
1595
|
-
}
|
|
1596
|
-
const val = item[valueKey];
|
|
1597
|
-
if (typeof val === "number") {
|
|
1598
|
-
values.push(val);
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
if (values.length === 0) {
|
|
1602
|
-
return void 0;
|
|
1603
|
-
}
|
|
1604
|
-
return {
|
|
1605
|
-
min: Math.min(...values),
|
|
1606
|
-
max: Math.max(...values)
|
|
1607
|
-
};
|
|
1608
|
-
}
|
|
1609
|
-
function generateTicks(min, max, count) {
|
|
1610
|
-
if (typeof min !== "number" || typeof max !== "number" || typeof count !== "number") {
|
|
1611
|
-
return [];
|
|
1612
|
-
}
|
|
1613
|
-
if (count <= 0) {
|
|
1614
|
-
return [];
|
|
1615
|
-
}
|
|
1616
|
-
if (min === max) {
|
|
1617
|
-
return [min];
|
|
1618
|
-
}
|
|
1619
|
-
if (count === 1) {
|
|
1620
|
-
return [min];
|
|
1621
|
-
}
|
|
1622
|
-
if (count === 2) {
|
|
1623
|
-
return [min, max];
|
|
1624
|
-
}
|
|
1625
|
-
const range = max - min;
|
|
1626
|
-
const rawStep = range / (count - 1);
|
|
1627
|
-
const niceStep = getNiceStep(rawStep);
|
|
1628
|
-
const niceMin = Math.floor(min / niceStep) * niceStep;
|
|
1629
|
-
const ticks = [];
|
|
1630
|
-
for (let i = 0; i < count; i++) {
|
|
1631
|
-
const tick = niceMin + i * niceStep;
|
|
1632
|
-
ticks.push(Math.round(tick * 1e10) / 1e10);
|
|
1633
|
-
}
|
|
1634
|
-
return ticks;
|
|
1635
|
-
}
|
|
1636
|
-
function getNiceStep(rawStep) {
|
|
1637
|
-
const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
|
|
1638
|
-
const normalized = rawStep / magnitude;
|
|
1639
|
-
let niceNormalized;
|
|
1640
|
-
if (normalized <= 1) {
|
|
1641
|
-
niceNormalized = 1;
|
|
1642
|
-
} else if (normalized <= 2) {
|
|
1643
|
-
niceNormalized = 2;
|
|
1644
|
-
} else if (normalized <= 2.5) {
|
|
1645
|
-
niceNormalized = 2.5;
|
|
1646
|
-
} else if (normalized <= 5) {
|
|
1647
|
-
niceNormalized = 5;
|
|
1648
|
-
} else {
|
|
1649
|
-
niceNormalized = 10;
|
|
1650
|
-
}
|
|
1651
|
-
return niceNormalized * magnitude;
|
|
1652
|
-
}
|
|
1653
|
-
function binData(data, valueKey, binCount) {
|
|
1654
|
-
if (!Array.isArray(data)) {
|
|
1655
|
-
return void 0;
|
|
1656
|
-
}
|
|
1657
|
-
if (typeof valueKey !== "string") {
|
|
1658
|
-
return void 0;
|
|
1659
|
-
}
|
|
1660
|
-
if (typeof binCount !== "number" || binCount <= 0) {
|
|
1661
|
-
return [];
|
|
1662
|
-
}
|
|
1663
|
-
if (data.length === 0) {
|
|
1664
|
-
return [];
|
|
1665
|
-
}
|
|
1666
|
-
const values = [];
|
|
1667
|
-
for (const item of data) {
|
|
1668
|
-
if (typeof item !== "object" || item === null) continue;
|
|
1669
|
-
const val = item[valueKey];
|
|
1670
|
-
if (typeof val === "number") {
|
|
1671
|
-
values.push(val);
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
if (values.length === 0) {
|
|
1675
|
-
return [];
|
|
1676
|
-
}
|
|
1677
|
-
const minVal = Math.min(...values);
|
|
1678
|
-
const maxVal = Math.max(...values);
|
|
1679
|
-
const binWidth = maxVal === minVal ? 1 : (maxVal - minVal) / binCount;
|
|
1680
|
-
const bins = [];
|
|
1681
|
-
for (let i = 0; i < binCount; i++) {
|
|
1682
|
-
bins.push({
|
|
1683
|
-
binStart: minVal + i * binWidth,
|
|
1684
|
-
binEnd: minVal + (i + 1) * binWidth,
|
|
1685
|
-
count: 0,
|
|
1686
|
-
values: []
|
|
1687
|
-
});
|
|
1688
|
-
}
|
|
1689
|
-
for (const val of values) {
|
|
1690
|
-
let binIndex = Math.floor((val - minVal) / binWidth);
|
|
1691
|
-
if (binIndex >= binCount) {
|
|
1692
|
-
binIndex = binCount - 1;
|
|
1693
|
-
}
|
|
1694
|
-
bins[binIndex].count++;
|
|
1695
|
-
bins[binIndex].values.push(val);
|
|
1696
|
-
}
|
|
1697
|
-
return bins;
|
|
1698
|
-
}
|
|
1699
|
-
function aggregateData(data, groupKey, valueKey, aggregation) {
|
|
1700
|
-
if (!Array.isArray(data)) {
|
|
1701
|
-
return void 0;
|
|
1702
|
-
}
|
|
1703
|
-
if (typeof groupKey !== "string" || typeof valueKey !== "string") {
|
|
1704
|
-
return void 0;
|
|
1705
|
-
}
|
|
1706
|
-
const validAggregations = /* @__PURE__ */ new Set(["sum", "avg", "min", "max", "count"]);
|
|
1707
|
-
if (typeof aggregation !== "string" || !validAggregations.has(aggregation)) {
|
|
1708
|
-
return void 0;
|
|
1709
|
-
}
|
|
1710
|
-
if (data.length === 0) {
|
|
1711
|
-
return [];
|
|
1712
|
-
}
|
|
1713
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1714
|
-
for (const item of data) {
|
|
1715
|
-
if (typeof item !== "object" || item === null) continue;
|
|
1716
|
-
const obj = item;
|
|
1717
|
-
const group = String(obj[groupKey] ?? "");
|
|
1718
|
-
const val = obj[valueKey];
|
|
1719
|
-
const numVal = typeof val === "number" ? val : 0;
|
|
1720
|
-
if (!groups.has(group)) {
|
|
1721
|
-
groups.set(group, []);
|
|
1722
|
-
}
|
|
1723
|
-
groups.get(group).push(numVal);
|
|
1724
|
-
}
|
|
1725
|
-
const result = [];
|
|
1726
|
-
for (const [group, values] of groups) {
|
|
1727
|
-
let aggregatedValue;
|
|
1728
|
-
switch (aggregation) {
|
|
1729
|
-
case "sum":
|
|
1730
|
-
aggregatedValue = values.reduce((sum, v2) => sum + v2, 0);
|
|
1731
|
-
break;
|
|
1732
|
-
case "avg":
|
|
1733
|
-
aggregatedValue = values.reduce((sum, v2) => sum + v2, 0) / values.length;
|
|
1734
|
-
break;
|
|
1735
|
-
case "min":
|
|
1736
|
-
aggregatedValue = Math.min(...values);
|
|
1737
|
-
break;
|
|
1738
|
-
case "max":
|
|
1739
|
-
aggregatedValue = Math.max(...values);
|
|
1740
|
-
break;
|
|
1741
|
-
case "count":
|
|
1742
|
-
aggregatedValue = values.length;
|
|
1743
|
-
break;
|
|
1744
|
-
default:
|
|
1745
|
-
aggregatedValue = 0;
|
|
1746
|
-
}
|
|
1747
|
-
result.push({ group, value: aggregatedValue });
|
|
1748
|
-
}
|
|
1749
|
-
return result;
|
|
1750
|
-
}
|
|
1751
|
-
function downsample(data, targetCount, method) {
|
|
1752
|
-
if (!Array.isArray(data)) {
|
|
1753
|
-
return void 0;
|
|
1754
|
-
}
|
|
1755
|
-
if (typeof targetCount !== "number" || targetCount <= 0) {
|
|
1756
|
-
return void 0;
|
|
1757
|
-
}
|
|
1758
|
-
const validMethods = /* @__PURE__ */ new Set(["uniform", "lttb"]);
|
|
1759
|
-
if (typeof method !== "string" || !validMethods.has(method)) {
|
|
1760
|
-
return void 0;
|
|
1761
|
-
}
|
|
1762
|
-
if (data.length === 0) {
|
|
1763
|
-
return [];
|
|
1764
|
-
}
|
|
1765
|
-
if (targetCount >= data.length) {
|
|
1766
|
-
return data;
|
|
1767
|
-
}
|
|
1768
|
-
if (method === "uniform") {
|
|
1769
|
-
return downsampleUniform(data, targetCount);
|
|
1770
|
-
} else {
|
|
1771
|
-
return downsampleLTTB(data, targetCount);
|
|
1772
|
-
}
|
|
1773
|
-
}
|
|
1774
|
-
function downsampleUniform(data, targetCount) {
|
|
1775
|
-
if (targetCount === 1) {
|
|
1776
|
-
return [data[0]];
|
|
1777
|
-
}
|
|
1778
|
-
if (targetCount === 2) {
|
|
1779
|
-
return [data[0], data[data.length - 1]];
|
|
1780
|
-
}
|
|
1781
|
-
const result = [];
|
|
1782
|
-
const step = (data.length - 1) / (targetCount - 1);
|
|
1783
|
-
for (let i = 0; i < targetCount; i++) {
|
|
1784
|
-
const index = Math.round(i * step);
|
|
1785
|
-
result.push(data[index]);
|
|
1786
|
-
}
|
|
1787
|
-
return result;
|
|
1788
|
-
}
|
|
1789
|
-
function downsampleLTTB(data, targetCount) {
|
|
1790
|
-
if (targetCount === 1) {
|
|
1791
|
-
return [data[0]];
|
|
1792
|
-
}
|
|
1793
|
-
if (targetCount === 2) {
|
|
1794
|
-
return [data[0], data[data.length - 1]];
|
|
1795
|
-
}
|
|
1796
|
-
const getXY = (point) => {
|
|
1797
|
-
if (typeof point !== "object" || point === null) {
|
|
1798
|
-
return { x: 0, y: 0 };
|
|
1799
|
-
}
|
|
1800
|
-
const obj = point;
|
|
1801
|
-
const x2 = typeof obj["x"] === "number" ? obj["x"] : typeof obj["timestamp"] === "number" ? obj["timestamp"] : 0;
|
|
1802
|
-
const y2 = typeof obj["y"] === "number" ? obj["y"] : typeof obj["value"] === "number" ? obj["value"] : 0;
|
|
1803
|
-
return { x: x2, y: y2 };
|
|
1804
|
-
};
|
|
1805
|
-
const result = [];
|
|
1806
|
-
result.push(data[0]);
|
|
1807
|
-
const numBuckets = targetCount - 2;
|
|
1808
|
-
const middleData = data.length - 2;
|
|
1809
|
-
const bucketSize = middleData / numBuckets;
|
|
1810
|
-
let prevSelectedIndex = 0;
|
|
1811
|
-
for (let bucketIndex = 0; bucketIndex < numBuckets; bucketIndex++) {
|
|
1812
|
-
const bucketStart = Math.floor(bucketIndex * bucketSize) + 1;
|
|
1813
|
-
const bucketEnd = Math.floor((bucketIndex + 1) * bucketSize) + 1;
|
|
1814
|
-
const nextBucketStart = bucketEnd;
|
|
1815
|
-
const nextBucketEnd = bucketIndex < numBuckets - 1 ? Math.floor((bucketIndex + 2) * bucketSize) + 1 : data.length;
|
|
1816
|
-
let avgX = 0;
|
|
1817
|
-
let avgY = 0;
|
|
1818
|
-
const nextLen = nextBucketEnd - nextBucketStart;
|
|
1819
|
-
if (nextLen > 0) {
|
|
1820
|
-
for (let j2 = nextBucketStart; j2 < nextBucketEnd; j2++) {
|
|
1821
|
-
const point = getXY(data[j2]);
|
|
1822
|
-
avgX += point.x;
|
|
1823
|
-
avgY += point.y;
|
|
1824
|
-
}
|
|
1825
|
-
avgX /= nextLen;
|
|
1826
|
-
avgY /= nextLen;
|
|
1827
|
-
} else {
|
|
1828
|
-
const lastPoint = getXY(data[data.length - 1]);
|
|
1829
|
-
avgX = lastPoint.x;
|
|
1830
|
-
avgY = lastPoint.y;
|
|
1831
|
-
}
|
|
1832
|
-
const pointA = getXY(data[prevSelectedIndex]);
|
|
1833
|
-
let maxArea = -1;
|
|
1834
|
-
let maxAreaIndex = bucketStart;
|
|
1835
|
-
for (let j2 = bucketStart; j2 < bucketEnd; j2++) {
|
|
1836
|
-
const pointB = getXY(data[j2]);
|
|
1837
|
-
const area = Math.abs(
|
|
1838
|
-
pointA.x * (pointB.y - avgY) + pointB.x * (avgY - pointA.y) + avgX * (pointA.y - pointB.y)
|
|
1839
|
-
);
|
|
1840
|
-
if (area > maxArea) {
|
|
1841
|
-
maxArea = area;
|
|
1842
|
-
maxAreaIndex = j2;
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1845
|
-
result.push(data[maxAreaIndex]);
|
|
1846
|
-
prevSelectedIndex = maxAreaIndex;
|
|
1847
|
-
}
|
|
1848
|
-
result.push(data[data.length - 1]);
|
|
1849
|
-
return result;
|
|
1850
|
-
}
|
|
1851
992
|
function evaluateStyle(expr, ctx) {
|
|
1852
993
|
const preset = ctx.styles?.[expr.name];
|
|
1853
994
|
if (!preset) return void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Runtime DOM renderer for Constela UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"dompurify": "^3.3.1",
|
|
19
19
|
"marked": "^17.0.1",
|
|
20
20
|
"shiki": "^3.20.0",
|
|
21
|
-
"@constela/compiler": "0.15.
|
|
22
|
-
"@constela/core": "0.
|
|
21
|
+
"@constela/compiler": "0.15.14",
|
|
22
|
+
"@constela/core": "0.19.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/dompurify": "^3.2.0",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"tsup": "^8.0.0",
|
|
30
30
|
"typescript": "^5.3.0",
|
|
31
31
|
"vitest": "^2.0.0",
|
|
32
|
-
"@constela/server": "
|
|
32
|
+
"@constela/server": "15.0.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@constela/ai": "
|
|
35
|
+
"@constela/ai": "4.0.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependenciesMeta": {
|
|
38
38
|
"@constela/ai": {
|