pptx-angular-viewer 1.1.39 → 1.1.41
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NgStyle, NgClass, NgTemplateOutlet } from '@angular/common';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { InjectionToken, input, output, computed, ChangeDetectionStrategy, Component, signal, Injectable, HostListener, effect, inject, DestroyRef, ElementRef, viewChild, afterNextRender, Injector } from '@angular/core';
|
|
4
|
-
import { guideEmuToPx, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hasShapeProperties, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, isImageLikeElement, hasTextProperties, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$2, THEME_COLOR_SCHEME_KEYS, getLinkedTextBoxSegments, deobfuscateFont, detectFontFormat, getSubstituteFontFamily, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, formatCommentTimestamp, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, chartDataChangeType, updateSmartArtNodeText, addSmartArtNodeAsChild, removeSmartArtNode, promoteSmartArtNode, demoteSmartArtNode, reorderSmartArtNode, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, PptxHandler, EncryptedFileError, parseSignatureXml, isInkElement, isZoomElement, THEME_PRESETS, applyThemeToData, getAnimationPresetInfo } from 'pptx-viewer-core';
|
|
4
|
+
import { guideEmuToPx, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hasShapeProperties, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, isImageLikeElement, hasTextProperties, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$2, THEME_COLOR_SCHEME_KEYS, getLinkedTextBoxSegments, svgPathToPolygons, deobfuscateFont, detectFontFormat, getSubstituteFontFamily, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, formatCommentTimestamp, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, chartDataChangeType, updateSmartArtNodeText, addSmartArtNodeAsChild, removeSmartArtNode, promoteSmartArtNode, demoteSmartArtNode, reorderSmartArtNode, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, PptxHandler, EncryptedFileError, parseSignatureXml, isInkElement, isZoomElement, THEME_PRESETS, applyThemeToData, getAnimationPresetInfo } from 'pptx-viewer-core';
|
|
5
5
|
import { jsPDF } from 'jspdf';
|
|
6
6
|
import html2canvasPro from 'html2canvas-pro';
|
|
7
7
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
@@ -5837,6 +5837,168 @@ function renderWinLossSparkline(data) {
|
|
|
5837
5837
|
].join('');
|
|
5838
5838
|
}
|
|
5839
5839
|
|
|
5840
|
+
const CHART_TYPE_OPTIONS = [
|
|
5841
|
+
{ value: 'bar', label: 'Bar' },
|
|
5842
|
+
{ value: 'line', label: 'Line' },
|
|
5843
|
+
{ value: 'pie', label: 'Pie' },
|
|
5844
|
+
{ value: 'doughnut', label: 'Doughnut' },
|
|
5845
|
+
{ value: 'area', label: 'Area' },
|
|
5846
|
+
{ value: 'scatter', label: 'Scatter' },
|
|
5847
|
+
{ value: 'bubble', label: 'Bubble' },
|
|
5848
|
+
{ value: 'radar', label: 'Radar' },
|
|
5849
|
+
{ value: 'stock', label: 'Stock' },
|
|
5850
|
+
{ value: 'waterfall', label: 'Waterfall' },
|
|
5851
|
+
{ value: 'combo', label: 'Combo' },
|
|
5852
|
+
];
|
|
5853
|
+
const GROUPING_OPTIONS = [
|
|
5854
|
+
{ value: 'clustered', label: 'Clustered' },
|
|
5855
|
+
{ value: 'stacked', label: 'Stacked' },
|
|
5856
|
+
{ value: 'percentStacked', label: '100% Stacked' },
|
|
5857
|
+
];
|
|
5858
|
+
const LEGEND_POSITION_OPTIONS = [
|
|
5859
|
+
{ value: 't', label: 'Top' },
|
|
5860
|
+
{ value: 'b', label: 'Bottom' },
|
|
5861
|
+
{ value: 'l', label: 'Left' },
|
|
5862
|
+
{ value: 'r', label: 'Right' },
|
|
5863
|
+
];
|
|
5864
|
+
const TICK_LABEL_POSITION_OPTIONS = [
|
|
5865
|
+
{ value: 'nextTo', label: 'Next to axis' },
|
|
5866
|
+
{ value: 'high', label: 'High' },
|
|
5867
|
+
{ value: 'low', label: 'Low' },
|
|
5868
|
+
{ value: 'none', label: 'None' },
|
|
5869
|
+
];
|
|
5870
|
+
const DISPLAY_UNITS_OPTIONS = [
|
|
5871
|
+
{ value: '', label: 'None' },
|
|
5872
|
+
{ value: 'hundreds', label: 'Hundreds' },
|
|
5873
|
+
{ value: 'thousands', label: 'Thousands' },
|
|
5874
|
+
{ value: 'tenThousands', label: 'Ten Thousands' },
|
|
5875
|
+
{ value: 'hundredThousands', label: 'Hundred Thousands' },
|
|
5876
|
+
{ value: 'millions', label: 'Millions' },
|
|
5877
|
+
{ value: 'tenMillions', label: 'Ten Millions' },
|
|
5878
|
+
{ value: 'hundredMillions', label: 'Hundred Millions' },
|
|
5879
|
+
{ value: 'billions', label: 'Billions' },
|
|
5880
|
+
{ value: 'trillions', label: 'Trillions' },
|
|
5881
|
+
];
|
|
5882
|
+
const DATA_LABEL_CONTENT_OPTIONS = [
|
|
5883
|
+
{ key: 'showValue', label: 'Value' },
|
|
5884
|
+
{ key: 'showCategory', label: 'Category name' },
|
|
5885
|
+
{ key: 'showSeriesName', label: 'Series name' },
|
|
5886
|
+
{ key: 'showPercent', label: 'Percentage' },
|
|
5887
|
+
{ key: 'showLegendKey', label: 'Legend key' },
|
|
5888
|
+
];
|
|
5889
|
+
const DATA_LABEL_POSITION_OPTIONS = [
|
|
5890
|
+
{ value: '', label: 'Default' },
|
|
5891
|
+
{ value: 'ctr', label: 'Center' },
|
|
5892
|
+
{ value: 'inEnd', label: 'Inside End' },
|
|
5893
|
+
{ value: 'inBase', label: 'Inside Base' },
|
|
5894
|
+
{ value: 'outEnd', label: 'Outside End' },
|
|
5895
|
+
{ value: 'bestFit', label: 'Best Fit' },
|
|
5896
|
+
];
|
|
5897
|
+
const TRENDLINE_TYPE_OPTIONS = [
|
|
5898
|
+
{ value: '', label: 'None' },
|
|
5899
|
+
{ value: 'linear', label: 'Linear' },
|
|
5900
|
+
{ value: 'exponential', label: 'Exponential' },
|
|
5901
|
+
{ value: 'logarithmic', label: 'Logarithmic' },
|
|
5902
|
+
{ value: 'polynomial', label: 'Polynomial' },
|
|
5903
|
+
{ value: 'power', label: 'Power' },
|
|
5904
|
+
{ value: 'movingAvg', label: 'Moving Average' },
|
|
5905
|
+
];
|
|
5906
|
+
const ERROR_BAR_VALTYPE_OPTIONS = [
|
|
5907
|
+
{ value: '', label: 'None' },
|
|
5908
|
+
{ value: 'fixedVal', label: 'Fixed value' },
|
|
5909
|
+
{ value: 'percentage', label: 'Percentage' },
|
|
5910
|
+
{ value: 'stdDev', label: 'Standard deviation' },
|
|
5911
|
+
{ value: 'stdErr', label: 'Standard error' },
|
|
5912
|
+
];
|
|
5913
|
+
const ERROR_BAR_TYPE_OPTIONS = [
|
|
5914
|
+
{ value: 'both', label: 'Both' },
|
|
5915
|
+
{ value: 'plus', label: 'Plus' },
|
|
5916
|
+
{ value: 'minus', label: 'Minus' },
|
|
5917
|
+
];
|
|
5918
|
+
const MARKER_SYMBOL_OPTIONS = [
|
|
5919
|
+
{ value: '', label: 'Auto' },
|
|
5920
|
+
{ value: 'none', label: 'None' },
|
|
5921
|
+
{ value: 'circle', label: 'Circle' },
|
|
5922
|
+
{ value: 'square', label: 'Square' },
|
|
5923
|
+
{ value: 'diamond', label: 'Diamond' },
|
|
5924
|
+
{ value: 'triangle', label: 'Triangle' },
|
|
5925
|
+
{ value: 'x', label: 'X' },
|
|
5926
|
+
{ value: 'star', label: 'Star' },
|
|
5927
|
+
{ value: 'plus', label: 'Plus' },
|
|
5928
|
+
{ value: 'dot', label: 'Dot' },
|
|
5929
|
+
{ value: 'dash', label: 'Dash' },
|
|
5930
|
+
];
|
|
5931
|
+
const GRIDLINE_DASH_OPTIONS = [
|
|
5932
|
+
{ value: '', label: 'Default' },
|
|
5933
|
+
{ value: 'solid', label: 'Solid' },
|
|
5934
|
+
{ value: 'dash', label: 'Dash' },
|
|
5935
|
+
{ value: 'dot', label: 'Dot' },
|
|
5936
|
+
{ value: 'dashDot', label: 'Dash Dot' },
|
|
5937
|
+
{ value: 'lgDash', label: 'Long Dash' },
|
|
5938
|
+
];
|
|
5939
|
+
const COMBO_SERIES_TYPE_OPTIONS = [
|
|
5940
|
+
{ value: '', label: 'Default' },
|
|
5941
|
+
{ value: 'bar', label: 'Bar' },
|
|
5942
|
+
{ value: 'line', label: 'Line' },
|
|
5943
|
+
{ value: 'area', label: 'Area' },
|
|
5944
|
+
{ value: 'scatter', label: 'Scatter' },
|
|
5945
|
+
];
|
|
5946
|
+
/** Axis kinds the inspector exposes, with whether they carry a numeric scale. */
|
|
5947
|
+
const EDITABLE_AXIS_ROWS = [
|
|
5948
|
+
{ type: 'valAx', label: 'Value axis', hasScale: true },
|
|
5949
|
+
{ type: 'dateAx', label: 'Date axis', hasScale: true },
|
|
5950
|
+
{ type: 'catAx', label: 'Category axis', hasScale: false },
|
|
5951
|
+
];
|
|
5952
|
+
/** Chart types that support clustered/stacked grouping modes. */
|
|
5953
|
+
const GROUPING_SUPPORTED_TYPES = new Set([
|
|
5954
|
+
'bar',
|
|
5955
|
+
'line',
|
|
5956
|
+
'area',
|
|
5957
|
+
]);
|
|
5958
|
+
/** Chart types where trendlines are meaningful. */
|
|
5959
|
+
const TRENDLINE_SUPPORTED_TYPES = new Set([
|
|
5960
|
+
'bar',
|
|
5961
|
+
'line',
|
|
5962
|
+
'area',
|
|
5963
|
+
'scatter',
|
|
5964
|
+
'bubble',
|
|
5965
|
+
]);
|
|
5966
|
+
/** Chart types where error bars are meaningful. */
|
|
5967
|
+
const ERROR_BAR_SUPPORTED_TYPES = new Set([
|
|
5968
|
+
'bar',
|
|
5969
|
+
'line',
|
|
5970
|
+
'area',
|
|
5971
|
+
'scatter',
|
|
5972
|
+
'bubble',
|
|
5973
|
+
]);
|
|
5974
|
+
/** Value types that take a numeric amount (stdErr does not). */
|
|
5975
|
+
const ERROR_BAR_VALUE_TYPES = new Set([
|
|
5976
|
+
'fixedVal',
|
|
5977
|
+
'percentage',
|
|
5978
|
+
'stdDev',
|
|
5979
|
+
]);
|
|
5980
|
+
/** Chart types where series markers are meaningful. */
|
|
5981
|
+
const MARKER_SUPPORTED_TYPES = new Set([
|
|
5982
|
+
'line',
|
|
5983
|
+
'scatter',
|
|
5984
|
+
'bubble',
|
|
5985
|
+
'radar',
|
|
5986
|
+
]);
|
|
5987
|
+
/** Cartesian chart types where a per-series combo type makes sense. */
|
|
5988
|
+
const COMBO_SUPPORTED_TYPES = new Set([
|
|
5989
|
+
'bar',
|
|
5990
|
+
'line',
|
|
5991
|
+
'area',
|
|
5992
|
+
'combo',
|
|
5993
|
+
]);
|
|
5994
|
+
/** Chart types where per-point slice explosion (pull-out) is meaningful. */
|
|
5995
|
+
const EXPLOSION_SUPPORTED_TYPES = new Set([
|
|
5996
|
+
'pie',
|
|
5997
|
+
'pie3D',
|
|
5998
|
+
'doughnut',
|
|
5999
|
+
'ofPie',
|
|
6000
|
+
]);
|
|
6001
|
+
|
|
5840
6002
|
const GRIDLINE_COLOR$1 = '#e2e8f0';
|
|
5841
6003
|
const AXIS_LABEL_COLOR$1 = '#64748b';
|
|
5842
6004
|
const SECONDARY_GRID_COLOR = '#e2e8f0';
|
|
@@ -11339,6 +11501,217 @@ function finalizeClickGroup(steps, options) {
|
|
|
11339
11501
|
return group;
|
|
11340
11502
|
}
|
|
11341
11503
|
|
|
11504
|
+
/**
|
|
11505
|
+
* `animation-advanced-triggers` (pure evaluation of compound and simultaneous
|
|
11506
|
+
* OOXML timing-tree start/end conditions (`p:stCondLst` / `p:endCondLst`).
|
|
11507
|
+
*
|
|
11508
|
+
* The parse layer (`pptx-viewer-core`) preserves the FULL set of `p:cond`
|
|
11509
|
+
* entries per node on {@link PptxNativeAnimation.startConditions} /
|
|
11510
|
+
* {@link PptxNativeAnimation.endConditions}, but the historic playback model
|
|
11511
|
+
* collapsed every node down to a single `trigger` + `triggerDelayMs`. That lost
|
|
11512
|
+
* compound triggers (e.g. "fire on click OR after a 2s delay") and conditions
|
|
11513
|
+
* that depend on another time node ending (e.g. "after several preceding
|
|
11514
|
+
* effects"). This module re-derives correct sequencing semantics from the full
|
|
11515
|
+
* condition set so {@link import('./animation-timeline-builder').buildTimeline}
|
|
11516
|
+
* and {@link import('./animation-sequencer').AnimationSequencer} can honour them.
|
|
11517
|
+
*
|
|
11518
|
+
* ECMA-376 §19.5.28 (CT_TLTimeCondition): a `stCondLst` holds one OR MORE
|
|
11519
|
+
* conditions; the node may begin as soon as ANY one of them is satisfied (a
|
|
11520
|
+
* logical OR). `endCondLst` ends the node when ANY of its conditions fire. We
|
|
11521
|
+
* therefore model the set, then pick the condition that governs auto-playback
|
|
11522
|
+
* (the earliest auto-satisfiable one) while still recording whether a click /
|
|
11523
|
+
* hover alternative exists.
|
|
11524
|
+
*
|
|
11525
|
+
* @module render/animation-advanced-triggers
|
|
11526
|
+
*/
|
|
11527
|
+
// ==========================================================================
|
|
11528
|
+
// Condition classification
|
|
11529
|
+
// ==========================================================================
|
|
11530
|
+
/** Events that begin a node as the result of a user click. */
|
|
11531
|
+
const CLICK_EVENTS = new Set(['onClick', 'onNext']);
|
|
11532
|
+
/** Events that begin a node as the result of a mouse hover. */
|
|
11533
|
+
const HOVER_EVENTS = new Set(['onMouseOver']);
|
|
11534
|
+
/**
|
|
11535
|
+
* Events that chain a node off another time node's lifecycle (begin/end).
|
|
11536
|
+
* These are the "after preceding effect(s)" conditions and always carry a
|
|
11537
|
+
* `targetTimeNodeId` (`@_tn`) pointing at the node they wait on.
|
|
11538
|
+
*/
|
|
11539
|
+
const TIMENODE_EVENTS = new Set([
|
|
11540
|
+
'onBegin',
|
|
11541
|
+
'onEnd',
|
|
11542
|
+
'begin',
|
|
11543
|
+
'end',
|
|
11544
|
+
]);
|
|
11545
|
+
/** Normalise a possibly-indefinite delay to a non-negative number of ms. */
|
|
11546
|
+
function normalizeDelay(delay) {
|
|
11547
|
+
if (delay === undefined) {
|
|
11548
|
+
return { ms: 0, indefinite: false };
|
|
11549
|
+
}
|
|
11550
|
+
if (delay < 0) {
|
|
11551
|
+
return { ms: 0, indefinite: true };
|
|
11552
|
+
}
|
|
11553
|
+
return { ms: delay, indefinite: false };
|
|
11554
|
+
}
|
|
11555
|
+
function classifyCondition(cond) {
|
|
11556
|
+
const evt = cond.event;
|
|
11557
|
+
if (evt && CLICK_EVENTS.has(evt)) {
|
|
11558
|
+
return 'click';
|
|
11559
|
+
}
|
|
11560
|
+
if (evt && HOVER_EVENTS.has(evt)) {
|
|
11561
|
+
return 'hover';
|
|
11562
|
+
}
|
|
11563
|
+
if (evt && TIMENODE_EVENTS.has(evt) && cond.targetTimeNodeId !== undefined) {
|
|
11564
|
+
return 'timenode';
|
|
11565
|
+
}
|
|
11566
|
+
// No event (or onBegin without a tn) with a delay is a pure time offset.
|
|
11567
|
+
return 'delay';
|
|
11568
|
+
}
|
|
11569
|
+
/**
|
|
11570
|
+
* Collapse a node's full `startConditions` OR-set into the single
|
|
11571
|
+
* {@link EffectiveStartCondition} that should drive playback, while preserving
|
|
11572
|
+
* the alternative interaction paths.
|
|
11573
|
+
*
|
|
11574
|
+
* Selection (OOXML "fire when ANY applies"):
|
|
11575
|
+
* 1. A time-node dependency (onEnd/onBegin of another node) governs sequencing
|
|
11576
|
+
* when present, so the effect chains after the referenced effect(s).
|
|
11577
|
+
* 2. Otherwise a pure delay governs (afterDelay / afterPrevious style).
|
|
11578
|
+
* 3. Otherwise the interactive trigger (click / hover) governs.
|
|
11579
|
+
* In every case, a coexisting click or hover condition is recorded as an
|
|
11580
|
+
* alternative so the engine can start the node early on user interaction.
|
|
11581
|
+
*
|
|
11582
|
+
* `fallbackTrigger` is the node's already-derived simple trigger; it is used
|
|
11583
|
+
* when the condition list is empty or carries no actionable semantics.
|
|
11584
|
+
*/
|
|
11585
|
+
function resolveEffectiveStartCondition(conditions, fallbackTrigger) {
|
|
11586
|
+
const base = {
|
|
11587
|
+
trigger: fallbackTrigger,
|
|
11588
|
+
delayMs: 0,
|
|
11589
|
+
hasClickAlternative: false,
|
|
11590
|
+
hasHoverAlternative: false,
|
|
11591
|
+
indefinite: false,
|
|
11592
|
+
};
|
|
11593
|
+
if (!conditions || conditions.length === 0) {
|
|
11594
|
+
return base;
|
|
11595
|
+
}
|
|
11596
|
+
let timenode;
|
|
11597
|
+
let delayCond;
|
|
11598
|
+
let clickCond;
|
|
11599
|
+
let hoverCond;
|
|
11600
|
+
for (const cond of conditions) {
|
|
11601
|
+
switch (classifyCondition(cond)) {
|
|
11602
|
+
case 'timenode':
|
|
11603
|
+
// Prefer the smallest target node id for deterministic ordering.
|
|
11604
|
+
if (!timenode || (cond.targetTimeNodeId ?? 0) < (timenode.targetTimeNodeId ?? 0)) {
|
|
11605
|
+
timenode = cond;
|
|
11606
|
+
}
|
|
11607
|
+
break;
|
|
11608
|
+
case 'delay':
|
|
11609
|
+
// Prefer the smallest delay (earliest auto-fire) among delay conds.
|
|
11610
|
+
if (!delayCond || (cond.delay ?? 0) < (delayCond.delay ?? 0)) {
|
|
11611
|
+
delayCond = cond;
|
|
11612
|
+
}
|
|
11613
|
+
break;
|
|
11614
|
+
case 'click':
|
|
11615
|
+
if (!clickCond) {
|
|
11616
|
+
clickCond = cond;
|
|
11617
|
+
}
|
|
11618
|
+
break;
|
|
11619
|
+
case 'hover':
|
|
11620
|
+
if (!hoverCond) {
|
|
11621
|
+
hoverCond = cond;
|
|
11622
|
+
}
|
|
11623
|
+
break;
|
|
11624
|
+
}
|
|
11625
|
+
}
|
|
11626
|
+
base.hasClickAlternative = clickCond !== undefined;
|
|
11627
|
+
base.hasHoverAlternative = hoverCond !== undefined;
|
|
11628
|
+
if (clickCond?.targetShapeId) {
|
|
11629
|
+
base.clickTargetShapeId = clickCond.targetShapeId;
|
|
11630
|
+
}
|
|
11631
|
+
// 1. Time-node dependency governs sequencing.
|
|
11632
|
+
if (timenode) {
|
|
11633
|
+
const { ms, indefinite } = normalizeDelay(timenode.delay);
|
|
11634
|
+
base.trigger =
|
|
11635
|
+
timenode.event === 'onBegin' || timenode.event === 'begin' ? 'withPrevious' : 'afterPrevious';
|
|
11636
|
+
base.delayMs = ms;
|
|
11637
|
+
base.indefinite = indefinite;
|
|
11638
|
+
base.dependsOnTimeNodeId = timenode.targetTimeNodeId;
|
|
11639
|
+
base.dependsOnEvent = timenode.event;
|
|
11640
|
+
return base;
|
|
11641
|
+
}
|
|
11642
|
+
// 2. Pure delay governs.
|
|
11643
|
+
if (delayCond && (delayCond.delay ?? 0) !== 0) {
|
|
11644
|
+
const { ms, indefinite } = normalizeDelay(delayCond.delay);
|
|
11645
|
+
// A delay alongside a click means "auto after delay, or sooner on click".
|
|
11646
|
+
base.trigger = clickCond ? 'onClick' : 'afterDelay';
|
|
11647
|
+
base.delayMs = ms;
|
|
11648
|
+
base.indefinite = indefinite;
|
|
11649
|
+
return base;
|
|
11650
|
+
}
|
|
11651
|
+
// 3. Interactive trigger governs.
|
|
11652
|
+
if (clickCond) {
|
|
11653
|
+
base.trigger = clickCond.targetShapeId ? 'onShapeClick' : 'onClick';
|
|
11654
|
+
return base;
|
|
11655
|
+
}
|
|
11656
|
+
if (hoverCond) {
|
|
11657
|
+
base.trigger = 'onHover';
|
|
11658
|
+
return base;
|
|
11659
|
+
}
|
|
11660
|
+
// 4. Zero-delay-only condition (onBegin / @_delay="0"): keep fallback but
|
|
11661
|
+
// surface that nothing interactive is required (auto with previous).
|
|
11662
|
+
if (delayCond) {
|
|
11663
|
+
base.trigger = fallbackTrigger;
|
|
11664
|
+
base.delayMs = 0;
|
|
11665
|
+
}
|
|
11666
|
+
return base;
|
|
11667
|
+
}
|
|
11668
|
+
/**
|
|
11669
|
+
* Resolve the effective start condition for a parsed native animation,
|
|
11670
|
+
* combining its full `startConditions` OR-set with its already-derived simple
|
|
11671
|
+
* `trigger` as a fallback.
|
|
11672
|
+
*/
|
|
11673
|
+
function resolveAnimationStart(anim) {
|
|
11674
|
+
return resolveEffectiveStartCondition(anim.startConditions, anim.trigger ?? 'onClick');
|
|
11675
|
+
}
|
|
11676
|
+
/** Collapse a node's `endConditions` OR-set into a playback-ready summary. */
|
|
11677
|
+
function resolveEffectiveEndCondition(conditions) {
|
|
11678
|
+
if (!conditions || conditions.length === 0) {
|
|
11679
|
+
return undefined;
|
|
11680
|
+
}
|
|
11681
|
+
const result = {
|
|
11682
|
+
endsOnMouseOut: false,
|
|
11683
|
+
endsOnClick: false,
|
|
11684
|
+
indefinite: false,
|
|
11685
|
+
};
|
|
11686
|
+
for (const cond of conditions) {
|
|
11687
|
+
const evt = cond.event;
|
|
11688
|
+
if (evt === 'onMouseOut') {
|
|
11689
|
+
result.endsOnMouseOut = true;
|
|
11690
|
+
}
|
|
11691
|
+
else if (evt && CLICK_EVENTS.has(evt)) {
|
|
11692
|
+
result.endsOnClick = true;
|
|
11693
|
+
if (cond.targetShapeId) {
|
|
11694
|
+
result.clickTargetShapeId = cond.targetShapeId;
|
|
11695
|
+
}
|
|
11696
|
+
}
|
|
11697
|
+
else if (evt && TIMENODE_EVENTS.has(evt) && cond.targetTimeNodeId !== undefined) {
|
|
11698
|
+
result.endsWithTimeNodeId = cond.targetTimeNodeId;
|
|
11699
|
+
}
|
|
11700
|
+
const { ms, indefinite } = normalizeDelay(cond.delay);
|
|
11701
|
+
if (indefinite) {
|
|
11702
|
+
result.indefinite = true;
|
|
11703
|
+
}
|
|
11704
|
+
else if (ms > 0 && result.delayMs === undefined) {
|
|
11705
|
+
result.delayMs = ms;
|
|
11706
|
+
}
|
|
11707
|
+
}
|
|
11708
|
+
return result;
|
|
11709
|
+
}
|
|
11710
|
+
/** Resolve the effective end condition for a parsed native animation. */
|
|
11711
|
+
function resolveAnimationEnd(anim) {
|
|
11712
|
+
return resolveEffectiveEndCondition(anim.endConditions);
|
|
11713
|
+
}
|
|
11714
|
+
|
|
11342
11715
|
/**
|
|
11343
11716
|
* `animation-timeline-text-build` — pure expansion of text-build animations
|
|
11344
11717
|
* (by-paragraph / by-word / by-char) into staggered per-segment sub-animations.
|
|
@@ -11636,10 +12009,16 @@ class AnimationSequencer {
|
|
|
11636
12009
|
this.dynamicKeyframeBlocks.push(dynamic.css);
|
|
11637
12010
|
}
|
|
11638
12011
|
const elementId = anim.targetId ?? '';
|
|
11639
|
-
|
|
12012
|
+
// Resolve compound / simultaneous start conditions (the OR-set in
|
|
12013
|
+
// p:stCondLst) into the effective sequencing trigger + governing
|
|
12014
|
+
// delay, instead of the single collapsed trigger.
|
|
12015
|
+
const effective = resolveAnimationStart(anim);
|
|
12016
|
+
const trigger = effective.trigger;
|
|
11640
12017
|
const duration = anim.durationMs ?? defaultDuration(anim.presetClass);
|
|
11641
12018
|
const animDelay = anim.delayMs ?? 0;
|
|
11642
|
-
const triggerDelay = anim.
|
|
12019
|
+
const triggerDelay = anim.startConditions && anim.startConditions.length > 0
|
|
12020
|
+
? effective.delayMs
|
|
12021
|
+
: (anim.triggerDelayMs ?? 0);
|
|
11643
12022
|
const fill = fillModeForClass(anim.presetClass);
|
|
11644
12023
|
// Compute repeat / direction from the native animation
|
|
11645
12024
|
const iterCount = anim.repeatCount ?? 1;
|
|
@@ -11648,8 +12027,9 @@ class AnimationSequencer {
|
|
|
11648
12027
|
let stepDelay;
|
|
11649
12028
|
switch (trigger) {
|
|
11650
12029
|
case 'onClick':
|
|
12030
|
+
case 'onShapeClick':
|
|
11651
12031
|
case 'onHover':
|
|
11652
|
-
// onClick / onHover
|
|
12032
|
+
// onClick / onShapeClick / onHover reset the timeline: delay only from explicit delay values.
|
|
11653
12033
|
cumulativeMs = 0;
|
|
11654
12034
|
stepDelay = animDelay + triggerDelay;
|
|
11655
12035
|
break;
|
|
@@ -11812,10 +12192,19 @@ function buildTimeline(nativeAnimations) {
|
|
|
11812
12192
|
dynamicBlocks.push(dynamic.css);
|
|
11813
12193
|
}
|
|
11814
12194
|
const elementId = singleAnim.targetId ?? '';
|
|
11815
|
-
|
|
12195
|
+
// Honour the FULL start-condition OR-set (compound / simultaneous
|
|
12196
|
+
// triggers) rather than the collapsed single trigger. The effective
|
|
12197
|
+
// condition drives grouping and supplies the governing start delay.
|
|
12198
|
+
const effective = resolveAnimationStart(singleAnim);
|
|
12199
|
+
const trigger = effective.trigger;
|
|
11816
12200
|
const duration = singleAnim.durationMs ?? defaultDuration(singleAnim.presetClass);
|
|
11817
12201
|
const animDelay = singleAnim.delayMs ?? 0;
|
|
11818
|
-
|
|
12202
|
+
// Use the governing condition delay when conditions were present;
|
|
12203
|
+
// otherwise fall back to the simple triggerDelayMs (afterDelay) so
|
|
12204
|
+
// existing single-condition slides are unchanged.
|
|
12205
|
+
const triggerDelay = singleAnim.startConditions && singleAnim.startConditions.length > 0
|
|
12206
|
+
? effective.delayMs
|
|
12207
|
+
: (singleAnim.triggerDelayMs ?? 0);
|
|
11819
12208
|
const presetClass = singleAnim.presetClass ?? 'entr';
|
|
11820
12209
|
const fill = fillModeForClass(singleAnim.presetClass);
|
|
11821
12210
|
// Compute repeat / direction
|
|
@@ -11825,8 +12214,10 @@ function buildTimeline(nativeAnimations) {
|
|
|
11825
12214
|
if (presetClass === 'entr' && elementId) {
|
|
11826
12215
|
entranceIds.add(elementId);
|
|
11827
12216
|
}
|
|
11828
|
-
// Determine whether to start a new click-group
|
|
11829
|
-
|
|
12217
|
+
// Determine whether to start a new click-group. A compound condition
|
|
12218
|
+
// that resolves to a click (onClick, or an inline shape click that was
|
|
12219
|
+
// not split into an interactive sequence) also starts a new group.
|
|
12220
|
+
const isOnClick = trigger === 'onClick' || trigger === 'onShapeClick';
|
|
11830
12221
|
const isFirstAnimation = clickGroups.length === 0 && currentGroup.length === 0;
|
|
11831
12222
|
if (isOnClick || isFirstAnimation) {
|
|
11832
12223
|
// Flush current group if non-empty
|
|
@@ -14785,6 +15176,151 @@ function setCellText(element, rowIndex, colIndex, text) {
|
|
|
14785
15176
|
return { ...element, tableData: { ...tableData, rows } };
|
|
14786
15177
|
}
|
|
14787
15178
|
|
|
15179
|
+
function cloneTextStyle(style) {
|
|
15180
|
+
if (!style) {
|
|
15181
|
+
return undefined;
|
|
15182
|
+
}
|
|
15183
|
+
return { ...style };
|
|
15184
|
+
}
|
|
15185
|
+
function cloneShapeStyle(style) {
|
|
15186
|
+
if (!style) {
|
|
15187
|
+
return undefined;
|
|
15188
|
+
}
|
|
15189
|
+
return {
|
|
15190
|
+
...style,
|
|
15191
|
+
...(style.fillGradientStops
|
|
15192
|
+
? { fillGradientStops: style.fillGradientStops.map((stop) => ({ ...stop })) }
|
|
15193
|
+
: {}),
|
|
15194
|
+
};
|
|
15195
|
+
}
|
|
15196
|
+
function cloneSlideTransition(transition) {
|
|
15197
|
+
if (!transition) {
|
|
15198
|
+
return undefined;
|
|
15199
|
+
}
|
|
15200
|
+
return { ...transition };
|
|
15201
|
+
}
|
|
15202
|
+
function cloneElementAnimation(animation) {
|
|
15203
|
+
return { ...animation };
|
|
15204
|
+
}
|
|
15205
|
+
function cloneChartData(data) {
|
|
15206
|
+
if (!data) {
|
|
15207
|
+
return undefined;
|
|
15208
|
+
}
|
|
15209
|
+
return {
|
|
15210
|
+
...data,
|
|
15211
|
+
categories: [...(data.categories || [])],
|
|
15212
|
+
series: (data.series || []).map((series) => ({
|
|
15213
|
+
...series,
|
|
15214
|
+
values: [...(series.values || [])],
|
|
15215
|
+
})),
|
|
15216
|
+
};
|
|
15217
|
+
}
|
|
15218
|
+
function cloneSmartArtData(data) {
|
|
15219
|
+
if (!data) {
|
|
15220
|
+
return undefined;
|
|
15221
|
+
}
|
|
15222
|
+
return {
|
|
15223
|
+
...data,
|
|
15224
|
+
nodes: (data.nodes || []).map((node) => ({ ...node })),
|
|
15225
|
+
};
|
|
15226
|
+
}
|
|
15227
|
+
function cloneElement(element) {
|
|
15228
|
+
switch (element.type) {
|
|
15229
|
+
case 'text':
|
|
15230
|
+
case 'shape':
|
|
15231
|
+
return {
|
|
15232
|
+
...element,
|
|
15233
|
+
...(element.textStyle ? { textStyle: cloneTextStyle(element.textStyle) } : {}),
|
|
15234
|
+
...(element.shapeStyle ? { shapeStyle: cloneShapeStyle(element.shapeStyle) } : {}),
|
|
15235
|
+
...(element.shapeAdjustments ? { shapeAdjustments: { ...element.shapeAdjustments } } : {}),
|
|
15236
|
+
...(element.textSegments
|
|
15237
|
+
? {
|
|
15238
|
+
textSegments: element.textSegments.map((segment) => ({
|
|
15239
|
+
...segment,
|
|
15240
|
+
style: cloneTextStyle(segment.style) || {},
|
|
15241
|
+
})),
|
|
15242
|
+
}
|
|
15243
|
+
: {}),
|
|
15244
|
+
};
|
|
15245
|
+
case 'connector':
|
|
15246
|
+
case 'image':
|
|
15247
|
+
case 'picture':
|
|
15248
|
+
return {
|
|
15249
|
+
...element,
|
|
15250
|
+
...(element.shapeStyle ? { shapeStyle: cloneShapeStyle(element.shapeStyle) } : {}),
|
|
15251
|
+
...(element.shapeAdjustments ? { shapeAdjustments: { ...element.shapeAdjustments } } : {}),
|
|
15252
|
+
};
|
|
15253
|
+
case 'table':
|
|
15254
|
+
return { ...element };
|
|
15255
|
+
case 'chart':
|
|
15256
|
+
return {
|
|
15257
|
+
...element,
|
|
15258
|
+
chartData: cloneChartData(element.chartData),
|
|
15259
|
+
};
|
|
15260
|
+
case 'smartArt':
|
|
15261
|
+
return {
|
|
15262
|
+
...element,
|
|
15263
|
+
smartArtData: cloneSmartArtData(element.smartArtData),
|
|
15264
|
+
};
|
|
15265
|
+
case 'ole':
|
|
15266
|
+
case 'media':
|
|
15267
|
+
case 'group':
|
|
15268
|
+
case 'ink':
|
|
15269
|
+
case 'zoom':
|
|
15270
|
+
case 'contentPart':
|
|
15271
|
+
case 'unknown':
|
|
15272
|
+
case 'model3d':
|
|
15273
|
+
return { ...element };
|
|
15274
|
+
default: {
|
|
15275
|
+
const _exhaustive = element;
|
|
15276
|
+
return _exhaustive;
|
|
15277
|
+
}
|
|
15278
|
+
}
|
|
15279
|
+
}
|
|
15280
|
+
function cloneSlide(slide) {
|
|
15281
|
+
return {
|
|
15282
|
+
...slide,
|
|
15283
|
+
transition: cloneSlideTransition(slide.transition),
|
|
15284
|
+
animations: slide.animations?.map(cloneElementAnimation),
|
|
15285
|
+
comments: slide.comments?.map((comment) => ({ ...comment })),
|
|
15286
|
+
warnings: slide.warnings?.map((warning) => ({ ...warning })),
|
|
15287
|
+
elements: slide.elements.map(cloneElement),
|
|
15288
|
+
};
|
|
15289
|
+
}
|
|
15290
|
+
function cloneTemplateElementsBySlideId(templateElementsBySlideId) {
|
|
15291
|
+
const cloned = {};
|
|
15292
|
+
Object.entries(templateElementsBySlideId).forEach(([slideId, elements]) => {
|
|
15293
|
+
cloned[slideId] = elements.map(cloneElement);
|
|
15294
|
+
});
|
|
15295
|
+
return cloned;
|
|
15296
|
+
}
|
|
15297
|
+
/**
|
|
15298
|
+
* Deep-clone the cloneable fields of a history snapshot. Note: matches the
|
|
15299
|
+
* original React behaviour by NOT copying any binding-specific extras (e.g.
|
|
15300
|
+
* `actionLabel`); only the structural {@link HistorySnapshotLike} fields are
|
|
15301
|
+
* rebuilt.
|
|
15302
|
+
*/
|
|
15303
|
+
function cloneHistorySnapshot(snapshot) {
|
|
15304
|
+
return {
|
|
15305
|
+
width: snapshot.width,
|
|
15306
|
+
height: snapshot.height,
|
|
15307
|
+
activeSlideIndex: snapshot.activeSlideIndex,
|
|
15308
|
+
slides: snapshot.slides.map(cloneSlide),
|
|
15309
|
+
templateElementsBySlideId: cloneTemplateElementsBySlideId(snapshot.templateElementsBySlideId),
|
|
15310
|
+
};
|
|
15311
|
+
}
|
|
15312
|
+
function cloneXmlObject(value) {
|
|
15313
|
+
if (!value) {
|
|
15314
|
+
return undefined;
|
|
15315
|
+
}
|
|
15316
|
+
try {
|
|
15317
|
+
return JSON.parse(JSON.stringify(value));
|
|
15318
|
+
}
|
|
15319
|
+
catch {
|
|
15320
|
+
return undefined;
|
|
15321
|
+
}
|
|
15322
|
+
}
|
|
15323
|
+
|
|
14788
15324
|
/**
|
|
14789
15325
|
* Pure geometry helpers for the align / distribute editor operations.
|
|
14790
15326
|
*
|
|
@@ -20129,6 +20665,527 @@ function matchTextTokens(fromTokens, toTokens) {
|
|
|
20129
20665
|
return pairs;
|
|
20130
20666
|
}
|
|
20131
20667
|
|
|
20668
|
+
/**
|
|
20669
|
+
* Intelligent token-level diffing and morph animation for text morphing.
|
|
20670
|
+
*
|
|
20671
|
+
* The base matcher in `morph-text` pairs tokens by exact text then proximity,
|
|
20672
|
+
* which loses ordering when the same word repeats and treats every change as a
|
|
20673
|
+
* crossfade. This module adds a Longest-Common-Subsequence (LCS) alignment so
|
|
20674
|
+
* that tokens present in both the outgoing and incoming text are matched in a
|
|
20675
|
+
* stable, order-preserving way and animated as a move (slide + restyle), while
|
|
20676
|
+
* tokens that only appear on one side are classified as added (fade in) or
|
|
20677
|
+
* removed (fade out).
|
|
20678
|
+
*
|
|
20679
|
+
* @module render/morph-text-tokens
|
|
20680
|
+
*/
|
|
20681
|
+
/**
|
|
20682
|
+
* Diff two ordered token lists into shared/added/removed operations using an
|
|
20683
|
+
* LCS backtrace. Shared tokens preserve order and repetition; insertions and
|
|
20684
|
+
* deletions are emitted in their natural sequence position.
|
|
20685
|
+
*
|
|
20686
|
+
* @param fromTokens Tokens from the outgoing element.
|
|
20687
|
+
* @param toTokens Tokens from the incoming element.
|
|
20688
|
+
* @returns Ordered diff operations describing the token-level transition.
|
|
20689
|
+
*/
|
|
20690
|
+
function diffTokens(fromTokens, toTokens) {
|
|
20691
|
+
const n = fromTokens.length;
|
|
20692
|
+
const m = toTokens.length;
|
|
20693
|
+
// LCS length table.
|
|
20694
|
+
const lcs = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
20695
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
20696
|
+
for (let j = m - 1; j >= 0; j--) {
|
|
20697
|
+
lcs[i][j] =
|
|
20698
|
+
fromTokens[i].text === toTokens[j].text
|
|
20699
|
+
? lcs[i + 1][j + 1] + 1
|
|
20700
|
+
: Math.max(lcs[i + 1][j], lcs[i][j + 1]);
|
|
20701
|
+
}
|
|
20702
|
+
}
|
|
20703
|
+
// Backtrace into ordered ops.
|
|
20704
|
+
const ops = [];
|
|
20705
|
+
let i = 0;
|
|
20706
|
+
let j = 0;
|
|
20707
|
+
while (i < n && j < m) {
|
|
20708
|
+
if (fromTokens[i].text === toTokens[j].text) {
|
|
20709
|
+
ops.push({
|
|
20710
|
+
change: 'shared',
|
|
20711
|
+
from: fromTokens[i],
|
|
20712
|
+
to: toTokens[j],
|
|
20713
|
+
fromIndex: i,
|
|
20714
|
+
toIndex: j,
|
|
20715
|
+
});
|
|
20716
|
+
i++;
|
|
20717
|
+
j++;
|
|
20718
|
+
}
|
|
20719
|
+
else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
|
|
20720
|
+
ops.push({ change: 'removed', from: fromTokens[i], to: null, fromIndex: i, toIndex: -1 });
|
|
20721
|
+
i++;
|
|
20722
|
+
}
|
|
20723
|
+
else {
|
|
20724
|
+
ops.push({ change: 'added', from: null, to: toTokens[j], fromIndex: -1, toIndex: j });
|
|
20725
|
+
j++;
|
|
20726
|
+
}
|
|
20727
|
+
}
|
|
20728
|
+
while (i < n) {
|
|
20729
|
+
ops.push({ change: 'removed', from: fromTokens[i], to: null, fromIndex: i, toIndex: -1 });
|
|
20730
|
+
i++;
|
|
20731
|
+
}
|
|
20732
|
+
while (j < m) {
|
|
20733
|
+
ops.push({ change: 'added', from: null, to: toTokens[j], fromIndex: -1, toIndex: j });
|
|
20734
|
+
j++;
|
|
20735
|
+
}
|
|
20736
|
+
return ops;
|
|
20737
|
+
}
|
|
20738
|
+
// ---------------------------------------------------------------------------
|
|
20739
|
+
// Animation building
|
|
20740
|
+
// ---------------------------------------------------------------------------
|
|
20741
|
+
/** Resolve a token colour to a CSS string, preferring a parsed rgba form. */
|
|
20742
|
+
function tokenColor(token) {
|
|
20743
|
+
const parsed = parseHexColor(token.color);
|
|
20744
|
+
return parsed ? lerpColor(parsed, parsed, 0) : token.color;
|
|
20745
|
+
}
|
|
20746
|
+
/** Build a shared-token move keyframe: slide + restyle between positions. */
|
|
20747
|
+
function sharedKeyframes(name, op) {
|
|
20748
|
+
const from = op.from;
|
|
20749
|
+
const to = op.to;
|
|
20750
|
+
return `
|
|
20751
|
+
@keyframes ${name} {
|
|
20752
|
+
\tfrom {
|
|
20753
|
+
\t\tleft: ${Number((from.x * 100).toFixed(2))}%;
|
|
20754
|
+
\t\ttop: ${Number((from.y * 100).toFixed(2))}%;
|
|
20755
|
+
\t\tfont-size: ${from.fontSize}pt;
|
|
20756
|
+
\t\tfont-weight: ${from.fontWeight};
|
|
20757
|
+
\t\tcolor: ${tokenColor(from)};
|
|
20758
|
+
\t\topacity: 1;
|
|
20759
|
+
\t}
|
|
20760
|
+
\tto {
|
|
20761
|
+
\t\tleft: ${Number((to.x * 100).toFixed(2))}%;
|
|
20762
|
+
\t\ttop: ${Number((to.y * 100).toFixed(2))}%;
|
|
20763
|
+
\t\tfont-size: ${to.fontSize}pt;
|
|
20764
|
+
\t\tfont-weight: ${to.fontWeight};
|
|
20765
|
+
\t\tcolor: ${tokenColor(to)};
|
|
20766
|
+
\t\topacity: 1;
|
|
20767
|
+
\t}
|
|
20768
|
+
}`;
|
|
20769
|
+
}
|
|
20770
|
+
/** Build a fade keyframe for an added (in) or removed (out) token. */
|
|
20771
|
+
function fadeKeyframes(name, fadeIn) {
|
|
20772
|
+
const a = fadeIn ? 0 : 1;
|
|
20773
|
+
const b = fadeIn ? 1 : 0;
|
|
20774
|
+
return `
|
|
20775
|
+
@keyframes ${name} {
|
|
20776
|
+
\tfrom { opacity: ${a}; }
|
|
20777
|
+
\tto { opacity: ${b}; }
|
|
20778
|
+
}`;
|
|
20779
|
+
}
|
|
20780
|
+
/**
|
|
20781
|
+
* Build per-token CSS animations from a token diff. Shared tokens animate their
|
|
20782
|
+
* position/size/colour between states; added tokens fade in; removed tokens
|
|
20783
|
+
* fade out. Element ids embed the originating token index so bindings can map
|
|
20784
|
+
* a generated `<span>` to its keyframe.
|
|
20785
|
+
*
|
|
20786
|
+
* @param ops Ordered token diff from {@link diffTokens}.
|
|
20787
|
+
* @param fromId The outgoing element id (used for removed tokens).
|
|
20788
|
+
* @param toId The incoming element id (used for shared/added tokens).
|
|
20789
|
+
* @param durationMs Animation duration in milliseconds.
|
|
20790
|
+
* @param pairIndex Index of the owning element pair for unique naming.
|
|
20791
|
+
* @returns Per-token animation style descriptors.
|
|
20792
|
+
*/
|
|
20793
|
+
function buildTokenMorphAnimations(ops, fromId, toId, durationMs, pairIndex) {
|
|
20794
|
+
const animations = [];
|
|
20795
|
+
for (let k = 0; k < ops.length; k++) {
|
|
20796
|
+
const op = ops[k];
|
|
20797
|
+
const name = `pptx-morph-tok-${pairIndex}-${k}`;
|
|
20798
|
+
const anim = `${name} ${durationMs}ms ${MORPH_EASING} forwards`;
|
|
20799
|
+
if (op.change === 'shared') {
|
|
20800
|
+
animations.push({
|
|
20801
|
+
elementId: `${toId}__token_${op.toIndex}`,
|
|
20802
|
+
animation: anim,
|
|
20803
|
+
keyframes: sharedKeyframes(name, op),
|
|
20804
|
+
});
|
|
20805
|
+
}
|
|
20806
|
+
else if (op.change === 'added') {
|
|
20807
|
+
animations.push({
|
|
20808
|
+
elementId: `${toId}__token_${op.toIndex}`,
|
|
20809
|
+
animation: anim,
|
|
20810
|
+
keyframes: fadeKeyframes(name, true),
|
|
20811
|
+
});
|
|
20812
|
+
}
|
|
20813
|
+
else {
|
|
20814
|
+
animations.push({
|
|
20815
|
+
elementId: `${fromId}__token_${op.fromIndex}`,
|
|
20816
|
+
animation: anim,
|
|
20817
|
+
keyframes: fadeKeyframes(name, false),
|
|
20818
|
+
});
|
|
20819
|
+
}
|
|
20820
|
+
}
|
|
20821
|
+
return animations;
|
|
20822
|
+
}
|
|
20823
|
+
|
|
20824
|
+
/** Number of sample points each outline is resampled to before interpolating. */
|
|
20825
|
+
const OUTLINE_SAMPLE_COUNT = 64;
|
|
20826
|
+
/** Number of points used to approximate an ellipse/circle outline. */
|
|
20827
|
+
const ELLIPSE_SAMPLE_COUNT = 48;
|
|
20828
|
+
// ---------------------------------------------------------------------------
|
|
20829
|
+
// CSS clip-path -> polygon
|
|
20830
|
+
// ---------------------------------------------------------------------------
|
|
20831
|
+
/** Resolve a CSS length token (`50%`, `12px`, `8`) against an axis length. */
|
|
20832
|
+
function resolveLength(token, axis) {
|
|
20833
|
+
const trimmed = token.trim();
|
|
20834
|
+
if (trimmed.endsWith('%')) {
|
|
20835
|
+
const pct = Number.parseFloat(trimmed.slice(0, -1));
|
|
20836
|
+
return Number.isFinite(pct) ? (pct / 100) * axis : 0;
|
|
20837
|
+
}
|
|
20838
|
+
const px = Number.parseFloat(trimmed.replace(/px$/u, ''));
|
|
20839
|
+
return Number.isFinite(px) ? px : 0;
|
|
20840
|
+
}
|
|
20841
|
+
/** Parse a `polygon(x y, x y, ...)` clip-path into a pixel-space polygon. */
|
|
20842
|
+
function polygonClipToPoints(value, width, height) {
|
|
20843
|
+
const inner = value.slice(value.indexOf('(') + 1, value.lastIndexOf(')'));
|
|
20844
|
+
const points = [];
|
|
20845
|
+
for (const pairStr of inner.split(',')) {
|
|
20846
|
+
const parts = pairStr.trim().split(/\s+/u);
|
|
20847
|
+
if (parts.length < 2) {
|
|
20848
|
+
continue;
|
|
20849
|
+
}
|
|
20850
|
+
points.push({
|
|
20851
|
+
x: resolveLength(parts[0], width),
|
|
20852
|
+
y: resolveLength(parts[1], height),
|
|
20853
|
+
});
|
|
20854
|
+
}
|
|
20855
|
+
return points;
|
|
20856
|
+
}
|
|
20857
|
+
/** Parse an `inset(t r b l ...)` clip-path into a rectangle polygon. */
|
|
20858
|
+
function insetClipToPoints(value, width, height) {
|
|
20859
|
+
const inner = value.slice(value.indexOf('(') + 1, value.lastIndexOf(')'));
|
|
20860
|
+
const tokens = inner.split(/round/u)[0].trim().split(/\s+/u);
|
|
20861
|
+
const top = resolveLength(tokens[0] ?? '0', height);
|
|
20862
|
+
const right = resolveLength(tokens[1] ?? tokens[0] ?? '0', width);
|
|
20863
|
+
const bottom = resolveLength(tokens[2] ?? tokens[0] ?? '0', height);
|
|
20864
|
+
const left = resolveLength(tokens[3] ?? tokens[1] ?? tokens[0] ?? '0', width);
|
|
20865
|
+
return [
|
|
20866
|
+
{ x: left, y: top },
|
|
20867
|
+
{ x: width - right, y: top },
|
|
20868
|
+
{ x: width - right, y: height - bottom },
|
|
20869
|
+
{ x: left, y: height - bottom },
|
|
20870
|
+
];
|
|
20871
|
+
}
|
|
20872
|
+
/** Sample an `ellipse(...)` / `circle(...)` clip-path into a polygon. */
|
|
20873
|
+
function ellipseClipToPoints(value, width, height) {
|
|
20874
|
+
const isCircle = value.startsWith('circle');
|
|
20875
|
+
const inner = value.slice(value.indexOf('(') + 1, value.lastIndexOf(')'));
|
|
20876
|
+
const [radii, position] = inner.split(/\s+at\s+/u);
|
|
20877
|
+
const radiusTokens = radii.trim().split(/\s+/u).filter(Boolean);
|
|
20878
|
+
let rx = width / 2;
|
|
20879
|
+
let ry = height / 2;
|
|
20880
|
+
if (isCircle) {
|
|
20881
|
+
const r = resolveLength(radiusTokens[0] ?? '50%', Math.min(width, height));
|
|
20882
|
+
rx = r;
|
|
20883
|
+
ry = r;
|
|
20884
|
+
}
|
|
20885
|
+
else {
|
|
20886
|
+
rx = resolveLength(radiusTokens[0] ?? '50%', width);
|
|
20887
|
+
ry = resolveLength(radiusTokens[1] ?? radiusTokens[0] ?? '50%', height);
|
|
20888
|
+
}
|
|
20889
|
+
let cx = width / 2;
|
|
20890
|
+
let cy = height / 2;
|
|
20891
|
+
if (position) {
|
|
20892
|
+
const posTokens = position.trim().split(/\s+/u);
|
|
20893
|
+
cx = resolveLength(posTokens[0] ?? '50%', width);
|
|
20894
|
+
cy = resolveLength(posTokens[1] ?? posTokens[0] ?? '50%', height);
|
|
20895
|
+
}
|
|
20896
|
+
const points = [];
|
|
20897
|
+
for (let i = 0; i < ELLIPSE_SAMPLE_COUNT; i++) {
|
|
20898
|
+
const a = (i / ELLIPSE_SAMPLE_COUNT) * Math.PI * 2;
|
|
20899
|
+
points.push({ x: cx + Math.cos(a) * rx, y: cy + Math.sin(a) * ry });
|
|
20900
|
+
}
|
|
20901
|
+
return points;
|
|
20902
|
+
}
|
|
20903
|
+
/**
|
|
20904
|
+
* Convert a CSS `clip-path` value into a single pixel-space polygon. Supports
|
|
20905
|
+
* `polygon`, `inset`, `ellipse`, `circle`, and `path('...')` forms. For `path`
|
|
20906
|
+
* outlines the largest sub-path (by point count) is used.
|
|
20907
|
+
*
|
|
20908
|
+
* @param value The CSS clip-path string.
|
|
20909
|
+
* @param width Element width in pixels.
|
|
20910
|
+
* @param height Element height in pixels.
|
|
20911
|
+
* @returns The outline polygon, or an empty array if it cannot be parsed.
|
|
20912
|
+
*/
|
|
20913
|
+
function clipPathToPolygon(value, width, height) {
|
|
20914
|
+
const v = value.trim();
|
|
20915
|
+
if (v.startsWith('polygon')) {
|
|
20916
|
+
return polygonClipToPoints(v, width, height);
|
|
20917
|
+
}
|
|
20918
|
+
if (v.startsWith('inset')) {
|
|
20919
|
+
return insetClipToPoints(v, width, height);
|
|
20920
|
+
}
|
|
20921
|
+
if (v.startsWith('ellipse') || v.startsWith('circle')) {
|
|
20922
|
+
return ellipseClipToPoints(v, width, height);
|
|
20923
|
+
}
|
|
20924
|
+
if (v.startsWith('path')) {
|
|
20925
|
+
const start = v.indexOf("'") >= 0 ? v.indexOf("'") : v.indexOf('"');
|
|
20926
|
+
const end = v.lastIndexOf("'") >= 0 ? v.lastIndexOf("'") : v.lastIndexOf('"');
|
|
20927
|
+
if (start >= 0 && end > start) {
|
|
20928
|
+
const d = v.slice(start + 1, end);
|
|
20929
|
+
const polys = svgPathToPolygons(d);
|
|
20930
|
+
if (polys.length === 0) {
|
|
20931
|
+
return [];
|
|
20932
|
+
}
|
|
20933
|
+
return polys.reduce((a, b) => (b.length > a.length ? b : a));
|
|
20934
|
+
}
|
|
20935
|
+
}
|
|
20936
|
+
return [];
|
|
20937
|
+
}
|
|
20938
|
+
// ---------------------------------------------------------------------------
|
|
20939
|
+
// Element outline resolution
|
|
20940
|
+
// ---------------------------------------------------------------------------
|
|
20941
|
+
/**
|
|
20942
|
+
* Resolve an element's outline polygon in its own pixel box. Falls back to the
|
|
20943
|
+
* element's bounding rectangle when no preset clip-path is available (e.g. a
|
|
20944
|
+
* plain `rect`, an image, or an unknown shape).
|
|
20945
|
+
*
|
|
20946
|
+
* @param element The element to resolve an outline for.
|
|
20947
|
+
* @returns A pixel-space polygon describing the element's outline.
|
|
20948
|
+
*/
|
|
20949
|
+
function resolveElementOutline(element) {
|
|
20950
|
+
const width = Math.max(element.width, 1);
|
|
20951
|
+
const height = Math.max(element.height, 1);
|
|
20952
|
+
const shapeType = element.shapeType;
|
|
20953
|
+
const adjustments = element.shapeAdjustments;
|
|
20954
|
+
const clip = getResolvedShapeClipPathFor$1(shapeType, width, height, adjustments);
|
|
20955
|
+
if (clip) {
|
|
20956
|
+
const poly = clipPathToPolygon(clip, width, height);
|
|
20957
|
+
if (poly.length >= 3) {
|
|
20958
|
+
return poly;
|
|
20959
|
+
}
|
|
20960
|
+
}
|
|
20961
|
+
// Rectangle fallback (covers rect / roundrect / images / unmatched presets).
|
|
20962
|
+
return [
|
|
20963
|
+
{ x: 0, y: 0 },
|
|
20964
|
+
{ x: width, y: 0 },
|
|
20965
|
+
{ x: width, y: height },
|
|
20966
|
+
{ x: 0, y: height },
|
|
20967
|
+
];
|
|
20968
|
+
}
|
|
20969
|
+
|
|
20970
|
+
// ---------------------------------------------------------------------------
|
|
20971
|
+
// Perimeter resampling
|
|
20972
|
+
// ---------------------------------------------------------------------------
|
|
20973
|
+
/** Euclidean distance between two points. */
|
|
20974
|
+
function dist(a, b) {
|
|
20975
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
20976
|
+
}
|
|
20977
|
+
/**
|
|
20978
|
+
* Resample a closed polygon to exactly `count` points spaced uniformly by arc
|
|
20979
|
+
* length around its perimeter.
|
|
20980
|
+
*
|
|
20981
|
+
* @param poly The source polygon (treated as closed).
|
|
20982
|
+
* @param count Desired number of output points (>= 3).
|
|
20983
|
+
* @returns A new polygon with `count` evenly-spaced vertices.
|
|
20984
|
+
*/
|
|
20985
|
+
function resamplePolygon(poly, count) {
|
|
20986
|
+
if (poly.length < 2) {
|
|
20987
|
+
return Array.from({ length: count }, () => ({ x: poly[0]?.x ?? 0, y: poly[0]?.y ?? 0 }));
|
|
20988
|
+
}
|
|
20989
|
+
// Cumulative perimeter length (closing edge included).
|
|
20990
|
+
const ring = [...poly, poly[0]];
|
|
20991
|
+
const segLen = [];
|
|
20992
|
+
let total = 0;
|
|
20993
|
+
for (let i = 0; i < ring.length - 1; i++) {
|
|
20994
|
+
const d = dist(ring[i], ring[i + 1]);
|
|
20995
|
+
segLen.push(d);
|
|
20996
|
+
total += d;
|
|
20997
|
+
}
|
|
20998
|
+
if (total === 0) {
|
|
20999
|
+
return Array.from({ length: count }, () => ({ x: poly[0].x, y: poly[0].y }));
|
|
21000
|
+
}
|
|
21001
|
+
const result = [];
|
|
21002
|
+
const step = total / count;
|
|
21003
|
+
let seg = 0;
|
|
21004
|
+
let segStart = 0;
|
|
21005
|
+
for (let i = 0; i < count; i++) {
|
|
21006
|
+
const target = i * step;
|
|
21007
|
+
while (seg < segLen.length - 1 && segStart + segLen[seg] < target) {
|
|
21008
|
+
segStart += segLen[seg];
|
|
21009
|
+
seg++;
|
|
21010
|
+
}
|
|
21011
|
+
const within = segLen[seg] > 0 ? (target - segStart) / segLen[seg] : 0;
|
|
21012
|
+
const a = ring[seg];
|
|
21013
|
+
const b = ring[seg + 1];
|
|
21014
|
+
result.push({ x: a.x + (b.x - a.x) * within, y: a.y + (b.y - a.y) * within });
|
|
21015
|
+
}
|
|
21016
|
+
return result;
|
|
21017
|
+
}
|
|
21018
|
+
// ---------------------------------------------------------------------------
|
|
21019
|
+
// Winding + rotation alignment
|
|
21020
|
+
// ---------------------------------------------------------------------------
|
|
21021
|
+
/** Signed area of a polygon; positive for counter-clockwise (SVG y-down). */
|
|
21022
|
+
function signedArea(poly) {
|
|
21023
|
+
let area = 0;
|
|
21024
|
+
for (let i = 0; i < poly.length; i++) {
|
|
21025
|
+
const a = poly[i];
|
|
21026
|
+
const b = poly[(i + 1) % poly.length];
|
|
21027
|
+
area += a.x * b.y - b.x * a.y;
|
|
21028
|
+
}
|
|
21029
|
+
return area / 2;
|
|
21030
|
+
}
|
|
21031
|
+
/** Rotate a ring so element `offset` becomes index 0. */
|
|
21032
|
+
function rotateRing(poly, offset) {
|
|
21033
|
+
const n = poly.length;
|
|
21034
|
+
const o = ((offset % n) + n) % n;
|
|
21035
|
+
return poly.slice(o).concat(poly.slice(0, o));
|
|
21036
|
+
}
|
|
21037
|
+
/**
|
|
21038
|
+
* Find the rotation of `to` that minimises total squared distance to `from`.
|
|
21039
|
+
* Both rings must already have the same length.
|
|
21040
|
+
*/
|
|
21041
|
+
function bestRotation(from, to) {
|
|
21042
|
+
let bestOffset = 0;
|
|
21043
|
+
let bestCost = Infinity;
|
|
21044
|
+
for (let offset = 0; offset < to.length; offset++) {
|
|
21045
|
+
let cost = 0;
|
|
21046
|
+
for (let i = 0; i < from.length; i++) {
|
|
21047
|
+
const t = to[(i + offset) % to.length];
|
|
21048
|
+
const dx = from[i].x - t.x;
|
|
21049
|
+
const dy = from[i].y - t.y;
|
|
21050
|
+
cost += dx * dx + dy * dy;
|
|
21051
|
+
if (cost >= bestCost) {
|
|
21052
|
+
break;
|
|
21053
|
+
}
|
|
21054
|
+
}
|
|
21055
|
+
if (cost < bestCost) {
|
|
21056
|
+
bestCost = cost;
|
|
21057
|
+
bestOffset = offset;
|
|
21058
|
+
}
|
|
21059
|
+
}
|
|
21060
|
+
return bestOffset;
|
|
21061
|
+
}
|
|
21062
|
+
// ---------------------------------------------------------------------------
|
|
21063
|
+
// Pair normalisation
|
|
21064
|
+
// ---------------------------------------------------------------------------
|
|
21065
|
+
/**
|
|
21066
|
+
* Normalise two outlines into equal-length, like-oriented, rotation-aligned
|
|
21067
|
+
* rings ready for vertex-wise interpolation.
|
|
21068
|
+
*
|
|
21069
|
+
* @param fromPoly The outgoing outline polygon.
|
|
21070
|
+
* @param toPoly The incoming outline polygon.
|
|
21071
|
+
* @param count Common sample count (defaults to {@link OUTLINE_SAMPLE_COUNT}).
|
|
21072
|
+
* @returns A tuple of two normalised polygons of identical length.
|
|
21073
|
+
*/
|
|
21074
|
+
function normalizeOutlinePair(fromPoly, toPoly, count = OUTLINE_SAMPLE_COUNT) {
|
|
21075
|
+
const from = resamplePolygon(fromPoly, count);
|
|
21076
|
+
let to = resamplePolygon(toPoly, count);
|
|
21077
|
+
// Align winding order so both rings travel the same direction.
|
|
21078
|
+
if (Math.sign(signedArea(from)) !== Math.sign(signedArea(to))) {
|
|
21079
|
+
to = [...to].reverse();
|
|
21080
|
+
}
|
|
21081
|
+
// Rotate `to` so its first vertex best matches `from`'s first vertex.
|
|
21082
|
+
const offset = bestRotation(from, to);
|
|
21083
|
+
to = rotateRing(to, offset);
|
|
21084
|
+
return [from, to];
|
|
21085
|
+
}
|
|
21086
|
+
// ---------------------------------------------------------------------------
|
|
21087
|
+
// Interpolation + serialisation
|
|
21088
|
+
// ---------------------------------------------------------------------------
|
|
21089
|
+
/**
|
|
21090
|
+
* Interpolate two normalised outlines at parameter `t` and serialise to an SVG
|
|
21091
|
+
* path `d` string (a single closed sub-path). Inputs should come from
|
|
21092
|
+
* {@link normalizeOutlinePair}; if lengths differ the shorter length is used.
|
|
21093
|
+
*
|
|
21094
|
+
* @param from The outgoing normalised polygon.
|
|
21095
|
+
* @param to The incoming normalised polygon.
|
|
21096
|
+
* @param t Interpolation parameter, clamped to [0, 1].
|
|
21097
|
+
* @returns An SVG path `d` string for the intermediate outline.
|
|
21098
|
+
*/
|
|
21099
|
+
function interpolateOutline(from, to, t) {
|
|
21100
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
21101
|
+
const len = Math.min(from.length, to.length);
|
|
21102
|
+
if (len === 0) {
|
|
21103
|
+
return '';
|
|
21104
|
+
}
|
|
21105
|
+
const parts = [];
|
|
21106
|
+
for (let i = 0; i < len; i++) {
|
|
21107
|
+
const x = from[i].x + (to[i].x - from[i].x) * clamped;
|
|
21108
|
+
const y = from[i].y + (to[i].y - from[i].y) * clamped;
|
|
21109
|
+
parts.push(`${i === 0 ? 'M' : 'L'}${Number(x.toFixed(2))} ${Number(y.toFixed(2))}`);
|
|
21110
|
+
}
|
|
21111
|
+
parts.push('Z');
|
|
21112
|
+
return parts.join(' ');
|
|
21113
|
+
}
|
|
21114
|
+
|
|
21115
|
+
/** Number of intermediate keyframe stops baked into a geometry morph. */
|
|
21116
|
+
const GEOMETRY_MORPH_STEPS = 8;
|
|
21117
|
+
/**
|
|
21118
|
+
* Decide whether a matched pair warrants geometry morphing rather than a plain
|
|
21119
|
+
* crossfade. True when both elements carry a shape type and those types differ
|
|
21120
|
+
* (or their adjustment outlines differ), since same-type same-adjustment shapes
|
|
21121
|
+
* already morph correctly via the transform/scale animation.
|
|
21122
|
+
*
|
|
21123
|
+
* @param pair The matched element pair.
|
|
21124
|
+
* @returns True when geometry interpolation should be applied.
|
|
21125
|
+
*/
|
|
21126
|
+
function shouldGeometryMorph(pair) {
|
|
21127
|
+
const fromType = pair.fromElement.shapeType;
|
|
21128
|
+
const toType = pair.toElement.shapeType;
|
|
21129
|
+
if (!fromType || !toType) {
|
|
21130
|
+
return false;
|
|
21131
|
+
}
|
|
21132
|
+
if (fromType.toLowerCase() !== toType.toLowerCase()) {
|
|
21133
|
+
return true;
|
|
21134
|
+
}
|
|
21135
|
+
const fromAdj = JSON.stringify(pair.fromElement.shapeAdjustments ?? {});
|
|
21136
|
+
const toAdj = JSON.stringify(pair.toElement.shapeAdjustments ?? {});
|
|
21137
|
+
return fromAdj !== toAdj;
|
|
21138
|
+
}
|
|
21139
|
+
/** Build the per-stop `clip-path` keyframe body for an outline morph. */
|
|
21140
|
+
function buildClipKeyframeBody(from, to, steps) {
|
|
21141
|
+
const [fromRing, toRing] = normalizeOutlinePair(resolveElementOutline(from), resolveElementOutline(to));
|
|
21142
|
+
if (fromRing.length === 0 || toRing.length === 0) {
|
|
21143
|
+
return null;
|
|
21144
|
+
}
|
|
21145
|
+
const lines = [];
|
|
21146
|
+
for (let s = 0; s <= steps; s++) {
|
|
21147
|
+
const t = s / steps;
|
|
21148
|
+
const d = interpolateOutline(fromRing, toRing, t);
|
|
21149
|
+
if (!d) {
|
|
21150
|
+
return null;
|
|
21151
|
+
}
|
|
21152
|
+
const pct = Number(((s / steps) * 100).toFixed(2));
|
|
21153
|
+
lines.push(`\t${pct}% {\n\t\tclip-path: path('${d}');\n\t}`);
|
|
21154
|
+
}
|
|
21155
|
+
return lines.join('\n');
|
|
21156
|
+
}
|
|
21157
|
+
/**
|
|
21158
|
+
* Generate a `clip-path` geometry-morph animation for a matched pair whose
|
|
21159
|
+
* shape outline changes. Returns null when the pair does not need geometry
|
|
21160
|
+
* morphing or its outlines cannot be resolved.
|
|
21161
|
+
*
|
|
21162
|
+
* The emitted animation targets the incoming element id and is intended to run
|
|
21163
|
+
* alongside the pair's transform/opacity animation, replacing the crossfade for
|
|
21164
|
+
* shape-type changes with a true outline tween.
|
|
21165
|
+
*
|
|
21166
|
+
* @param pair The matched element pair.
|
|
21167
|
+
* @param durationMs Animation duration in milliseconds.
|
|
21168
|
+
* @param pairIndex Index of the pair for unique keyframe naming.
|
|
21169
|
+
* @param steps Number of baked stops (defaults to {@link GEOMETRY_MORPH_STEPS}).
|
|
21170
|
+
* @returns A geometry-morph animation style, or null.
|
|
21171
|
+
*/
|
|
21172
|
+
function generateGeometryMorphAnimation(pair, durationMs, pairIndex, steps = GEOMETRY_MORPH_STEPS) {
|
|
21173
|
+
if (!shouldGeometryMorph(pair)) {
|
|
21174
|
+
return null;
|
|
21175
|
+
}
|
|
21176
|
+
const body = buildClipKeyframeBody(pair.fromElement, pair.toElement, steps);
|
|
21177
|
+
if (!body) {
|
|
21178
|
+
return null;
|
|
21179
|
+
}
|
|
21180
|
+
const safeName = `pptx-morph-geo-${pairIndex}-${pair.toElement.id.replace(/[^a-zA-Z0-9]/gu, '')}`;
|
|
21181
|
+
const keyframes = `\n@keyframes ${safeName} {\n${body}\n}`;
|
|
21182
|
+
return {
|
|
21183
|
+
elementId: pair.toElement.id,
|
|
21184
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
21185
|
+
keyframes,
|
|
21186
|
+
};
|
|
21187
|
+
}
|
|
21188
|
+
|
|
20132
21189
|
// ---------------------------------------------------------------------------
|
|
20133
21190
|
// Build colour/stroke interpolation keyframes
|
|
20134
21191
|
// ---------------------------------------------------------------------------
|
|
@@ -20332,70 +21389,10 @@ function generateTextMorphAnimations(pair, durationMs, mode, pairIndex) {
|
|
|
20332
21389
|
if (fromTokens.length === 0 && toTokens.length === 0) {
|
|
20333
21390
|
return [];
|
|
20334
21391
|
}
|
|
20335
|
-
|
|
20336
|
-
|
|
20337
|
-
|
|
20338
|
-
|
|
20339
|
-
const safeName = `pptx-morph-text-${pairIndex}-${ti}`;
|
|
20340
|
-
if (tp.from && tp.to) {
|
|
20341
|
-
// Matched token: animate position, size, color
|
|
20342
|
-
const fromX = tp.from.x * 100;
|
|
20343
|
-
const toX = tp.to.x * 100;
|
|
20344
|
-
const fromColor = parseHexColor(tp.from.color);
|
|
20345
|
-
const toColor = parseHexColor(tp.to.color);
|
|
20346
|
-
const fromColorStr = fromColor ? lerpColor(fromColor, fromColor, 0) : tp.from.color;
|
|
20347
|
-
const toColorStr = toColor ? lerpColor(toColor, toColor, 0) : tp.to.color;
|
|
20348
|
-
const keyframes = `
|
|
20349
|
-
@keyframes ${safeName} {
|
|
20350
|
-
\tfrom {
|
|
20351
|
-
\t\tleft: ${fromX}%;
|
|
20352
|
-
\t\tfont-size: ${tp.from.fontSize}pt;
|
|
20353
|
-
\t\tfont-weight: ${tp.from.fontWeight};
|
|
20354
|
-
\t\tcolor: ${fromColorStr};
|
|
20355
|
-
\t\topacity: 1;
|
|
20356
|
-
\t}
|
|
20357
|
-
\tto {
|
|
20358
|
-
\t\tleft: ${toX}%;
|
|
20359
|
-
\t\tfont-size: ${tp.to.fontSize}pt;
|
|
20360
|
-
\t\tfont-weight: ${tp.to.fontWeight};
|
|
20361
|
-
\t\tcolor: ${toColorStr};
|
|
20362
|
-
\t\topacity: 1;
|
|
20363
|
-
\t}
|
|
20364
|
-
}`;
|
|
20365
|
-
animations.push({
|
|
20366
|
-
elementId: `${pair.toElement.id}__token_${ti}`,
|
|
20367
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
20368
|
-
keyframes,
|
|
20369
|
-
});
|
|
20370
|
-
}
|
|
20371
|
-
else if (tp.from && !tp.to) {
|
|
20372
|
-
// Disappearing token: fade out
|
|
20373
|
-
const keyframes = `
|
|
20374
|
-
@keyframes ${safeName} {
|
|
20375
|
-
\tfrom { opacity: 1; }
|
|
20376
|
-
\tto { opacity: 0; }
|
|
20377
|
-
}`;
|
|
20378
|
-
animations.push({
|
|
20379
|
-
elementId: `${pair.fromElement.id}__token_${ti}`,
|
|
20380
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
20381
|
-
keyframes,
|
|
20382
|
-
});
|
|
20383
|
-
}
|
|
20384
|
-
else if (!tp.from && tp.to) {
|
|
20385
|
-
// Appearing token: fade in
|
|
20386
|
-
const keyframes = `
|
|
20387
|
-
@keyframes ${safeName} {
|
|
20388
|
-
\tfrom { opacity: 0; }
|
|
20389
|
-
\tto { opacity: 1; }
|
|
20390
|
-
}`;
|
|
20391
|
-
animations.push({
|
|
20392
|
-
elementId: `${pair.toElement.id}__token_${ti}`,
|
|
20393
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
20394
|
-
keyframes,
|
|
20395
|
-
});
|
|
20396
|
-
}
|
|
20397
|
-
}
|
|
20398
|
-
return animations;
|
|
21392
|
+
// Order-preserving LCS diff: shared tokens slide/restyle between positions,
|
|
21393
|
+
// added tokens fade in, removed tokens fade out (intelligent token morph).
|
|
21394
|
+
const ops = diffTokens(fromTokens, toTokens);
|
|
21395
|
+
return buildTokenMorphAnimations(ops, pair.fromElement.id, pair.toElement.id, durationMs, pairIndex);
|
|
20399
21396
|
}
|
|
20400
21397
|
// ---------------------------------------------------------------------------
|
|
20401
21398
|
// Full morph transition orchestrator
|
|
@@ -20418,6 +21415,15 @@ function generateFullMorphTransition(fromSlide, toSlide, durationMs, mode = 'obj
|
|
|
20418
21415
|
// Generate main element morph animations
|
|
20419
21416
|
const pairAnims = generateMorphAnimations(matchResult.pairs, durationMs, mode);
|
|
20420
21417
|
allAnimations.push(...pairAnims);
|
|
21418
|
+
// Shape-geometry morph: for matched pairs whose shape outline changes
|
|
21419
|
+
// (different shape type or adjustment outline), interpolate the resolved
|
|
21420
|
+
// outlines instead of relying on a plain crossfade.
|
|
21421
|
+
for (let i = 0; i < matchResult.pairs.length; i++) {
|
|
21422
|
+
const geo = generateGeometryMorphAnimation(matchResult.pairs[i], durationMs, i);
|
|
21423
|
+
if (geo) {
|
|
21424
|
+
allAnimations.push(geo);
|
|
21425
|
+
}
|
|
21426
|
+
}
|
|
20421
21427
|
// Generate text morph animations for text-bearing matched pairs
|
|
20422
21428
|
if (mode === 'word' || mode === 'character') {
|
|
20423
21429
|
for (let i = 0; i < matchResult.pairs.length; i++) {
|
|
@@ -25518,6 +26524,13 @@ function createTouchGestureRecognizer(config) {
|
|
|
25518
26524
|
// Swipe state.
|
|
25519
26525
|
let swipeStartX = 0;
|
|
25520
26526
|
let swipeStartY = 0;
|
|
26527
|
+
// Most recent single-finger position. Lets a swipe still be measured when
|
|
26528
|
+
// `touchend` arrives with an empty `changedTouches` list (some synthetic
|
|
26529
|
+
// dispatchers, e.g. CDP `Input.dispatchTouchEvent`, omit it). Real
|
|
26530
|
+
// browsers always populate `changedTouches`, so their behaviour is
|
|
26531
|
+
// unchanged.
|
|
26532
|
+
let swipeLastX = 0;
|
|
26533
|
+
let swipeLastY = 0;
|
|
25521
26534
|
// Long-press state.
|
|
25522
26535
|
let longPressTimer = null;
|
|
25523
26536
|
let longPressStartX = 0;
|
|
@@ -25541,6 +26554,8 @@ function createTouchGestureRecognizer(config) {
|
|
|
25541
26554
|
// Potential swipe or long-press.
|
|
25542
26555
|
swipeStartX = e.touches[0].clientX;
|
|
25543
26556
|
swipeStartY = e.touches[0].clientY;
|
|
26557
|
+
swipeLastX = swipeStartX;
|
|
26558
|
+
swipeLastY = swipeStartY;
|
|
25544
26559
|
longPressStartX = e.touches[0].clientX;
|
|
25545
26560
|
longPressStartY = e.touches[0].clientY;
|
|
25546
26561
|
cancelLongPress();
|
|
@@ -25561,6 +26576,8 @@ function createTouchGestureRecognizer(config) {
|
|
|
25561
26576
|
}
|
|
25562
26577
|
}
|
|
25563
26578
|
else if (e.touches.length === 1) {
|
|
26579
|
+
swipeLastX = e.touches[0].clientX;
|
|
26580
|
+
swipeLastY = e.touches[0].clientY;
|
|
25564
26581
|
// Cancel the long-press if the finger moved too far.
|
|
25565
26582
|
const dx = e.touches[0].clientX - longPressStartX;
|
|
25566
26583
|
const dy = e.touches[0].clientY - longPressStartY;
|
|
@@ -25577,10 +26594,13 @@ function createTouchGestureRecognizer(config) {
|
|
|
25577
26594
|
return;
|
|
25578
26595
|
}
|
|
25579
26596
|
cancelLongPress();
|
|
25580
|
-
// Detect a swipe from the touch that just ended
|
|
25581
|
-
|
|
25582
|
-
|
|
25583
|
-
|
|
26597
|
+
// Detect a swipe from the touch that just ended, but only once every
|
|
26598
|
+
// finger is up. Prefer the lifted touch's coordinates; fall back to the
|
|
26599
|
+
// last tracked move position when `changedTouches` is empty (synthetic
|
|
26600
|
+
// dispatchers), so a swipe is not silently dropped.
|
|
26601
|
+
if (e.touches.length === 0) {
|
|
26602
|
+
const endX = e.changedTouches.length >= 1 ? e.changedTouches[0].clientX : swipeLastX;
|
|
26603
|
+
const endY = e.changedTouches.length >= 1 ? e.changedTouches[0].clientY : swipeLastY;
|
|
25584
26604
|
const deltaX = endX - swipeStartX;
|
|
25585
26605
|
const deltaY = endY - swipeStartY;
|
|
25586
26606
|
if (Math.abs(deltaX) >= SWIPE_THRESHOLD_PX && Math.abs(deltaY) < SWIPE_MAX_VERTICAL_PX) {
|
|
@@ -33562,6 +34582,559 @@ function numberFromInput(event) {
|
|
|
33562
34582
|
return Number.isFinite(parsed) ? parsed : null;
|
|
33563
34583
|
}
|
|
33564
34584
|
|
|
34585
|
+
/**
|
|
34586
|
+
* chart-advanced-helpers.ts: Pure immutable wrappers around the remaining
|
|
34587
|
+
* advanced chart-editing core ops that `chart-data-helpers.ts` does not already
|
|
34588
|
+
* expose (legend, chart-level data labels, axis scale/format edits, chart title,
|
|
34589
|
+
* per-series trendlines/error bars, per-data-point label overrides).
|
|
34590
|
+
*
|
|
34591
|
+
* Each function clones the element's `chartData`, runs the in-place core op on
|
|
34592
|
+
* the clone, and returns a new `ChartPptxElement` so the Angular editor's
|
|
34593
|
+
* immutable contract (and clean history entries) is preserved. The heavy lifting
|
|
34594
|
+
* lives in `pptx-viewer-core`; these are thin framework-agnostic adapters.
|
|
34595
|
+
*
|
|
34596
|
+
* @module angular-viewer/chart-advanced-helpers
|
|
34597
|
+
*/
|
|
34598
|
+
/** Apply an in-place core chart op to a deep clone of `element`. */
|
|
34599
|
+
function withClonedChart$1(element, mutate) {
|
|
34600
|
+
if (!element.chartData) {
|
|
34601
|
+
return element;
|
|
34602
|
+
}
|
|
34603
|
+
const clone = {
|
|
34604
|
+
...element,
|
|
34605
|
+
chartData: structuredClone(element.chartData),
|
|
34606
|
+
};
|
|
34607
|
+
mutate(clone);
|
|
34608
|
+
return clone;
|
|
34609
|
+
}
|
|
34610
|
+
// ---------------------------------------------------------------------------
|
|
34611
|
+
// Chart title
|
|
34612
|
+
// ---------------------------------------------------------------------------
|
|
34613
|
+
/** Set the chart title text. */
|
|
34614
|
+
function setTitle(element, title) {
|
|
34615
|
+
return withClonedChart$1(element, (el) => setChartTitle(el, title));
|
|
34616
|
+
}
|
|
34617
|
+
// ---------------------------------------------------------------------------
|
|
34618
|
+
// Legend
|
|
34619
|
+
// ---------------------------------------------------------------------------
|
|
34620
|
+
/** Show/hide the chart legend and/or set its position. */
|
|
34621
|
+
function setLegend(element, options) {
|
|
34622
|
+
return withClonedChart$1(element, (el) => setChartLegend(el, options));
|
|
34623
|
+
}
|
|
34624
|
+
// ---------------------------------------------------------------------------
|
|
34625
|
+
// Chart-level data labels
|
|
34626
|
+
// ---------------------------------------------------------------------------
|
|
34627
|
+
/** Toggle chart-level data labels and set their content/position. */
|
|
34628
|
+
function setDataLabels(element, edit) {
|
|
34629
|
+
return withClonedChart$1(element, (el) => setChartDataLabels(el, edit));
|
|
34630
|
+
}
|
|
34631
|
+
// ---------------------------------------------------------------------------
|
|
34632
|
+
// Axis scale / number format / gridline visibility / tick labels / units
|
|
34633
|
+
// ---------------------------------------------------------------------------
|
|
34634
|
+
/** Edit value/category axis formatting (min/max/units/format/gridlines/etc.). */
|
|
34635
|
+
function setAxis(element, axisType, edit) {
|
|
34636
|
+
return withClonedChart$1(element, (el) => setChartAxis(el, axisType, edit));
|
|
34637
|
+
}
|
|
34638
|
+
// ---------------------------------------------------------------------------
|
|
34639
|
+
// Per-series trendlines / error bars
|
|
34640
|
+
// ---------------------------------------------------------------------------
|
|
34641
|
+
/** Set or clear the primary trendline on a series. */
|
|
34642
|
+
function setSeriesTrendline(element, seriesIndex, trendline) {
|
|
34643
|
+
return withClonedChart$1(element, (el) => setChartSeriesTrendline(el, seriesIndex, trendline));
|
|
34644
|
+
}
|
|
34645
|
+
/** Set or clear the error bars on a series. */
|
|
34646
|
+
function setSeriesErrorBars(element, seriesIndex, errBars) {
|
|
34647
|
+
return withClonedChart$1(element, (el) => setChartSeriesErrorBars(el, seriesIndex, errBars));
|
|
34648
|
+
}
|
|
34649
|
+
// ---------------------------------------------------------------------------
|
|
34650
|
+
// Per-data-point label overrides
|
|
34651
|
+
// ---------------------------------------------------------------------------
|
|
34652
|
+
/** Set or clear a single data point's label override. */
|
|
34653
|
+
function setDataPointLabel(element, seriesIndex, pointIndex, edit) {
|
|
34654
|
+
return withClonedChart$1(element, (el) => setChartDataPointLabel(el, seriesIndex, pointIndex, edit));
|
|
34655
|
+
}
|
|
34656
|
+
|
|
34657
|
+
/**
|
|
34658
|
+
* chart-editor-styles.ts: Shared CSS string for the advanced chart-editor
|
|
34659
|
+
* inspector control components. Each control component reuses the same
|
|
34660
|
+
* `pptx-chart-card` look (heading, rows, inputs, swatches) so the panel reads
|
|
34661
|
+
* as one cohesive section. Kept as a single exported template-literal so the
|
|
34662
|
+
* styling lives in one place rather than being copy-pasted per component.
|
|
34663
|
+
*
|
|
34664
|
+
* @module angular-viewer/chart-editor-styles
|
|
34665
|
+
*/
|
|
34666
|
+
/** Shared styles for all chart-editor control components. */
|
|
34667
|
+
const CHART_EDITOR_STYLES = `
|
|
34668
|
+
.pptx-chart-card {
|
|
34669
|
+
display: flex;
|
|
34670
|
+
flex-direction: column;
|
|
34671
|
+
gap: 0.35rem;
|
|
34672
|
+
padding: 0.5rem 0;
|
|
34673
|
+
border-top: 1px solid var(--pptx-inspector-border, #333);
|
|
34674
|
+
}
|
|
34675
|
+
|
|
34676
|
+
.pptx-chart-card__heading {
|
|
34677
|
+
font-size: 10px;
|
|
34678
|
+
font-weight: 600;
|
|
34679
|
+
text-transform: uppercase;
|
|
34680
|
+
letter-spacing: 0.05em;
|
|
34681
|
+
color: var(--pptx-inspector-muted, #888);
|
|
34682
|
+
margin: 0;
|
|
34683
|
+
}
|
|
34684
|
+
|
|
34685
|
+
.pptx-chart-card__group {
|
|
34686
|
+
display: flex;
|
|
34687
|
+
flex-direction: column;
|
|
34688
|
+
gap: 0.3rem;
|
|
34689
|
+
}
|
|
34690
|
+
|
|
34691
|
+
.pptx-chart-card__group--indent {
|
|
34692
|
+
margin-left: 0.5rem;
|
|
34693
|
+
}
|
|
34694
|
+
|
|
34695
|
+
.pptx-chart-card__subhead {
|
|
34696
|
+
font-size: 11px;
|
|
34697
|
+
font-weight: 600;
|
|
34698
|
+
}
|
|
34699
|
+
|
|
34700
|
+
.pptx-chart-card__row {
|
|
34701
|
+
display: flex;
|
|
34702
|
+
align-items: center;
|
|
34703
|
+
gap: 0.4rem;
|
|
34704
|
+
font-size: 11px;
|
|
34705
|
+
}
|
|
34706
|
+
|
|
34707
|
+
.pptx-chart-card__label {
|
|
34708
|
+
flex: 0 0 auto;
|
|
34709
|
+
width: 5rem;
|
|
34710
|
+
color: var(--pptx-inspector-muted, #888);
|
|
34711
|
+
}
|
|
34712
|
+
|
|
34713
|
+
.pptx-chart-card__label--wide {
|
|
34714
|
+
width: 6.5rem;
|
|
34715
|
+
}
|
|
34716
|
+
|
|
34717
|
+
.pptx-chart-card__name {
|
|
34718
|
+
flex: 1 1 auto;
|
|
34719
|
+
min-width: 0;
|
|
34720
|
+
overflow: hidden;
|
|
34721
|
+
text-overflow: ellipsis;
|
|
34722
|
+
white-space: nowrap;
|
|
34723
|
+
}
|
|
34724
|
+
|
|
34725
|
+
.pptx-chart-card__check {
|
|
34726
|
+
display: flex;
|
|
34727
|
+
align-items: center;
|
|
34728
|
+
gap: 0.35rem;
|
|
34729
|
+
font-size: 11px;
|
|
34730
|
+
cursor: pointer;
|
|
34731
|
+
}
|
|
34732
|
+
|
|
34733
|
+
.pptx-chart-card__input {
|
|
34734
|
+
flex: 1 1 auto;
|
|
34735
|
+
min-width: 0;
|
|
34736
|
+
box-sizing: border-box;
|
|
34737
|
+
padding: 2px 4px;
|
|
34738
|
+
font-size: 11px;
|
|
34739
|
+
background: var(--pptx-inspector-input-bg, #2d2d2d);
|
|
34740
|
+
border: 1px solid var(--pptx-inspector-border, #444);
|
|
34741
|
+
border-radius: 3px;
|
|
34742
|
+
color: inherit;
|
|
34743
|
+
outline: none;
|
|
34744
|
+
}
|
|
34745
|
+
|
|
34746
|
+
.pptx-chart-card__input--num {
|
|
34747
|
+
flex: 0 0 auto;
|
|
34748
|
+
width: 4rem;
|
|
34749
|
+
text-align: right;
|
|
34750
|
+
}
|
|
34751
|
+
|
|
34752
|
+
.pptx-chart-card__input:focus {
|
|
34753
|
+
border-color: var(--pptx-inspector-active, #0078d4);
|
|
34754
|
+
}
|
|
34755
|
+
|
|
34756
|
+
.pptx-chart-card__input:disabled {
|
|
34757
|
+
opacity: 0.6;
|
|
34758
|
+
cursor: not-allowed;
|
|
34759
|
+
}
|
|
34760
|
+
|
|
34761
|
+
.pptx-chart-card__color {
|
|
34762
|
+
flex: 0 0 auto;
|
|
34763
|
+
width: 26px;
|
|
34764
|
+
height: 20px;
|
|
34765
|
+
padding: 0;
|
|
34766
|
+
border: 1px solid var(--pptx-inspector-border, #444);
|
|
34767
|
+
border-radius: 3px;
|
|
34768
|
+
background: transparent;
|
|
34769
|
+
cursor: pointer;
|
|
34770
|
+
}
|
|
34771
|
+
|
|
34772
|
+
.pptx-chart-card__color:disabled {
|
|
34773
|
+
opacity: 0.6;
|
|
34774
|
+
cursor: not-allowed;
|
|
34775
|
+
}
|
|
34776
|
+
|
|
34777
|
+
.pptx-chart-card__clear {
|
|
34778
|
+
flex: 0 0 auto;
|
|
34779
|
+
padding: 0 2px;
|
|
34780
|
+
font-size: 12px;
|
|
34781
|
+
line-height: 1;
|
|
34782
|
+
background: none;
|
|
34783
|
+
border: none;
|
|
34784
|
+
color: var(--pptx-inspector-muted, #888);
|
|
34785
|
+
cursor: pointer;
|
|
34786
|
+
}
|
|
34787
|
+
|
|
34788
|
+
.pptx-chart-card__clear:hover {
|
|
34789
|
+
color: var(--pptx-inspector-danger, #f47c7c);
|
|
34790
|
+
}
|
|
34791
|
+
|
|
34792
|
+
.pptx-chart-card__input--num::-webkit-outer-spin-button,
|
|
34793
|
+
.pptx-chart-card__input--num::-webkit-inner-spin-button {
|
|
34794
|
+
-webkit-appearance: none;
|
|
34795
|
+
margin: 0;
|
|
34796
|
+
}
|
|
34797
|
+
`;
|
|
34798
|
+
|
|
34799
|
+
/**
|
|
34800
|
+
* chart-event-helpers.ts: Small typed DOM-event readers shared by the chart
|
|
34801
|
+
* inspector control components. They narrow `event.target` to the right element
|
|
34802
|
+
* type and pull the value out, returning `null` when the target is unexpected so
|
|
34803
|
+
* callers can bail without firing a no-op edit.
|
|
34804
|
+
*
|
|
34805
|
+
* @module angular-viewer/chart-event-helpers
|
|
34806
|
+
*/
|
|
34807
|
+
/** Read the string value from an `<input>` or `<select>` change/input event. */
|
|
34808
|
+
function stringFromEvent$5(event) {
|
|
34809
|
+
const target = event.target;
|
|
34810
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLSelectElement) {
|
|
34811
|
+
return target.value;
|
|
34812
|
+
}
|
|
34813
|
+
return null;
|
|
34814
|
+
}
|
|
34815
|
+
/** Read the value from a `<select>` change event. */
|
|
34816
|
+
function selectValue$1(event) {
|
|
34817
|
+
const target = event.target;
|
|
34818
|
+
return target instanceof HTMLSelectElement ? target.value : null;
|
|
34819
|
+
}
|
|
34820
|
+
/** Read the checked state from a checkbox `<input>` change event. */
|
|
34821
|
+
function boolFromEvent(event) {
|
|
34822
|
+
const target = event.target;
|
|
34823
|
+
return target instanceof HTMLInputElement ? target.checked : false;
|
|
34824
|
+
}
|
|
34825
|
+
/**
|
|
34826
|
+
* Read a numeric value from an `<input type="number">`. Returns `null` for an
|
|
34827
|
+
* empty field (a "clear the override" signal) and `undefined` for a non-finite
|
|
34828
|
+
* entry (ignore). A finite parse returns the number.
|
|
34829
|
+
*/
|
|
34830
|
+
function numFromEvent(event) {
|
|
34831
|
+
const raw = stringFromEvent$5(event);
|
|
34832
|
+
if (raw === null || raw === '') {
|
|
34833
|
+
return null;
|
|
34834
|
+
}
|
|
34835
|
+
const num = Number.parseFloat(raw);
|
|
34836
|
+
return Number.isFinite(num) ? num : undefined;
|
|
34837
|
+
}
|
|
34838
|
+
|
|
34839
|
+
/**
|
|
34840
|
+
* chart-axis-options.component.ts: Per-axis scale + label formatting controls.
|
|
34841
|
+
*
|
|
34842
|
+
* Selector: `pptx-chart-axis-options`
|
|
34843
|
+
*
|
|
34844
|
+
* Mirrors React's `ChartAxisOptions.tsx`: for each axis present on the chart it
|
|
34845
|
+
* exposes min/max/major-unit/minor-unit (scaled axes only), display units, axis
|
|
34846
|
+
* title text, number format, tick-label position, and major/minor gridline
|
|
34847
|
+
* visibility. Edits route through the headless `setChartAxis` core op (via the
|
|
34848
|
+
* `setAxis` immutable wrapper) and emit a new `ChartPptxElement`.
|
|
34849
|
+
*
|
|
34850
|
+
* @module angular-viewer/chart-axis-options
|
|
34851
|
+
*/
|
|
34852
|
+
const AXIS_DEFS$1 = [
|
|
34853
|
+
{ type: 'valAx', label: 'Value axis', hasScale: true },
|
|
34854
|
+
{ type: 'dateAx', label: 'Date axis', hasScale: true },
|
|
34855
|
+
{ type: 'catAx', label: 'Category axis', hasScale: false },
|
|
34856
|
+
];
|
|
34857
|
+
/** Numeric scale fields, paired with their label, rendered for scaled axes. */
|
|
34858
|
+
const SCALE_FIELDS = [
|
|
34859
|
+
{ key: 'min', label: 'Minimum' },
|
|
34860
|
+
{ key: 'max', label: 'Maximum' },
|
|
34861
|
+
{ key: 'majorUnit', label: 'Major unit' },
|
|
34862
|
+
{ key: 'minorUnit', label: 'Minor unit' },
|
|
34863
|
+
];
|
|
34864
|
+
class ChartAxisOptionsComponent {
|
|
34865
|
+
element = input.required(/* @ts-ignore */
|
|
34866
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
34867
|
+
canEdit = input(true, /* @ts-ignore */
|
|
34868
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
34869
|
+
elementChange = output();
|
|
34870
|
+
scaleFields = SCALE_FIELDS;
|
|
34871
|
+
displayUnitOptions = DISPLAY_UNITS_OPTIONS;
|
|
34872
|
+
tickPositionOptions = TICK_LABEL_POSITION_OPTIONS;
|
|
34873
|
+
/** Only the axes that actually exist on the chart (pie charts have none). */
|
|
34874
|
+
rows = computed(() => {
|
|
34875
|
+
const axes = this.element().chartData?.axes ?? [];
|
|
34876
|
+
const result = [];
|
|
34877
|
+
for (const def of AXIS_DEFS$1) {
|
|
34878
|
+
const axis = axes.find((a) => a.axisType === def.type);
|
|
34879
|
+
if (axis) {
|
|
34880
|
+
result.push({ ...def, axis });
|
|
34881
|
+
}
|
|
34882
|
+
}
|
|
34883
|
+
return result;
|
|
34884
|
+
}, /* @ts-ignore */
|
|
34885
|
+
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
34886
|
+
numValue(axis, key) {
|
|
34887
|
+
const value = axis[key];
|
|
34888
|
+
return value === undefined ? '' : String(value);
|
|
34889
|
+
}
|
|
34890
|
+
onScaleField(axisType, key, event) {
|
|
34891
|
+
const num = numFromEvent(event);
|
|
34892
|
+
if (num === undefined) {
|
|
34893
|
+
return;
|
|
34894
|
+
}
|
|
34895
|
+
this.emit(axisType, { [key]: num });
|
|
34896
|
+
}
|
|
34897
|
+
onDisplayUnits(axisType, event) {
|
|
34898
|
+
const value = selectValue$1(event);
|
|
34899
|
+
if (value === null) {
|
|
34900
|
+
return;
|
|
34901
|
+
}
|
|
34902
|
+
this.emit(axisType, {
|
|
34903
|
+
displayUnits: (value || null),
|
|
34904
|
+
});
|
|
34905
|
+
}
|
|
34906
|
+
onTitleText(axisType, event) {
|
|
34907
|
+
const value = stringFromEvent$5(event);
|
|
34908
|
+
if (value === null) {
|
|
34909
|
+
return;
|
|
34910
|
+
}
|
|
34911
|
+
this.emit(axisType, { title: value });
|
|
34912
|
+
}
|
|
34913
|
+
onNumberFormat(axisType, event) {
|
|
34914
|
+
const value = stringFromEvent$5(event);
|
|
34915
|
+
if (value === null) {
|
|
34916
|
+
return;
|
|
34917
|
+
}
|
|
34918
|
+
this.emit(axisType, { numberFormat: value });
|
|
34919
|
+
}
|
|
34920
|
+
onTickPosition(axisType, event) {
|
|
34921
|
+
const value = selectValue$1(event);
|
|
34922
|
+
if (value === null) {
|
|
34923
|
+
return;
|
|
34924
|
+
}
|
|
34925
|
+
this.emit(axisType, { tickLabelPosition: value });
|
|
34926
|
+
}
|
|
34927
|
+
onGridlines(axisType, which, event) {
|
|
34928
|
+
const checked = boolFromEvent(event);
|
|
34929
|
+
this.emit(axisType, which === 'major' ? { majorGridlines: checked } : { minorGridlines: checked });
|
|
34930
|
+
}
|
|
34931
|
+
emit(axisType, edit) {
|
|
34932
|
+
this.elementChange.emit(setAxis(this.element(), axisType, edit));
|
|
34933
|
+
}
|
|
34934
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartAxisOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
34935
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartAxisOptionsComponent, isStandalone: true, selector: "pptx-chart-axis-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
34936
|
+
@if (rows().length > 0) {
|
|
34937
|
+
<section class="pptx-chart-card" aria-label="Axis options">
|
|
34938
|
+
<h4 class="pptx-chart-card__heading">Axes</h4>
|
|
34939
|
+
@for (row of rows(); track row.type) {
|
|
34940
|
+
<div class="pptx-chart-card__group">
|
|
34941
|
+
<div class="pptx-chart-card__subhead">{{ row.label }}</div>
|
|
34942
|
+
<div class="pptx-chart-card__group pptx-chart-card__group--indent">
|
|
34943
|
+
@if (row.hasScale) {
|
|
34944
|
+
@for (field of scaleFields; track field.key) {
|
|
34945
|
+
<label class="pptx-chart-card__row">
|
|
34946
|
+
<span class="pptx-chart-card__label">{{ field.label }}</span>
|
|
34947
|
+
<input
|
|
34948
|
+
type="number"
|
|
34949
|
+
class="pptx-chart-card__input"
|
|
34950
|
+
placeholder="Auto"
|
|
34951
|
+
[disabled]="!canEdit()"
|
|
34952
|
+
[value]="numValue(row.axis, field.key)"
|
|
34953
|
+
(change)="onScaleField(row.type, field.key, $event)"
|
|
34954
|
+
/>
|
|
34955
|
+
</label>
|
|
34956
|
+
}
|
|
34957
|
+
<label class="pptx-chart-card__row">
|
|
34958
|
+
<span class="pptx-chart-card__label">Display units</span>
|
|
34959
|
+
<select
|
|
34960
|
+
class="pptx-chart-card__input"
|
|
34961
|
+
[disabled]="!canEdit()"
|
|
34962
|
+
[value]="row.axis.displayUnits ?? ''"
|
|
34963
|
+
(change)="onDisplayUnits(row.type, $event)"
|
|
34964
|
+
>
|
|
34965
|
+
@for (opt of displayUnitOptions; track opt.value) {
|
|
34966
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
34967
|
+
}
|
|
34968
|
+
</select>
|
|
34969
|
+
</label>
|
|
34970
|
+
}
|
|
34971
|
+
|
|
34972
|
+
<label class="pptx-chart-card__row">
|
|
34973
|
+
<span class="pptx-chart-card__label">Axis title</span>
|
|
34974
|
+
<input
|
|
34975
|
+
type="text"
|
|
34976
|
+
class="pptx-chart-card__input"
|
|
34977
|
+
placeholder="Axis title"
|
|
34978
|
+
[disabled]="!canEdit()"
|
|
34979
|
+
[value]="row.axis.titleText ?? ''"
|
|
34980
|
+
(change)="onTitleText(row.type, $event)"
|
|
34981
|
+
/>
|
|
34982
|
+
</label>
|
|
34983
|
+
|
|
34984
|
+
<label class="pptx-chart-card__row">
|
|
34985
|
+
<span class="pptx-chart-card__label">Number format</span>
|
|
34986
|
+
<input
|
|
34987
|
+
type="text"
|
|
34988
|
+
class="pptx-chart-card__input"
|
|
34989
|
+
placeholder="General"
|
|
34990
|
+
[disabled]="!canEdit()"
|
|
34991
|
+
[value]="row.axis.numFmt?.formatCode ?? ''"
|
|
34992
|
+
(change)="onNumberFormat(row.type, $event)"
|
|
34993
|
+
/>
|
|
34994
|
+
</label>
|
|
34995
|
+
|
|
34996
|
+
<label class="pptx-chart-card__row">
|
|
34997
|
+
<span class="pptx-chart-card__label">Tick labels</span>
|
|
34998
|
+
<select
|
|
34999
|
+
class="pptx-chart-card__input"
|
|
35000
|
+
[disabled]="!canEdit()"
|
|
35001
|
+
[value]="row.axis.tickLblPos ?? 'nextTo'"
|
|
35002
|
+
(change)="onTickPosition(row.type, $event)"
|
|
35003
|
+
>
|
|
35004
|
+
@for (opt of tickPositionOptions; track opt.value) {
|
|
35005
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35006
|
+
}
|
|
35007
|
+
</select>
|
|
35008
|
+
</label>
|
|
35009
|
+
|
|
35010
|
+
<label class="pptx-chart-card__check">
|
|
35011
|
+
<input
|
|
35012
|
+
type="checkbox"
|
|
35013
|
+
[disabled]="!canEdit()"
|
|
35014
|
+
[checked]="row.axis.majorGridlines ?? false"
|
|
35015
|
+
(change)="onGridlines(row.type, 'major', $event)"
|
|
35016
|
+
/>
|
|
35017
|
+
<span>Major gridlines</span>
|
|
35018
|
+
</label>
|
|
35019
|
+
<label class="pptx-chart-card__check">
|
|
35020
|
+
<input
|
|
35021
|
+
type="checkbox"
|
|
35022
|
+
[disabled]="!canEdit()"
|
|
35023
|
+
[checked]="row.axis.minorGridlines ?? false"
|
|
35024
|
+
(change)="onGridlines(row.type, 'minor', $event)"
|
|
35025
|
+
/>
|
|
35026
|
+
<span>Minor gridlines</span>
|
|
35027
|
+
</label>
|
|
35028
|
+
</div>
|
|
35029
|
+
</div>
|
|
35030
|
+
}
|
|
35031
|
+
</section>
|
|
35032
|
+
}
|
|
35033
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35034
|
+
}
|
|
35035
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartAxisOptionsComponent, decorators: [{
|
|
35036
|
+
type: Component,
|
|
35037
|
+
args: [{ selector: 'pptx-chart-axis-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
35038
|
+
@if (rows().length > 0) {
|
|
35039
|
+
<section class="pptx-chart-card" aria-label="Axis options">
|
|
35040
|
+
<h4 class="pptx-chart-card__heading">Axes</h4>
|
|
35041
|
+
@for (row of rows(); track row.type) {
|
|
35042
|
+
<div class="pptx-chart-card__group">
|
|
35043
|
+
<div class="pptx-chart-card__subhead">{{ row.label }}</div>
|
|
35044
|
+
<div class="pptx-chart-card__group pptx-chart-card__group--indent">
|
|
35045
|
+
@if (row.hasScale) {
|
|
35046
|
+
@for (field of scaleFields; track field.key) {
|
|
35047
|
+
<label class="pptx-chart-card__row">
|
|
35048
|
+
<span class="pptx-chart-card__label">{{ field.label }}</span>
|
|
35049
|
+
<input
|
|
35050
|
+
type="number"
|
|
35051
|
+
class="pptx-chart-card__input"
|
|
35052
|
+
placeholder="Auto"
|
|
35053
|
+
[disabled]="!canEdit()"
|
|
35054
|
+
[value]="numValue(row.axis, field.key)"
|
|
35055
|
+
(change)="onScaleField(row.type, field.key, $event)"
|
|
35056
|
+
/>
|
|
35057
|
+
</label>
|
|
35058
|
+
}
|
|
35059
|
+
<label class="pptx-chart-card__row">
|
|
35060
|
+
<span class="pptx-chart-card__label">Display units</span>
|
|
35061
|
+
<select
|
|
35062
|
+
class="pptx-chart-card__input"
|
|
35063
|
+
[disabled]="!canEdit()"
|
|
35064
|
+
[value]="row.axis.displayUnits ?? ''"
|
|
35065
|
+
(change)="onDisplayUnits(row.type, $event)"
|
|
35066
|
+
>
|
|
35067
|
+
@for (opt of displayUnitOptions; track opt.value) {
|
|
35068
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35069
|
+
}
|
|
35070
|
+
</select>
|
|
35071
|
+
</label>
|
|
35072
|
+
}
|
|
35073
|
+
|
|
35074
|
+
<label class="pptx-chart-card__row">
|
|
35075
|
+
<span class="pptx-chart-card__label">Axis title</span>
|
|
35076
|
+
<input
|
|
35077
|
+
type="text"
|
|
35078
|
+
class="pptx-chart-card__input"
|
|
35079
|
+
placeholder="Axis title"
|
|
35080
|
+
[disabled]="!canEdit()"
|
|
35081
|
+
[value]="row.axis.titleText ?? ''"
|
|
35082
|
+
(change)="onTitleText(row.type, $event)"
|
|
35083
|
+
/>
|
|
35084
|
+
</label>
|
|
35085
|
+
|
|
35086
|
+
<label class="pptx-chart-card__row">
|
|
35087
|
+
<span class="pptx-chart-card__label">Number format</span>
|
|
35088
|
+
<input
|
|
35089
|
+
type="text"
|
|
35090
|
+
class="pptx-chart-card__input"
|
|
35091
|
+
placeholder="General"
|
|
35092
|
+
[disabled]="!canEdit()"
|
|
35093
|
+
[value]="row.axis.numFmt?.formatCode ?? ''"
|
|
35094
|
+
(change)="onNumberFormat(row.type, $event)"
|
|
35095
|
+
/>
|
|
35096
|
+
</label>
|
|
35097
|
+
|
|
35098
|
+
<label class="pptx-chart-card__row">
|
|
35099
|
+
<span class="pptx-chart-card__label">Tick labels</span>
|
|
35100
|
+
<select
|
|
35101
|
+
class="pptx-chart-card__input"
|
|
35102
|
+
[disabled]="!canEdit()"
|
|
35103
|
+
[value]="row.axis.tickLblPos ?? 'nextTo'"
|
|
35104
|
+
(change)="onTickPosition(row.type, $event)"
|
|
35105
|
+
>
|
|
35106
|
+
@for (opt of tickPositionOptions; track opt.value) {
|
|
35107
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35108
|
+
}
|
|
35109
|
+
</select>
|
|
35110
|
+
</label>
|
|
35111
|
+
|
|
35112
|
+
<label class="pptx-chart-card__check">
|
|
35113
|
+
<input
|
|
35114
|
+
type="checkbox"
|
|
35115
|
+
[disabled]="!canEdit()"
|
|
35116
|
+
[checked]="row.axis.majorGridlines ?? false"
|
|
35117
|
+
(change)="onGridlines(row.type, 'major', $event)"
|
|
35118
|
+
/>
|
|
35119
|
+
<span>Major gridlines</span>
|
|
35120
|
+
</label>
|
|
35121
|
+
<label class="pptx-chart-card__check">
|
|
35122
|
+
<input
|
|
35123
|
+
type="checkbox"
|
|
35124
|
+
[disabled]="!canEdit()"
|
|
35125
|
+
[checked]="row.axis.minorGridlines ?? false"
|
|
35126
|
+
(change)="onGridlines(row.type, 'minor', $event)"
|
|
35127
|
+
/>
|
|
35128
|
+
<span>Minor gridlines</span>
|
|
35129
|
+
</label>
|
|
35130
|
+
</div>
|
|
35131
|
+
</div>
|
|
35132
|
+
}
|
|
35133
|
+
</section>
|
|
35134
|
+
}
|
|
35135
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
35136
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
35137
|
+
|
|
33565
35138
|
/**
|
|
33566
35139
|
* chart-data-helpers.ts: Pure immutable helpers for chart data editing.
|
|
33567
35140
|
*
|
|
@@ -33743,162 +35316,1696 @@ function removeCategory(element, catIndex) {
|
|
|
33743
35316
|
* Update a single numeric value in a chart series, returning a new
|
|
33744
35317
|
* `ChartPptxElement`.
|
|
33745
35318
|
*
|
|
33746
|
-
* Parses `rawValue` as a float. When the parsed value is not finite, the
|
|
33747
|
-
* element is returned unchanged.
|
|
35319
|
+
* Parses `rawValue` as a float. When the parsed value is not finite, the
|
|
35320
|
+
* element is returned unchanged.
|
|
35321
|
+
*
|
|
35322
|
+
* @param element - The source chart element (not mutated).
|
|
35323
|
+
* @param seriesIndex - Zero-based series index.
|
|
35324
|
+
* @param catIndex - Zero-based category (point) index.
|
|
35325
|
+
* @param rawValue - The new value as a string (from an `<input type="number">`).
|
|
35326
|
+
* @returns A new `ChartPptxElement`, or the original when the value is invalid.
|
|
35327
|
+
*
|
|
35328
|
+
* @example
|
|
35329
|
+
* ```ts
|
|
35330
|
+
* const updated = setSeriesValue(el, 0, 2, "42.5");
|
|
35331
|
+
* ```
|
|
35332
|
+
*/
|
|
35333
|
+
function setSeriesValue(element, seriesIndex, catIndex, rawValue) {
|
|
35334
|
+
const chartData = element.chartData;
|
|
35335
|
+
if (!chartData) {
|
|
35336
|
+
return element;
|
|
35337
|
+
}
|
|
35338
|
+
const num = parseFloat(rawValue);
|
|
35339
|
+
if (!Number.isFinite(num)) {
|
|
35340
|
+
return element;
|
|
35341
|
+
}
|
|
35342
|
+
return { ...element, chartData: chartDataUpdatePoint(chartData, seriesIndex, catIndex, num) };
|
|
35343
|
+
}
|
|
35344
|
+
// ---------------------------------------------------------------------------
|
|
35345
|
+
// setSeriesName
|
|
35346
|
+
// ---------------------------------------------------------------------------
|
|
35347
|
+
/**
|
|
35348
|
+
* Rename a series in a `ChartPptxElement`, returning a new element.
|
|
35349
|
+
*
|
|
35350
|
+
* @param element - The source chart element (not mutated).
|
|
35351
|
+
* @param seriesIndex - Zero-based index of the series to rename.
|
|
35352
|
+
* @param name - The new series name.
|
|
35353
|
+
* @returns A new `ChartPptxElement`.
|
|
35354
|
+
*
|
|
35355
|
+
* @example
|
|
35356
|
+
* ```ts
|
|
35357
|
+
* const updated = setSeriesName(el, 0, "Revenue");
|
|
35358
|
+
* ```
|
|
35359
|
+
*/
|
|
35360
|
+
function setSeriesName(element, seriesIndex, name) {
|
|
35361
|
+
const chartData = element.chartData;
|
|
35362
|
+
if (!chartData) {
|
|
35363
|
+
return element;
|
|
35364
|
+
}
|
|
35365
|
+
const series = chartData.series.map((s, i) => (i === seriesIndex ? { ...s, name } : s));
|
|
35366
|
+
return { ...element, chartData: { ...chartData, series } };
|
|
35367
|
+
}
|
|
35368
|
+
// ---------------------------------------------------------------------------
|
|
35369
|
+
// setCategoryLabel
|
|
35370
|
+
// ---------------------------------------------------------------------------
|
|
35371
|
+
/**
|
|
35372
|
+
* Rename a category label in a `ChartPptxElement`, returning a new element.
|
|
35373
|
+
*
|
|
35374
|
+
* @param element - The source chart element (not mutated).
|
|
35375
|
+
* @param catIndex - Zero-based index of the category to rename.
|
|
35376
|
+
* @param label - The new label text.
|
|
35377
|
+
* @returns A new `ChartPptxElement`.
|
|
35378
|
+
*
|
|
35379
|
+
* @example
|
|
35380
|
+
* ```ts
|
|
35381
|
+
* const updated = setCategoryLabel(el, 0, "Q1 2025");
|
|
35382
|
+
* ```
|
|
35383
|
+
*/
|
|
35384
|
+
function setCategoryLabel(element, catIndex, label) {
|
|
35385
|
+
const chartData = element.chartData;
|
|
35386
|
+
if (!chartData) {
|
|
35387
|
+
return element;
|
|
35388
|
+
}
|
|
35389
|
+
const categories = chartData.categories.map((c, i) => (i === catIndex ? label : c));
|
|
35390
|
+
return { ...element, chartData: { ...chartData, categories } };
|
|
35391
|
+
}
|
|
35392
|
+
// ---------------------------------------------------------------------------
|
|
35393
|
+
// setSeriesColor
|
|
35394
|
+
// ---------------------------------------------------------------------------
|
|
35395
|
+
/**
|
|
35396
|
+
* Set (or clear) the solid fill colour of a chart series, returning a new
|
|
35397
|
+
* `ChartPptxElement`. Pass a hex string (`#RRGGBB` or `RRGGBB`) to set the
|
|
35398
|
+
* colour, or `null` to clear it so the series falls back to its theme colour.
|
|
35399
|
+
*
|
|
35400
|
+
* Mirrors the headless `setChartSeriesColor` SDK op (which mutates in place)
|
|
35401
|
+
* with an immutable element-level wrapper for the inspector.
|
|
35402
|
+
*
|
|
35403
|
+
* @param element - The source chart element (not mutated).
|
|
35404
|
+
* @param seriesIndex - Zero-based index of the series to recolour.
|
|
35405
|
+
* @param color - Hex colour string, or `null` to clear.
|
|
35406
|
+
* @returns A new `ChartPptxElement`.
|
|
35407
|
+
*
|
|
35408
|
+
* @example
|
|
35409
|
+
* ```ts
|
|
35410
|
+
* const updated = setSeriesColor(el, 0, "#4472C4");
|
|
35411
|
+
* ```
|
|
35412
|
+
*/
|
|
35413
|
+
function setSeriesColor(element, seriesIndex, color) {
|
|
35414
|
+
const chartData = element.chartData;
|
|
35415
|
+
if (!chartData) {
|
|
35416
|
+
return element;
|
|
35417
|
+
}
|
|
35418
|
+
const normalized = color ? normalizeHex(color) : undefined;
|
|
35419
|
+
const series = chartData.series.map((s, i) => (i === seriesIndex ? { ...s, color: normalized } : s));
|
|
35420
|
+
return { ...element, chartData: { ...chartData, series } };
|
|
35421
|
+
}
|
|
35422
|
+
/** Normalise a hex colour to a `#`-prefixed form, trimming whitespace. */
|
|
35423
|
+
function normalizeHex(color) {
|
|
35424
|
+
const trimmed = color.trim();
|
|
35425
|
+
return trimmed.startsWith('#') ? trimmed : `#${trimmed}`;
|
|
35426
|
+
}
|
|
35427
|
+
// ---------------------------------------------------------------------------
|
|
35428
|
+
// patchChartStyle
|
|
35429
|
+
// ---------------------------------------------------------------------------
|
|
35430
|
+
/**
|
|
35431
|
+
* Merge a `Partial<PptxChartStyle>` patch into a `ChartPptxElement`,
|
|
35432
|
+
* returning a new element.
|
|
35433
|
+
*
|
|
35434
|
+
* @param element - The source chart element (not mutated).
|
|
35435
|
+
* @param patch - Style fields to merge.
|
|
35436
|
+
* @returns A new `ChartPptxElement`.
|
|
35437
|
+
*/
|
|
35438
|
+
function patchChartStyle(element, patch) {
|
|
35439
|
+
const chartData = element.chartData;
|
|
35440
|
+
if (!chartData) {
|
|
35441
|
+
return element;
|
|
35442
|
+
}
|
|
35443
|
+
return {
|
|
35444
|
+
...element,
|
|
35445
|
+
chartData: { ...chartData, style: { ...chartData.style, ...patch } },
|
|
35446
|
+
};
|
|
35447
|
+
}
|
|
35448
|
+
// ---------------------------------------------------------------------------
|
|
35449
|
+
// patchChartData
|
|
35450
|
+
// ---------------------------------------------------------------------------
|
|
35451
|
+
/**
|
|
35452
|
+
* Merge a `Partial<PptxChartData>` patch into a `ChartPptxElement`.
|
|
35453
|
+
*
|
|
35454
|
+
* When the patch contains a `chartType` change, the smart
|
|
35455
|
+
* `chartDataChangeType` helper is used so grouping and category formats
|
|
35456
|
+
* are adapted automatically.
|
|
35457
|
+
*
|
|
35458
|
+
* @param element - The source chart element (not mutated).
|
|
35459
|
+
* @param patch - Chart data fields to merge.
|
|
35460
|
+
* @returns A new `ChartPptxElement`.
|
|
35461
|
+
*/
|
|
35462
|
+
function patchChartData(element, patch) {
|
|
35463
|
+
const chartData = element.chartData;
|
|
35464
|
+
if (!chartData) {
|
|
35465
|
+
return element;
|
|
35466
|
+
}
|
|
35467
|
+
if (patch.chartType && patch.chartType !== chartData.chartType) {
|
|
35468
|
+
const adapted = chartDataChangeType(chartData, patch.chartType);
|
|
35469
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
35470
|
+
const { chartType: _ct, ...rest } = patch;
|
|
35471
|
+
return { ...element, chartData: { ...adapted, ...rest } };
|
|
35472
|
+
}
|
|
35473
|
+
return { ...element, chartData: { ...chartData, ...patch } };
|
|
35474
|
+
}
|
|
35475
|
+
|
|
35476
|
+
/**
|
|
35477
|
+
* chart-axis-style-options.component.ts: Per-axis log scaling, title font, and
|
|
35478
|
+
* gridline line styling.
|
|
35479
|
+
*
|
|
35480
|
+
* Selector: `pptx-chart-axis-style-options`
|
|
35481
|
+
*
|
|
35482
|
+
* Mirrors React's `ChartAxisStyleOptions.tsx`: logarithmic scale (value/date
|
|
35483
|
+
* axes) with a base, axis-title font family/size/bold/colour, and major/minor
|
|
35484
|
+
* gridline colour/width/dash styling (shown only when the matching gridlines are
|
|
35485
|
+
* enabled). Routes through `setAxisLogScale` / `setAxisTitleStyle` /
|
|
35486
|
+
* `setGridlineStyle` and emits a new `ChartPptxElement`.
|
|
35487
|
+
*
|
|
35488
|
+
* @module angular-viewer/chart-axis-style-options
|
|
35489
|
+
*/
|
|
35490
|
+
const AXIS_DEFS = [
|
|
35491
|
+
{ type: 'valAx', label: 'Value axis', hasScale: true },
|
|
35492
|
+
{ type: 'dateAx', label: 'Date axis', hasScale: true },
|
|
35493
|
+
{ type: 'catAx', label: 'Category axis', hasScale: false },
|
|
35494
|
+
];
|
|
35495
|
+
class ChartAxisStyleOptionsComponent {
|
|
35496
|
+
element = input.required(/* @ts-ignore */
|
|
35497
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
35498
|
+
canEdit = input(true, /* @ts-ignore */
|
|
35499
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
35500
|
+
elementChange = output();
|
|
35501
|
+
dashOptions = GRIDLINE_DASH_OPTIONS;
|
|
35502
|
+
gridlineKinds = ['major', 'minor'];
|
|
35503
|
+
rows = computed(() => {
|
|
35504
|
+
const axes = this.element().chartData?.axes ?? [];
|
|
35505
|
+
const result = [];
|
|
35506
|
+
for (const def of AXIS_DEFS) {
|
|
35507
|
+
const axis = axes.find((a) => a.axisType === def.type);
|
|
35508
|
+
if (axis) {
|
|
35509
|
+
result.push({ ...def, axis });
|
|
35510
|
+
}
|
|
35511
|
+
}
|
|
35512
|
+
return result;
|
|
35513
|
+
}, /* @ts-ignore */
|
|
35514
|
+
...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
|
|
35515
|
+
gridlineEnabled(axis, which) {
|
|
35516
|
+
return which === 'major' ? (axis.majorGridlines ?? false) : (axis.minorGridlines ?? false);
|
|
35517
|
+
}
|
|
35518
|
+
gridlineSpPr(axis, which) {
|
|
35519
|
+
return which === 'major' ? axis.majorGridlinesSpPr : axis.minorGridlinesSpPr;
|
|
35520
|
+
}
|
|
35521
|
+
onLogScale(axisType, axis, event) {
|
|
35522
|
+
this.elementChange.emit(setAxisLogScale(this.element(), axisType, {
|
|
35523
|
+
enabled: boolFromEvent(event),
|
|
35524
|
+
base: axis.logBase,
|
|
35525
|
+
}));
|
|
35526
|
+
}
|
|
35527
|
+
onLogBase(axisType, event) {
|
|
35528
|
+
const num = numFromEvent(event);
|
|
35529
|
+
if (typeof num !== 'number' || num <= 1) {
|
|
35530
|
+
return;
|
|
35531
|
+
}
|
|
35532
|
+
this.elementChange.emit(setAxisLogScale(this.element(), axisType, { enabled: true, base: num }));
|
|
35533
|
+
}
|
|
35534
|
+
onTitleFont(axisType, event) {
|
|
35535
|
+
const value = stringFromEvent$5(event);
|
|
35536
|
+
if (value === null) {
|
|
35537
|
+
return;
|
|
35538
|
+
}
|
|
35539
|
+
this.elementChange.emit(setAxisTitleStyle(this.element(), axisType, { fontFamily: value || null }));
|
|
35540
|
+
}
|
|
35541
|
+
onTitleSize(axisType, event) {
|
|
35542
|
+
const num = numFromEvent(event);
|
|
35543
|
+
if (num === undefined) {
|
|
35544
|
+
return;
|
|
35545
|
+
}
|
|
35546
|
+
this.elementChange.emit(setAxisTitleStyle(this.element(), axisType, { fontSize: num }));
|
|
35547
|
+
}
|
|
35548
|
+
onTitleBold(axisType, event) {
|
|
35549
|
+
this.elementChange.emit(setAxisTitleStyle(this.element(), axisType, { fontBold: boolFromEvent(event) }));
|
|
35550
|
+
}
|
|
35551
|
+
onTitleColor(axisType, event) {
|
|
35552
|
+
const value = stringFromEvent$5(event);
|
|
35553
|
+
if (value === null) {
|
|
35554
|
+
return;
|
|
35555
|
+
}
|
|
35556
|
+
this.elementChange.emit(setAxisTitleStyle(this.element(), axisType, { fontColor: value }));
|
|
35557
|
+
}
|
|
35558
|
+
onGridlineColor(axisType, which, event) {
|
|
35559
|
+
const value = stringFromEvent$5(event);
|
|
35560
|
+
if (value === null) {
|
|
35561
|
+
return;
|
|
35562
|
+
}
|
|
35563
|
+
this.elementChange.emit(setGridlineStyle(this.element(), axisType, which, { color: value }));
|
|
35564
|
+
}
|
|
35565
|
+
onGridlineWidth(axisType, which, event) {
|
|
35566
|
+
const num = numFromEvent(event);
|
|
35567
|
+
if (num === undefined) {
|
|
35568
|
+
return;
|
|
35569
|
+
}
|
|
35570
|
+
this.elementChange.emit(setGridlineStyle(this.element(), axisType, which, { width: num }));
|
|
35571
|
+
}
|
|
35572
|
+
onGridlineDash(axisType, which, event) {
|
|
35573
|
+
const value = selectValue$1(event);
|
|
35574
|
+
if (value === null) {
|
|
35575
|
+
return;
|
|
35576
|
+
}
|
|
35577
|
+
this.elementChange.emit(setGridlineStyle(this.element(), axisType, which, { dashStyle: value || null }));
|
|
35578
|
+
}
|
|
35579
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartAxisStyleOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
35580
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartAxisStyleOptionsComponent, isStandalone: true, selector: "pptx-chart-axis-style-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
35581
|
+
@if (rows().length > 0) {
|
|
35582
|
+
<section class="pptx-chart-card" aria-label="Axis styling">
|
|
35583
|
+
<h4 class="pptx-chart-card__heading">Axis Styling</h4>
|
|
35584
|
+
@for (row of rows(); track row.type) {
|
|
35585
|
+
<div class="pptx-chart-card__group">
|
|
35586
|
+
<div class="pptx-chart-card__subhead">{{ row.label }}</div>
|
|
35587
|
+
<div class="pptx-chart-card__group pptx-chart-card__group--indent">
|
|
35588
|
+
@if (row.hasScale) {
|
|
35589
|
+
<div class="pptx-chart-card__row">
|
|
35590
|
+
<label class="pptx-chart-card__check">
|
|
35591
|
+
<input
|
|
35592
|
+
type="checkbox"
|
|
35593
|
+
[disabled]="!canEdit()"
|
|
35594
|
+
[checked]="row.axis.logScale ?? false"
|
|
35595
|
+
(change)="onLogScale(row.type, row.axis, $event)"
|
|
35596
|
+
/>
|
|
35597
|
+
<span>Logarithmic scale</span>
|
|
35598
|
+
</label>
|
|
35599
|
+
@if (row.axis.logScale) {
|
|
35600
|
+
<input
|
|
35601
|
+
type="number"
|
|
35602
|
+
min="2"
|
|
35603
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
35604
|
+
title="Log base"
|
|
35605
|
+
[disabled]="!canEdit()"
|
|
35606
|
+
[value]="row.axis.logBase ?? 10"
|
|
35607
|
+
(change)="onLogBase(row.type, $event)"
|
|
35608
|
+
/>
|
|
35609
|
+
}
|
|
35610
|
+
</div>
|
|
35611
|
+
}
|
|
35612
|
+
|
|
35613
|
+
<div class="pptx-chart-card__row">
|
|
35614
|
+
<span class="pptx-chart-card__label">Title font</span>
|
|
35615
|
+
<input
|
|
35616
|
+
type="text"
|
|
35617
|
+
class="pptx-chart-card__input"
|
|
35618
|
+
placeholder="Auto"
|
|
35619
|
+
[disabled]="!canEdit()"
|
|
35620
|
+
[value]="row.axis.fontFamily ?? ''"
|
|
35621
|
+
(change)="onTitleFont(row.type, $event)"
|
|
35622
|
+
/>
|
|
35623
|
+
<input
|
|
35624
|
+
type="number"
|
|
35625
|
+
min="4"
|
|
35626
|
+
max="96"
|
|
35627
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
35628
|
+
title="Font size"
|
|
35629
|
+
placeholder="Auto"
|
|
35630
|
+
[disabled]="!canEdit()"
|
|
35631
|
+
[value]="row.axis.fontSize ?? ''"
|
|
35632
|
+
(change)="onTitleSize(row.type, $event)"
|
|
35633
|
+
/>
|
|
35634
|
+
</div>
|
|
35635
|
+
<div class="pptx-chart-card__row">
|
|
35636
|
+
<label class="pptx-chart-card__check">
|
|
35637
|
+
<input
|
|
35638
|
+
type="checkbox"
|
|
35639
|
+
[disabled]="!canEdit()"
|
|
35640
|
+
[checked]="row.axis.fontBold ?? false"
|
|
35641
|
+
(change)="onTitleBold(row.type, $event)"
|
|
35642
|
+
/>
|
|
35643
|
+
<span>Bold</span>
|
|
35644
|
+
</label>
|
|
35645
|
+
<span class="pptx-chart-card__label">Colour</span>
|
|
35646
|
+
<input
|
|
35647
|
+
type="color"
|
|
35648
|
+
class="pptx-chart-card__color"
|
|
35649
|
+
[disabled]="!canEdit()"
|
|
35650
|
+
[value]="row.axis.fontColor ?? '#000000'"
|
|
35651
|
+
(input)="onTitleColor(row.type, $event)"
|
|
35652
|
+
/>
|
|
35653
|
+
</div>
|
|
35654
|
+
|
|
35655
|
+
@for (which of gridlineKinds; track which) {
|
|
35656
|
+
@if (gridlineEnabled(row.axis, which)) {
|
|
35657
|
+
<div class="pptx-chart-card__row">
|
|
35658
|
+
<span class="pptx-chart-card__label">
|
|
35659
|
+
{{ which === 'major' ? 'Major lines' : 'Minor lines' }}
|
|
35660
|
+
</span>
|
|
35661
|
+
<input
|
|
35662
|
+
type="color"
|
|
35663
|
+
class="pptx-chart-card__color"
|
|
35664
|
+
title="Gridline colour"
|
|
35665
|
+
[disabled]="!canEdit()"
|
|
35666
|
+
[value]="gridlineSpPr(row.axis, which)?.strokeColor ?? '#d9d9d9'"
|
|
35667
|
+
(input)="onGridlineColor(row.type, which, $event)"
|
|
35668
|
+
/>
|
|
35669
|
+
<input
|
|
35670
|
+
type="number"
|
|
35671
|
+
min="0.25"
|
|
35672
|
+
step="0.25"
|
|
35673
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
35674
|
+
title="Gridline width"
|
|
35675
|
+
placeholder="Auto"
|
|
35676
|
+
[disabled]="!canEdit()"
|
|
35677
|
+
[value]="gridlineSpPr(row.axis, which)?.strokeWidth ?? ''"
|
|
35678
|
+
(change)="onGridlineWidth(row.type, which, $event)"
|
|
35679
|
+
/>
|
|
35680
|
+
<select
|
|
35681
|
+
class="pptx-chart-card__input"
|
|
35682
|
+
title="Gridline dash"
|
|
35683
|
+
[disabled]="!canEdit()"
|
|
35684
|
+
[value]="gridlineSpPr(row.axis, which)?.strokeDashStyle ?? ''"
|
|
35685
|
+
(change)="onGridlineDash(row.type, which, $event)"
|
|
35686
|
+
>
|
|
35687
|
+
@for (opt of dashOptions; track opt.value) {
|
|
35688
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35689
|
+
}
|
|
35690
|
+
</select>
|
|
35691
|
+
</div>
|
|
35692
|
+
}
|
|
35693
|
+
}
|
|
35694
|
+
</div>
|
|
35695
|
+
</div>
|
|
35696
|
+
}
|
|
35697
|
+
</section>
|
|
35698
|
+
}
|
|
35699
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35700
|
+
}
|
|
35701
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartAxisStyleOptionsComponent, decorators: [{
|
|
35702
|
+
type: Component,
|
|
35703
|
+
args: [{ selector: 'pptx-chart-axis-style-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
35704
|
+
@if (rows().length > 0) {
|
|
35705
|
+
<section class="pptx-chart-card" aria-label="Axis styling">
|
|
35706
|
+
<h4 class="pptx-chart-card__heading">Axis Styling</h4>
|
|
35707
|
+
@for (row of rows(); track row.type) {
|
|
35708
|
+
<div class="pptx-chart-card__group">
|
|
35709
|
+
<div class="pptx-chart-card__subhead">{{ row.label }}</div>
|
|
35710
|
+
<div class="pptx-chart-card__group pptx-chart-card__group--indent">
|
|
35711
|
+
@if (row.hasScale) {
|
|
35712
|
+
<div class="pptx-chart-card__row">
|
|
35713
|
+
<label class="pptx-chart-card__check">
|
|
35714
|
+
<input
|
|
35715
|
+
type="checkbox"
|
|
35716
|
+
[disabled]="!canEdit()"
|
|
35717
|
+
[checked]="row.axis.logScale ?? false"
|
|
35718
|
+
(change)="onLogScale(row.type, row.axis, $event)"
|
|
35719
|
+
/>
|
|
35720
|
+
<span>Logarithmic scale</span>
|
|
35721
|
+
</label>
|
|
35722
|
+
@if (row.axis.logScale) {
|
|
35723
|
+
<input
|
|
35724
|
+
type="number"
|
|
35725
|
+
min="2"
|
|
35726
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
35727
|
+
title="Log base"
|
|
35728
|
+
[disabled]="!canEdit()"
|
|
35729
|
+
[value]="row.axis.logBase ?? 10"
|
|
35730
|
+
(change)="onLogBase(row.type, $event)"
|
|
35731
|
+
/>
|
|
35732
|
+
}
|
|
35733
|
+
</div>
|
|
35734
|
+
}
|
|
35735
|
+
|
|
35736
|
+
<div class="pptx-chart-card__row">
|
|
35737
|
+
<span class="pptx-chart-card__label">Title font</span>
|
|
35738
|
+
<input
|
|
35739
|
+
type="text"
|
|
35740
|
+
class="pptx-chart-card__input"
|
|
35741
|
+
placeholder="Auto"
|
|
35742
|
+
[disabled]="!canEdit()"
|
|
35743
|
+
[value]="row.axis.fontFamily ?? ''"
|
|
35744
|
+
(change)="onTitleFont(row.type, $event)"
|
|
35745
|
+
/>
|
|
35746
|
+
<input
|
|
35747
|
+
type="number"
|
|
35748
|
+
min="4"
|
|
35749
|
+
max="96"
|
|
35750
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
35751
|
+
title="Font size"
|
|
35752
|
+
placeholder="Auto"
|
|
35753
|
+
[disabled]="!canEdit()"
|
|
35754
|
+
[value]="row.axis.fontSize ?? ''"
|
|
35755
|
+
(change)="onTitleSize(row.type, $event)"
|
|
35756
|
+
/>
|
|
35757
|
+
</div>
|
|
35758
|
+
<div class="pptx-chart-card__row">
|
|
35759
|
+
<label class="pptx-chart-card__check">
|
|
35760
|
+
<input
|
|
35761
|
+
type="checkbox"
|
|
35762
|
+
[disabled]="!canEdit()"
|
|
35763
|
+
[checked]="row.axis.fontBold ?? false"
|
|
35764
|
+
(change)="onTitleBold(row.type, $event)"
|
|
35765
|
+
/>
|
|
35766
|
+
<span>Bold</span>
|
|
35767
|
+
</label>
|
|
35768
|
+
<span class="pptx-chart-card__label">Colour</span>
|
|
35769
|
+
<input
|
|
35770
|
+
type="color"
|
|
35771
|
+
class="pptx-chart-card__color"
|
|
35772
|
+
[disabled]="!canEdit()"
|
|
35773
|
+
[value]="row.axis.fontColor ?? '#000000'"
|
|
35774
|
+
(input)="onTitleColor(row.type, $event)"
|
|
35775
|
+
/>
|
|
35776
|
+
</div>
|
|
35777
|
+
|
|
35778
|
+
@for (which of gridlineKinds; track which) {
|
|
35779
|
+
@if (gridlineEnabled(row.axis, which)) {
|
|
35780
|
+
<div class="pptx-chart-card__row">
|
|
35781
|
+
<span class="pptx-chart-card__label">
|
|
35782
|
+
{{ which === 'major' ? 'Major lines' : 'Minor lines' }}
|
|
35783
|
+
</span>
|
|
35784
|
+
<input
|
|
35785
|
+
type="color"
|
|
35786
|
+
class="pptx-chart-card__color"
|
|
35787
|
+
title="Gridline colour"
|
|
35788
|
+
[disabled]="!canEdit()"
|
|
35789
|
+
[value]="gridlineSpPr(row.axis, which)?.strokeColor ?? '#d9d9d9'"
|
|
35790
|
+
(input)="onGridlineColor(row.type, which, $event)"
|
|
35791
|
+
/>
|
|
35792
|
+
<input
|
|
35793
|
+
type="number"
|
|
35794
|
+
min="0.25"
|
|
35795
|
+
step="0.25"
|
|
35796
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
35797
|
+
title="Gridline width"
|
|
35798
|
+
placeholder="Auto"
|
|
35799
|
+
[disabled]="!canEdit()"
|
|
35800
|
+
[value]="gridlineSpPr(row.axis, which)?.strokeWidth ?? ''"
|
|
35801
|
+
(change)="onGridlineWidth(row.type, which, $event)"
|
|
35802
|
+
/>
|
|
35803
|
+
<select
|
|
35804
|
+
class="pptx-chart-card__input"
|
|
35805
|
+
title="Gridline dash"
|
|
35806
|
+
[disabled]="!canEdit()"
|
|
35807
|
+
[value]="gridlineSpPr(row.axis, which)?.strokeDashStyle ?? ''"
|
|
35808
|
+
(change)="onGridlineDash(row.type, which, $event)"
|
|
35809
|
+
>
|
|
35810
|
+
@for (opt of dashOptions; track opt.value) {
|
|
35811
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35812
|
+
}
|
|
35813
|
+
</select>
|
|
35814
|
+
</div>
|
|
35815
|
+
}
|
|
35816
|
+
}
|
|
35817
|
+
</div>
|
|
35818
|
+
</div>
|
|
35819
|
+
}
|
|
35820
|
+
</section>
|
|
35821
|
+
}
|
|
35822
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
35823
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
35824
|
+
|
|
35825
|
+
/**
|
|
35826
|
+
* chart-combo-type-options.component.ts: Per-series combo chart-type controls.
|
|
35827
|
+
*
|
|
35828
|
+
* Selector: `pptx-chart-combo-type-options`
|
|
35829
|
+
*
|
|
35830
|
+
* Mirrors React's `ChartComboTypeOptions.tsx`: for cartesian charts (and existing
|
|
35831
|
+
* combos) with 2+ series, each series gets a chart-type selector so it can be
|
|
35832
|
+
* plotted with a different type (e.g. a line series inside a bar chart). Routes
|
|
35833
|
+
* through the `setSeriesChartType` immutable wrapper and emits a new
|
|
35834
|
+
* `ChartPptxElement`.
|
|
35835
|
+
*
|
|
35836
|
+
* @module angular-viewer/chart-combo-type-options
|
|
35837
|
+
*/
|
|
35838
|
+
class ChartComboTypeOptionsComponent {
|
|
35839
|
+
element = input.required(/* @ts-ignore */
|
|
35840
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
35841
|
+
canEdit = input(true, /* @ts-ignore */
|
|
35842
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
35843
|
+
elementChange = output();
|
|
35844
|
+
typeOptions = COMBO_SERIES_TYPE_OPTIONS;
|
|
35845
|
+
series = computed(() => this.element().chartData?.series ?? [], /* @ts-ignore */
|
|
35846
|
+
...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
|
|
35847
|
+
supported = computed(() => {
|
|
35848
|
+
const type = this.element().chartData?.chartType;
|
|
35849
|
+
return type !== undefined && COMBO_SUPPORTED_TYPES.has(type) && this.series().length >= 2;
|
|
35850
|
+
}, /* @ts-ignore */
|
|
35851
|
+
...(ngDevMode ? [{ debugName: "supported" }] : /* istanbul ignore next */ []));
|
|
35852
|
+
onType(index, event) {
|
|
35853
|
+
const value = selectValue$1(event);
|
|
35854
|
+
if (value === null) {
|
|
35855
|
+
return;
|
|
35856
|
+
}
|
|
35857
|
+
this.elementChange.emit(setSeriesChartType(this.element(), index, value === '' ? null : value));
|
|
35858
|
+
}
|
|
35859
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartComboTypeOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
35860
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartComboTypeOptionsComponent, isStandalone: true, selector: "pptx-chart-combo-type-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
35861
|
+
@if (supported()) {
|
|
35862
|
+
<section class="pptx-chart-card" aria-label="Combo type options">
|
|
35863
|
+
<h4 class="pptx-chart-card__heading">Combo Types</h4>
|
|
35864
|
+
<div class="pptx-chart-card__group">
|
|
35865
|
+
@for (s of series(); track $index; let i = $index) {
|
|
35866
|
+
<div class="pptx-chart-card__row">
|
|
35867
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
35868
|
+
<select
|
|
35869
|
+
class="pptx-chart-card__input"
|
|
35870
|
+
[disabled]="!canEdit()"
|
|
35871
|
+
[value]="s.seriesChartType ?? ''"
|
|
35872
|
+
(change)="onType(i, $event)"
|
|
35873
|
+
>
|
|
35874
|
+
@for (opt of typeOptions; track opt.value) {
|
|
35875
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35876
|
+
}
|
|
35877
|
+
</select>
|
|
35878
|
+
</div>
|
|
35879
|
+
}
|
|
35880
|
+
</div>
|
|
35881
|
+
</section>
|
|
35882
|
+
}
|
|
35883
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35884
|
+
}
|
|
35885
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartComboTypeOptionsComponent, decorators: [{
|
|
35886
|
+
type: Component,
|
|
35887
|
+
args: [{ selector: 'pptx-chart-combo-type-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
35888
|
+
@if (supported()) {
|
|
35889
|
+
<section class="pptx-chart-card" aria-label="Combo type options">
|
|
35890
|
+
<h4 class="pptx-chart-card__heading">Combo Types</h4>
|
|
35891
|
+
<div class="pptx-chart-card__group">
|
|
35892
|
+
@for (s of series(); track $index; let i = $index) {
|
|
35893
|
+
<div class="pptx-chart-card__row">
|
|
35894
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
35895
|
+
<select
|
|
35896
|
+
class="pptx-chart-card__input"
|
|
35897
|
+
[disabled]="!canEdit()"
|
|
35898
|
+
[value]="s.seriesChartType ?? ''"
|
|
35899
|
+
(change)="onType(i, $event)"
|
|
35900
|
+
>
|
|
35901
|
+
@for (opt of typeOptions; track opt.value) {
|
|
35902
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35903
|
+
}
|
|
35904
|
+
</select>
|
|
35905
|
+
</div>
|
|
35906
|
+
}
|
|
35907
|
+
</div>
|
|
35908
|
+
</section>
|
|
35909
|
+
}
|
|
35910
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
35911
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
35912
|
+
|
|
35913
|
+
/**
|
|
35914
|
+
* chart-data-label-options.component.ts: Chart-level data-label content +
|
|
35915
|
+
* position controls.
|
|
35916
|
+
*
|
|
35917
|
+
* Selector: `pptx-chart-data-label-options`
|
|
35918
|
+
*
|
|
35919
|
+
* Mirrors React's `ChartDataLabelOptions.tsx`: only renders when data labels are
|
|
35920
|
+
* switched on (the master toggle lives in `pptx-chart-display-options`). Lets the
|
|
35921
|
+
* user pick which content appears (value/category/series name/percent/legend key)
|
|
35922
|
+
* and the label position. Emits a complete new `ChartPptxElement`.
|
|
35923
|
+
*
|
|
35924
|
+
* @module angular-viewer/chart-data-label-options
|
|
35925
|
+
*/
|
|
35926
|
+
class ChartDataLabelOptionsComponent {
|
|
35927
|
+
element = input.required(/* @ts-ignore */
|
|
35928
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
35929
|
+
canEdit = input(true, /* @ts-ignore */
|
|
35930
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
35931
|
+
elementChange = output();
|
|
35932
|
+
contentOptions = DATA_LABEL_CONTENT_OPTIONS;
|
|
35933
|
+
positionOptions = DATA_LABEL_POSITION_OPTIONS;
|
|
35934
|
+
style = computed(() => this.element().chartData?.style ?? {}, /* @ts-ignore */
|
|
35935
|
+
...(ngDevMode ? [{ debugName: "style" }] : /* istanbul ignore next */ []));
|
|
35936
|
+
labels = computed(() => this.style().dataLabels ?? {}, /* @ts-ignore */
|
|
35937
|
+
...(ngDevMode ? [{ debugName: "labels" }] : /* istanbul ignore next */ []));
|
|
35938
|
+
onToggleContent(key, event) {
|
|
35939
|
+
this.elementChange.emit(setDataLabels(this.element(), { [key]: boolFromEvent(event) }));
|
|
35940
|
+
}
|
|
35941
|
+
onPosition(event) {
|
|
35942
|
+
const value = selectValue$1(event);
|
|
35943
|
+
if (value === null) {
|
|
35944
|
+
return;
|
|
35945
|
+
}
|
|
35946
|
+
this.elementChange.emit(setDataLabels(this.element(), {
|
|
35947
|
+
position: (value || undefined),
|
|
35948
|
+
}));
|
|
35949
|
+
}
|
|
35950
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDataLabelOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
35951
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartDataLabelOptionsComponent, isStandalone: true, selector: "pptx-chart-data-label-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
35952
|
+
@if (style().hasDataLabels) {
|
|
35953
|
+
<section class="pptx-chart-card" aria-label="Data label options">
|
|
35954
|
+
<h4 class="pptx-chart-card__heading">Data Labels</h4>
|
|
35955
|
+
<div class="pptx-chart-card__group">
|
|
35956
|
+
@for (opt of contentOptions; track opt.key) {
|
|
35957
|
+
<label class="pptx-chart-card__check">
|
|
35958
|
+
<input
|
|
35959
|
+
type="checkbox"
|
|
35960
|
+
[disabled]="!canEdit()"
|
|
35961
|
+
[checked]="labels()[opt.key] ?? false"
|
|
35962
|
+
(change)="onToggleContent(opt.key, $event)"
|
|
35963
|
+
/>
|
|
35964
|
+
<span>{{ opt.label }}</span>
|
|
35965
|
+
</label>
|
|
35966
|
+
}
|
|
35967
|
+
|
|
35968
|
+
<label class="pptx-chart-card__row">
|
|
35969
|
+
<span class="pptx-chart-card__label">Position</span>
|
|
35970
|
+
<select
|
|
35971
|
+
class="pptx-chart-card__input"
|
|
35972
|
+
[disabled]="!canEdit()"
|
|
35973
|
+
[value]="labels().position ?? ''"
|
|
35974
|
+
(change)="onPosition($event)"
|
|
35975
|
+
>
|
|
35976
|
+
@for (opt of positionOptions; track opt.value) {
|
|
35977
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
35978
|
+
}
|
|
35979
|
+
</select>
|
|
35980
|
+
</label>
|
|
35981
|
+
</div>
|
|
35982
|
+
</section>
|
|
35983
|
+
}
|
|
35984
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
35985
|
+
}
|
|
35986
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDataLabelOptionsComponent, decorators: [{
|
|
35987
|
+
type: Component,
|
|
35988
|
+
args: [{ selector: 'pptx-chart-data-label-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
35989
|
+
@if (style().hasDataLabels) {
|
|
35990
|
+
<section class="pptx-chart-card" aria-label="Data label options">
|
|
35991
|
+
<h4 class="pptx-chart-card__heading">Data Labels</h4>
|
|
35992
|
+
<div class="pptx-chart-card__group">
|
|
35993
|
+
@for (opt of contentOptions; track opt.key) {
|
|
35994
|
+
<label class="pptx-chart-card__check">
|
|
35995
|
+
<input
|
|
35996
|
+
type="checkbox"
|
|
35997
|
+
[disabled]="!canEdit()"
|
|
35998
|
+
[checked]="labels()[opt.key] ?? false"
|
|
35999
|
+
(change)="onToggleContent(opt.key, $event)"
|
|
36000
|
+
/>
|
|
36001
|
+
<span>{{ opt.label }}</span>
|
|
36002
|
+
</label>
|
|
36003
|
+
}
|
|
36004
|
+
|
|
36005
|
+
<label class="pptx-chart-card__row">
|
|
36006
|
+
<span class="pptx-chart-card__label">Position</span>
|
|
36007
|
+
<select
|
|
36008
|
+
class="pptx-chart-card__input"
|
|
36009
|
+
[disabled]="!canEdit()"
|
|
36010
|
+
[value]="labels().position ?? ''"
|
|
36011
|
+
(change)="onPosition($event)"
|
|
36012
|
+
>
|
|
36013
|
+
@for (opt of positionOptions; track opt.value) {
|
|
36014
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36015
|
+
}
|
|
36016
|
+
</select>
|
|
36017
|
+
</label>
|
|
36018
|
+
</div>
|
|
36019
|
+
</section>
|
|
36020
|
+
}
|
|
36021
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
36022
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
36023
|
+
|
|
36024
|
+
/**
|
|
36025
|
+
* chart-datapoint-options.component.ts: Per-data-point fill + slice explosion.
|
|
36026
|
+
*
|
|
36027
|
+
* Selector: `pptx-chart-datapoint-options`
|
|
36028
|
+
*
|
|
36029
|
+
* Mirrors React's `ChartDataPointOptions.tsx`: a series picker (per-point edits
|
|
36030
|
+
* target one series at a time) and, per category, a fill-colour override (with a
|
|
36031
|
+
* clear button) plus a pie/doughnut slice-explosion amount for the chart types
|
|
36032
|
+
* that support it. Routes through `setDataPointFill` / `setDataPointExplosion`
|
|
36033
|
+
* and emits a new `ChartPptxElement`.
|
|
36034
|
+
*
|
|
36035
|
+
* @module angular-viewer/chart-datapoint-options
|
|
36036
|
+
*/
|
|
36037
|
+
class ChartDatapointOptionsComponent {
|
|
36038
|
+
element = input.required(/* @ts-ignore */
|
|
36039
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
36040
|
+
canEdit = input(true, /* @ts-ignore */
|
|
36041
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
36042
|
+
elementChange = output();
|
|
36043
|
+
seriesIndex = signal(0, /* @ts-ignore */
|
|
36044
|
+
...(ngDevMode ? [{ debugName: "seriesIndex" }] : /* istanbul ignore next */ []));
|
|
36045
|
+
series = computed(() => this.element().chartData?.series ?? [], /* @ts-ignore */
|
|
36046
|
+
...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
|
|
36047
|
+
categories = computed(() => this.element().chartData?.categories ?? [], /* @ts-ignore */
|
|
36048
|
+
...(ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []));
|
|
36049
|
+
/** Clamp the chosen series index to the current series count. */
|
|
36050
|
+
activeIndex = computed(() => Math.min(this.seriesIndex(), Math.max(0, this.series().length - 1)), /* @ts-ignore */
|
|
36051
|
+
...(ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []));
|
|
36052
|
+
showExplosion = computed(() => {
|
|
36053
|
+
const type = this.element().chartData?.chartType;
|
|
36054
|
+
return type !== undefined && EXPLOSION_SUPPORTED_TYPES.has(type);
|
|
36055
|
+
}, /* @ts-ignore */
|
|
36056
|
+
...(ngDevMode ? [{ debugName: "showExplosion" }] : /* istanbul ignore next */ []));
|
|
36057
|
+
pointAt(pointIndex) {
|
|
36058
|
+
return this.series()[this.activeIndex()]?.dataPoints?.find((p) => p.idx === pointIndex);
|
|
36059
|
+
}
|
|
36060
|
+
pointFill(pointIndex) {
|
|
36061
|
+
const active = this.series()[this.activeIndex()];
|
|
36062
|
+
return this.pointAt(pointIndex)?.spPr?.fillColor ?? active?.color ?? '#4472c4';
|
|
36063
|
+
}
|
|
36064
|
+
onSeries(event) {
|
|
36065
|
+
const value = selectValue$1(event);
|
|
36066
|
+
if (value === null) {
|
|
36067
|
+
return;
|
|
36068
|
+
}
|
|
36069
|
+
const num = Number.parseInt(value, 10);
|
|
36070
|
+
if (Number.isFinite(num)) {
|
|
36071
|
+
this.seriesIndex.set(num);
|
|
36072
|
+
}
|
|
36073
|
+
}
|
|
36074
|
+
onFill(pointIndex, event) {
|
|
36075
|
+
const value = stringFromEvent$5(event);
|
|
36076
|
+
if (value === null) {
|
|
36077
|
+
return;
|
|
36078
|
+
}
|
|
36079
|
+
this.elementChange.emit(setDataPointFill(this.element(), this.activeIndex(), pointIndex, value));
|
|
36080
|
+
}
|
|
36081
|
+
onClearFill(pointIndex) {
|
|
36082
|
+
this.elementChange.emit(setDataPointFill(this.element(), this.activeIndex(), pointIndex, null));
|
|
36083
|
+
}
|
|
36084
|
+
onExplosion(pointIndex, event) {
|
|
36085
|
+
const num = numFromEvent(event);
|
|
36086
|
+
if (num === undefined) {
|
|
36087
|
+
return;
|
|
36088
|
+
}
|
|
36089
|
+
this.elementChange.emit(setDataPointExplosion(this.element(), this.activeIndex(), pointIndex, num));
|
|
36090
|
+
}
|
|
36091
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDatapointOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
36092
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartDatapointOptionsComponent, isStandalone: true, selector: "pptx-chart-datapoint-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
36093
|
+
@if (categories().length > 0 && series().length > 0) {
|
|
36094
|
+
<section class="pptx-chart-card" aria-label="Data point options">
|
|
36095
|
+
<h4 class="pptx-chart-card__heading">Data Points</h4>
|
|
36096
|
+
|
|
36097
|
+
@if (series().length > 1) {
|
|
36098
|
+
<label class="pptx-chart-card__row">
|
|
36099
|
+
<span class="pptx-chart-card__label">Series</span>
|
|
36100
|
+
<select
|
|
36101
|
+
class="pptx-chart-card__input"
|
|
36102
|
+
[disabled]="!canEdit()"
|
|
36103
|
+
[value]="activeIndex()"
|
|
36104
|
+
(change)="onSeries($event)"
|
|
36105
|
+
>
|
|
36106
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36107
|
+
<option [value]="i">{{ s.name }}</option>
|
|
36108
|
+
}
|
|
36109
|
+
</select>
|
|
36110
|
+
</label>
|
|
36111
|
+
}
|
|
36112
|
+
|
|
36113
|
+
<div class="pptx-chart-card__group">
|
|
36114
|
+
@for (cat of categories(); track $index; let ci = $index) {
|
|
36115
|
+
<div class="pptx-chart-card__row">
|
|
36116
|
+
<span class="pptx-chart-card__name" [title]="cat">{{ cat }}</span>
|
|
36117
|
+
<input
|
|
36118
|
+
type="color"
|
|
36119
|
+
class="pptx-chart-card__color"
|
|
36120
|
+
title="Point fill"
|
|
36121
|
+
[disabled]="!canEdit()"
|
|
36122
|
+
[value]="pointFill(ci)"
|
|
36123
|
+
(input)="onFill(ci, $event)"
|
|
36124
|
+
/>
|
|
36125
|
+
@if (pointAt(ci)?.spPr?.fillColor) {
|
|
36126
|
+
<button
|
|
36127
|
+
type="button"
|
|
36128
|
+
class="pptx-chart-card__clear"
|
|
36129
|
+
title="Clear point fill"
|
|
36130
|
+
[disabled]="!canEdit()"
|
|
36131
|
+
(click)="onClearFill(ci)"
|
|
36132
|
+
>
|
|
36133
|
+
×
|
|
36134
|
+
</button>
|
|
36135
|
+
}
|
|
36136
|
+
@if (showExplosion()) {
|
|
36137
|
+
<input
|
|
36138
|
+
type="number"
|
|
36139
|
+
min="0"
|
|
36140
|
+
max="100"
|
|
36141
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
36142
|
+
title="Slice explosion"
|
|
36143
|
+
placeholder="0"
|
|
36144
|
+
[disabled]="!canEdit()"
|
|
36145
|
+
[value]="pointAt(ci)?.explosion ?? ''"
|
|
36146
|
+
(change)="onExplosion(ci, $event)"
|
|
36147
|
+
/>
|
|
36148
|
+
}
|
|
36149
|
+
</div>
|
|
36150
|
+
}
|
|
36151
|
+
</div>
|
|
36152
|
+
</section>
|
|
36153
|
+
}
|
|
36154
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
36155
|
+
}
|
|
36156
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDatapointOptionsComponent, decorators: [{
|
|
36157
|
+
type: Component,
|
|
36158
|
+
args: [{ selector: 'pptx-chart-datapoint-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
36159
|
+
@if (categories().length > 0 && series().length > 0) {
|
|
36160
|
+
<section class="pptx-chart-card" aria-label="Data point options">
|
|
36161
|
+
<h4 class="pptx-chart-card__heading">Data Points</h4>
|
|
36162
|
+
|
|
36163
|
+
@if (series().length > 1) {
|
|
36164
|
+
<label class="pptx-chart-card__row">
|
|
36165
|
+
<span class="pptx-chart-card__label">Series</span>
|
|
36166
|
+
<select
|
|
36167
|
+
class="pptx-chart-card__input"
|
|
36168
|
+
[disabled]="!canEdit()"
|
|
36169
|
+
[value]="activeIndex()"
|
|
36170
|
+
(change)="onSeries($event)"
|
|
36171
|
+
>
|
|
36172
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36173
|
+
<option [value]="i">{{ s.name }}</option>
|
|
36174
|
+
}
|
|
36175
|
+
</select>
|
|
36176
|
+
</label>
|
|
36177
|
+
}
|
|
36178
|
+
|
|
36179
|
+
<div class="pptx-chart-card__group">
|
|
36180
|
+
@for (cat of categories(); track $index; let ci = $index) {
|
|
36181
|
+
<div class="pptx-chart-card__row">
|
|
36182
|
+
<span class="pptx-chart-card__name" [title]="cat">{{ cat }}</span>
|
|
36183
|
+
<input
|
|
36184
|
+
type="color"
|
|
36185
|
+
class="pptx-chart-card__color"
|
|
36186
|
+
title="Point fill"
|
|
36187
|
+
[disabled]="!canEdit()"
|
|
36188
|
+
[value]="pointFill(ci)"
|
|
36189
|
+
(input)="onFill(ci, $event)"
|
|
36190
|
+
/>
|
|
36191
|
+
@if (pointAt(ci)?.spPr?.fillColor) {
|
|
36192
|
+
<button
|
|
36193
|
+
type="button"
|
|
36194
|
+
class="pptx-chart-card__clear"
|
|
36195
|
+
title="Clear point fill"
|
|
36196
|
+
[disabled]="!canEdit()"
|
|
36197
|
+
(click)="onClearFill(ci)"
|
|
36198
|
+
>
|
|
36199
|
+
×
|
|
36200
|
+
</button>
|
|
36201
|
+
}
|
|
36202
|
+
@if (showExplosion()) {
|
|
36203
|
+
<input
|
|
36204
|
+
type="number"
|
|
36205
|
+
min="0"
|
|
36206
|
+
max="100"
|
|
36207
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
36208
|
+
title="Slice explosion"
|
|
36209
|
+
placeholder="0"
|
|
36210
|
+
[disabled]="!canEdit()"
|
|
36211
|
+
[value]="pointAt(ci)?.explosion ?? ''"
|
|
36212
|
+
(change)="onExplosion(ci, $event)"
|
|
36213
|
+
/>
|
|
36214
|
+
}
|
|
36215
|
+
</div>
|
|
36216
|
+
}
|
|
36217
|
+
</div>
|
|
36218
|
+
</section>
|
|
36219
|
+
}
|
|
36220
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
36221
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
36222
|
+
|
|
36223
|
+
/**
|
|
36224
|
+
* chart-display-options.component.ts: Chart-level display toggles.
|
|
36225
|
+
*
|
|
36226
|
+
* Selector: `pptx-chart-display-options`
|
|
36227
|
+
*
|
|
36228
|
+
* Mirrors React's `ChartDisplayOptions.tsx`: show/hide title, legend (with
|
|
36229
|
+
* position), gridlines, and the data-labels master toggle. Emits a complete new
|
|
36230
|
+
* `ChartPptxElement` via `elementChange` after each edit; holds no mutable state.
|
|
36231
|
+
*
|
|
36232
|
+
* @module angular-viewer/chart-display-options
|
|
36233
|
+
*/
|
|
36234
|
+
class ChartDisplayOptionsComponent {
|
|
36235
|
+
element = input.required(/* @ts-ignore */
|
|
36236
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
36237
|
+
canEdit = input(true, /* @ts-ignore */
|
|
36238
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
36239
|
+
elementChange = output();
|
|
36240
|
+
legendPositions = LEGEND_POSITION_OPTIONS;
|
|
36241
|
+
style = computed(() => this.element().chartData?.style ?? {}, /* @ts-ignore */
|
|
36242
|
+
...(ngDevMode ? [{ debugName: "style" }] : /* istanbul ignore next */ []));
|
|
36243
|
+
onToggleTitle(event) {
|
|
36244
|
+
this.elementChange.emit(patchChartStyle(this.element(), { hasTitle: boolFromEvent(event) }));
|
|
36245
|
+
}
|
|
36246
|
+
onToggleLegend(event) {
|
|
36247
|
+
this.elementChange.emit(setLegend(this.element(), { show: boolFromEvent(event) }));
|
|
36248
|
+
}
|
|
36249
|
+
onLegendPosition(event) {
|
|
36250
|
+
const value = selectValue$1(event);
|
|
36251
|
+
if (value === null) {
|
|
36252
|
+
return;
|
|
36253
|
+
}
|
|
36254
|
+
this.elementChange.emit(setLegend(this.element(), { position: value }));
|
|
36255
|
+
}
|
|
36256
|
+
onToggleGridlines(event) {
|
|
36257
|
+
this.elementChange.emit(patchChartStyle(this.element(), { hasGridlines: boolFromEvent(event) }));
|
|
36258
|
+
}
|
|
36259
|
+
onToggleDataLabels(event) {
|
|
36260
|
+
// Route through the dedicated op so content keys initialise consistently.
|
|
36261
|
+
this.elementChange.emit(setDataLabels(this.element(), { show: boolFromEvent(event) }));
|
|
36262
|
+
}
|
|
36263
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDisplayOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
36264
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartDisplayOptionsComponent, isStandalone: true, selector: "pptx-chart-display-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
36265
|
+
<section class="pptx-chart-card" aria-label="Chart display options">
|
|
36266
|
+
<h4 class="pptx-chart-card__heading">Display</h4>
|
|
36267
|
+
<div class="pptx-chart-card__group">
|
|
36268
|
+
<label class="pptx-chart-card__check">
|
|
36269
|
+
<input
|
|
36270
|
+
type="checkbox"
|
|
36271
|
+
[disabled]="!canEdit()"
|
|
36272
|
+
[checked]="style().hasTitle ?? false"
|
|
36273
|
+
(change)="onToggleTitle($event)"
|
|
36274
|
+
/>
|
|
36275
|
+
<span>Show title</span>
|
|
36276
|
+
</label>
|
|
36277
|
+
|
|
36278
|
+
<label class="pptx-chart-card__check">
|
|
36279
|
+
<input
|
|
36280
|
+
type="checkbox"
|
|
36281
|
+
[disabled]="!canEdit()"
|
|
36282
|
+
[checked]="style().hasLegend ?? false"
|
|
36283
|
+
(change)="onToggleLegend($event)"
|
|
36284
|
+
/>
|
|
36285
|
+
<span>Show legend</span>
|
|
36286
|
+
</label>
|
|
36287
|
+
|
|
36288
|
+
@if (style().hasLegend) {
|
|
36289
|
+
<label class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36290
|
+
<span class="pptx-chart-card__label">Position</span>
|
|
36291
|
+
<select
|
|
36292
|
+
class="pptx-chart-card__input"
|
|
36293
|
+
[disabled]="!canEdit()"
|
|
36294
|
+
[value]="style().legendPosition ?? 'b'"
|
|
36295
|
+
(change)="onLegendPosition($event)"
|
|
36296
|
+
>
|
|
36297
|
+
@for (opt of legendPositions; track opt.value) {
|
|
36298
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36299
|
+
}
|
|
36300
|
+
</select>
|
|
36301
|
+
</label>
|
|
36302
|
+
}
|
|
36303
|
+
|
|
36304
|
+
<label class="pptx-chart-card__check">
|
|
36305
|
+
<input
|
|
36306
|
+
type="checkbox"
|
|
36307
|
+
[disabled]="!canEdit()"
|
|
36308
|
+
[checked]="style().hasGridlines ?? false"
|
|
36309
|
+
(change)="onToggleGridlines($event)"
|
|
36310
|
+
/>
|
|
36311
|
+
<span>Show gridlines</span>
|
|
36312
|
+
</label>
|
|
36313
|
+
|
|
36314
|
+
<label class="pptx-chart-card__check">
|
|
36315
|
+
<input
|
|
36316
|
+
type="checkbox"
|
|
36317
|
+
[disabled]="!canEdit()"
|
|
36318
|
+
[checked]="style().hasDataLabels ?? false"
|
|
36319
|
+
(change)="onToggleDataLabels($event)"
|
|
36320
|
+
/>
|
|
36321
|
+
<span>Show data labels</span>
|
|
36322
|
+
</label>
|
|
36323
|
+
</div>
|
|
36324
|
+
</section>
|
|
36325
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
36326
|
+
}
|
|
36327
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDisplayOptionsComponent, decorators: [{
|
|
36328
|
+
type: Component,
|
|
36329
|
+
args: [{ selector: 'pptx-chart-display-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
36330
|
+
<section class="pptx-chart-card" aria-label="Chart display options">
|
|
36331
|
+
<h4 class="pptx-chart-card__heading">Display</h4>
|
|
36332
|
+
<div class="pptx-chart-card__group">
|
|
36333
|
+
<label class="pptx-chart-card__check">
|
|
36334
|
+
<input
|
|
36335
|
+
type="checkbox"
|
|
36336
|
+
[disabled]="!canEdit()"
|
|
36337
|
+
[checked]="style().hasTitle ?? false"
|
|
36338
|
+
(change)="onToggleTitle($event)"
|
|
36339
|
+
/>
|
|
36340
|
+
<span>Show title</span>
|
|
36341
|
+
</label>
|
|
36342
|
+
|
|
36343
|
+
<label class="pptx-chart-card__check">
|
|
36344
|
+
<input
|
|
36345
|
+
type="checkbox"
|
|
36346
|
+
[disabled]="!canEdit()"
|
|
36347
|
+
[checked]="style().hasLegend ?? false"
|
|
36348
|
+
(change)="onToggleLegend($event)"
|
|
36349
|
+
/>
|
|
36350
|
+
<span>Show legend</span>
|
|
36351
|
+
</label>
|
|
36352
|
+
|
|
36353
|
+
@if (style().hasLegend) {
|
|
36354
|
+
<label class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36355
|
+
<span class="pptx-chart-card__label">Position</span>
|
|
36356
|
+
<select
|
|
36357
|
+
class="pptx-chart-card__input"
|
|
36358
|
+
[disabled]="!canEdit()"
|
|
36359
|
+
[value]="style().legendPosition ?? 'b'"
|
|
36360
|
+
(change)="onLegendPosition($event)"
|
|
36361
|
+
>
|
|
36362
|
+
@for (opt of legendPositions; track opt.value) {
|
|
36363
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36364
|
+
}
|
|
36365
|
+
</select>
|
|
36366
|
+
</label>
|
|
36367
|
+
}
|
|
36368
|
+
|
|
36369
|
+
<label class="pptx-chart-card__check">
|
|
36370
|
+
<input
|
|
36371
|
+
type="checkbox"
|
|
36372
|
+
[disabled]="!canEdit()"
|
|
36373
|
+
[checked]="style().hasGridlines ?? false"
|
|
36374
|
+
(change)="onToggleGridlines($event)"
|
|
36375
|
+
/>
|
|
36376
|
+
<span>Show gridlines</span>
|
|
36377
|
+
</label>
|
|
36378
|
+
|
|
36379
|
+
<label class="pptx-chart-card__check">
|
|
36380
|
+
<input
|
|
36381
|
+
type="checkbox"
|
|
36382
|
+
[disabled]="!canEdit()"
|
|
36383
|
+
[checked]="style().hasDataLabels ?? false"
|
|
36384
|
+
(change)="onToggleDataLabels($event)"
|
|
36385
|
+
/>
|
|
36386
|
+
<span>Show data labels</span>
|
|
36387
|
+
</label>
|
|
36388
|
+
</div>
|
|
36389
|
+
</section>
|
|
36390
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
36391
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
36392
|
+
|
|
36393
|
+
/**
|
|
36394
|
+
* chart-error-bar-options.component.ts: Per-series error-bar controls.
|
|
36395
|
+
*
|
|
36396
|
+
* Selector: `pptx-chart-error-bar-options`
|
|
33748
36397
|
*
|
|
33749
|
-
*
|
|
33750
|
-
*
|
|
33751
|
-
*
|
|
33752
|
-
*
|
|
33753
|
-
*
|
|
36398
|
+
* Mirrors React's `ChartErrorBarOptions.tsx`: for bar/line/area/scatter/bubble
|
|
36399
|
+
* charts, each series gets an error-bar value-type selector, and (when set) a
|
|
36400
|
+
* direction-type selector plus a numeric amount for the value types that take
|
|
36401
|
+
* one. Routes through the `setSeriesErrorBars` immutable wrapper and emits a new
|
|
36402
|
+
* `ChartPptxElement`.
|
|
33754
36403
|
*
|
|
33755
|
-
* @
|
|
33756
|
-
* ```ts
|
|
33757
|
-
* const updated = setSeriesValue(el, 0, 2, "42.5");
|
|
33758
|
-
* ```
|
|
36404
|
+
* @module angular-viewer/chart-error-bar-options
|
|
33759
36405
|
*/
|
|
33760
|
-
|
|
33761
|
-
|
|
33762
|
-
|
|
33763
|
-
|
|
36406
|
+
class ChartErrorBarOptionsComponent {
|
|
36407
|
+
element = input.required(/* @ts-ignore */
|
|
36408
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
36409
|
+
canEdit = input(true, /* @ts-ignore */
|
|
36410
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
36411
|
+
elementChange = output();
|
|
36412
|
+
valTypeOptions = ERROR_BAR_VALTYPE_OPTIONS;
|
|
36413
|
+
barTypeOptions = ERROR_BAR_TYPE_OPTIONS;
|
|
36414
|
+
series = computed(() => this.element().chartData?.series ?? [], /* @ts-ignore */
|
|
36415
|
+
...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
|
|
36416
|
+
supported = computed(() => {
|
|
36417
|
+
const type = this.element().chartData?.chartType;
|
|
36418
|
+
return type !== undefined && ERROR_BAR_SUPPORTED_TYPES.has(type) && this.series().length > 0;
|
|
36419
|
+
}, /* @ts-ignore */
|
|
36420
|
+
...(ngDevMode ? [{ debugName: "supported" }] : /* istanbul ignore next */ []));
|
|
36421
|
+
barsOf(s) {
|
|
36422
|
+
return s.errBars?.[0];
|
|
33764
36423
|
}
|
|
33765
|
-
|
|
33766
|
-
|
|
33767
|
-
return element;
|
|
36424
|
+
showValue(bars) {
|
|
36425
|
+
return ERROR_BAR_VALUE_TYPES.has(bars.valType);
|
|
33768
36426
|
}
|
|
33769
|
-
|
|
33770
|
-
|
|
33771
|
-
|
|
33772
|
-
|
|
33773
|
-
|
|
33774
|
-
|
|
33775
|
-
|
|
33776
|
-
|
|
33777
|
-
|
|
33778
|
-
|
|
33779
|
-
|
|
33780
|
-
|
|
33781
|
-
|
|
33782
|
-
|
|
33783
|
-
|
|
33784
|
-
|
|
33785
|
-
* ```
|
|
33786
|
-
*/
|
|
33787
|
-
function setSeriesName(element, seriesIndex, name) {
|
|
33788
|
-
const chartData = element.chartData;
|
|
33789
|
-
if (!chartData) {
|
|
33790
|
-
return element;
|
|
36427
|
+
onValType(index, s, event) {
|
|
36428
|
+
const value = selectValue$1(event);
|
|
36429
|
+
if (value === null) {
|
|
36430
|
+
return;
|
|
36431
|
+
}
|
|
36432
|
+
if (value === '') {
|
|
36433
|
+
this.elementChange.emit(setSeriesErrorBars(this.element(), index, null));
|
|
36434
|
+
return;
|
|
36435
|
+
}
|
|
36436
|
+
const existing = this.barsOf(s);
|
|
36437
|
+
this.elementChange.emit(setSeriesErrorBars(this.element(), index, {
|
|
36438
|
+
direction: existing?.direction ?? 'y',
|
|
36439
|
+
barType: existing?.barType ?? 'both',
|
|
36440
|
+
valType: value,
|
|
36441
|
+
val: existing?.val,
|
|
36442
|
+
}));
|
|
33791
36443
|
}
|
|
33792
|
-
|
|
33793
|
-
|
|
36444
|
+
onBarType(index, bars, event) {
|
|
36445
|
+
const value = selectValue$1(event);
|
|
36446
|
+
if (value === null) {
|
|
36447
|
+
return;
|
|
36448
|
+
}
|
|
36449
|
+
this.elementChange.emit(setSeriesErrorBars(this.element(), index, {
|
|
36450
|
+
...bars,
|
|
36451
|
+
barType: value,
|
|
36452
|
+
}));
|
|
36453
|
+
}
|
|
36454
|
+
onValue(index, bars, event) {
|
|
36455
|
+
const num = numFromEvent(event);
|
|
36456
|
+
if (num === undefined) {
|
|
36457
|
+
return;
|
|
36458
|
+
}
|
|
36459
|
+
this.elementChange.emit(setSeriesErrorBars(this.element(), index, { ...bars, val: num ?? undefined }));
|
|
36460
|
+
}
|
|
36461
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartErrorBarOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
36462
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartErrorBarOptionsComponent, isStandalone: true, selector: "pptx-chart-error-bar-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
36463
|
+
@if (supported()) {
|
|
36464
|
+
<section class="pptx-chart-card" aria-label="Error bar options">
|
|
36465
|
+
<h4 class="pptx-chart-card__heading">Error Bars</h4>
|
|
36466
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36467
|
+
<div class="pptx-chart-card__group">
|
|
36468
|
+
<div class="pptx-chart-card__row">
|
|
36469
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
36470
|
+
<select
|
|
36471
|
+
class="pptx-chart-card__input"
|
|
36472
|
+
[disabled]="!canEdit()"
|
|
36473
|
+
[value]="barsOf(s)?.valType ?? ''"
|
|
36474
|
+
(change)="onValType(i, s, $event)"
|
|
36475
|
+
>
|
|
36476
|
+
@for (opt of valTypeOptions; track opt.value) {
|
|
36477
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36478
|
+
}
|
|
36479
|
+
</select>
|
|
36480
|
+
</div>
|
|
36481
|
+
|
|
36482
|
+
@if (barsOf(s); as bars) {
|
|
36483
|
+
<div class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36484
|
+
<select
|
|
36485
|
+
class="pptx-chart-card__input"
|
|
36486
|
+
[disabled]="!canEdit()"
|
|
36487
|
+
[value]="bars.barType"
|
|
36488
|
+
(change)="onBarType(i, bars, $event)"
|
|
36489
|
+
>
|
|
36490
|
+
@for (opt of barTypeOptions; track opt.value) {
|
|
36491
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36492
|
+
}
|
|
36493
|
+
</select>
|
|
36494
|
+
@if (showValue(bars)) {
|
|
36495
|
+
<input
|
|
36496
|
+
type="number"
|
|
36497
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
36498
|
+
placeholder="Amount"
|
|
36499
|
+
[disabled]="!canEdit()"
|
|
36500
|
+
[value]="bars.val ?? ''"
|
|
36501
|
+
(change)="onValue(i, bars, $event)"
|
|
36502
|
+
/>
|
|
36503
|
+
}
|
|
36504
|
+
</div>
|
|
36505
|
+
}
|
|
36506
|
+
</div>
|
|
36507
|
+
}
|
|
36508
|
+
</section>
|
|
36509
|
+
}
|
|
36510
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
33794
36511
|
}
|
|
33795
|
-
|
|
33796
|
-
|
|
33797
|
-
|
|
36512
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartErrorBarOptionsComponent, decorators: [{
|
|
36513
|
+
type: Component,
|
|
36514
|
+
args: [{ selector: 'pptx-chart-error-bar-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
36515
|
+
@if (supported()) {
|
|
36516
|
+
<section class="pptx-chart-card" aria-label="Error bar options">
|
|
36517
|
+
<h4 class="pptx-chart-card__heading">Error Bars</h4>
|
|
36518
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36519
|
+
<div class="pptx-chart-card__group">
|
|
36520
|
+
<div class="pptx-chart-card__row">
|
|
36521
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
36522
|
+
<select
|
|
36523
|
+
class="pptx-chart-card__input"
|
|
36524
|
+
[disabled]="!canEdit()"
|
|
36525
|
+
[value]="barsOf(s)?.valType ?? ''"
|
|
36526
|
+
(change)="onValType(i, s, $event)"
|
|
36527
|
+
>
|
|
36528
|
+
@for (opt of valTypeOptions; track opt.value) {
|
|
36529
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36530
|
+
}
|
|
36531
|
+
</select>
|
|
36532
|
+
</div>
|
|
36533
|
+
|
|
36534
|
+
@if (barsOf(s); as bars) {
|
|
36535
|
+
<div class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36536
|
+
<select
|
|
36537
|
+
class="pptx-chart-card__input"
|
|
36538
|
+
[disabled]="!canEdit()"
|
|
36539
|
+
[value]="bars.barType"
|
|
36540
|
+
(change)="onBarType(i, bars, $event)"
|
|
36541
|
+
>
|
|
36542
|
+
@for (opt of barTypeOptions; track opt.value) {
|
|
36543
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36544
|
+
}
|
|
36545
|
+
</select>
|
|
36546
|
+
@if (showValue(bars)) {
|
|
36547
|
+
<input
|
|
36548
|
+
type="number"
|
|
36549
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
36550
|
+
placeholder="Amount"
|
|
36551
|
+
[disabled]="!canEdit()"
|
|
36552
|
+
[value]="bars.val ?? ''"
|
|
36553
|
+
(change)="onValue(i, bars, $event)"
|
|
36554
|
+
/>
|
|
36555
|
+
}
|
|
36556
|
+
</div>
|
|
36557
|
+
}
|
|
36558
|
+
</div>
|
|
36559
|
+
}
|
|
36560
|
+
</section>
|
|
36561
|
+
}
|
|
36562
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
36563
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
36564
|
+
|
|
33798
36565
|
/**
|
|
33799
|
-
*
|
|
36566
|
+
* chart-marker-options.component.ts: Per-series marker controls.
|
|
33800
36567
|
*
|
|
33801
|
-
*
|
|
33802
|
-
* @param catIndex - Zero-based index of the category to rename.
|
|
33803
|
-
* @param label - The new label text.
|
|
33804
|
-
* @returns A new `ChartPptxElement`.
|
|
36568
|
+
* Selector: `pptx-chart-marker-options`
|
|
33805
36569
|
*
|
|
33806
|
-
*
|
|
33807
|
-
*
|
|
33808
|
-
*
|
|
33809
|
-
*
|
|
36570
|
+
* Mirrors React's `ChartMarkerOptions.tsx`: for line/scatter/bubble/radar charts,
|
|
36571
|
+
* each series gets a marker-symbol selector and (when a visible symbol is chosen)
|
|
36572
|
+
* size and fill-colour controls. Routes through `setSeriesMarker` and emits a new
|
|
36573
|
+
* `ChartPptxElement`.
|
|
36574
|
+
*
|
|
36575
|
+
* @module angular-viewer/chart-marker-options
|
|
33810
36576
|
*/
|
|
33811
|
-
|
|
33812
|
-
|
|
33813
|
-
|
|
33814
|
-
|
|
36577
|
+
class ChartMarkerOptionsComponent {
|
|
36578
|
+
element = input.required(/* @ts-ignore */
|
|
36579
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
36580
|
+
canEdit = input(true, /* @ts-ignore */
|
|
36581
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
36582
|
+
elementChange = output();
|
|
36583
|
+
symbolOptions = MARKER_SYMBOL_OPTIONS;
|
|
36584
|
+
series = computed(() => this.element().chartData?.series ?? [], /* @ts-ignore */
|
|
36585
|
+
...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
|
|
36586
|
+
supported = computed(() => {
|
|
36587
|
+
const type = this.element().chartData?.chartType;
|
|
36588
|
+
return type !== undefined && MARKER_SUPPORTED_TYPES.has(type) && this.series().length > 0;
|
|
36589
|
+
}, /* @ts-ignore */
|
|
36590
|
+
...(ngDevMode ? [{ debugName: "supported" }] : /* istanbul ignore next */ []));
|
|
36591
|
+
onSymbol(index, event) {
|
|
36592
|
+
const value = selectValue$1(event);
|
|
36593
|
+
if (value === null) {
|
|
36594
|
+
return;
|
|
36595
|
+
}
|
|
36596
|
+
this.elementChange.emit(setSeriesMarker(this.element(), index, value === '' ? null : { symbol: value }));
|
|
33815
36597
|
}
|
|
33816
|
-
|
|
33817
|
-
|
|
36598
|
+
onSize(index, event) {
|
|
36599
|
+
const num = numFromEvent(event);
|
|
36600
|
+
this.elementChange.emit(setSeriesMarker(this.element(), index, { size: typeof num === 'number' ? num : undefined }));
|
|
36601
|
+
}
|
|
36602
|
+
onFill(index, event) {
|
|
36603
|
+
const value = stringFromEvent$5(event);
|
|
36604
|
+
if (value === null) {
|
|
36605
|
+
return;
|
|
36606
|
+
}
|
|
36607
|
+
this.elementChange.emit(setSeriesMarker(this.element(), index, { fillColor: value }));
|
|
36608
|
+
}
|
|
36609
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartMarkerOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
36610
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartMarkerOptionsComponent, isStandalone: true, selector: "pptx-chart-marker-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
36611
|
+
@if (supported()) {
|
|
36612
|
+
<section class="pptx-chart-card" aria-label="Marker options">
|
|
36613
|
+
<h4 class="pptx-chart-card__heading">Markers</h4>
|
|
36614
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36615
|
+
<div class="pptx-chart-card__group">
|
|
36616
|
+
<div class="pptx-chart-card__row">
|
|
36617
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
36618
|
+
<select
|
|
36619
|
+
class="pptx-chart-card__input"
|
|
36620
|
+
[disabled]="!canEdit()"
|
|
36621
|
+
[value]="s.marker?.symbol ?? ''"
|
|
36622
|
+
(change)="onSymbol(i, $event)"
|
|
36623
|
+
>
|
|
36624
|
+
@for (opt of symbolOptions; track opt.value) {
|
|
36625
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36626
|
+
}
|
|
36627
|
+
</select>
|
|
36628
|
+
</div>
|
|
36629
|
+
|
|
36630
|
+
@if (s.marker && s.marker.symbol !== 'none') {
|
|
36631
|
+
<div class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36632
|
+
<span class="pptx-chart-card__label">Size</span>
|
|
36633
|
+
<input
|
|
36634
|
+
type="number"
|
|
36635
|
+
min="2"
|
|
36636
|
+
max="72"
|
|
36637
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
36638
|
+
placeholder="Auto"
|
|
36639
|
+
[disabled]="!canEdit()"
|
|
36640
|
+
[value]="s.marker.size ?? ''"
|
|
36641
|
+
(change)="onSize(i, $event)"
|
|
36642
|
+
/>
|
|
36643
|
+
<span class="pptx-chart-card__label">Fill</span>
|
|
36644
|
+
<input
|
|
36645
|
+
type="color"
|
|
36646
|
+
class="pptx-chart-card__color"
|
|
36647
|
+
[disabled]="!canEdit()"
|
|
36648
|
+
[value]="s.marker.spPr?.fillColor ?? '#4472c4'"
|
|
36649
|
+
(input)="onFill(i, $event)"
|
|
36650
|
+
/>
|
|
36651
|
+
</div>
|
|
36652
|
+
}
|
|
36653
|
+
</div>
|
|
36654
|
+
}
|
|
36655
|
+
</section>
|
|
36656
|
+
}
|
|
36657
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
33818
36658
|
}
|
|
33819
|
-
|
|
33820
|
-
|
|
33821
|
-
|
|
36659
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartMarkerOptionsComponent, decorators: [{
|
|
36660
|
+
type: Component,
|
|
36661
|
+
args: [{ selector: 'pptx-chart-marker-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
36662
|
+
@if (supported()) {
|
|
36663
|
+
<section class="pptx-chart-card" aria-label="Marker options">
|
|
36664
|
+
<h4 class="pptx-chart-card__heading">Markers</h4>
|
|
36665
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36666
|
+
<div class="pptx-chart-card__group">
|
|
36667
|
+
<div class="pptx-chart-card__row">
|
|
36668
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
36669
|
+
<select
|
|
36670
|
+
class="pptx-chart-card__input"
|
|
36671
|
+
[disabled]="!canEdit()"
|
|
36672
|
+
[value]="s.marker?.symbol ?? ''"
|
|
36673
|
+
(change)="onSymbol(i, $event)"
|
|
36674
|
+
>
|
|
36675
|
+
@for (opt of symbolOptions; track opt.value) {
|
|
36676
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36677
|
+
}
|
|
36678
|
+
</select>
|
|
36679
|
+
</div>
|
|
36680
|
+
|
|
36681
|
+
@if (s.marker && s.marker.symbol !== 'none') {
|
|
36682
|
+
<div class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36683
|
+
<span class="pptx-chart-card__label">Size</span>
|
|
36684
|
+
<input
|
|
36685
|
+
type="number"
|
|
36686
|
+
min="2"
|
|
36687
|
+
max="72"
|
|
36688
|
+
class="pptx-chart-card__input pptx-chart-card__input--num"
|
|
36689
|
+
placeholder="Auto"
|
|
36690
|
+
[disabled]="!canEdit()"
|
|
36691
|
+
[value]="s.marker.size ?? ''"
|
|
36692
|
+
(change)="onSize(i, $event)"
|
|
36693
|
+
/>
|
|
36694
|
+
<span class="pptx-chart-card__label">Fill</span>
|
|
36695
|
+
<input
|
|
36696
|
+
type="color"
|
|
36697
|
+
class="pptx-chart-card__color"
|
|
36698
|
+
[disabled]="!canEdit()"
|
|
36699
|
+
[value]="s.marker.spPr?.fillColor ?? '#4472c4'"
|
|
36700
|
+
(input)="onFill(i, $event)"
|
|
36701
|
+
/>
|
|
36702
|
+
</div>
|
|
36703
|
+
}
|
|
36704
|
+
</div>
|
|
36705
|
+
}
|
|
36706
|
+
</section>
|
|
36707
|
+
}
|
|
36708
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
36709
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
36710
|
+
|
|
33822
36711
|
/**
|
|
33823
|
-
*
|
|
33824
|
-
* `ChartPptxElement`. Pass a hex string (`#RRGGBB` or `RRGGBB`) to set the
|
|
33825
|
-
* colour, or `null` to clear it so the series falls back to its theme colour.
|
|
36712
|
+
* chart-trendline-options.component.ts: Per-series trendline controls.
|
|
33826
36713
|
*
|
|
33827
|
-
*
|
|
33828
|
-
* with an immutable element-level wrapper for the inspector.
|
|
36714
|
+
* Selector: `pptx-chart-trendline-options`
|
|
33829
36715
|
*
|
|
33830
|
-
*
|
|
33831
|
-
*
|
|
33832
|
-
*
|
|
33833
|
-
*
|
|
36716
|
+
* Mirrors React's `ChartTrendlineOptions.tsx`: for bar/line/area/scatter/bubble
|
|
36717
|
+
* charts, each series gets a trendline-type selector plus (when a trendline is
|
|
36718
|
+
* set) display-equation and display-R-squared toggles. Routes through the
|
|
36719
|
+
* `setSeriesTrendline` immutable wrapper and emits a new `ChartPptxElement`.
|
|
33834
36720
|
*
|
|
33835
|
-
* @
|
|
33836
|
-
* ```ts
|
|
33837
|
-
* const updated = setSeriesColor(el, 0, "#4472C4");
|
|
33838
|
-
* ```
|
|
36721
|
+
* @module angular-viewer/chart-trendline-options
|
|
33839
36722
|
*/
|
|
33840
|
-
|
|
33841
|
-
|
|
33842
|
-
|
|
33843
|
-
|
|
36723
|
+
class ChartTrendlineOptionsComponent {
|
|
36724
|
+
element = input.required(/* @ts-ignore */
|
|
36725
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
36726
|
+
canEdit = input(true, /* @ts-ignore */
|
|
36727
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
36728
|
+
elementChange = output();
|
|
36729
|
+
typeOptions = TRENDLINE_TYPE_OPTIONS;
|
|
36730
|
+
series = computed(() => this.element().chartData?.series ?? [], /* @ts-ignore */
|
|
36731
|
+
...(ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []));
|
|
36732
|
+
supported = computed(() => {
|
|
36733
|
+
const type = this.element().chartData?.chartType;
|
|
36734
|
+
return type !== undefined && TRENDLINE_SUPPORTED_TYPES.has(type) && this.series().length > 0;
|
|
36735
|
+
}, /* @ts-ignore */
|
|
36736
|
+
...(ngDevMode ? [{ debugName: "supported" }] : /* istanbul ignore next */ []));
|
|
36737
|
+
trendlineOf(s) {
|
|
36738
|
+
return s.trendlines?.[0];
|
|
33844
36739
|
}
|
|
33845
|
-
|
|
33846
|
-
|
|
33847
|
-
|
|
33848
|
-
|
|
33849
|
-
|
|
33850
|
-
|
|
33851
|
-
|
|
33852
|
-
|
|
33853
|
-
}
|
|
33854
|
-
|
|
33855
|
-
|
|
33856
|
-
|
|
33857
|
-
|
|
33858
|
-
|
|
33859
|
-
* returning a new element.
|
|
33860
|
-
*
|
|
33861
|
-
* @param element - The source chart element (not mutated).
|
|
33862
|
-
* @param patch - Style fields to merge.
|
|
33863
|
-
* @returns A new `ChartPptxElement`.
|
|
33864
|
-
*/
|
|
33865
|
-
function patchChartStyle(element, patch) {
|
|
33866
|
-
const chartData = element.chartData;
|
|
33867
|
-
if (!chartData) {
|
|
33868
|
-
return element;
|
|
36740
|
+
onType(index, s, event) {
|
|
36741
|
+
const value = selectValue$1(event);
|
|
36742
|
+
if (value === null) {
|
|
36743
|
+
return;
|
|
36744
|
+
}
|
|
36745
|
+
if (value === '') {
|
|
36746
|
+
this.elementChange.emit(setSeriesTrendline(this.element(), index, null));
|
|
36747
|
+
return;
|
|
36748
|
+
}
|
|
36749
|
+
const existing = this.trendlineOf(s);
|
|
36750
|
+
this.elementChange.emit(setSeriesTrendline(this.element(), index, {
|
|
36751
|
+
...existing,
|
|
36752
|
+
trendlineType: value,
|
|
36753
|
+
}));
|
|
33869
36754
|
}
|
|
33870
|
-
|
|
33871
|
-
|
|
33872
|
-
|
|
33873
|
-
|
|
36755
|
+
onToggleEq(index, tl, event) {
|
|
36756
|
+
this.elementChange.emit(setSeriesTrendline(this.element(), index, { ...tl, displayEq: boolFromEvent(event) }));
|
|
36757
|
+
}
|
|
36758
|
+
onToggleRSq(index, tl, event) {
|
|
36759
|
+
this.elementChange.emit(setSeriesTrendline(this.element(), index, { ...tl, displayRSq: boolFromEvent(event) }));
|
|
36760
|
+
}
|
|
36761
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartTrendlineOptionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
36762
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: ChartTrendlineOptionsComponent, isStandalone: true, selector: "pptx-chart-trendline-options", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
36763
|
+
@if (supported()) {
|
|
36764
|
+
<section class="pptx-chart-card" aria-label="Trendline options">
|
|
36765
|
+
<h4 class="pptx-chart-card__heading">Trendlines</h4>
|
|
36766
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36767
|
+
<div class="pptx-chart-card__group">
|
|
36768
|
+
<div class="pptx-chart-card__row">
|
|
36769
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
36770
|
+
<select
|
|
36771
|
+
class="pptx-chart-card__input"
|
|
36772
|
+
[disabled]="!canEdit()"
|
|
36773
|
+
[value]="trendlineOf(s)?.trendlineType ?? ''"
|
|
36774
|
+
(change)="onType(i, s, $event)"
|
|
36775
|
+
>
|
|
36776
|
+
@for (opt of typeOptions; track opt.value) {
|
|
36777
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36778
|
+
}
|
|
36779
|
+
</select>
|
|
36780
|
+
</div>
|
|
36781
|
+
|
|
36782
|
+
@if (trendlineOf(s); as tl) {
|
|
36783
|
+
<div class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36784
|
+
<label class="pptx-chart-card__check">
|
|
36785
|
+
<input
|
|
36786
|
+
type="checkbox"
|
|
36787
|
+
[disabled]="!canEdit()"
|
|
36788
|
+
[checked]="tl.displayEq ?? false"
|
|
36789
|
+
(change)="onToggleEq(i, tl, $event)"
|
|
36790
|
+
/>
|
|
36791
|
+
<span>Equation</span>
|
|
36792
|
+
</label>
|
|
36793
|
+
<label class="pptx-chart-card__check">
|
|
36794
|
+
<input
|
|
36795
|
+
type="checkbox"
|
|
36796
|
+
[disabled]="!canEdit()"
|
|
36797
|
+
[checked]="tl.displayRSq ?? false"
|
|
36798
|
+
(change)="onToggleRSq(i, tl, $event)"
|
|
36799
|
+
/>
|
|
36800
|
+
<span>R-squared</span>
|
|
36801
|
+
</label>
|
|
36802
|
+
</div>
|
|
36803
|
+
}
|
|
36804
|
+
</div>
|
|
36805
|
+
}
|
|
36806
|
+
</section>
|
|
36807
|
+
}
|
|
36808
|
+
`, isInline: true, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
33874
36809
|
}
|
|
33875
|
-
|
|
33876
|
-
|
|
33877
|
-
|
|
36810
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartTrendlineOptionsComponent, decorators: [{
|
|
36811
|
+
type: Component,
|
|
36812
|
+
args: [{ selector: 'pptx-chart-trendline-options', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
36813
|
+
@if (supported()) {
|
|
36814
|
+
<section class="pptx-chart-card" aria-label="Trendline options">
|
|
36815
|
+
<h4 class="pptx-chart-card__heading">Trendlines</h4>
|
|
36816
|
+
@for (s of series(); track $index; let i = $index) {
|
|
36817
|
+
<div class="pptx-chart-card__group">
|
|
36818
|
+
<div class="pptx-chart-card__row">
|
|
36819
|
+
<span class="pptx-chart-card__name" [title]="s.name">{{ s.name }}</span>
|
|
36820
|
+
<select
|
|
36821
|
+
class="pptx-chart-card__input"
|
|
36822
|
+
[disabled]="!canEdit()"
|
|
36823
|
+
[value]="trendlineOf(s)?.trendlineType ?? ''"
|
|
36824
|
+
(change)="onType(i, s, $event)"
|
|
36825
|
+
>
|
|
36826
|
+
@for (opt of typeOptions; track opt.value) {
|
|
36827
|
+
<option [value]="opt.value">{{ opt.label }}</option>
|
|
36828
|
+
}
|
|
36829
|
+
</select>
|
|
36830
|
+
</div>
|
|
36831
|
+
|
|
36832
|
+
@if (trendlineOf(s); as tl) {
|
|
36833
|
+
<div class="pptx-chart-card__row pptx-chart-card__group--indent">
|
|
36834
|
+
<label class="pptx-chart-card__check">
|
|
36835
|
+
<input
|
|
36836
|
+
type="checkbox"
|
|
36837
|
+
[disabled]="!canEdit()"
|
|
36838
|
+
[checked]="tl.displayEq ?? false"
|
|
36839
|
+
(change)="onToggleEq(i, tl, $event)"
|
|
36840
|
+
/>
|
|
36841
|
+
<span>Equation</span>
|
|
36842
|
+
</label>
|
|
36843
|
+
<label class="pptx-chart-card__check">
|
|
36844
|
+
<input
|
|
36845
|
+
type="checkbox"
|
|
36846
|
+
[disabled]="!canEdit()"
|
|
36847
|
+
[checked]="tl.displayRSq ?? false"
|
|
36848
|
+
(change)="onToggleRSq(i, tl, $event)"
|
|
36849
|
+
/>
|
|
36850
|
+
<span>R-squared</span>
|
|
36851
|
+
</label>
|
|
36852
|
+
</div>
|
|
36853
|
+
}
|
|
36854
|
+
</div>
|
|
36855
|
+
}
|
|
36856
|
+
</section>
|
|
36857
|
+
}
|
|
36858
|
+
`, styles: [".pptx-chart-card{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-top:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-card__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-card__group{display:flex;flex-direction:column;gap:.3rem}.pptx-chart-card__group--indent{margin-left:.5rem}.pptx-chart-card__subhead{font-size:11px;font-weight:600}.pptx-chart-card__row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-chart-card__label{flex:0 0 auto;width:5rem;color:var(--pptx-inspector-muted, #888)}.pptx-chart-card__label--wide{width:6.5rem}.pptx-chart-card__name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-chart-card__check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-chart-card__input{flex:1 1 auto;min-width:0;box-sizing:border-box;padding:2px 4px;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;color:inherit;outline:none}.pptx-chart-card__input--num{flex:0 0 auto;width:4rem;text-align:right}.pptx-chart-card__input:focus{border-color:var(--pptx-inspector-active, #0078d4)}.pptx-chart-card__input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__color{flex:0 0 auto;width:26px;height:20px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-card__color:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-card__clear{flex:0 0 auto;padding:0 2px;font-size:12px;line-height:1;background:none;border:none;color:var(--pptx-inspector-muted, #888);cursor:pointer}.pptx-chart-card__clear:hover{color:var(--pptx-inspector-danger, #f47c7c)}.pptx-chart-card__input--num::-webkit-outer-spin-button,.pptx-chart-card__input--num::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
|
|
36859
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
36860
|
+
|
|
33878
36861
|
/**
|
|
33879
|
-
*
|
|
36862
|
+
* advanced-chart-editor.component.ts: Full chart inspector for the Angular
|
|
36863
|
+
* binding, at parity with the React `ChartDataPanel`.
|
|
33880
36864
|
*
|
|
33881
|
-
*
|
|
33882
|
-
* `chartDataChangeType` helper is used so grouping and category formats
|
|
33883
|
-
* are adapted automatically.
|
|
36865
|
+
* Selector: `pptx-advanced-chart-editor`
|
|
33884
36866
|
*
|
|
33885
|
-
*
|
|
33886
|
-
*
|
|
33887
|
-
*
|
|
36867
|
+
* Composes the existing data grid (`pptx-chart-data-editor`) with the advanced
|
|
36868
|
+
* formatting controls: display toggles, data labels, axis scale/format, axis
|
|
36869
|
+
* styling, markers, combo per-series types, per-data-point overrides, trendlines,
|
|
36870
|
+
* and error bars. Every child emits a complete new `ChartPptxElement`, which this
|
|
36871
|
+
* component re-emits via its own `elementChange` output so the parent commits a
|
|
36872
|
+
* single history entry per edit. Holds no mutable state.
|
|
36873
|
+
*
|
|
36874
|
+
* @module angular-viewer/advanced-chart-editor
|
|
33888
36875
|
*/
|
|
33889
|
-
|
|
33890
|
-
|
|
33891
|
-
|
|
33892
|
-
|
|
33893
|
-
|
|
33894
|
-
|
|
33895
|
-
|
|
33896
|
-
|
|
33897
|
-
|
|
33898
|
-
|
|
33899
|
-
}
|
|
33900
|
-
|
|
36876
|
+
class AdvancedChartEditorComponent {
|
|
36877
|
+
/** The chart element being edited. */
|
|
36878
|
+
element = input.required(/* @ts-ignore */
|
|
36879
|
+
...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
|
|
36880
|
+
/** Whether editing is enabled (read-only mode when false). */
|
|
36881
|
+
canEdit = input(true, /* @ts-ignore */
|
|
36882
|
+
...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
|
|
36883
|
+
/** Emits the updated element after any edit operation in any child control. */
|
|
36884
|
+
elementChange = output();
|
|
36885
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AdvancedChartEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
36886
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.2", type: AdvancedChartEditorComponent, isStandalone: true, selector: "pptx-advanced-chart-editor", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
|
|
36887
|
+
<div class="pptx-advanced-chart">
|
|
36888
|
+
<pptx-chart-display-options
|
|
36889
|
+
[element]="element()"
|
|
36890
|
+
[canEdit]="canEdit()"
|
|
36891
|
+
(elementChange)="elementChange.emit($event)"
|
|
36892
|
+
/>
|
|
36893
|
+
<pptx-chart-data-label-options
|
|
36894
|
+
[element]="element()"
|
|
36895
|
+
[canEdit]="canEdit()"
|
|
36896
|
+
(elementChange)="elementChange.emit($event)"
|
|
36897
|
+
/>
|
|
36898
|
+
<pptx-chart-axis-options
|
|
36899
|
+
[element]="element()"
|
|
36900
|
+
[canEdit]="canEdit()"
|
|
36901
|
+
(elementChange)="elementChange.emit($event)"
|
|
36902
|
+
/>
|
|
36903
|
+
<pptx-chart-axis-style-options
|
|
36904
|
+
[element]="element()"
|
|
36905
|
+
[canEdit]="canEdit()"
|
|
36906
|
+
(elementChange)="elementChange.emit($event)"
|
|
36907
|
+
/>
|
|
36908
|
+
<pptx-chart-marker-options
|
|
36909
|
+
[element]="element()"
|
|
36910
|
+
[canEdit]="canEdit()"
|
|
36911
|
+
(elementChange)="elementChange.emit($event)"
|
|
36912
|
+
/>
|
|
36913
|
+
<pptx-chart-combo-type-options
|
|
36914
|
+
[element]="element()"
|
|
36915
|
+
[canEdit]="canEdit()"
|
|
36916
|
+
(elementChange)="elementChange.emit($event)"
|
|
36917
|
+
/>
|
|
36918
|
+
<pptx-chart-datapoint-options
|
|
36919
|
+
[element]="element()"
|
|
36920
|
+
[canEdit]="canEdit()"
|
|
36921
|
+
(elementChange)="elementChange.emit($event)"
|
|
36922
|
+
/>
|
|
36923
|
+
<pptx-chart-trendline-options
|
|
36924
|
+
[element]="element()"
|
|
36925
|
+
[canEdit]="canEdit()"
|
|
36926
|
+
(elementChange)="elementChange.emit($event)"
|
|
36927
|
+
/>
|
|
36928
|
+
<pptx-chart-error-bar-options
|
|
36929
|
+
[element]="element()"
|
|
36930
|
+
[canEdit]="canEdit()"
|
|
36931
|
+
(elementChange)="elementChange.emit($event)"
|
|
36932
|
+
/>
|
|
36933
|
+
<pptx-chart-data-editor
|
|
36934
|
+
[element]="element()"
|
|
36935
|
+
[canEdit]="canEdit()"
|
|
36936
|
+
(elementChange)="elementChange.emit($event)"
|
|
36937
|
+
/>
|
|
36938
|
+
</div>
|
|
36939
|
+
`, isInline: true, styles: [".pptx-advanced-chart{display:flex;flex-direction:column}\n"], dependencies: [{ kind: "component", type: ChartDataEditorComponent, selector: "pptx-chart-data-editor", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartDisplayOptionsComponent, selector: "pptx-chart-display-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartDataLabelOptionsComponent, selector: "pptx-chart-data-label-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartAxisOptionsComponent, selector: "pptx-chart-axis-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartAxisStyleOptionsComponent, selector: "pptx-chart-axis-style-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartMarkerOptionsComponent, selector: "pptx-chart-marker-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartComboTypeOptionsComponent, selector: "pptx-chart-combo-type-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartDatapointOptionsComponent, selector: "pptx-chart-datapoint-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartTrendlineOptionsComponent, selector: "pptx-chart-trendline-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartErrorBarOptionsComponent, selector: "pptx-chart-error-bar-options", inputs: ["element", "canEdit"], outputs: ["elementChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
33901
36940
|
}
|
|
36941
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: AdvancedChartEditorComponent, decorators: [{
|
|
36942
|
+
type: Component,
|
|
36943
|
+
args: [{ selector: 'pptx-advanced-chart-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
36944
|
+
ChartDataEditorComponent,
|
|
36945
|
+
ChartDisplayOptionsComponent,
|
|
36946
|
+
ChartDataLabelOptionsComponent,
|
|
36947
|
+
ChartAxisOptionsComponent,
|
|
36948
|
+
ChartAxisStyleOptionsComponent,
|
|
36949
|
+
ChartMarkerOptionsComponent,
|
|
36950
|
+
ChartComboTypeOptionsComponent,
|
|
36951
|
+
ChartDatapointOptionsComponent,
|
|
36952
|
+
ChartTrendlineOptionsComponent,
|
|
36953
|
+
ChartErrorBarOptionsComponent,
|
|
36954
|
+
], template: `
|
|
36955
|
+
<div class="pptx-advanced-chart">
|
|
36956
|
+
<pptx-chart-display-options
|
|
36957
|
+
[element]="element()"
|
|
36958
|
+
[canEdit]="canEdit()"
|
|
36959
|
+
(elementChange)="elementChange.emit($event)"
|
|
36960
|
+
/>
|
|
36961
|
+
<pptx-chart-data-label-options
|
|
36962
|
+
[element]="element()"
|
|
36963
|
+
[canEdit]="canEdit()"
|
|
36964
|
+
(elementChange)="elementChange.emit($event)"
|
|
36965
|
+
/>
|
|
36966
|
+
<pptx-chart-axis-options
|
|
36967
|
+
[element]="element()"
|
|
36968
|
+
[canEdit]="canEdit()"
|
|
36969
|
+
(elementChange)="elementChange.emit($event)"
|
|
36970
|
+
/>
|
|
36971
|
+
<pptx-chart-axis-style-options
|
|
36972
|
+
[element]="element()"
|
|
36973
|
+
[canEdit]="canEdit()"
|
|
36974
|
+
(elementChange)="elementChange.emit($event)"
|
|
36975
|
+
/>
|
|
36976
|
+
<pptx-chart-marker-options
|
|
36977
|
+
[element]="element()"
|
|
36978
|
+
[canEdit]="canEdit()"
|
|
36979
|
+
(elementChange)="elementChange.emit($event)"
|
|
36980
|
+
/>
|
|
36981
|
+
<pptx-chart-combo-type-options
|
|
36982
|
+
[element]="element()"
|
|
36983
|
+
[canEdit]="canEdit()"
|
|
36984
|
+
(elementChange)="elementChange.emit($event)"
|
|
36985
|
+
/>
|
|
36986
|
+
<pptx-chart-datapoint-options
|
|
36987
|
+
[element]="element()"
|
|
36988
|
+
[canEdit]="canEdit()"
|
|
36989
|
+
(elementChange)="elementChange.emit($event)"
|
|
36990
|
+
/>
|
|
36991
|
+
<pptx-chart-trendline-options
|
|
36992
|
+
[element]="element()"
|
|
36993
|
+
[canEdit]="canEdit()"
|
|
36994
|
+
(elementChange)="elementChange.emit($event)"
|
|
36995
|
+
/>
|
|
36996
|
+
<pptx-chart-error-bar-options
|
|
36997
|
+
[element]="element()"
|
|
36998
|
+
[canEdit]="canEdit()"
|
|
36999
|
+
(elementChange)="elementChange.emit($event)"
|
|
37000
|
+
/>
|
|
37001
|
+
<pptx-chart-data-editor
|
|
37002
|
+
[element]="element()"
|
|
37003
|
+
[canEdit]="canEdit()"
|
|
37004
|
+
(elementChange)="elementChange.emit($event)"
|
|
37005
|
+
/>
|
|
37006
|
+
</div>
|
|
37007
|
+
`, styles: [".pptx-advanced-chart{display:flex;flex-direction:column}\n"] }]
|
|
37008
|
+
}], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
|
|
33902
37009
|
|
|
33903
37010
|
/**
|
|
33904
37011
|
* chart-data-editor.component.ts: Presentational chart data editor panel.
|
|
@@ -34152,15 +37259,20 @@ class ChartDataEditorComponent {
|
|
|
34152
37259
|
</tbody>
|
|
34153
37260
|
</table>
|
|
34154
37261
|
</div>
|
|
37262
|
+
<pptx-advanced-chart-editor
|
|
37263
|
+
[element]="element()"
|
|
37264
|
+
[canEdit]="canEdit()"
|
|
37265
|
+
(elementChange)="elementChange.emit($event)"
|
|
37266
|
+
/>
|
|
34155
37267
|
} @else {
|
|
34156
37268
|
<p class="pptx-chart-editor__empty">No chart data available.</p>
|
|
34157
37269
|
}
|
|
34158
37270
|
</section>
|
|
34159
|
-
`, isInline: true, styles: [".pptx-chart-editor{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-bottom:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-editor__header{display:flex;align-items:center;justify-content:space-between;gap:.35rem;flex-wrap:wrap}.pptx-chart-editor__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-editor__actions{display:flex;gap:.2rem;flex-wrap:wrap}.pptx-chart-editor__btn{padding:2px 5px;font-size:10px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;cursor:pointer;white-space:nowrap}.pptx-chart-editor__btn:disabled{opacity:.4;cursor:not-allowed}.pptx-chart-editor__btn--danger{color:var(--pptx-inspector-danger, #f47c7c);border-color:var(--pptx-inspector-danger-border, #6b2a2a)}.pptx-chart-editor__scroll{overflow-x:auto}.pptx-chart-editor__table{border-collapse:collapse;font-size:11px;min-width:100%}.pptx-chart-editor__corner{min-width:64px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-editor__series-header{background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #333);padding:2px 3px;white-space:nowrap;min-width:80px}.pptx-chart-editor__name-input{width:72px;box-sizing:border-box;padding:2px 3px;font-size:11px;background:transparent;border:1px solid transparent;color:inherit;outline:none}.pptx-chart-editor__name-input:focus{border-color:var(--pptx-inspector-active, #0078d4);background:var(--pptx-inspector-active-bg, #1a3a5c)}.pptx-chart-editor__name-input:disabled{opacity:.6}.pptx-chart-editor__remove-btn{padding:0 2px;font-size:11px;line-height:1;background:none;border:none;color:var(--pptx-inspector-danger, #f47c7c);cursor:pointer;vertical-align:middle}.pptx-chart-editor__color-wrap{display:inline-flex;align-items:center;gap:1px;margin-left:2px;vertical-align:middle}.pptx-chart-editor__color-input{width:22px;height:18px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-editor__color-input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-editor__cat-cell{border:1px solid var(--pptx-inspector-border, #333);padding:1px;background:var(--pptx-inspector-input-bg, #2d2d2d)}.pptx-chart-editor__cat-wrap{display:flex;align-items:center;gap:1px}.pptx-chart-editor__cat-input{width:60px;box-sizing:border-box;padding:2px 3px;font-size:11px;background:transparent;border:none;color:var(--pptx-inspector-muted, #aaa);outline:none}.pptx-chart-editor__cat-input:focus{color:inherit;background:var(--pptx-inspector-active-bg, #1a3a5c)}.pptx-chart-editor__cat-input:disabled{opacity:.6}.pptx-chart-editor__value-cell{border:1px solid var(--pptx-inspector-border, #333);padding:1px}.pptx-chart-editor__value-input{width:72px;box-sizing:border-box;padding:2px 3px;font-size:11px;text-align:right;background:var(--pptx-inspector-input-bg, #2d2d2d);border:none;color:inherit;outline:none}.pptx-chart-editor__value-input:focus{background:var(--pptx-inspector-active-bg, #1a3a5c)}.pptx-chart-editor__value-input:disabled{opacity:.6}.pptx-chart-editor__value-input::-webkit-outer-spin-button,.pptx-chart-editor__value-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.pptx-chart-editor__empty{font-size:11px;color:var(--pptx-inspector-muted, #888);margin:.25rem 0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
37271
|
+
`, isInline: true, styles: [".pptx-chart-editor{display:flex;flex-direction:column;gap:.35rem;padding:.5rem 0;border-bottom:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-editor__header{display:flex;align-items:center;justify-content:space-between;gap:.35rem;flex-wrap:wrap}.pptx-chart-editor__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-chart-editor__actions{display:flex;gap:.2rem;flex-wrap:wrap}.pptx-chart-editor__btn{padding:2px 5px;font-size:10px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;cursor:pointer;white-space:nowrap}.pptx-chart-editor__btn:disabled{opacity:.4;cursor:not-allowed}.pptx-chart-editor__btn--danger{color:var(--pptx-inspector-danger, #f47c7c);border-color:var(--pptx-inspector-danger-border, #6b2a2a)}.pptx-chart-editor__scroll{overflow-x:auto}.pptx-chart-editor__table{border-collapse:collapse;font-size:11px;min-width:100%}.pptx-chart-editor__corner{min-width:64px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #333)}.pptx-chart-editor__series-header{background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #333);padding:2px 3px;white-space:nowrap;min-width:80px}.pptx-chart-editor__name-input{width:72px;box-sizing:border-box;padding:2px 3px;font-size:11px;background:transparent;border:1px solid transparent;color:inherit;outline:none}.pptx-chart-editor__name-input:focus{border-color:var(--pptx-inspector-active, #0078d4);background:var(--pptx-inspector-active-bg, #1a3a5c)}.pptx-chart-editor__name-input:disabled{opacity:.6}.pptx-chart-editor__remove-btn{padding:0 2px;font-size:11px;line-height:1;background:none;border:none;color:var(--pptx-inspector-danger, #f47c7c);cursor:pointer;vertical-align:middle}.pptx-chart-editor__color-wrap{display:inline-flex;align-items:center;gap:1px;margin-left:2px;vertical-align:middle}.pptx-chart-editor__color-input{width:22px;height:18px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-chart-editor__color-input:disabled{opacity:.6;cursor:not-allowed}.pptx-chart-editor__cat-cell{border:1px solid var(--pptx-inspector-border, #333);padding:1px;background:var(--pptx-inspector-input-bg, #2d2d2d)}.pptx-chart-editor__cat-wrap{display:flex;align-items:center;gap:1px}.pptx-chart-editor__cat-input{width:60px;box-sizing:border-box;padding:2px 3px;font-size:11px;background:transparent;border:none;color:var(--pptx-inspector-muted, #aaa);outline:none}.pptx-chart-editor__cat-input:focus{color:inherit;background:var(--pptx-inspector-active-bg, #1a3a5c)}.pptx-chart-editor__cat-input:disabled{opacity:.6}.pptx-chart-editor__value-cell{border:1px solid var(--pptx-inspector-border, #333);padding:1px}.pptx-chart-editor__value-input{width:72px;box-sizing:border-box;padding:2px 3px;font-size:11px;text-align:right;background:var(--pptx-inspector-input-bg, #2d2d2d);border:none;color:inherit;outline:none}.pptx-chart-editor__value-input:focus{background:var(--pptx-inspector-active-bg, #1a3a5c)}.pptx-chart-editor__value-input:disabled{opacity:.6}.pptx-chart-editor__value-input::-webkit-outer-spin-button,.pptx-chart-editor__value-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.pptx-chart-editor__empty{font-size:11px;color:var(--pptx-inspector-muted, #888);margin:.25rem 0}\n"], dependencies: [{ kind: "component", type: AdvancedChartEditorComponent, selector: "pptx-advanced-chart-editor", inputs: ["element", "canEdit"], outputs: ["elementChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
34160
37272
|
}
|
|
34161
37273
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: ChartDataEditorComponent, decorators: [{
|
|
34162
37274
|
type: Component,
|
|
34163
|
-
args: [{ selector: 'pptx-chart-data-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
37275
|
+
args: [{ selector: 'pptx-chart-data-editor', standalone: true, imports: [AdvancedChartEditorComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
34164
37276
|
<section class="pptx-chart-editor" aria-label="Chart data editor">
|
|
34165
37277
|
<header class="pptx-chart-editor__header">
|
|
34166
37278
|
<h3 class="pptx-chart-editor__heading">Chart Data</h3>
|
|
@@ -34300,6 +37412,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
34300
37412
|
</tbody>
|
|
34301
37413
|
</table>
|
|
34302
37414
|
</div>
|
|
37415
|
+
<pptx-advanced-chart-editor
|
|
37416
|
+
[element]="element()"
|
|
37417
|
+
[canEdit]="canEdit()"
|
|
37418
|
+
(elementChange)="elementChange.emit($event)"
|
|
37419
|
+
/>
|
|
34303
37420
|
} @else {
|
|
34304
37421
|
<p class="pptx-chart-editor__empty">No chart data available.</p>
|
|
34305
37422
|
}
|
|
@@ -48457,6 +51574,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
48457
51574
|
`, styles: [":host{display:block;position:absolute;inset:0;overflow:hidden;pointer-events:none}.pptx-ng-transition-layer{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}\n"] }]
|
|
48458
51575
|
}], ctorParameters: () => [], propDecorators: { outgoingSlide: [{ type: i0.Input, args: [{ isSignal: true, alias: "outgoingSlide", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], transition: [{ type: i0.Input, args: [{ isSignal: true, alias: "transition", required: true }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], durationMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "durationMs", required: false }] }], complete: [{ type: i0.Output, args: ["complete"] }] } });
|
|
48459
51576
|
|
|
51577
|
+
/**
|
|
51578
|
+
* touch-gestures.ts: thin Angular adapter over the framework-agnostic
|
|
51579
|
+
* `createTouchGestureRecognizer` from `pptx-viewer-shared`.
|
|
51580
|
+
*
|
|
51581
|
+
* The gesture state machine itself (pinch-to-zoom, swipe, long-press) lives in
|
|
51582
|
+
* shared and is identical across React / Vue / Angular. This adapter only owns
|
|
51583
|
+
* the DOM listener attach/detach lifecycle, mirroring the React hook
|
|
51584
|
+
* `packages/react/src/viewer/hooks/useTouchGestures.ts`:
|
|
51585
|
+
* - `touchstart` / `touchmove` are registered with `{ passive: false }` so the
|
|
51586
|
+
* recogniser can call `preventDefault()` to suppress the browser's native
|
|
51587
|
+
* pinch-zoom on the canvas;
|
|
51588
|
+
* - `touchend` / `touchcancel` are passive (they never call preventDefault).
|
|
51589
|
+
*
|
|
51590
|
+
* `attachTouchGestures(element, config)` returns a teardown function that
|
|
51591
|
+
* removes every listener and cancels any pending long-press timer. Components
|
|
51592
|
+
* call it from `afterNextRender` (when the target node is live) and run the
|
|
51593
|
+
* teardown via `DestroyRef.onDestroy`.
|
|
51594
|
+
*
|
|
51595
|
+
* @module touch-gestures (angular)
|
|
51596
|
+
*/
|
|
51597
|
+
/**
|
|
51598
|
+
* Viewer zoom bounds. The Angular viewer clamps zoom to [0.2, 3] (see
|
|
51599
|
+
* `ZOOM_MIN` / `ZOOM_MAX` in `power-point-viewer.component.ts`); the pinch path
|
|
51600
|
+
* must clamp to the same range so a pinch can never exceed the buttons.
|
|
51601
|
+
*/
|
|
51602
|
+
const MIN_ZOOM_SCALE = 0.2;
|
|
51603
|
+
const MAX_ZOOM_SCALE = 3;
|
|
51604
|
+
/** Clamp a scale value to the Angular viewer's allowed zoom range. */
|
|
51605
|
+
function clampScale(value) {
|
|
51606
|
+
return clampScale$1(value, MIN_ZOOM_SCALE, MAX_ZOOM_SCALE);
|
|
51607
|
+
}
|
|
51608
|
+
/**
|
|
51609
|
+
* Attach the shared touch-gesture recogniser to `element` and return a teardown
|
|
51610
|
+
* function. Mirrors the React hook's listener lifecycle exactly:
|
|
51611
|
+
* `touchstart`/`touchmove` are non-passive (so pinch can `preventDefault`),
|
|
51612
|
+
* `touchend`/`touchcancel` are passive.
|
|
51613
|
+
*/
|
|
51614
|
+
function attachTouchGestures(element, config) {
|
|
51615
|
+
const recognizer = createTouchGestureRecognizer({
|
|
51616
|
+
getScale: config.getScale,
|
|
51617
|
+
minScale: MIN_ZOOM_SCALE,
|
|
51618
|
+
maxScale: MAX_ZOOM_SCALE,
|
|
51619
|
+
callbacks: config.callbacks,
|
|
51620
|
+
});
|
|
51621
|
+
const onStart = (e) => recognizer.onTouchStart(e);
|
|
51622
|
+
const onMove = (e) => recognizer.onTouchMove(e);
|
|
51623
|
+
const onEnd = (e) => recognizer.onTouchEnd(e);
|
|
51624
|
+
const onCancel = () => recognizer.onTouchCancel();
|
|
51625
|
+
element.addEventListener('touchstart', onStart, { passive: false });
|
|
51626
|
+
element.addEventListener('touchmove', onMove, { passive: false });
|
|
51627
|
+
element.addEventListener('touchend', onEnd, { passive: true });
|
|
51628
|
+
element.addEventListener('touchcancel', onCancel, { passive: true });
|
|
51629
|
+
return () => {
|
|
51630
|
+
element.removeEventListener('touchstart', onStart);
|
|
51631
|
+
element.removeEventListener('touchmove', onMove);
|
|
51632
|
+
element.removeEventListener('touchend', onEnd);
|
|
51633
|
+
element.removeEventListener('touchcancel', onCancel);
|
|
51634
|
+
recognizer.cancel();
|
|
51635
|
+
};
|
|
51636
|
+
}
|
|
51637
|
+
|
|
48460
51638
|
/**
|
|
48461
51639
|
* PresentationOverlayComponent: full-viewport black overlay that renders
|
|
48462
51640
|
* slides in presentation (kiosk) mode.
|
|
@@ -48526,7 +51704,11 @@ class PresentationOverlayComponent {
|
|
|
48526
51704
|
/** The slide stage root; animation styles are applied to its elements. */
|
|
48527
51705
|
stageRef = viewChild('stage', /* @ts-ignore */
|
|
48528
51706
|
...(ngDevMode ? [{ debugName: "stageRef" }] : /* istanbul ignore next */ []));
|
|
51707
|
+
/** The overlay root; the shared touch-gesture recogniser attaches here. */
|
|
51708
|
+
rootRef = viewChild('root', /* @ts-ignore */
|
|
51709
|
+
...(ngDevMode ? [{ debugName: "rootRef" }] : /* istanbul ignore next */ []));
|
|
48529
51710
|
constructor() {
|
|
51711
|
+
this.setupTouchGestures();
|
|
48530
51712
|
// Feed the current slide's element animations into playback (resets to the
|
|
48531
51713
|
// pre-build state so entrance-animated elements start hidden).
|
|
48532
51714
|
effect(() => {
|
|
@@ -48690,21 +51872,36 @@ class PresentationOverlayComponent {
|
|
|
48690
51872
|
'z-index': '10001',
|
|
48691
51873
|
};
|
|
48692
51874
|
// ------------------------------------------------------------------
|
|
48693
|
-
// Touch / swipe
|
|
51875
|
+
// Touch / swipe handling (delegated to the shared gesture recogniser)
|
|
48694
51876
|
// ------------------------------------------------------------------
|
|
48695
|
-
/** Horizontal swipe distance (px) required to trigger navigation. */
|
|
48696
|
-
static SWIPE_THRESHOLD = 50;
|
|
48697
|
-
/** X coordinate captured on touchstart, or null when no swipe is active. */
|
|
48698
|
-
touchStartX = null;
|
|
48699
|
-
touchStartY = null;
|
|
48700
51877
|
/**
|
|
48701
|
-
*
|
|
48702
|
-
*
|
|
48703
|
-
*
|
|
48704
|
-
*
|
|
51878
|
+
* Wire the shared touch-gesture recogniser to the overlay root so a
|
|
51879
|
+
* horizontal swipe navigates: swipe left (direction -1) advances to the
|
|
51880
|
+
* next visible slide, swipe right (direction 1) returns to the previous,
|
|
51881
|
+
* matching the prior bespoke handler's semantics. Pinch is made inert
|
|
51882
|
+
* (equal min/max scale, no-op getScale) and there is no long-press in
|
|
51883
|
+
* presentation mode. Attach happens once the root node is live
|
|
51884
|
+
* (afterNextRender) and is torn down on destroy.
|
|
48705
51885
|
*/
|
|
48706
|
-
|
|
48707
|
-
|
|
51886
|
+
setupTouchGestures() {
|
|
51887
|
+
const destroyRef = inject(DestroyRef);
|
|
51888
|
+
afterNextRender(() => {
|
|
51889
|
+
const el = this.rootRef()?.nativeElement;
|
|
51890
|
+
if (!el) {
|
|
51891
|
+
return;
|
|
51892
|
+
}
|
|
51893
|
+
const teardown = attachTouchGestures(el, {
|
|
51894
|
+
getScale: () => 1,
|
|
51895
|
+
callbacks: {
|
|
51896
|
+
onSwipe: (direction) => {
|
|
51897
|
+
// direction 1 = swipe right (previous), -1 = swipe left (next).
|
|
51898
|
+
this.navigate(direction === 1 ? 'prev' : 'next');
|
|
51899
|
+
},
|
|
51900
|
+
},
|
|
51901
|
+
});
|
|
51902
|
+
destroyRef.onDestroy(teardown);
|
|
51903
|
+
});
|
|
51904
|
+
}
|
|
48708
51905
|
// ------------------------------------------------------------------
|
|
48709
51906
|
// Lifecycle
|
|
48710
51907
|
// ------------------------------------------------------------------
|
|
@@ -48715,9 +51912,6 @@ class PresentationOverlayComponent {
|
|
|
48715
51912
|
// Snapshot the viewport dimensions on mount (SSR-safe guard).
|
|
48716
51913
|
this.snapViewport();
|
|
48717
51914
|
}
|
|
48718
|
-
ngOnDestroy() {
|
|
48719
|
-
// Nothing to clean up; HostListeners are removed automatically.
|
|
48720
|
-
}
|
|
48721
51915
|
// ------------------------------------------------------------------
|
|
48722
51916
|
// Resize awareness
|
|
48723
51917
|
// ------------------------------------------------------------------
|
|
@@ -48821,73 +52015,6 @@ class PresentationOverlayComponent {
|
|
|
48821
52015
|
this.navigate('next');
|
|
48822
52016
|
}
|
|
48823
52017
|
// ------------------------------------------------------------------
|
|
48824
|
-
// Swipe handling (touch devices have no keyboard)
|
|
48825
|
-
// ------------------------------------------------------------------
|
|
48826
|
-
/** Record the initial touch position. */
|
|
48827
|
-
onTouchStart(event) {
|
|
48828
|
-
const touch = event.changedTouches[0];
|
|
48829
|
-
if (!touch) {
|
|
48830
|
-
this.touchStartX = null;
|
|
48831
|
-
this.touchStartY = null;
|
|
48832
|
-
this.touchLastX = null;
|
|
48833
|
-
this.touchLastY = null;
|
|
48834
|
-
return;
|
|
48835
|
-
}
|
|
48836
|
-
this.touchStartX = touch.clientX;
|
|
48837
|
-
this.touchStartY = touch.clientY;
|
|
48838
|
-
this.touchLastX = touch.clientX;
|
|
48839
|
-
this.touchLastY = touch.clientY;
|
|
48840
|
-
}
|
|
48841
|
-
/** Track the latest gesture position so touchend can compute the delta even
|
|
48842
|
-
* when the touchend event carries no `changedTouches`. */
|
|
48843
|
-
onTouchMove(event) {
|
|
48844
|
-
const touch = event.changedTouches[0] ?? event.touches[0];
|
|
48845
|
-
if (touch) {
|
|
48846
|
-
this.touchLastX = touch.clientX;
|
|
48847
|
-
this.touchLastY = touch.clientY;
|
|
48848
|
-
}
|
|
48849
|
-
}
|
|
48850
|
-
/**
|
|
48851
|
-
* On touchend, treat a predominantly horizontal drag past the threshold as a
|
|
48852
|
-
* swipe: left-swipe → next, right-swipe → prev.
|
|
48853
|
-
*/
|
|
48854
|
-
onTouchEnd(event) {
|
|
48855
|
-
const startX = this.touchStartX;
|
|
48856
|
-
const startY = this.touchStartY;
|
|
48857
|
-
const lastX = this.touchLastX;
|
|
48858
|
-
const lastY = this.touchLastY;
|
|
48859
|
-
this.touchStartX = null;
|
|
48860
|
-
this.touchStartY = null;
|
|
48861
|
-
this.touchLastX = null;
|
|
48862
|
-
this.touchLastY = null;
|
|
48863
|
-
if (startX === null || startY === null) {
|
|
48864
|
-
return;
|
|
48865
|
-
}
|
|
48866
|
-
// Prefer the touchend coordinates; fall back to the last touchmove
|
|
48867
|
-
// position (CDP dispatches touchEnd with an empty changedTouches list).
|
|
48868
|
-
const touch = event.changedTouches[0];
|
|
48869
|
-
const endX = touch ? touch.clientX : lastX;
|
|
48870
|
-
const endY = touch ? touch.clientY : lastY;
|
|
48871
|
-
if (endX === null || endY === null) {
|
|
48872
|
-
return;
|
|
48873
|
-
}
|
|
48874
|
-
const dx = endX - startX;
|
|
48875
|
-
const dy = endY - startY;
|
|
48876
|
-
// Require a mostly-horizontal gesture past the threshold.
|
|
48877
|
-
if (Math.abs(dx) < PresentationOverlayComponent.SWIPE_THRESHOLD) {
|
|
48878
|
-
return;
|
|
48879
|
-
}
|
|
48880
|
-
if (Math.abs(dx) <= Math.abs(dy)) {
|
|
48881
|
-
return;
|
|
48882
|
-
}
|
|
48883
|
-
if (dx < 0) {
|
|
48884
|
-
this.navigate('next');
|
|
48885
|
-
}
|
|
48886
|
-
else {
|
|
48887
|
-
this.navigate('prev');
|
|
48888
|
-
}
|
|
48889
|
-
}
|
|
48890
|
-
// ------------------------------------------------------------------
|
|
48891
52018
|
// Navigation helpers
|
|
48892
52019
|
// ------------------------------------------------------------------
|
|
48893
52020
|
navigate(direction) {
|
|
@@ -48938,13 +52065,8 @@ class PresentationOverlayComponent {
|
|
|
48938
52065
|
this.closed.emit();
|
|
48939
52066
|
}
|
|
48940
52067
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: PresentationOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
48941
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: PresentationOverlayComponent, isStandalone: true, selector: "pptx-presentation-overlay", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { indexChange: "indexChange", closed: "closed" }, host: { listeners: { "window:resize": "onWindowResize()", "document:keydown": "onKeyDown($event)" } }, providers: [AnimationPlaybackService, PresentationAnnotationsService], viewQueries: [{ propertyName: "stageRef", first: true, predicate: ["stage"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
48942
|
-
<div
|
|
48943
|
-
class="pptx-ng-presentation-root"
|
|
48944
|
-
(touchstart)="onTouchStart($event)"
|
|
48945
|
-
(touchmove)="onTouchMove($event)"
|
|
48946
|
-
(touchend)="onTouchEnd($event)"
|
|
48947
|
-
>
|
|
52068
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: PresentationOverlayComponent, isStandalone: true, selector: "pptx-presentation-overlay", inputs: { slides: { classPropertyName: "slides", publicName: "slides", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, startIndex: { classPropertyName: "startIndex", publicName: "startIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { indexChange: "indexChange", closed: "closed" }, host: { listeners: { "window:resize": "onWindowResize()", "document:keydown": "onKeyDown($event)" } }, providers: [AnimationPlaybackService, PresentationAnnotationsService], viewQueries: [{ propertyName: "stageRef", first: true, predicate: ["stage"], descendants: true, isSignal: true }, { propertyName: "rootRef", first: true, predicate: ["root"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
52069
|
+
<div #root class="pptx-ng-presentation-root">
|
|
48948
52070
|
<!--
|
|
48949
52071
|
Slide counter, rendered first in DOM (before slide content) so a
|
|
48950
52072
|
generic "N / M" text query resolves to it rather than to any slide-text
|
|
@@ -49080,12 +52202,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
49080
52202
|
PresentationAnnotationOverlayComponent,
|
|
49081
52203
|
PresentationSubtitleBarComponent,
|
|
49082
52204
|
], providers: [AnimationPlaybackService, PresentationAnnotationsService], template: `
|
|
49083
|
-
<div
|
|
49084
|
-
class="pptx-ng-presentation-root"
|
|
49085
|
-
(touchstart)="onTouchStart($event)"
|
|
49086
|
-
(touchmove)="onTouchMove($event)"
|
|
49087
|
-
(touchend)="onTouchEnd($event)"
|
|
49088
|
-
>
|
|
52205
|
+
<div #root class="pptx-ng-presentation-root">
|
|
49089
52206
|
<!--
|
|
49090
52207
|
Slide counter, rendered first in DOM (before slide content) so a
|
|
49091
52208
|
generic "N / M" text query resolves to it rather than to any slide-text
|
|
@@ -49211,7 +52328,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
49211
52328
|
</button>
|
|
49212
52329
|
</div>
|
|
49213
52330
|
`, styles: [":host{display:block;position:fixed;inset:0;z-index:10000;background:#000;cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-presentation-root{position:absolute;inset:0;touch-action:pan-y}.pptx-ng-presentation-close:hover,.pptx-ng-presentation-nav:hover{background:#000000bf}.pptx-ng-presentation-tools{position:absolute;bottom:max(1rem,env(safe-area-inset-bottom));left:1rem;display:flex;gap:.25rem;padding:.25rem;border-radius:.5rem;background:#0000008c;z-index:80}.pptx-ng-presentation-tools button{width:2rem;height:2rem;border:none;border-radius:.35rem;background:transparent;color:#fff;font-size:1rem;cursor:pointer}.pptx-ng-presentation-tools button:hover{background:#ffffff26}.pptx-ng-presentation-tools button.is-active{background:#ffffff4d}\n"] }]
|
|
49214
|
-
}], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], startIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "startIndex", required: false }] }], indexChange: [{ type: i0.Output, args: ["indexChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], stageRef: [{ type: i0.ViewChild, args: ['stage', { isSignal: true }] }], onWindowResize: [{
|
|
52331
|
+
}], ctorParameters: () => [], propDecorators: { slides: [{ type: i0.Input, args: [{ isSignal: true, alias: "slides", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], startIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "startIndex", required: false }] }], indexChange: [{ type: i0.Output, args: ["indexChange"] }], closed: [{ type: i0.Output, args: ["closed"] }], stageRef: [{ type: i0.ViewChild, args: ['stage', { isSignal: true }] }], rootRef: [{ type: i0.ViewChild, args: ['root', { isSignal: true }] }], onWindowResize: [{
|
|
49215
52332
|
type: HostListener,
|
|
49216
52333
|
args: ['window:resize']
|
|
49217
52334
|
}], onKeyDown: [{
|
|
@@ -54527,67 +57644,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImpor
|
|
|
54527
57644
|
}]
|
|
54528
57645
|
}], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], activeName: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeName", required: false }] }], applyTheme: [{ type: i0.Output, args: ["applyTheme"] }], close: [{ type: i0.Output, args: ["close"] }] } });
|
|
54529
57646
|
|
|
54530
|
-
/**
|
|
54531
|
-
* touch-gestures.ts: thin Angular adapter over the framework-agnostic
|
|
54532
|
-
* `createTouchGestureRecognizer` from `pptx-viewer-shared`.
|
|
54533
|
-
*
|
|
54534
|
-
* The gesture state machine itself (pinch-to-zoom, swipe, long-press) lives in
|
|
54535
|
-
* shared and is identical across React / Vue / Angular. This adapter only owns
|
|
54536
|
-
* the DOM listener attach/detach lifecycle, mirroring the React hook
|
|
54537
|
-
* `packages/react/src/viewer/hooks/useTouchGestures.ts`:
|
|
54538
|
-
* - `touchstart` / `touchmove` are registered with `{ passive: false }` so the
|
|
54539
|
-
* recogniser can call `preventDefault()` to suppress the browser's native
|
|
54540
|
-
* pinch-zoom on the canvas;
|
|
54541
|
-
* - `touchend` / `touchcancel` are passive (they never call preventDefault).
|
|
54542
|
-
*
|
|
54543
|
-
* `attachTouchGestures(element, config)` returns a teardown function that
|
|
54544
|
-
* removes every listener and cancels any pending long-press timer. Components
|
|
54545
|
-
* call it from `afterNextRender` (when the target node is live) and run the
|
|
54546
|
-
* teardown via `DestroyRef.onDestroy`.
|
|
54547
|
-
*
|
|
54548
|
-
* @module touch-gestures (angular)
|
|
54549
|
-
*/
|
|
54550
|
-
/**
|
|
54551
|
-
* Viewer zoom bounds. The Angular viewer clamps zoom to [0.2, 3] (see
|
|
54552
|
-
* `ZOOM_MIN` / `ZOOM_MAX` in `power-point-viewer.component.ts`); the pinch path
|
|
54553
|
-
* must clamp to the same range so a pinch can never exceed the buttons.
|
|
54554
|
-
*/
|
|
54555
|
-
const MIN_ZOOM_SCALE = 0.2;
|
|
54556
|
-
const MAX_ZOOM_SCALE = 3;
|
|
54557
|
-
/** Clamp a scale value to the Angular viewer's allowed zoom range. */
|
|
54558
|
-
function clampScale(value) {
|
|
54559
|
-
return clampScale$1(value, MIN_ZOOM_SCALE, MAX_ZOOM_SCALE);
|
|
54560
|
-
}
|
|
54561
|
-
/**
|
|
54562
|
-
* Attach the shared touch-gesture recogniser to `element` and return a teardown
|
|
54563
|
-
* function. Mirrors the React hook's listener lifecycle exactly:
|
|
54564
|
-
* `touchstart`/`touchmove` are non-passive (so pinch can `preventDefault`),
|
|
54565
|
-
* `touchend`/`touchcancel` are passive.
|
|
54566
|
-
*/
|
|
54567
|
-
function attachTouchGestures(element, config) {
|
|
54568
|
-
const recognizer = createTouchGestureRecognizer({
|
|
54569
|
-
getScale: config.getScale,
|
|
54570
|
-
minScale: MIN_ZOOM_SCALE,
|
|
54571
|
-
maxScale: MAX_ZOOM_SCALE,
|
|
54572
|
-
callbacks: config.callbacks,
|
|
54573
|
-
});
|
|
54574
|
-
const onStart = (e) => recognizer.onTouchStart(e);
|
|
54575
|
-
const onMove = (e) => recognizer.onTouchMove(e);
|
|
54576
|
-
const onEnd = (e) => recognizer.onTouchEnd(e);
|
|
54577
|
-
const onCancel = () => recognizer.onTouchCancel();
|
|
54578
|
-
element.addEventListener('touchstart', onStart, { passive: false });
|
|
54579
|
-
element.addEventListener('touchmove', onMove, { passive: false });
|
|
54580
|
-
element.addEventListener('touchend', onEnd, { passive: true });
|
|
54581
|
-
element.addEventListener('touchcancel', onCancel, { passive: true });
|
|
54582
|
-
return () => {
|
|
54583
|
-
element.removeEventListener('touchstart', onStart);
|
|
54584
|
-
element.removeEventListener('touchmove', onMove);
|
|
54585
|
-
element.removeEventListener('touchend', onEnd);
|
|
54586
|
-
element.removeEventListener('touchcancel', onCancel);
|
|
54587
|
-
recognizer.cancel();
|
|
54588
|
-
};
|
|
54589
|
-
}
|
|
54590
|
-
|
|
54591
57647
|
const ZOOM_STEP = 0.1;
|
|
54592
57648
|
const ZOOM_MIN = 0.2;
|
|
54593
57649
|
const ZOOM_MAX = 3;
|
|
@@ -57392,5 +60448,5 @@ function cn(...values) {
|
|
|
57392
60448
|
* Generated bundle index. Do not edit.
|
|
57393
60449
|
*/
|
|
57394
60450
|
|
|
57395
|
-
export { AccessibilityPanelComponent, AccessibilityService, AnimationAuthorPanelComponent, AnimationPanelComponent, AnimationPlaybackService, BroadcastDialogComponent, CURSOR_PALETTE, ChartDataEditorComponent, ChartRendererComponent, CollaborationCursorsComponent, CollaborationService, CommentsPanelComponent, CommentsService, ConnectorRendererComponent, ConnectorTextOverlayComponent, DEFAULT_BROADCAST_SERVER_URL, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_FILL_COLOR, DEFAULT_PRINT_SETTINGS, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR$1 as DEFAULT_TEXT_COLOR, EMBEDDED_FONTS_STYLE_ID, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, EffectsPanelComponent, ElementRendererComponent, EmbeddedFontsService, EquationRendererComponent, ExportService, FindBarComponent, FindReplaceBarComponent, GradientPickerComponent, HANDOUT_OPTIONS, HyperlinkDialogComponent, InkRendererComponent, InspectorPanelComponent, IsMobileService, LoadContentService, MobileBottomBarComponent, MobileMenuSheetComponent, MobilePresenterViewComponent, MobileSheetComponent, MobileSlidesSheetComponent, MobileToolbarComponent, ModalDialogComponent, Model3DRendererComponent, NotesPanelComponent, OleRendererComponent, PowerPointViewerComponent, PresentationAnnotationOverlayComponent, PresentationAnnotationsService, PresentationOverlayComponent, PresentationSubtitleBarComponent, PresentationTransitionOverlayComponent, PresenterViewComponent, PrintDialogComponent, PrintService, PrintSettingsPanelComponent, PropertiesDialogComponent, RESIZE_HANDLES, SEVERITY_GROUPS, SEVERITY_LABELS, SLIDE_TRANSITION_KEYFRAMES, SVG_WARP_PRESETS, ShareDialogComponent, SignaturesPanelComponent, SignaturesService, SlideCanvasComponent, SlideSorterOverlayComponent, SlidesPanelComponent, SmartArtRendererComponent, TYPE_LABELS$1 as TYPE_LABELS, TableDataEditorComponent, TableRendererComponent, TextAdvancedPanelComponent, VIEWER_THEME, WEBM_MIME_CANDIDATES, ZoomRendererComponent, addCommentToList, advanceStep, applyFindReplacements, applyFormatToElement, applyMove, applyResize, assignUserColor, bringForward, bringToFront, buildBroadcastConfig, buildBroadcastViewerUrl, buildClearHyperlinkPatch, buildClickGroups, buildCollaborationConfig, buildCssGradientFromShapeStyle, buildDuotoneFilter, buildDuotoneFilterId, buildEmbeddedFontStyles, buildFontFaceRule, buildHyperlinkPatch, buildPatternFillCss, buildPrintHtmlDocument as buildPrintDocument, buildPropertiesPatch, buildShareUrl, bulletIndentPx, canStartBroadcast, canStartShare, canUseClipboard, clampCursorPosition, clampGifDimensions, clampNotesFontSize, clampStep, cn, collectAccessibilityIssues, collectElementText, collectSlideText, computeHandoutLayout, computeIsMobile, computeIsTablet, computePageCount, computeSlideIndices, computeTimerProgress, convertOmmlToMathMl, copyFormatFromElement, countAccessibilityIssues, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, derivePresenceList, duplicateElementById, durationOf, encodeGif, estimatePageCount, findInSlides, fontMimeForFormat, formatAutoNumber, formatCursorLabel, formatElapsed, formatPropertyDate, formatTime, fpsToFrameIntervalMs, generateBroadcastRoomId, generateCommentId, getContainerStyle, getDuotoneFilterDef, getImageSrc, getPatternSvg, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getSlideTransitionAnimations, getTextBlockStyle, getTextWarp, getWarpCategory, getWarpPath, groupIssuesBySeverity, hasCopyableFormat, hasExistingLink, headerLabel, isInjectableUrl, isPpactionUrl, isSigned, isUrlSafe, isValidRoomId, issueTrackKey, issueTypeLabel, moveElementBy, msToFrameDelayCs, normalizeFontFormat, normalizeSlidesPerPage, ommlToMathml, overallStatus, pendingElementStyles, pickSupportedMimeType, planGifFrames, planVideoSegments, presenceToCursors, provideViewerTheme, recordWebm, removeCommentFromList, renderToCanvas, replaceInSlides, replaceMatch, resizeElement, resolveFontVariant, resolveHyperlinkHref, resolveParagraphBullet, resolvePresenterNotes, resolveTransitionDuration, revealedElementStyles, routeOrthogonalConnector, sanitizeColor, sanitizeSlideIndex, sanitizeUserName, searchSlides, seedBroadcastFields, seedHyperlinkDraft, seedPropertiesDraft, seedShareFields, segmentFrameCount, sendBackward, sendToBack, setElementPosition, shouldUseSvgWarp, signatureCountLabel, signatureKey, signatureTimestamp, signerName, statusKind, statusLabel, themeStyle, themeToCssVars, toggleCommentResolvedInList, updateElementById, validatePrintSettings, validateRoomId, waypointsToPathD, worstStatus };
|
|
60451
|
+
export { AccessibilityPanelComponent, AccessibilityService, AdvancedChartEditorComponent, AnimationAuthorPanelComponent, AnimationPanelComponent, AnimationPlaybackService, BroadcastDialogComponent, CURSOR_PALETTE, ChartAxisOptionsComponent, ChartAxisStyleOptionsComponent, ChartComboTypeOptionsComponent, ChartDataEditorComponent, ChartDataLabelOptionsComponent, ChartDatapointOptionsComponent, ChartDisplayOptionsComponent, ChartErrorBarOptionsComponent, ChartMarkerOptionsComponent, ChartRendererComponent, ChartTrendlineOptionsComponent, CollaborationCursorsComponent, CollaborationService, CommentsPanelComponent, CommentsService, ConnectorRendererComponent, ConnectorTextOverlayComponent, DEFAULT_BROADCAST_SERVER_URL, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_FILL_COLOR, DEFAULT_PRINT_SETTINGS, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_COLOR$1 as DEFAULT_TEXT_COLOR, EMBEDDED_FONTS_STYLE_ID, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, EffectsPanelComponent, ElementRendererComponent, EmbeddedFontsService, EquationRendererComponent, ExportService, FindBarComponent, FindReplaceBarComponent, GradientPickerComponent, HANDOUT_OPTIONS, HyperlinkDialogComponent, InkRendererComponent, InspectorPanelComponent, IsMobileService, LoadContentService, MobileBottomBarComponent, MobileMenuSheetComponent, MobilePresenterViewComponent, MobileSheetComponent, MobileSlidesSheetComponent, MobileToolbarComponent, ModalDialogComponent, Model3DRendererComponent, NotesPanelComponent, OleRendererComponent, PowerPointViewerComponent, PresentationAnnotationOverlayComponent, PresentationAnnotationsService, PresentationOverlayComponent, PresentationSubtitleBarComponent, PresentationTransitionOverlayComponent, PresenterViewComponent, PrintDialogComponent, PrintService, PrintSettingsPanelComponent, PropertiesDialogComponent, RESIZE_HANDLES, SEVERITY_GROUPS, SEVERITY_LABELS, SLIDE_TRANSITION_KEYFRAMES, SVG_WARP_PRESETS, ShareDialogComponent, SignaturesPanelComponent, SignaturesService, SlideCanvasComponent, SlideSorterOverlayComponent, SlidesPanelComponent, SmartArtRendererComponent, TYPE_LABELS$1 as TYPE_LABELS, TableDataEditorComponent, TableRendererComponent, TextAdvancedPanelComponent, VIEWER_THEME, WEBM_MIME_CANDIDATES, ZoomRendererComponent, addCommentToList, advanceStep, applyFindReplacements, applyFormatToElement, applyMove, applyResize, assignUserColor, bringForward, bringToFront, buildBroadcastConfig, buildBroadcastViewerUrl, buildClearHyperlinkPatch, buildClickGroups, buildCollaborationConfig, buildCssGradientFromShapeStyle, buildDuotoneFilter, buildDuotoneFilterId, buildEmbeddedFontStyles, buildFontFaceRule, buildHyperlinkPatch, buildPatternFillCss, buildPrintHtmlDocument as buildPrintDocument, buildPropertiesPatch, buildShareUrl, bulletIndentPx, canStartBroadcast, canStartShare, canUseClipboard, clampCursorPosition, clampGifDimensions, clampNotesFontSize, clampStep, cn, collectAccessibilityIssues, collectElementText, collectSlideText, computeHandoutLayout, computeIsMobile, computeIsTablet, computePageCount, computeSlideIndices, computeTimerProgress, convertOmmlToMathMl, copyFormatFromElement, countAccessibilityIssues, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, derivePresenceList, duplicateElementById, durationOf, encodeGif, estimatePageCount, findInSlides, fontMimeForFormat, formatAutoNumber, formatCursorLabel, formatElapsed, formatPropertyDate, formatTime, fpsToFrameIntervalMs, generateBroadcastRoomId, generateCommentId, getContainerStyle, getDuotoneFilterDef, getImageSrc, getPatternSvg, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getSlideTransitionAnimations, getTextBlockStyle, getTextWarp, getWarpCategory, getWarpPath, groupIssuesBySeverity, hasCopyableFormat, hasExistingLink, headerLabel, isInjectableUrl, isPpactionUrl, isSigned, isUrlSafe, isValidRoomId, issueTrackKey, issueTypeLabel, moveElementBy, msToFrameDelayCs, normalizeFontFormat, normalizeSlidesPerPage, ommlToMathml, overallStatus, pendingElementStyles, pickSupportedMimeType, planGifFrames, planVideoSegments, presenceToCursors, provideViewerTheme, recordWebm, removeCommentFromList, renderToCanvas, replaceInSlides, replaceMatch, resizeElement, resolveFontVariant, resolveHyperlinkHref, resolveParagraphBullet, resolvePresenterNotes, resolveTransitionDuration, revealedElementStyles, routeOrthogonalConnector, sanitizeColor, sanitizeSlideIndex, sanitizeUserName, searchSlides, seedBroadcastFields, seedHyperlinkDraft, seedPropertiesDraft, seedShareFields, segmentFrameCount, sendBackward, sendToBack, setElementPosition, shouldUseSvgWarp, signatureCountLabel, signatureKey, signatureTimestamp, signerName, statusKind, statusLabel, themeStyle, themeToCssVars, toggleCommentResolvedInList, updateElementById, validatePrintSettings, validateRoomId, waypointsToPathD, worstStatus };
|
|
57396
60452
|
//# sourceMappingURL=pptx-angular-viewer.mjs.map
|