diff --git a/Package.swift b/Package.swift index ecbc1d0c..907ada2d 100644 --- a/Package.swift +++ b/Package.swift @@ -110,6 +110,18 @@ let package = Package( name: "BarChartFilledCircleHatchedExample", dependencies: ["AGGRenderer", "SVGRenderer", "SwiftPlot"], path: "examples/BarChartFilledCircleHatched"), + .target( + name: "BarChartOrientationHorizontalExample", + dependencies: ["AGGRenderer", "SVGRenderer", "SwiftPlot"], + path: "examples/BarChartOrientationHorizontal"), + .target( + name: "BarChartVerticalStackedExample", + dependencies: ["AGGRenderer", "SVGRenderer", "SwiftPlot"], + path: "examples/BarChartVerticalStacked"), + .target( + name: "BarChartHorizontalStackedExample", + dependencies: ["AGGRenderer", "SVGRenderer", "SwiftPlot"], + path: "examples/BarChartHorizontalStacked"), //.testTarget( // name: "swiftplotTests", // dependencies: ["swiftplot"]), diff --git a/examples/BarChartHorizontalStacked/main.swift b/examples/BarChartHorizontalStacked/main.swift new file mode 100644 index 00000000..b5235813 --- /dev/null +++ b/examples/BarChartHorizontalStacked/main.swift @@ -0,0 +1,24 @@ +import SwiftPlot +import AGGRenderer +import SVGRenderer + +var filePath = "examples/Reference/" +let fileName = "_18_bar_chart_horizontal_stacked" + +let x:[String] = ["2008","2009","2010","2011"] +let y:[Float] = [320,-100,420,500] +let y1:[Float] = [100,100,220,245] + +var agg_renderer: AGGRenderer = AGGRenderer() +var svg_renderer: SVGRenderer = SVGRenderer() + +var plotTitle: PlotTitle = PlotTitle() + +var barGraph: BarGraph = BarGraph() +barGraph.addSeries(x, y, label: "Plot 1", color: .orange, graphOrientation: .horizontal) +barGraph.addStackSeries(y1, label: "Plot 2", color: .blue) +plotTitle.title = "BAR CHART" +barGraph.plotTitle = plotTitle + +barGraph.drawGraphAndOutput(fileName: filePath+"agg/"+fileName, renderer: agg_renderer) +barGraph.drawGraphAndOutput(fileName: filePath+"svg/"+fileName, renderer: svg_renderer) diff --git a/examples/BarChartOrientationHorizontal/main.swift b/examples/BarChartOrientationHorizontal/main.swift new file mode 100644 index 00000000..48e80ca1 --- /dev/null +++ b/examples/BarChartOrientationHorizontal/main.swift @@ -0,0 +1,22 @@ +import SwiftPlot +import AGGRenderer +import SVGRenderer + +var filePath = "examples/Reference/" +let fileName = "_08_bar_chart" + +let x:[String] = ["2008","2009","2010","2011"] +let y:[Float] = [320,-100,420,500] + +var agg_renderer: AGGRenderer = AGGRenderer() +var svg_renderer: SVGRenderer = SVGRenderer() + +var plotTitle: PlotTitle = PlotTitle() + +var barGraph: BarGraph = BarGraph() +barGraph.addSeries(x, y, label: "Plot 1", color: .orange, graphOrientation: .horizontal) +plotTitle.title = "BAR CHART" +barGraph.plotTitle = plotTitle + +barGraph.drawGraphAndOutput(fileName: filePath+"agg/"+fileName, renderer: agg_renderer) +barGraph.drawGraphAndOutput(fileName: filePath+"svg/"+fileName, renderer: svg_renderer) diff --git a/examples/BarChartVerticalStacked/main.swift b/examples/BarChartVerticalStacked/main.swift new file mode 100644 index 00000000..fe5a0825 --- /dev/null +++ b/examples/BarChartVerticalStacked/main.swift @@ -0,0 +1,24 @@ +import SwiftPlot +import AGGRenderer +import SVGRenderer + +var filePath = "examples/Reference/" +let fileName = "_17_bar_chart_vertical_stacked" + +let x:[String] = ["2008","2009","2010","2011"] +let y:[Float] = [320,-100,420,500] +let y1:[Float] = [100,100,220,245] + +var agg_renderer: AGGRenderer = AGGRenderer() +var svg_renderer: SVGRenderer = SVGRenderer() + +var plotTitle: PlotTitle = PlotTitle() + +var barGraph: BarGraph = BarGraph() +barGraph.addSeries(x, y, label: "Plot 1", color: .orange) +barGraph.addStackSeries(y1, label: "Plot 2", color: .blue) +plotTitle.title = "BAR CHART" +barGraph.plotTitle = plotTitle + +barGraph.drawGraphAndOutput(fileName: filePath+"agg/"+fileName, renderer: agg_renderer) +barGraph.drawGraphAndOutput(fileName: filePath+"svg/"+fileName, renderer: svg_renderer) diff --git a/examples/Reference/agg/_08_bar_chart.png b/examples/Reference/agg/_08_bar_chart.png index c8011a5b..84942e09 100644 Binary files a/examples/Reference/agg/_08_bar_chart.png and b/examples/Reference/agg/_08_bar_chart.png differ diff --git a/examples/Reference/agg/_09_bar_chart_forward_slash_hatched.png b/examples/Reference/agg/_09_bar_chart_forward_slash_hatched.png index 97fa1359..3aacf333 100644 Binary files a/examples/Reference/agg/_09_bar_chart_forward_slash_hatched.png and b/examples/Reference/agg/_09_bar_chart_forward_slash_hatched.png differ diff --git a/examples/Reference/agg/_10_bar_chart_backward_slash_hatched.png b/examples/Reference/agg/_10_bar_chart_backward_slash_hatched.png index c70afdda..fb1c7023 100644 Binary files a/examples/Reference/agg/_10_bar_chart_backward_slash_hatched.png and b/examples/Reference/agg/_10_bar_chart_backward_slash_hatched.png differ diff --git a/examples/Reference/agg/_11_bar_chart_vertical_hatched.png b/examples/Reference/agg/_11_bar_chart_vertical_hatched.png index 1b7695a3..ddc5a2b8 100644 Binary files a/examples/Reference/agg/_11_bar_chart_vertical_hatched.png and b/examples/Reference/agg/_11_bar_chart_vertical_hatched.png differ diff --git a/examples/Reference/agg/_12_bar_chart_horizontal_hatched.png b/examples/Reference/agg/_12_bar_chart_horizontal_hatched.png index 5f4b4218..ff5c23b4 100644 Binary files a/examples/Reference/agg/_12_bar_chart_horizontal_hatched.png and b/examples/Reference/agg/_12_bar_chart_horizontal_hatched.png differ diff --git a/examples/Reference/agg/_13_bar_chart_grid_hatched.png b/examples/Reference/agg/_13_bar_chart_grid_hatched.png index 7997ec3b..d948f040 100644 Binary files a/examples/Reference/agg/_13_bar_chart_grid_hatched.png and b/examples/Reference/agg/_13_bar_chart_grid_hatched.png differ diff --git a/examples/Reference/agg/_14_bar_chart_cross_hatched.png b/examples/Reference/agg/_14_bar_chart_cross_hatched.png index 18e4d162..6029495b 100644 Binary files a/examples/Reference/agg/_14_bar_chart_cross_hatched.png and b/examples/Reference/agg/_14_bar_chart_cross_hatched.png differ diff --git a/examples/Reference/agg/_15_bar_chart_hollow_circle_hatched.png b/examples/Reference/agg/_15_bar_chart_hollow_circle_hatched.png index 1c67bb83..e1a0ae26 100644 Binary files a/examples/Reference/agg/_15_bar_chart_hollow_circle_hatched.png and b/examples/Reference/agg/_15_bar_chart_hollow_circle_hatched.png differ diff --git a/examples/Reference/agg/_16_bar_chart_filled_circle_hatched.png b/examples/Reference/agg/_16_bar_chart_filled_circle_hatched.png index e2c01d4a..2d530c60 100644 Binary files a/examples/Reference/agg/_16_bar_chart_filled_circle_hatched.png and b/examples/Reference/agg/_16_bar_chart_filled_circle_hatched.png differ diff --git a/examples/Reference/agg/_17_bar_chart_vertical_stacked.png b/examples/Reference/agg/_17_bar_chart_vertical_stacked.png new file mode 100644 index 00000000..b01d5d15 Binary files /dev/null and b/examples/Reference/agg/_17_bar_chart_vertical_stacked.png differ diff --git a/examples/Reference/agg/_18_bar_chart_horizontal_stacked.png b/examples/Reference/agg/_18_bar_chart_horizontal_stacked.png new file mode 100644 index 00000000..4f1bf99d Binary files /dev/null and b/examples/Reference/agg/_18_bar_chart_horizontal_stacked.png differ diff --git a/examples/Reference/svg/_08_bar_chart.svg b/examples/Reference/svg/_08_bar_chart.svg index 823abd0e..2f721fe5 100644 --- a/examples/Reference/svg/_08_bar_chart.svg +++ b/examples/Reference/svg/_08_bar_chart.svg @@ -30,4 +30,7 @@ BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_09_bar_chart_forward_slash_hatched.svg b/examples/Reference/svg/_09_bar_chart_forward_slash_hatched.svg index 8beb0ca4..1d15b400 100644 --- a/examples/Reference/svg/_09_bar_chart_forward_slash_hatched.svg +++ b/examples/Reference/svg/_09_bar_chart_forward_slash_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_10_bar_chart_backward_slash_hatched.svg b/examples/Reference/svg/_10_bar_chart_backward_slash_hatched.svg index 96be771b..ce6f5496 100644 --- a/examples/Reference/svg/_10_bar_chart_backward_slash_hatched.svg +++ b/examples/Reference/svg/_10_bar_chart_backward_slash_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_11_bar_chart_vertical_hatched.svg b/examples/Reference/svg/_11_bar_chart_vertical_hatched.svg index a04071e9..8ad1e4c1 100644 --- a/examples/Reference/svg/_11_bar_chart_vertical_hatched.svg +++ b/examples/Reference/svg/_11_bar_chart_vertical_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_12_bar_chart_horizontal_hatched.svg b/examples/Reference/svg/_12_bar_chart_horizontal_hatched.svg index 432e4adc..137e4551 100644 --- a/examples/Reference/svg/_12_bar_chart_horizontal_hatched.svg +++ b/examples/Reference/svg/_12_bar_chart_horizontal_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_13_bar_chart_grid_hatched.svg b/examples/Reference/svg/_13_bar_chart_grid_hatched.svg index 0054d556..77ff4987 100644 --- a/examples/Reference/svg/_13_bar_chart_grid_hatched.svg +++ b/examples/Reference/svg/_13_bar_chart_grid_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_14_bar_chart_cross_hatched.svg b/examples/Reference/svg/_14_bar_chart_cross_hatched.svg index 9d5cc342..99ba23e5 100644 --- a/examples/Reference/svg/_14_bar_chart_cross_hatched.svg +++ b/examples/Reference/svg/_14_bar_chart_cross_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_15_bar_chart_hollow_circle_hatched.svg b/examples/Reference/svg/_15_bar_chart_hollow_circle_hatched.svg index 23eb183c..4f377e70 100644 --- a/examples/Reference/svg/_15_bar_chart_hollow_circle_hatched.svg +++ b/examples/Reference/svg/_15_bar_chart_hollow_circle_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_16_bar_chart_filled_circle_hatched.svg b/examples/Reference/svg/_16_bar_chart_filled_circle_hatched.svg index fe2d18bd..fa4a7341 100644 --- a/examples/Reference/svg/_16_bar_chart_filled_circle_hatched.svg +++ b/examples/Reference/svg/_16_bar_chart_filled_circle_hatched.svg @@ -30,4 +30,7 @@ HATCHED BAR CHART X-Axis Y-Axis + + +Plot 1 \ No newline at end of file diff --git a/examples/Reference/svg/_17_bar_chart_vertical_stacked.svg b/examples/Reference/svg/_17_bar_chart_vertical_stacked.svg new file mode 100644 index 00000000..c51eb7a8 --- /dev/null +++ b/examples/Reference/svg/_17_bar_chart_vertical_stacked.svg @@ -0,0 +1,48 @@ + + + + +2008 + +2009 + +2010 + +2011 + +0.0 + +100.0 + +200.0 + +300.0 + +400.0 + +500.0 + +600.0 + +700.0 + +800.0 + +-100.0 + + + + + + + + +BAR CHART +X-Axis +Y-Axis + + +Plot 1 + +Plot 2 + \ No newline at end of file diff --git a/examples/Reference/svg/_18_bar_chart_horizontal_stacked.svg b/examples/Reference/svg/_18_bar_chart_horizontal_stacked.svg new file mode 100644 index 00000000..abaa607a --- /dev/null +++ b/examples/Reference/svg/_18_bar_chart_horizontal_stacked.svg @@ -0,0 +1,50 @@ + + + + +0.0 + +100.0 + +200.0 + +300.0 + +400.0 + +500.0 + +600.0 + +700.0 + +800.0 + +-100.0 + +-200.0 + +2008 + +2009 + +2010 + +2011 + + + + + + + + +BAR CHART +X-Axis +Y-Axis + + +Plot 1 + +Plot 2 + \ No newline at end of file diff --git a/framework/SVGRenderer/SVGRenderer.swift b/framework/SVGRenderer/SVGRenderer.swift index 54334816..8cca474a 100644 --- a/framework/SVGRenderer/SVGRenderer.swift +++ b/framework/SVGRenderer/SVGRenderer.swift @@ -67,7 +67,7 @@ public class SVGRenderer: Renderer{ let h: Float = abs(p2.y - p3.y) var y = max(p1.y,p2.y,p3.y,p4.y) + (0.1*plotDimensions.subHeight) - yOffset y = plotDimensions.subHeight - y - let x = p1.x + xOffset + (0.1*plotDimensions.subWidth) + let x = min(p1.x, p2.x, p3.x, p4.x) + xOffset + (0.1*plotDimensions.subWidth) let rect: String = "" image = image + "\n" + rect drawHatchingRect(x: x, y: y, width: w, height: h, hatchPattern: hatchPattern) diff --git a/framework/SwiftPlot/BarChart.swift b/framework/SwiftPlot/BarChart.swift index b563da68..3c710f3d 100644 --- a/framework/SwiftPlot/BarChart.swift +++ b/framework/SwiftPlot/BarChart.swift @@ -21,10 +21,16 @@ public class BarGraph: Plot { plotLegend.legendTopLeft = Point(plotBorder.topLeft.x + 20, plotBorder.topLeft.y - 20) } } - + public enum GraphOrientation { + case vertical + case horizontal + } + public var graphOrientation: GraphOrientation = .vertical public var scaleY: Float = 1 + public var scaleX: Float = 1 public var plotMarkers: PlotMarkers = PlotMarkers() public var series: Series = Series() + public var stackSeries = [Series]() var barWidth : Int = 0 public var space: Int = 20 @@ -37,25 +43,74 @@ public class BarGraph: Plot { public func addSeries(_ s: Series){ series = s } + public func addStackSeries(_ s: Series) { + if (series.points.count != 0 && series.points.count == s.points.count) { + stackSeries.append(s) + } + else { + print("Stack point count does not match the Series point count.") + } + } + public func addStackSeries(_ x: [Float], label: String, color: Color = .lightBlue, hatchPattern: BarGraphSeriesOptions.Hatching = .none) { + var pts = [Point]() + if (graphOrientation == .vertical) { + for i in 0.. maximumY) { - maximumY = y - } - y = getMinY(points: pts) - if (y < minimumY) { - minimumY = y - } + if (graphOrientation == .vertical) { + for s in stackSeries { + let minStackY = getMinY(points: s.points) + let maxStackY = getMaxY(points: s.points) + + if (maxStackY>0) { + maximumY = maximumY + maxStackY + } + if (minStackY<0) { + minimumY = minimumY + minStackY + } - if minimumY>=0.0 { - origin = Point.zero - minimumY = 0.0 - } - else{ - origin = Point(0.0, (plotDimensions.graphHeight/(maximumY-minimumY))*(-minimumY)) - } + } - let topScaleMargin: Float = (plotDimensions.subHeight - plotDimensions.graphHeight)/2.0 - 10.0; - scaleY = (maximumY - minimumY) / (plotDimensions.graphHeight - topScaleMargin); - - let nD1: Int = max(getNumberOfDigits(maximumY), getNumberOfDigits(minimumY)) - var v1: Float - if (nD1 > 1 && maximumY <= pow(Float(10), Float(nD1 - 1))) { - v1 = Float(pow(Float(10), Float(nD1 - 2))) - } else if (nD1 > 1) { - v1 = Float(pow(Float(10), Float(nD1 - 1))) - } else { - v1 = Float(pow(Float(10), Float(0))) - } + if minimumY>=0.0 { + origin = Point.zero + minimumY = 0.0 + } + else{ + origin = Point(0.0, (plotDimensions.graphHeight/(maximumY-minimumY))*(-minimumY)) + } - let nY: Float = v1/scaleY - var inc1: Float = nY - if(plotDimensions.graphHeight/nY > MAX_DIV){ - inc1 = (plotDimensions.graphHeight/nY)*inc1/MAX_DIV - } + let topScaleMargin: Float = (plotDimensions.subHeight - plotDimensions.graphHeight)/2.0 - 10.0; + scaleY = (maximumY - minimumY) / (plotDimensions.graphHeight - topScaleMargin); + + let nD1: Int = max(getNumberOfDigits(maximumY), getNumberOfDigits(minimumY)) + var v1: Float + if (nD1 > 1 && maximumY <= pow(Float(10), Float(nD1 - 1))) { + v1 = Float(pow(Float(10), Float(nD1 - 2))) + } else if (nD1 > 1) { + v1 = Float(pow(Float(10), Float(nD1 - 1))) + } else { + v1 = Float(pow(Float(10), Float(0))) + } - var yM: Float = origin.y - while yM<=plotDimensions.graphHeight { - if(yM+inc1<0.0 || yM<0.0){ + let nY: Float = v1/scaleY + var inc1: Float = nY + if(plotDimensions.graphHeight/nY > MAX_DIV){ + inc1 = (plotDimensions.graphHeight/nY)*inc1/MAX_DIV + } + + var yM: Float = origin.y + while yM<=plotDimensions.graphHeight { + if(yM+inc1<0.0 || yM<0.0){ + yM = yM + inc1 + continue + } + let p: Point = Point(0, yM) + plotMarkers.yMarkers.append(p) + let text_p: Point = Point(-(renderer.getTextWidth(text: "\(ceil(scaleY*(yM-origin.y)))", textSize: plotMarkers.markerTextSize)+5), yM - 4) + plotMarkers.yMarkersTextLocation.append(text_p) + plotMarkers.yMarkersText.append("\(ceil(scaleY*(yM-origin.y)))") yM = yM + inc1 - continue } - let p: Point = Point(0, yM) - plotMarkers.yMarkers.append(p) - let text_p: Point = Point(-(renderer.getTextWidth(text: "\(ceil(scaleY*(yM-origin.y)))", textSize: plotMarkers.markerTextSize)+5), yM - 4) - plotMarkers.yMarkersTextLocation.append(text_p) - plotMarkers.yMarkersText.append("\(ceil(scaleY*(yM-origin.y)))") - yM = yM + inc1 - } - yM = origin.y - inc1 - while yM>0.0 { - let p: Point = Point(0, yM) - plotMarkers.yMarkers.append(p) - let text_p: Point = Point(-(renderer.getTextWidth(text: "\(floor(scaleY*(yM-origin.y)))", textSize: plotMarkers.markerTextSize)+5), yM - 4) - plotMarkers.yMarkersTextLocation.append(text_p) - plotMarkers.yMarkersText.append("\(floor(scaleY*(yM-origin.y)))") - yM = yM - inc1 - } + yM = origin.y - inc1 + while yM>0.0 { + let p: Point = Point(0, yM) + plotMarkers.yMarkers.append(p) + let text_p: Point = Point(-(renderer.getTextWidth(text: "\(floor(scaleY*(yM-origin.y)))", textSize: plotMarkers.markerTextSize)+5), yM - 4) + plotMarkers.yMarkersTextLocation.append(text_p) + plotMarkers.yMarkersText.append("\(floor(scaleY*(yM-origin.y)))") + yM = yM - inc1 + } - for i in 0..= 0.0 && pt.y <= plotDimensions.graphHeight) { + series.scaledPoints.append(pt) + // } + } + for index in 0..= 0.0 && pt.y <= plotDimensions.graphHeight) { + stackSeries[index].scaledPoints.append(pt) + // } + } + } } - // scale points to be plotted according to plot size - let scaleYInv: Float = 1.0/scaleY - series.scaledPoints.removeAll(); - for j in 0..= 0.0 && pt.y <= plotDimensions.graphHeight) { - series.scaledPoints.append(pt) - // } + else{ + var x: Float = getMaxX(points: pts) + if (x > maximumX) { + maximumX = x + } + x = getMinX(points: pts) + if (x < minimumX) { + minimumX = x + } + + for s in stackSeries { + let minStackX = getMinX(points: s.points) + let maxStackX = getMaxX(points: s.points) + maximumX = maximumX + maxStackX + minimumX = minimumX - minStackX + } + + if minimumX>=0.0 { + origin = Point.zero + minimumX = 0.0 + } + else{ + origin = Point((plotDimensions.graphWidth/(maximumX-minimumX))*(-minimumX), 0.0) + } + + let rightScaleMargin: Float = (plotDimensions.subWidth - plotDimensions.graphWidth)/2.0 - 10.0 + scaleX = (maximumX - minimumX) / (plotDimensions.graphWidth - rightScaleMargin) + + let nD1: Int = max(getNumberOfDigits(maximumX), getNumberOfDigits(minimumX)) + var v1: Float + if (nD1 > 1 && maximumX <= pow(Float(10), Float(nD1 - 1))) { + v1 = Float(pow(Float(10), Float(nD1 - 2))) + } else if (nD1 > 1) { + v1 = Float(pow(Float(10), Float(nD1 - 1))) + } else { + v1 = Float(pow(Float(10), Float(0))) + } + + let nX: Float = v1/scaleX + var inc1: Float = nX + if(plotDimensions.graphWidth/nX > MAX_DIV){ + inc1 = (plotDimensions.graphWidth/nX)*inc1/MAX_DIV + } + + var xM: Float = origin.x + while xM<=plotDimensions.graphWidth { + if(xM+inc1<0.0 || xM<0.0){ + xM = xM + inc1 + continue + } + let p: Point = Point(xM, 0) + plotMarkers.xMarkers.append(p) + let text_p: Point = Point(xM - (renderer.getTextWidth(text: "\(floor(scaleX*(xM-origin.x)))", textSize: plotMarkers.markerTextSize)/2.0) + 8, -15) + plotMarkers.xMarkersTextLocation.append(text_p) + plotMarkers.xMarkersText.append("\(ceil(scaleX*(xM-origin.x)))") + xM = xM + inc1 + } + xM = origin.x - inc1 + while xM>0.0 { + let p: Point = Point(xM, 0) + plotMarkers.xMarkers.append(p) + let text_p: Point = Point(xM - (renderer.getTextWidth(text: "\(floor(scaleX*(xM-origin.x)))", textSize: plotMarkers.markerTextSize)/2.0) + 8, -15) + plotMarkers.xMarkersTextLocation.append(text_p) + plotMarkers.xMarkersText.append("\(floor(scaleX*(xM-origin.x)))") + xM = xM - inc1 + } + + for i in 0..= 0.0 && pt.y <= plotDimensions.graphHeight) { + series.scaledPoints.append(pt) + // } + } + for index in 0..= 0.0 && pt.y <= plotDimensions.graphHeight) { + stackSeries[index].scaledPoints.append(pt) + // } + } + } } } @@ -239,13 +418,88 @@ extension BarGraph { } func drawPlots(renderer: Renderer) { - for index in 0..= 0) { + currentHeightPositive = tL.y - bL.y + } + else { + currentHeightNegative = tL.y - bL.y + } + renderer.drawSolidRect(topLeftPoint: tL, topRightPoint: tR, bottomRightPoint: bR, bottomLeftPoint: bL, fillColor: series.color, hatchPattern: series.barGraphSeriesOptions.hatchPattern, isOriginShifted: true) + for s in stackSeries { + tL = Point(plotMarkers.xMarkers[index].x - Float(barWidth)/2.0 + Float(space)/2.0, s.scaledPoints[index].y) + bL = Point(plotMarkers.xMarkers[index].x - Float(barWidth)/2.0 + Float(space)/2.0, origin.y) + if (tL.y - bL.y >= 0) { + tL = Point(plotMarkers.xMarkers[index].x - Float(barWidth)/2.0 + Float(space)/2.0, s.scaledPoints[index].y + currentHeightPositive) + tR = Point(plotMarkers.xMarkers[index].x + Float(barWidth)/2.0 - Float(space)/2.0, s.scaledPoints[index].y + currentHeightPositive) + bL = Point(plotMarkers.xMarkers[index].x - Float(barWidth)/2.0 + Float(space)/2.0, origin.y + currentHeightPositive) + bR = Point(plotMarkers.xMarkers[index].x + Float(barWidth)/2.0 - Float(space)/2.0, origin.y + currentHeightPositive) + } + else { + tL = Point(plotMarkers.xMarkers[index].x - Float(barWidth)/2.0 + Float(space)/2.0, s.scaledPoints[index].y + currentHeightNegative) + tR = Point(plotMarkers.xMarkers[index].x + Float(barWidth)/2.0 - Float(space)/2.0, s.scaledPoints[index].y + currentHeightNegative) + bL = Point(plotMarkers.xMarkers[index].x - Float(barWidth)/2.0 + Float(space)/2.0, origin.y + currentHeightNegative) + bR = Point(plotMarkers.xMarkers[index].x + Float(barWidth)/2.0 - Float(space)/2.0, origin.y + currentHeightNegative) + } + let heightIncrement = tL.y - bL.y + if (heightIncrement >= 0) { + currentHeightPositive = currentHeightPositive + heightIncrement + } + else { + currentHeightNegative = currentHeightNegative + heightIncrement + } + renderer.drawSolidRect(topLeftPoint: tL, topRightPoint: tR, bottomRightPoint: bR, bottomLeftPoint: bL, fillColor: s.color, hatchPattern: s.barGraphSeriesOptions.hatchPattern, isOriginShifted: true) + } + } + } + else { + for index in 0..= 0) { + currentWidthPositive = tR.x - tL.x + } + else { + currentWidthNegative = tR.x - tL.x + } + renderer.drawSolidRect(topLeftPoint: tL, topRightPoint: tR, bottomRightPoint: bR, bottomLeftPoint: bL, fillColor: series.color, hatchPattern: series.barGraphSeriesOptions.hatchPattern, isOriginShifted: true) + for s in stackSeries { + + tL = Point(origin.x, plotMarkers.yMarkers[index].y + Float(barWidth)/2.0 - Float(space)/2.0) + tR = Point(s.scaledPoints[index].x, plotMarkers.yMarkers[index].y + Float(barWidth)/2.0 - Float(space)/2.0) + if (tR.x - tL.x >= 0) { + tL = Point(origin.x + currentWidthPositive, plotMarkers.yMarkers[index].y + Float(barWidth)/2.0 - Float(space)/2.0) + tR = Point(s.scaledPoints[index].x + currentWidthPositive, plotMarkers.yMarkers[index].y + Float(barWidth)/2.0 - Float(space)/2.0) + bL = Point(origin.x + currentWidthPositive, plotMarkers.yMarkers[index].y - Float(barWidth)/2.0 + Float(space)/2.0) + bR = Point(s.scaledPoints[index].x + currentWidthPositive, plotMarkers.yMarkers[index].y - Float(barWidth)/2.0 + Float(space)/2.0) + } + else { + tL = Point(origin.x + currentWidthNegative, plotMarkers.yMarkers[index].y + Float(barWidth)/2.0 - Float(space)/2.0) + tR = Point(s.scaledPoints[index].x + currentWidthNegative, plotMarkers.yMarkers[index].y + Float(barWidth)/2.0 - Float(space)/2.0) + bL = Point(origin.x + currentWidthNegative, plotMarkers.yMarkers[index].y - Float(barWidth)/2.0 + Float(space)/2.0) + bR = Point(s.scaledPoints[index].x + currentWidthNegative, plotMarkers.yMarkers[index].y - Float(barWidth)/2.0 + Float(space)/2.0) + } + let widthIncrement = tR.x - tL.x + if (widthIncrement >= 0) { + currentWidthPositive = currentWidthPositive + widthIncrement + } + else { + currentWidthNegative = currentWidthNegative + widthIncrement + } + renderer.drawSolidRect(topLeftPoint: tL, topRightPoint: tR, bottomRightPoint: bR, bottomLeftPoint: bL, fillColor: s.color, hatchPattern: s.barGraphSeriesOptions.hatchPattern, isOriginShifted: true) + } + } } } @@ -260,33 +514,34 @@ extension BarGraph { } func drawLegends(renderer: Renderer) { - // var maxWidth: Float = 0 - // for s in series { - // let w = renderer.getTextWidth(text: s.label, textSize: plotLegend.legendTextSize) - // if (w > maxWidth) { - // maxWidth = w - // } - // } - // - // plotLegend.legendWidth = maxWidth + 3.5*plotLegend.legendTextSize - // plotLegend.legendHeight = (Float(series.count)*2.0 + 1.0)*plotLegend.legendTextSize - // - // let p1: Point = Point(plotLegend.legendTopLeft.x, plotLegend.legendTopLeft.y) - // let p2: Point = Point(plotLegend.legendTopLeft.x + plotLegend.legendWidth, plotLegend.legendTopLeft.y) - // let p3: Point = Point(plotLegend.legendTopLeft.x + plotLegend.legendWidth, plotLegend.legendTopLeft.y - plotLegend.legendHeight) - // let p4: Point = Point(plotLegend.legendTopLeft.x, plotLegend.legendTopLeft.y - plotLegend.legendHeight) - // - // renderer.drawSolidRectWithBorder(topLeftPoint: p1, topRightPoint: p2, bottomRightPoint: p3, bottomLeftPoint: p4, strokeWidth: plotBorder.borderThickness, fillColor: Color.transluscentWhite, borderColor: Color.black) - // - // for i in 0.. maxWidth) { + maxWidth = w + } + } + plotLegend.legendWidth = maxWidth + 3.5*plotLegend.legendTextSize + plotLegend.legendHeight = (Float(stackSeries.count + 1)*2.0 + 1.0)*plotLegend.legendTextSize + + let p1: Point = Point(plotLegend.legendTopLeft.x, plotLegend.legendTopLeft.y) + let p2: Point = Point(plotLegend.legendTopLeft.x + plotLegend.legendWidth, plotLegend.legendTopLeft.y) + let p3: Point = Point(plotLegend.legendTopLeft.x + plotLegend.legendWidth, plotLegend.legendTopLeft.y - plotLegend.legendHeight) + let p4: Point = Point(plotLegend.legendTopLeft.x, plotLegend.legendTopLeft.y - plotLegend.legendHeight) + + renderer.drawSolidRectWithBorder(topLeftPoint: p1, topRightPoint: p2, bottomRightPoint: p3, bottomLeftPoint: p4, strokeWidth: plotBorder.borderThickness, fillColor: Color.transluscentWhite, borderColor: Color.black, isOriginShifted: false) + + for i in 0.. Float { var min = p[0].x for index in 1..