Skip to content

Commit ef3ce28

Browse files
committed
WIP
1 parent 1d26201 commit ef3ce28

6 files changed

Lines changed: 118 additions & 54 deletions

File tree

src/EPPlus.Export.ImageRenderer.Test/Chart/LineChartToSvgTests.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ public void GenerateSvgForLineCharts_sheet1()
2020
var ws = p.Workbook.Worksheets[0];
2121
var renderer = new EPPlusImageRenderer.ImageRenderer();
2222

23-
//var ix = 4;
24-
//var c = ws.Drawings[ix];
25-
//var svg = renderer.RenderDrawingToSvg(c);
26-
//SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg);
23+
var ix = 1;
24+
var c = ws.Drawings[ix];
25+
var svg = renderer.RenderDrawingToSvg(c);
26+
SaveTextFileToWorkbook($"svg\\ChartForSvg_ind{ix++}.svg", svg);
2727

28-
var ix = 0;
29-
foreach (ExcelChart c in ws.Drawings)
30-
{
31-
var svg = renderer.RenderDrawingToSvg(c);
32-
SaveTextFileToWorkbook($"svg\\ChartForSvg{ix++}.svg", svg);
33-
}
28+
//var ix = 0;
29+
//foreach (ExcelChart c in ws.Drawings)
30+
//{
31+
// var svg = renderer.RenderDrawingToSvg(c);
32+
// SaveTextFileToWorkbook($"svg\\ChartForSvg{ix++}.svg", svg);
33+
//}
3434
}
3535
}
3636

src/EPPlus.Export.ImageRenderer.Test/TextRenderTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,8 @@ public void VerifyVerticalAlignBottom()
345345

346346
var ir = new EPPlusImageRenderer.ImageRenderer();
347347
var svg = ir.RenderDrawingToSvg(shape);
348-
348+
SaveTextFileToWorkbook("bottom.svg", svg);
349+
SaveWorkbook("vaBottom.xlsx", p);
349350
//Appears off by ~2 px because of border width
350351
Assert.AreEqual(278d, tbItem.Bounds.GlobalTop.PointToPixel(), 1.0);
351352
}

