pptx-glimpse 0.4.1 → 0.6.0
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.cjs +102 -27
- package/dist/index.js +102 -17
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/index.ts
|
|
@@ -1580,17 +1570,20 @@ function parseXmlOrdered(xml) {
|
|
|
1580
1570
|
}
|
|
1581
1571
|
|
|
1582
1572
|
// src/png/png-converter.ts
|
|
1583
|
-
var
|
|
1573
|
+
var import_resvg_js = require("@resvg/resvg-js");
|
|
1584
1574
|
async function svgToPng(svgString, options) {
|
|
1585
|
-
const
|
|
1586
|
-
let pipeline = (0, import_sharp.default)(svgBuffer);
|
|
1575
|
+
const resvgOptions = {};
|
|
1587
1576
|
if (options?.width) {
|
|
1588
|
-
|
|
1577
|
+
resvgOptions.fitTo = { mode: "width", value: options.width };
|
|
1589
1578
|
} else if (options?.height) {
|
|
1590
|
-
|
|
1579
|
+
resvgOptions.fitTo = { mode: "height", value: options.height };
|
|
1591
1580
|
}
|
|
1592
|
-
const
|
|
1593
|
-
return {
|
|
1581
|
+
const rendered = await (0, import_resvg_js.renderAsync)(svgString, resvgOptions);
|
|
1582
|
+
return {
|
|
1583
|
+
png: Buffer.from(rendered.asPng()),
|
|
1584
|
+
width: rendered.width,
|
|
1585
|
+
height: rendered.height
|
|
1586
|
+
};
|
|
1594
1587
|
}
|
|
1595
1588
|
|
|
1596
1589
|
// src/warning-logger.ts
|
|
@@ -2491,10 +2484,19 @@ function extractCategories(serList) {
|
|
|
2491
2484
|
if (!cat) continue;
|
|
2492
2485
|
const strRef = cat.strRef;
|
|
2493
2486
|
const numRef = cat.numRef;
|
|
2487
|
+
const multiLvlStrRef = cat.multiLvlStrRef;
|
|
2494
2488
|
const strCache = strRef?.strCache ?? numRef?.numCache;
|
|
2495
2489
|
if (strCache?.pt) {
|
|
2496
2490
|
return strCache.pt.slice().sort((a, b) => Number(a["@_idx"]) - Number(b["@_idx"])).map((pt) => String(pt.v ?? ""));
|
|
2497
2491
|
}
|
|
2492
|
+
const multiCache = multiLvlStrRef?.multiLvlStrCache;
|
|
2493
|
+
if (multiCache?.lvl) {
|
|
2494
|
+
const lvls = Array.isArray(multiCache.lvl) ? multiCache.lvl : [multiCache.lvl];
|
|
2495
|
+
const firstLvl = lvls[0];
|
|
2496
|
+
if (firstLvl?.pt) {
|
|
2497
|
+
return firstLvl.pt.slice().sort((a, b) => Number(a["@_idx"]) - Number(b["@_idx"])).map((pt) => String(pt.v ?? ""));
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2498
2500
|
}
|
|
2499
2501
|
return [];
|
|
2500
2502
|
}
|
|
@@ -4983,12 +4985,26 @@ function renderBarChart(chart, x, y, w, h) {
|
|
|
4983
4985
|
return "";
|
|
4984
4986
|
}
|
|
4985
4987
|
const isHorizontal = chart.barDirection === "bar";
|
|
4988
|
+
const ticks = computeNiceTicks(0, maxVal);
|
|
4989
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
4986
4990
|
parts.push(
|
|
4987
4991
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
4988
4992
|
);
|
|
4989
4993
|
parts.push(
|
|
4990
4994
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
4991
4995
|
);
|
|
4996
|
+
if (isHorizontal) {
|
|
4997
|
+
for (const tick of ticks) {
|
|
4998
|
+
const ratio = tick / scaleMax;
|
|
4999
|
+
if (ratio < -1e-3 || ratio > 1.001) continue;
|
|
5000
|
+
const tickX = x + ratio * w;
|
|
5001
|
+
parts.push(
|
|
5002
|
+
`<text x="${round(tickX)}" y="${round(y + h + 15)}" text-anchor="middle" font-size="10" fill="#595959">${escapeXml(formatTickValue(tick))}</text>`
|
|
5003
|
+
);
|
|
5004
|
+
}
|
|
5005
|
+
} else {
|
|
5006
|
+
parts.push(renderValueAxisLabels(ticks, 0, scaleMax, x, y, h));
|
|
5007
|
+
}
|
|
4992
5008
|
if (isHorizontal) {
|
|
4993
5009
|
const groupHeight = h / catCount;
|
|
4994
5010
|
const barHeight = groupHeight * 0.7 / series.length;
|
|
@@ -5004,7 +5020,7 @@ function renderBarChart(chart, x, y, w, h) {
|
|
|
5004
5020
|
const color = series[s].color;
|
|
5005
5021
|
for (let c = 0; c < series[s].values.length; c++) {
|
|
5006
5022
|
const val = series[s].values[c];
|
|
5007
|
-
const barW = val /
|
|
5023
|
+
const barW = val / scaleMax * w;
|
|
5008
5024
|
const barX = x;
|
|
5009
5025
|
const barY = y + c * groupHeight + groupPadding + s * barHeight;
|
|
5010
5026
|
parts.push(
|
|
@@ -5027,7 +5043,7 @@ function renderBarChart(chart, x, y, w, h) {
|
|
|
5027
5043
|
const color = series[s].color;
|
|
5028
5044
|
for (let c = 0; c < series[s].values.length; c++) {
|
|
5029
5045
|
const val = series[s].values[c];
|
|
5030
|
-
const barH = val /
|
|
5046
|
+
const barH = val / scaleMax * h;
|
|
5031
5047
|
const barX = x + c * groupWidth + groupPadding + s * barWidth;
|
|
5032
5048
|
const barY = y + h - barH;
|
|
5033
5049
|
parts.push(
|
|
@@ -5055,12 +5071,15 @@ function renderLineChart(chart, x, y, w, h) {
|
|
|
5055
5071
|
debug("chart.line", "category count is 0");
|
|
5056
5072
|
return "";
|
|
5057
5073
|
}
|
|
5074
|
+
const ticks = computeNiceTicks(0, maxVal);
|
|
5075
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
5058
5076
|
parts.push(
|
|
5059
5077
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5060
5078
|
);
|
|
5061
5079
|
parts.push(
|
|
5062
5080
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5063
5081
|
);
|
|
5082
|
+
parts.push(renderValueAxisLabels(ticks, 0, scaleMax, x, y, h));
|
|
5064
5083
|
for (let c = 0; c < catCount; c++) {
|
|
5065
5084
|
const label = categories[c] ?? "";
|
|
5066
5085
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
@@ -5074,7 +5093,7 @@ function renderLineChart(chart, x, y, w, h) {
|
|
|
5074
5093
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
5075
5094
|
const points = series[s].values.map((val, i) => {
|
|
5076
5095
|
const px = round(x + i / divisor * w);
|
|
5077
|
-
const py = round(y + h - val /
|
|
5096
|
+
const py = round(y + h - val / scaleMax * h);
|
|
5078
5097
|
return `${px},${py}`;
|
|
5079
5098
|
});
|
|
5080
5099
|
parts.push(
|
|
@@ -5104,12 +5123,15 @@ function renderAreaChart(chart, x, y, w, h) {
|
|
|
5104
5123
|
debug("chart.area", "category count is 0");
|
|
5105
5124
|
return "";
|
|
5106
5125
|
}
|
|
5126
|
+
const ticks = computeNiceTicks(0, maxVal);
|
|
5127
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
5107
5128
|
parts.push(
|
|
5108
5129
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5109
5130
|
);
|
|
5110
5131
|
parts.push(
|
|
5111
5132
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5112
5133
|
);
|
|
5134
|
+
parts.push(renderValueAxisLabels(ticks, 0, scaleMax, x, y, h));
|
|
5113
5135
|
for (let c = 0; c < catCount; c++) {
|
|
5114
5136
|
const label = categories[c] ?? "";
|
|
5115
5137
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
@@ -5124,7 +5146,7 @@ function renderAreaChart(chart, x, y, w, h) {
|
|
|
5124
5146
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
5125
5147
|
const dataPoints = series[s].values.map((val, i) => {
|
|
5126
5148
|
const px = round(x + i / divisor * w);
|
|
5127
|
-
const py = round(y + h - val /
|
|
5149
|
+
const py = round(y + h - val / scaleMax * h);
|
|
5128
5150
|
return { px, py };
|
|
5129
5151
|
});
|
|
5130
5152
|
const topPoints = dataPoints.map((p) => `${p.px},${p.py}`).join(" ");
|
|
@@ -5238,12 +5260,15 @@ function renderScatterChart(chart, x, y, w, h) {
|
|
|
5238
5260
|
}
|
|
5239
5261
|
if (maxX === 0) maxX = 1;
|
|
5240
5262
|
if (maxY === 0) maxY = 1;
|
|
5263
|
+
const yTicks = computeNiceTicks(0, maxY);
|
|
5264
|
+
const scaleMaxY = yTicks[yTicks.length - 1];
|
|
5241
5265
|
parts.push(
|
|
5242
5266
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5243
5267
|
);
|
|
5244
5268
|
parts.push(
|
|
5245
5269
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5246
5270
|
);
|
|
5271
|
+
parts.push(renderValueAxisLabels(yTicks, 0, scaleMaxY, x, y, h));
|
|
5247
5272
|
for (let s = 0; s < series.length; s++) {
|
|
5248
5273
|
const color = series[s].color;
|
|
5249
5274
|
const xVals = series[s].xValues ?? [];
|
|
@@ -5251,7 +5276,7 @@ function renderScatterChart(chart, x, y, w, h) {
|
|
|
5251
5276
|
const xVal = xVals[i] ?? i;
|
|
5252
5277
|
const yVal = series[s].values[i];
|
|
5253
5278
|
const px = x + xVal / maxX * w;
|
|
5254
|
-
const py = y + h - yVal /
|
|
5279
|
+
const py = y + h - yVal / scaleMaxY * h;
|
|
5255
5280
|
parts.push(`<circle cx="${round(px)}" cy="${round(py)}" r="4" ${fillAttr(color)}/>`);
|
|
5256
5281
|
}
|
|
5257
5282
|
}
|
|
@@ -5278,12 +5303,15 @@ function renderBubbleChart(chart, x, y, w, h) {
|
|
|
5278
5303
|
if (maxY === 0) maxY = 1;
|
|
5279
5304
|
if (maxBubble === 0) maxBubble = 1;
|
|
5280
5305
|
const maxRadius = Math.min(w, h) * 0.08;
|
|
5306
|
+
const yTicks = computeNiceTicks(0, maxY);
|
|
5307
|
+
const scaleMaxY = yTicks[yTicks.length - 1];
|
|
5281
5308
|
parts.push(
|
|
5282
5309
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5283
5310
|
);
|
|
5284
5311
|
parts.push(
|
|
5285
5312
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5286
5313
|
);
|
|
5314
|
+
parts.push(renderValueAxisLabels(yTicks, 0, scaleMaxY, x, y, h));
|
|
5287
5315
|
for (let s = 0; s < series.length; s++) {
|
|
5288
5316
|
const color = series[s].color;
|
|
5289
5317
|
const xVals = series[s].xValues ?? [];
|
|
@@ -5293,7 +5321,7 @@ function renderBubbleChart(chart, x, y, w, h) {
|
|
|
5293
5321
|
const yVal = series[s].values[i];
|
|
5294
5322
|
const size = sizes[i] ?? 1;
|
|
5295
5323
|
const px = x + xVal / maxX * w;
|
|
5296
|
-
const py = y + h - yVal /
|
|
5324
|
+
const py = y + h - yVal / scaleMaxY * h;
|
|
5297
5325
|
const r = Math.max(2, Math.sqrt(size / maxBubble) * maxRadius);
|
|
5298
5326
|
parts.push(
|
|
5299
5327
|
`<circle cx="${round(px)}" cy="${round(py)}" r="${round(r)}" ${fillAttr(color)} fill-opacity="0.6"/>`
|
|
@@ -5406,12 +5434,16 @@ function renderStockChart(chart, x, y, w, h) {
|
|
|
5406
5434
|
debug("chart.stock", "max equals min value");
|
|
5407
5435
|
return "";
|
|
5408
5436
|
}
|
|
5437
|
+
const ticks = computeNiceTicks(minVal, maxVal);
|
|
5438
|
+
const scaleMin = ticks[0];
|
|
5439
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
5409
5440
|
parts.push(
|
|
5410
5441
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5411
5442
|
);
|
|
5412
5443
|
parts.push(
|
|
5413
5444
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5414
5445
|
);
|
|
5446
|
+
parts.push(renderValueAxisLabels(ticks, scaleMin, scaleMax, x, y, h));
|
|
5415
5447
|
for (let c = 0; c < catCount; c++) {
|
|
5416
5448
|
const label = categories[c] ?? "";
|
|
5417
5449
|
const labelX = x + (c + 0.5) * (w / catCount);
|
|
@@ -5419,15 +5451,15 @@ function renderStockChart(chart, x, y, w, h) {
|
|
|
5419
5451
|
`<text x="${round(labelX)}" y="${round(y + h + 15)}" text-anchor="middle" font-size="10" fill="#595959">${escapeXml(label)}</text>`
|
|
5420
5452
|
);
|
|
5421
5453
|
}
|
|
5422
|
-
const range =
|
|
5454
|
+
const range = scaleMax - scaleMin;
|
|
5423
5455
|
for (let c = 0; c < catCount; c++) {
|
|
5424
5456
|
const cx = x + (c + 0.5) * (w / catCount);
|
|
5425
5457
|
const highVal = highSeries.values[c] ?? 0;
|
|
5426
5458
|
const lowVal = lowSeries.values[c] ?? 0;
|
|
5427
5459
|
const closeVal = closeSeries.values[c] ?? 0;
|
|
5428
|
-
const highY = y + h - (highVal -
|
|
5429
|
-
const lowY = y + h - (lowVal -
|
|
5430
|
-
const closeY = y + h - (closeVal -
|
|
5460
|
+
const highY = y + h - (highVal - scaleMin) / range * h;
|
|
5461
|
+
const lowY = y + h - (lowVal - scaleMin) / range * h;
|
|
5462
|
+
const closeY = y + h - (closeVal - scaleMin) / range * h;
|
|
5431
5463
|
parts.push(
|
|
5432
5464
|
`<line x1="${round(cx)}" y1="${round(highY)}" x2="${round(cx)}" y2="${round(lowY)}" stroke="#404040" stroke-width="2"/>`
|
|
5433
5465
|
);
|
|
@@ -5660,6 +5692,49 @@ function getPieSliceColor(index, chart) {
|
|
|
5660
5692
|
}
|
|
5661
5693
|
return DEFAULT_SERIES_COLORS[index % DEFAULT_SERIES_COLORS.length];
|
|
5662
5694
|
}
|
|
5695
|
+
function computeNiceTicks(minVal, maxVal, targetCount = 5) {
|
|
5696
|
+
const range = maxVal - minVal;
|
|
5697
|
+
if (range === 0) return [minVal];
|
|
5698
|
+
const roughStep = range / targetCount;
|
|
5699
|
+
const magnitude = Math.pow(10, Math.floor(Math.log10(roughStep)));
|
|
5700
|
+
const residual = roughStep / magnitude;
|
|
5701
|
+
let niceStep;
|
|
5702
|
+
if (residual <= 1.5) niceStep = magnitude;
|
|
5703
|
+
else if (residual <= 3) niceStep = 2 * magnitude;
|
|
5704
|
+
else if (residual <= 7) niceStep = 5 * magnitude;
|
|
5705
|
+
else niceStep = 10 * magnitude;
|
|
5706
|
+
const niceMin = Math.floor(minVal / niceStep) * niceStep;
|
|
5707
|
+
const niceMax = Math.ceil(maxVal / niceStep) * niceStep;
|
|
5708
|
+
const ticks = [];
|
|
5709
|
+
for (let v = niceMin; v <= niceMax + niceStep * 0.5; v += niceStep) {
|
|
5710
|
+
ticks.push(Math.round(v * 1e10) / 1e10);
|
|
5711
|
+
}
|
|
5712
|
+
return ticks;
|
|
5713
|
+
}
|
|
5714
|
+
function renderValueAxisLabels(ticks, scaleMin, scaleMax, x, y, h) {
|
|
5715
|
+
const parts = [];
|
|
5716
|
+
const range = scaleMax - scaleMin;
|
|
5717
|
+
if (range === 0) return "";
|
|
5718
|
+
for (const tick of ticks) {
|
|
5719
|
+
const ratio = (tick - scaleMin) / range;
|
|
5720
|
+
if (ratio < -1e-3 || ratio > 1.001) continue;
|
|
5721
|
+
const tickY = y + h - ratio * h;
|
|
5722
|
+
parts.push(
|
|
5723
|
+
`<text x="${round(x - 5)}" y="${round(tickY + 4)}" text-anchor="end" font-size="10" fill="#595959">${escapeXml(formatTickValue(tick))}</text>`
|
|
5724
|
+
);
|
|
5725
|
+
parts.push(
|
|
5726
|
+
`<line x1="${round(x - 3)}" y1="${round(tickY)}" x2="${round(x)}" y2="${round(tickY)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5727
|
+
);
|
|
5728
|
+
}
|
|
5729
|
+
return parts.join("");
|
|
5730
|
+
}
|
|
5731
|
+
function formatTickValue(value) {
|
|
5732
|
+
if (Math.abs(value) >= 1e9) return `${round(value / 1e9)}B`;
|
|
5733
|
+
if (Math.abs(value) >= 1e6) return `${round(value / 1e6)}M`;
|
|
5734
|
+
if (Math.abs(value) >= 1e4) return `${round(value / 1e3)}K`;
|
|
5735
|
+
if (Number.isInteger(value)) return String(value);
|
|
5736
|
+
return String(round(value));
|
|
5737
|
+
}
|
|
5663
5738
|
function getMaxValue(series) {
|
|
5664
5739
|
let max = 0;
|
|
5665
5740
|
for (const s of series) {
|
package/dist/index.js
CHANGED
|
@@ -1535,17 +1535,20 @@ function parseXmlOrdered(xml) {
|
|
|
1535
1535
|
}
|
|
1536
1536
|
|
|
1537
1537
|
// src/png/png-converter.ts
|
|
1538
|
-
import
|
|
1538
|
+
import { renderAsync } from "@resvg/resvg-js";
|
|
1539
1539
|
async function svgToPng(svgString, options) {
|
|
1540
|
-
const
|
|
1541
|
-
let pipeline = sharp(svgBuffer);
|
|
1540
|
+
const resvgOptions = {};
|
|
1542
1541
|
if (options?.width) {
|
|
1543
|
-
|
|
1542
|
+
resvgOptions.fitTo = { mode: "width", value: options.width };
|
|
1544
1543
|
} else if (options?.height) {
|
|
1545
|
-
|
|
1544
|
+
resvgOptions.fitTo = { mode: "height", value: options.height };
|
|
1546
1545
|
}
|
|
1547
|
-
const
|
|
1548
|
-
return {
|
|
1546
|
+
const rendered = await renderAsync(svgString, resvgOptions);
|
|
1547
|
+
return {
|
|
1548
|
+
png: Buffer.from(rendered.asPng()),
|
|
1549
|
+
width: rendered.width,
|
|
1550
|
+
height: rendered.height
|
|
1551
|
+
};
|
|
1549
1552
|
}
|
|
1550
1553
|
|
|
1551
1554
|
// src/warning-logger.ts
|
|
@@ -2446,10 +2449,19 @@ function extractCategories(serList) {
|
|
|
2446
2449
|
if (!cat) continue;
|
|
2447
2450
|
const strRef = cat.strRef;
|
|
2448
2451
|
const numRef = cat.numRef;
|
|
2452
|
+
const multiLvlStrRef = cat.multiLvlStrRef;
|
|
2449
2453
|
const strCache = strRef?.strCache ?? numRef?.numCache;
|
|
2450
2454
|
if (strCache?.pt) {
|
|
2451
2455
|
return strCache.pt.slice().sort((a, b) => Number(a["@_idx"]) - Number(b["@_idx"])).map((pt) => String(pt.v ?? ""));
|
|
2452
2456
|
}
|
|
2457
|
+
const multiCache = multiLvlStrRef?.multiLvlStrCache;
|
|
2458
|
+
if (multiCache?.lvl) {
|
|
2459
|
+
const lvls = Array.isArray(multiCache.lvl) ? multiCache.lvl : [multiCache.lvl];
|
|
2460
|
+
const firstLvl = lvls[0];
|
|
2461
|
+
if (firstLvl?.pt) {
|
|
2462
|
+
return firstLvl.pt.slice().sort((a, b) => Number(a["@_idx"]) - Number(b["@_idx"])).map((pt) => String(pt.v ?? ""));
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2453
2465
|
}
|
|
2454
2466
|
return [];
|
|
2455
2467
|
}
|
|
@@ -4938,12 +4950,26 @@ function renderBarChart(chart, x, y, w, h) {
|
|
|
4938
4950
|
return "";
|
|
4939
4951
|
}
|
|
4940
4952
|
const isHorizontal = chart.barDirection === "bar";
|
|
4953
|
+
const ticks = computeNiceTicks(0, maxVal);
|
|
4954
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
4941
4955
|
parts.push(
|
|
4942
4956
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
4943
4957
|
);
|
|
4944
4958
|
parts.push(
|
|
4945
4959
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
4946
4960
|
);
|
|
4961
|
+
if (isHorizontal) {
|
|
4962
|
+
for (const tick of ticks) {
|
|
4963
|
+
const ratio = tick / scaleMax;
|
|
4964
|
+
if (ratio < -1e-3 || ratio > 1.001) continue;
|
|
4965
|
+
const tickX = x + ratio * w;
|
|
4966
|
+
parts.push(
|
|
4967
|
+
`<text x="${round(tickX)}" y="${round(y + h + 15)}" text-anchor="middle" font-size="10" fill="#595959">${escapeXml(formatTickValue(tick))}</text>`
|
|
4968
|
+
);
|
|
4969
|
+
}
|
|
4970
|
+
} else {
|
|
4971
|
+
parts.push(renderValueAxisLabels(ticks, 0, scaleMax, x, y, h));
|
|
4972
|
+
}
|
|
4947
4973
|
if (isHorizontal) {
|
|
4948
4974
|
const groupHeight = h / catCount;
|
|
4949
4975
|
const barHeight = groupHeight * 0.7 / series.length;
|
|
@@ -4959,7 +4985,7 @@ function renderBarChart(chart, x, y, w, h) {
|
|
|
4959
4985
|
const color = series[s].color;
|
|
4960
4986
|
for (let c = 0; c < series[s].values.length; c++) {
|
|
4961
4987
|
const val = series[s].values[c];
|
|
4962
|
-
const barW = val /
|
|
4988
|
+
const barW = val / scaleMax * w;
|
|
4963
4989
|
const barX = x;
|
|
4964
4990
|
const barY = y + c * groupHeight + groupPadding + s * barHeight;
|
|
4965
4991
|
parts.push(
|
|
@@ -4982,7 +5008,7 @@ function renderBarChart(chart, x, y, w, h) {
|
|
|
4982
5008
|
const color = series[s].color;
|
|
4983
5009
|
for (let c = 0; c < series[s].values.length; c++) {
|
|
4984
5010
|
const val = series[s].values[c];
|
|
4985
|
-
const barH = val /
|
|
5011
|
+
const barH = val / scaleMax * h;
|
|
4986
5012
|
const barX = x + c * groupWidth + groupPadding + s * barWidth;
|
|
4987
5013
|
const barY = y + h - barH;
|
|
4988
5014
|
parts.push(
|
|
@@ -5010,12 +5036,15 @@ function renderLineChart(chart, x, y, w, h) {
|
|
|
5010
5036
|
debug("chart.line", "category count is 0");
|
|
5011
5037
|
return "";
|
|
5012
5038
|
}
|
|
5039
|
+
const ticks = computeNiceTicks(0, maxVal);
|
|
5040
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
5013
5041
|
parts.push(
|
|
5014
5042
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5015
5043
|
);
|
|
5016
5044
|
parts.push(
|
|
5017
5045
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5018
5046
|
);
|
|
5047
|
+
parts.push(renderValueAxisLabels(ticks, 0, scaleMax, x, y, h));
|
|
5019
5048
|
for (let c = 0; c < catCount; c++) {
|
|
5020
5049
|
const label = categories[c] ?? "";
|
|
5021
5050
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
@@ -5029,7 +5058,7 @@ function renderLineChart(chart, x, y, w, h) {
|
|
|
5029
5058
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
5030
5059
|
const points = series[s].values.map((val, i) => {
|
|
5031
5060
|
const px = round(x + i / divisor * w);
|
|
5032
|
-
const py = round(y + h - val /
|
|
5061
|
+
const py = round(y + h - val / scaleMax * h);
|
|
5033
5062
|
return `${px},${py}`;
|
|
5034
5063
|
});
|
|
5035
5064
|
parts.push(
|
|
@@ -5059,12 +5088,15 @@ function renderAreaChart(chart, x, y, w, h) {
|
|
|
5059
5088
|
debug("chart.area", "category count is 0");
|
|
5060
5089
|
return "";
|
|
5061
5090
|
}
|
|
5091
|
+
const ticks = computeNiceTicks(0, maxVal);
|
|
5092
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
5062
5093
|
parts.push(
|
|
5063
5094
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5064
5095
|
);
|
|
5065
5096
|
parts.push(
|
|
5066
5097
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5067
5098
|
);
|
|
5099
|
+
parts.push(renderValueAxisLabels(ticks, 0, scaleMax, x, y, h));
|
|
5068
5100
|
for (let c = 0; c < catCount; c++) {
|
|
5069
5101
|
const label = categories[c] ?? "";
|
|
5070
5102
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
@@ -5079,7 +5111,7 @@ function renderAreaChart(chart, x, y, w, h) {
|
|
|
5079
5111
|
const divisor = catCount > 1 ? catCount - 1 : 1;
|
|
5080
5112
|
const dataPoints = series[s].values.map((val, i) => {
|
|
5081
5113
|
const px = round(x + i / divisor * w);
|
|
5082
|
-
const py = round(y + h - val /
|
|
5114
|
+
const py = round(y + h - val / scaleMax * h);
|
|
5083
5115
|
return { px, py };
|
|
5084
5116
|
});
|
|
5085
5117
|
const topPoints = dataPoints.map((p) => `${p.px},${p.py}`).join(" ");
|
|
@@ -5193,12 +5225,15 @@ function renderScatterChart(chart, x, y, w, h) {
|
|
|
5193
5225
|
}
|
|
5194
5226
|
if (maxX === 0) maxX = 1;
|
|
5195
5227
|
if (maxY === 0) maxY = 1;
|
|
5228
|
+
const yTicks = computeNiceTicks(0, maxY);
|
|
5229
|
+
const scaleMaxY = yTicks[yTicks.length - 1];
|
|
5196
5230
|
parts.push(
|
|
5197
5231
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5198
5232
|
);
|
|
5199
5233
|
parts.push(
|
|
5200
5234
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5201
5235
|
);
|
|
5236
|
+
parts.push(renderValueAxisLabels(yTicks, 0, scaleMaxY, x, y, h));
|
|
5202
5237
|
for (let s = 0; s < series.length; s++) {
|
|
5203
5238
|
const color = series[s].color;
|
|
5204
5239
|
const xVals = series[s].xValues ?? [];
|
|
@@ -5206,7 +5241,7 @@ function renderScatterChart(chart, x, y, w, h) {
|
|
|
5206
5241
|
const xVal = xVals[i] ?? i;
|
|
5207
5242
|
const yVal = series[s].values[i];
|
|
5208
5243
|
const px = x + xVal / maxX * w;
|
|
5209
|
-
const py = y + h - yVal /
|
|
5244
|
+
const py = y + h - yVal / scaleMaxY * h;
|
|
5210
5245
|
parts.push(`<circle cx="${round(px)}" cy="${round(py)}" r="4" ${fillAttr(color)}/>`);
|
|
5211
5246
|
}
|
|
5212
5247
|
}
|
|
@@ -5233,12 +5268,15 @@ function renderBubbleChart(chart, x, y, w, h) {
|
|
|
5233
5268
|
if (maxY === 0) maxY = 1;
|
|
5234
5269
|
if (maxBubble === 0) maxBubble = 1;
|
|
5235
5270
|
const maxRadius = Math.min(w, h) * 0.08;
|
|
5271
|
+
const yTicks = computeNiceTicks(0, maxY);
|
|
5272
|
+
const scaleMaxY = yTicks[yTicks.length - 1];
|
|
5236
5273
|
parts.push(
|
|
5237
5274
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5238
5275
|
);
|
|
5239
5276
|
parts.push(
|
|
5240
5277
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5241
5278
|
);
|
|
5279
|
+
parts.push(renderValueAxisLabels(yTicks, 0, scaleMaxY, x, y, h));
|
|
5242
5280
|
for (let s = 0; s < series.length; s++) {
|
|
5243
5281
|
const color = series[s].color;
|
|
5244
5282
|
const xVals = series[s].xValues ?? [];
|
|
@@ -5248,7 +5286,7 @@ function renderBubbleChart(chart, x, y, w, h) {
|
|
|
5248
5286
|
const yVal = series[s].values[i];
|
|
5249
5287
|
const size = sizes[i] ?? 1;
|
|
5250
5288
|
const px = x + xVal / maxX * w;
|
|
5251
|
-
const py = y + h - yVal /
|
|
5289
|
+
const py = y + h - yVal / scaleMaxY * h;
|
|
5252
5290
|
const r = Math.max(2, Math.sqrt(size / maxBubble) * maxRadius);
|
|
5253
5291
|
parts.push(
|
|
5254
5292
|
`<circle cx="${round(px)}" cy="${round(py)}" r="${round(r)}" ${fillAttr(color)} fill-opacity="0.6"/>`
|
|
@@ -5361,12 +5399,16 @@ function renderStockChart(chart, x, y, w, h) {
|
|
|
5361
5399
|
debug("chart.stock", "max equals min value");
|
|
5362
5400
|
return "";
|
|
5363
5401
|
}
|
|
5402
|
+
const ticks = computeNiceTicks(minVal, maxVal);
|
|
5403
|
+
const scaleMin = ticks[0];
|
|
5404
|
+
const scaleMax = ticks[ticks.length - 1];
|
|
5364
5405
|
parts.push(
|
|
5365
5406
|
`<line x1="${round(x)}" y1="${round(y + h)}" x2="${round(x + w)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5366
5407
|
);
|
|
5367
5408
|
parts.push(
|
|
5368
5409
|
`<line x1="${round(x)}" y1="${round(y)}" x2="${round(x)}" y2="${round(y + h)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5369
5410
|
);
|
|
5411
|
+
parts.push(renderValueAxisLabels(ticks, scaleMin, scaleMax, x, y, h));
|
|
5370
5412
|
for (let c = 0; c < catCount; c++) {
|
|
5371
5413
|
const label = categories[c] ?? "";
|
|
5372
5414
|
const labelX = x + (c + 0.5) * (w / catCount);
|
|
@@ -5374,15 +5416,15 @@ function renderStockChart(chart, x, y, w, h) {
|
|
|
5374
5416
|
`<text x="${round(labelX)}" y="${round(y + h + 15)}" text-anchor="middle" font-size="10" fill="#595959">${escapeXml(label)}</text>`
|
|
5375
5417
|
);
|
|
5376
5418
|
}
|
|
5377
|
-
const range =
|
|
5419
|
+
const range = scaleMax - scaleMin;
|
|
5378
5420
|
for (let c = 0; c < catCount; c++) {
|
|
5379
5421
|
const cx = x + (c + 0.5) * (w / catCount);
|
|
5380
5422
|
const highVal = highSeries.values[c] ?? 0;
|
|
5381
5423
|
const lowVal = lowSeries.values[c] ?? 0;
|
|
5382
5424
|
const closeVal = closeSeries.values[c] ?? 0;
|
|
5383
|
-
const highY = y + h - (highVal -
|
|
5384
|
-
const lowY = y + h - (lowVal -
|
|
5385
|
-
const closeY = y + h - (closeVal -
|
|
5425
|
+
const highY = y + h - (highVal - scaleMin) / range * h;
|
|
5426
|
+
const lowY = y + h - (lowVal - scaleMin) / range * h;
|
|
5427
|
+
const closeY = y + h - (closeVal - scaleMin) / range * h;
|
|
5386
5428
|
parts.push(
|
|
5387
5429
|
`<line x1="${round(cx)}" y1="${round(highY)}" x2="${round(cx)}" y2="${round(lowY)}" stroke="#404040" stroke-width="2"/>`
|
|
5388
5430
|
);
|
|
@@ -5615,6 +5657,49 @@ function getPieSliceColor(index, chart) {
|
|
|
5615
5657
|
}
|
|
5616
5658
|
return DEFAULT_SERIES_COLORS[index % DEFAULT_SERIES_COLORS.length];
|
|
5617
5659
|
}
|
|
5660
|
+
function computeNiceTicks(minVal, maxVal, targetCount = 5) {
|
|
5661
|
+
const range = maxVal - minVal;
|
|
5662
|
+
if (range === 0) return [minVal];
|
|
5663
|
+
const roughStep = range / targetCount;
|
|
5664
|
+
const magnitude = Math.pow(10, Math.floor(Math.log10(roughStep)));
|
|
5665
|
+
const residual = roughStep / magnitude;
|
|
5666
|
+
let niceStep;
|
|
5667
|
+
if (residual <= 1.5) niceStep = magnitude;
|
|
5668
|
+
else if (residual <= 3) niceStep = 2 * magnitude;
|
|
5669
|
+
else if (residual <= 7) niceStep = 5 * magnitude;
|
|
5670
|
+
else niceStep = 10 * magnitude;
|
|
5671
|
+
const niceMin = Math.floor(minVal / niceStep) * niceStep;
|
|
5672
|
+
const niceMax = Math.ceil(maxVal / niceStep) * niceStep;
|
|
5673
|
+
const ticks = [];
|
|
5674
|
+
for (let v = niceMin; v <= niceMax + niceStep * 0.5; v += niceStep) {
|
|
5675
|
+
ticks.push(Math.round(v * 1e10) / 1e10);
|
|
5676
|
+
}
|
|
5677
|
+
return ticks;
|
|
5678
|
+
}
|
|
5679
|
+
function renderValueAxisLabels(ticks, scaleMin, scaleMax, x, y, h) {
|
|
5680
|
+
const parts = [];
|
|
5681
|
+
const range = scaleMax - scaleMin;
|
|
5682
|
+
if (range === 0) return "";
|
|
5683
|
+
for (const tick of ticks) {
|
|
5684
|
+
const ratio = (tick - scaleMin) / range;
|
|
5685
|
+
if (ratio < -1e-3 || ratio > 1.001) continue;
|
|
5686
|
+
const tickY = y + h - ratio * h;
|
|
5687
|
+
parts.push(
|
|
5688
|
+
`<text x="${round(x - 5)}" y="${round(tickY + 4)}" text-anchor="end" font-size="10" fill="#595959">${escapeXml(formatTickValue(tick))}</text>`
|
|
5689
|
+
);
|
|
5690
|
+
parts.push(
|
|
5691
|
+
`<line x1="${round(x - 3)}" y1="${round(tickY)}" x2="${round(x)}" y2="${round(tickY)}" stroke="#D9D9D9" stroke-width="1"/>`
|
|
5692
|
+
);
|
|
5693
|
+
}
|
|
5694
|
+
return parts.join("");
|
|
5695
|
+
}
|
|
5696
|
+
function formatTickValue(value) {
|
|
5697
|
+
if (Math.abs(value) >= 1e9) return `${round(value / 1e9)}B`;
|
|
5698
|
+
if (Math.abs(value) >= 1e6) return `${round(value / 1e6)}M`;
|
|
5699
|
+
if (Math.abs(value) >= 1e4) return `${round(value / 1e3)}K`;
|
|
5700
|
+
if (Number.isInteger(value)) return String(value);
|
|
5701
|
+
return String(round(value));
|
|
5702
|
+
}
|
|
5618
5703
|
function getMaxValue(series) {
|
|
5619
5704
|
let max = 0;
|
|
5620
5705
|
for (const s of series) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pptx-glimpse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A lightweight JavaScript library for rendering PowerPoint (.pptx) files as SVG or PNG in Node.js. No LibreOffice required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -64,10 +64,10 @@
|
|
|
64
64
|
"author": "hirokisakabe",
|
|
65
65
|
"license": "MIT",
|
|
66
66
|
"dependencies": {
|
|
67
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
67
68
|
"fast-xml-parser": "^5.3.6",
|
|
68
69
|
"fflate": "^0.8.2",
|
|
69
|
-
"opentype.js": "^1.3.4"
|
|
70
|
-
"sharp": "^0.34.5"
|
|
70
|
+
"opentype.js": "^1.3.4"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@changesets/cli": "^2.29.8",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"knip": "^5.85.0",
|
|
82
82
|
"pixelmatch": "^7.1.0",
|
|
83
83
|
"prettier": "^3.0.0",
|
|
84
|
+
"sharp": "^0.34.5",
|
|
84
85
|
"tsup": "^8.0.0",
|
|
85
86
|
"tsx": "^4.21.0",
|
|
86
87
|
"typescript": "^5.9.3",
|