I'm drawing bar graphs, and I have several stacked CGRects that are directly on top of each other (i.e. one rect's minY is the previous rect's maxY). However, there are still semi-transparent gaps between the rects. Is there any way to fix this? I've found that this also happens when drawing touching adjacent arcs.
Here's a screenshot of what I mean:

By zooming in, I've confirmed that this isn't just an optical illusion like one would find between adjacent red and blue rects. I would appreciate any input.
var upToNowSegmentTotal: CGFloat = 0
for k in 0..<data[i].bars[j].segments.count {
var segmentRect: CGRect = CGRect()
if barDirection == "vertical" {
let a: CGFloat = translateY(upToNowSegmentTotal)
let b: CGFloat = translateY(upToNowSegmentTotal + data[i].bars[j].segments[k].length)
upToNowSegmentTotal += data[i].bars[j].segments[k].length
var rectY: CGFloat
if a > b {
rectY = b
} else {
rectY = a
}
segmentRect = CGRect(
x: barWidthPosition,
y: rectY,
width: barWidthAbsolute,
height: abs(a - b)
)
}
}
Ignore the stuff about the width of the bars. Here's the translateY function. Basically, it translates coordinates from the graphing window into x/y stuff that's drawn. Remember that because the window/ graphing area does not change between drawn rects, the same y input will always produce the same result.
private func translateY(y: CGFloat) -> CGFloat {
if barsAreReversed {
return graphingArea.minY + graphingArea.height * (y - graphingWindow.startValue) / (graphingWindow.length)
} else {
return graphingArea.maxY - graphingArea.height * (y - graphingWindow.startValue) / (graphingWindow.length)
}
}
EDIT 2:
Here's a simplified version of my code that shows the problem:
override func drawRect(rect: CGRect) {
let rect1: CGRect = CGRect(
x: 0,
y: 0,
width: 40,
height: 33.7
)
let rect2: CGRect = CGRect(
x: 0,
y: rect1.height,
width: 40,
height: 33.5
)
let context: CGContextRef = UIGraphicsGetCurrentContext()
CGContextSetFillColorWithColor(context, UIColor(red: 1 / 255, green: 29 / 255, blue: 29 / 255, alpha: 1).CGColor)
CGContextAddRect(context, rect1)
CGContextFillRect(context, rect1)
CGContextSetFillColorWithColor(context, UIColor(red: 9 / 255, green: 47 / 255, blue: 46 / 255, alpha: 1).CGColor)
CGContextAddRect(context, rect2)
CGContextFillRect(context, rect2)
}
It produces this:

I suspect that in this particular case, the rects you are filling are not integral, i.e they might have origins/heights that are by default rendered with slightly transparent pixels (anti-aliasing). You could avoid this by properly rounding your Y-axis translation
private func translateY(y: CGFloat) -> CGFloat {
if barsAreReversed {
return round(graphingArea.minY + graphingArea.height * (y - graphingWindow.startValue) / (graphingWindow.length))
} else {
return round(graphingArea.maxY - graphingArea.height * (y - graphingWindow.startValue) / (graphingWindow.length))
}
}
With arcs and other shapes it is not as easy, however, you could try and get rid of it, by leaving a bit of overlap between shapes. Of course, as pointed out by matt, you could simply turn anti-aliasing off, in which case these transparent "half-pixels" will all be rendered as if they are actually fully-within the rect.
This is likely happening because the rectangle coordinates you are using to draw shapes are fractional values. As a result Core Graphics performs antialiasing at the edges of those rectangles when your coordinates land between pixel boundaries.
You could solve this by simply rounding the coordinates of the rectangles before drawing. You can use the CGRectIntegral function which performs this kind of rounding, for example:
CGContextFillRect(context, CGRectIntegral(rect1))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With