src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChartAxis.cs

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -476,18 +476,38 @@ private List<SvgTextBox> GetAxisValueTextBoxes()
476476
//Align the axis labels according to the label alignment setting. This is only relevant for horizontal axis, vertical axis are always right aligned.
477477
var lblAlignment = (Axis as ExcelChartAxisStandard)?.LabelAlignment??OfficeOpenXml.eAxisLabelAlignment.Center;
478478
var majorWidth = Rectangle.Width / AxisValues.Count;
479-
foreach (var tb in ret)
479+
if (Axis.CrossBetween == eCrossBetween.Between)
480480
{
481-
switch (lblAlignment)
481+
foreach (var tb in ret)
482482
{
483-
case OfficeOpenXml.eAxisLabelAlignment.Left:
484-
break;
485-
case OfficeOpenXml.eAxisLabelAlignment.Center:
486-
tb.Left += majorWidth / 2 - tb.Width / 2;
487-
break;
488-
case OfficeOpenXml.eAxisLabelAlignment.Right:
489-
tb.Left += majorWidth - tb.Width;
490-
break;
483+
switch (lblAlignment)
484+
{
485+
case OfficeOpenXml.eAxisLabelAlignment.Left:
486+
tb.Left -= tb.Width;
487+
break;
488+
case OfficeOpenXml.eAxisLabelAlignment.Center:
489+
tb.Left -= tb.Width / 2;
490+
break;
491+
case OfficeOpenXml.eAxisLabelAlignment.Right:
492+
break;
493+
}
494+
}
495+
}
496+
else
497+
{
498+
foreach (var tb in ret)
499+
{
500+
switch (lblAlignment)
501+
{
502+
case OfficeOpenXml.eAxisLabelAlignment.Left:
503+
break;
504+
case OfficeOpenXml.eAxisLabelAlignment.Center:
505+
tb.Left += majorWidth / 2 - tb.Width / 2;
506+
break;
507+
case OfficeOpenXml.eAxisLabelAlignment.Right:
508+
tb.Left += majorWidth - tb.Width;
509+
break;
510+
}
491511
}
492512
}
493513
}
@@ -510,7 +530,15 @@ private double GetAxisItemLeft(int i, OfficeOpenXml.Interfaces.Drawing.Text.Text
510530
{
511531
if (IsCatAx())
512532
{
513-
var majorWidth = Rectangle.Width / AxisValues.Count;
533+
double majorWidth;
534+
if (Axis.CrossBetween == eCrossBetween.Between)
535+
{
536+
majorWidth = Rectangle.Width / (AxisValues.Count - 1);
537+
}
538+
else
539+
{
540+
majorWidth = Rectangle.Width / AxisValues.Count;
541+
}
514542
var majorTickStartingPosition = Rectangle.Left + majorWidth * i;
515543
return majorTickStartingPosition;
516544
}
@@ -607,7 +635,14 @@ private List<SvgRenderLineItem> AddTickmarks(double units, eTimeUnit? dateUnit,
607635
if (Axis.AxisType == eAxisType.Cat)
608636
{
609637
min = 1;
610-
max = AxisValues.Count;
638+
if(Axis.CrossBetween == eCrossBetween.Between)
639+
{
640+
max = AxisValues.Count-1;
641+
}
642+
else
643+
{
644+
max = AxisValues.Count;
645+
}
611646
}
612647
else
613648
{
@@ -849,7 +884,15 @@ internal double GetPositionInPlotarea(double val, bool startValue=false)
849884
}
850885
else
851886
{
852-
return majorHeight * val + (majorHeight / 2);
887+
if (Axis.CrossBetween == eCrossBetween.Between)
888+
{
889+
majorHeight = SvgChart.Plotarea.Rectangle.Height / (Max - 1);
890+
return majorHeight * val;
891+
}
892+
else
893+
{
894+
return majorHeight * val + (majorHeight / 2);
895+
}
853896
}
854897
}
855898
else if (Axis.AxisType == eAxisType.Date && IsDateScale == false)
@@ -876,7 +919,15 @@ internal double GetPositionInPlotarea(double val, bool startValue=false)
876919
}
877920
else
878921
{
879-
return majorWidth * val + (majorWidth / 2);
922+
if(Axis.CrossBetween==eCrossBetween.Between)
923+
{
924+
majorWidth = SvgChart.Plotarea.Rectangle.Width / (Max - 1);
925+
return majorWidth * val;
926+
}
927+
else
928+
{
929+
return majorWidth * val + (majorWidth / 2);
930+
}
880931
}
881932
}
882933
else if(Axis.AxisType == eAxisType.Date && IsDateScale==false)

src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChartLegend.cs

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -291,18 +291,12 @@ internal void SetLegend(SvgChart sc, double entryWidth, double entryHeight)
291291
private void SetLineLegend(SvgChart sc, int index, SvgLegendSerie pSls, eLegendPosition pos, ExcelChartSerie s, SvgLegendSerie sls, double entryWidth, double entryHeight)
292292
{
293293
var ls = (ExcelLineChartSerie)s;
294-
var tm = _seriesHeadersMeasure[index];
295-
TextMeasurement prevTm = tm;
296-
if (pSls != null)
297-
{
298-
prevTm = _seriesHeadersMeasure[index - 1];
299-
}
300294

301-
var si = GetLineSeriesIcon(sc, ls, prevTm, tm, pSls, entryWidth, entryHeight);
295+
var si = GetLineSeriesIcon(sc, ls, pSls, entryWidth, entryHeight);
302296
sls.SeriesIcon = si;
303297

304298
var tbLeft = si.X2 + MarginExtra;
305-
var tbTop = si.Y2 - tm.Height * 0.5; //TODO:Should probably be font ascent
299+
var tbTop = si.Y2 - entryHeight * 0.5; //TODO:Should probably be font ascent
306300
double tbWidth;
307301
if (pos == eLegendPosition.Left || pos == eLegendPosition.Right)
308302
{
@@ -313,15 +307,13 @@ private void SetLineLegend(SvgChart sc, int index, SvgLegendSerie pSls, eLegendP
313307
tbWidth = Bounds.Width - tbLeft - RightMargin;
314308
}
315309

316-
var tbHeight = tm.Height;
310+
var tbHeight = entryHeight;
317311
sls.Textbox = new SvgTextBodyItem(ChartRenderer, Bounds, tbLeft, tbTop, tbWidth, tbHeight, false, true);
318-
//sls.Textbox.Bounds.Left = si.X2 + MarginExtra;
319312

320313
var entry = Chart.Legend.Entries.FirstOrDefault(x => x.Index == index);
321314
var headerText = s.GetHeaderText(index);
322315
if (entry == null || entry.Font.IsEmpty)
323316
{
324-
//sls.Textbox.AddText(s.GetHeaderText(), sc.Chart.Legend.Font);
325317
sls.Textbox.ImportParagraph(sc.Chart.Legend.TextBody.Paragraphs.FirstOrDefault(), 0, headerText);
326318
}
327319
else
@@ -352,12 +344,7 @@ private void SetBarLegend(SvgChart sc, int index, SvgLegendSerie pSls, eLegendPo
352344
{
353345
var bs = (ExcelBarChartSerie)s;
354346
var tm = _seriesHeadersMeasure[index];
355-
TextMeasurement prevTm = tm;
356-
if (pSls != null)
357-
{
358-
prevTm = _seriesHeadersMeasure[index - 1];
359-
}
360-
var si = GetBarSeriesIcon(sc, bs, prevTm, tm, pSls, entryWidth, entryHeight);
347+
var si = GetBarSeriesIcon(sc, bs, pSls, entryWidth, entryHeight);
361348
sls.SeriesIcon = si;
362349

363350
var tbLeft = si.Right + MarginExtra;
@@ -384,14 +371,14 @@ private void SetBarLegend(SvgChart sc, int index, SvgLegendSerie pSls, eLegendPo
384371
}
385372
}
386373

387-
private SvgRenderLineItem GetLineSeriesIcon(SvgChart sc, ExcelChartStandardSerie cStandardSerie, TextMeasurement pTm, TextMeasurement tm, SvgLegendSerie pSls, double entryWidth, double entryHeight)
374+
private SvgRenderLineItem GetLineSeriesIcon(SvgChart sc, ExcelChartStandardSerie cStandardSerie, SvgLegendSerie pSls, double entryWidth, double entryHeight)
388375
{
389376
var line = new SvgRenderLineItem(sc, Rectangle.Bounds);
390377
line.SetDrawingPropertiesFill(cStandardSerie.Fill, sc.Chart.StyleManager.Style.SeriesLine.FillReference.Color);
391378
line.SetDrawingPropertiesBorder(cStandardSerie.Border, sc.Chart.StyleManager.Style.SeriesLine.BorderReference.Color, cStandardSerie.Border.Fill.Style != eFillStyle.NoFill, 0.75);
392379
var icon = pSls?.SeriesIcon as SvgRenderLineItem;
393380

394-
GetItemPosition(sc, pTm, tm, pSls, entryWidth, entryHeight, icon?.X1 ?? 0D, icon?.Y1 ?? 0D, out double x, out double y);
381+
GetItemPosition(sc, pSls, entryWidth, entryHeight, icon?.X1 ?? 0D, icon?.Y1 ?? 0D, out double x, out double y);
395382

396383
line.X1 = x;
397384
line.Y1 = y;
@@ -402,15 +389,15 @@ private SvgRenderLineItem GetLineSeriesIcon(SvgChart sc, ExcelChartStandardSerie
402389
return line;
403390
}
404391

405-
private SvgRenderRectItem GetBarSeriesIcon(SvgChart sc, ExcelChartStandardSerie cStandardSerie, TextMeasurement pTm, TextMeasurement tm, SvgLegendSerie pSls, double entryWidth, double entryHeight)
392+
private SvgRenderRectItem GetBarSeriesIcon(SvgChart sc, ExcelChartStandardSerie cStandardSerie, SvgLegendSerie pSls, double entryWidth, double entryHeight)
406393
{
407394
var item = new SvgRenderRectItem(sc, Rectangle.Bounds);
408395
item.SetDrawingPropertiesFill(cStandardSerie.Fill, sc.Chart.StyleManager.Style.SeriesLine.FillReference.Color);
409396
item.SetDrawingPropertiesBorder(cStandardSerie.Border, sc.Chart.StyleManager.Style.SeriesLine.BorderReference.Color, cStandardSerie.Border.Fill.Style != eFillStyle.NoFill, 0.75);
410397
var iconHeight = GetIconLenght(sc, entryHeight);
411398
var icon = pSls?.SeriesIcon as SvgRenderRectItem;
412399

413-
GetItemPosition(sc, pTm, tm, pSls, entryWidth, entryHeight, icon?.Left ?? 0D, icon?.Top ?? 0D, out double x, out double y);
400+
GetItemPosition(sc, pSls, entryWidth, entryHeight, icon?.Left ?? 0D, icon?.Top ?? 0D, out double x, out double y);
414401

415402
item.LineCap = eLineCap.Round;
416403
item.Left = x;
@@ -421,7 +408,7 @@ private SvgRenderRectItem GetBarSeriesIcon(SvgChart sc, ExcelChartStandardSerie
421408
return item;
422409
}
423410

424-
private double GetItemPosition(SvgChart sc, TextMeasurement pTm, TextMeasurement tm, SvgLegendSerie pSls, double entryWidth, double entryHeight, double iconLeft, double iconTop, out double x, out double y)
411+
private double GetItemPosition(SvgChart sc, SvgLegendSerie pSls, double entryWidth, double entryHeight, double iconLeft, double iconTop, out double x, out double y)
425412
{
426413
var topOffset = 0D;
427414
if (sc.Chart.Legend.Position == eLegendPosition.Top ||
@@ -445,7 +432,7 @@ private double GetItemPosition(SvgChart sc, TextMeasurement pTm, TextMeasurement
445432
}
446433
if (pSls == null)
447434
{
448-
y = Rectangle.Top + TopMargin + tm.Height / 2;
435+
y = Rectangle.Top + TopMargin + entryHeight / 2;
449436
}
450437
else
451438
{
@@ -458,11 +445,11 @@ private double GetItemPosition(SvgChart sc, TextMeasurement pTm, TextMeasurement
458445
{
459446
if (pSls == null)
460447
{
461-
y = TopMargin;
448+
y = TopMargin + entryHeight / 2;
462449
}
463450
else
464451
{
465-
y = pSls.Textbox.Bounds.Bottom + MiddleMargin;
452+
y = pSls.Textbox.Bounds.Top + entryHeight + MiddleMargin;
466453
}
467454
x = LeftMargin;
468455

src/EPPlus.Export.ImageRenderer/Svg/Chart/SvgChartPlotarea.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Date Author Change
1515
using OfficeOpenXml.Drawing;
1616
using OfficeOpenXml.Drawing.Chart;
1717
using System.Collections.Generic;
18+
using System.Linq;
1819

1920
namespace EPPlusImageRenderer.Svg
2021
{
@@ -73,15 +74,39 @@ private double GetPlotAreaWidth(SvgChart sc, SvgRenderRectItem rect)
7374
sc.Legend.Bounds.GlobalLeft - RightMargin :
7475
sc.ChartArea.Rectangle.Width - RightMargin);
7576

77+
78+
double rightWidth;
7679
if (rightAxis == null)
7780
{
78-
return left - rect.GlobalLeft;
81+
rightWidth = 0;
7982
}
8083
else
8184
{
82-
var rightWidth = (rightAxis.Title?.TextBox.GetActualWidth() ?? 0D) + (rightAxis.Rectangle?.Width ?? 0D);
83-
return left - rightWidth - rect.Left;
85+
rightWidth = (rightAxis.Title?.TextBox.GetActualWidth() ?? 0D) + (rightAxis.Rectangle?.Width ?? 0D);
86+
87+
//return left - rightWidth - rect.GlobalLeft;
88+
}
89+
90+
var width = left - rightWidth;
91+
//Reserve space for the last label that will be on the tick label instead of Middle of the category.
92+
if (sc.HorizontalAxis != null && sc.HorizontalAxis.Axis.CrossBetween == eCrossBetween.Between)
93+
{
94+
var minusPA = width / sc.HorizontalAxis.AxisValues.Count / 2;
95+
if (minusPA > rightWidth)
96+
{
97+
rightWidth = minusPA;
98+
}
8499
}
100+
if (sc.SecondHorizontalAxis != null && sc.SecondHorizontalAxis.Axis.CrossBetween == eCrossBetween.Between)
101+
{
102+
var minusSA = width / sc.SecondHorizontalAxis.AxisValues.Count / 2;
103+
if (minusSA > rightWidth)
104+
{
105+
rightWidth = minusSA;
106+
}
107+
}
108+
109+
return left - rightWidth-rect.GlobalLeft;
85110
}
86111
private double GetPlotAreaLeft(SvgChart sc)
87112
{

src/EPPlus.Export.ImageRenderer/Svg/SvgShape.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ public void Render(StringBuilder sb)
258258
// gItemTest.RenderEndGroup(sb);
259259
//}
260260

261-
RenderDebugTextBox(sb);
261+
//RenderDebugTextBox(sb);
262262
sb.AppendLine("</svg>");
263263
}
264264

0 commit comments

Comments
 (0)