iOS-Charts : minOffset not working - ios-charts

When I am setting minOffset to 0, it's not removing the extra padding/margin in the bar chart.
Is there any way to hide that space?
attached the screenshot, I like to remove that extra space/padding/margin from the top.
and if you add zero to one of the bars then this margin will increase. Attaching the screenshot for that too
Extra spacing on top
Margin/space increase if one of the bars value is zero
Configuration parameters of graphs
func setUpGraph() {
self.vwChart.chartDescription?.enabled = false
self.vwChart.drawGridBackgroundEnabled = false
self.vwChart.drawBordersEnabled = false
self.vwChart.dragEnabled = false;
self.vwChart.setScaleEnabled(true)
self.vwChart.pinchZoomEnabled = false
self.vwChart.minOffset = 0
self.vwChart.animate(yAxisDuration: 1.0)
self.vwChart.xAxis.enabled = false
self.vwChart.leftAxis.enabled = false
self.vwChart.leftAxis.inverted = true
self.vwChart.rightAxis.enabled = false
self.vwChart.legend.enabled = false
self.vwChart.xAxis.drawAxisLineEnabled = false
self.vwChart.leftAxis.drawAxisLineEnabled = false
self.vwChart.rightAxis.drawAxisLineEnabled = false
self.vwChart.xAxis.drawGridLinesEnabled = false
self.vwChart.leftAxis.drawGridLinesEnabled = false
self.vwChart.rightAxis.drawGridLinesEnabled = false
self.vwChart.xAxis.drawLabelsEnabled = false
self.vwChart.xAxis.drawLabelsEnabled = false
self.vwChart.leftAxis.drawLabelsEnabled = false
self.vwChart.rightAxis.drawLabelsEnabled = false
}
func setGraphData() {
var yVals:Array<BarChartDataEntry> = Array<BarChartDataEntry>()
yVals.append(BarChartDataEntry(x: 0, y: 10))
yVals.append(BarChartDataEntry(x: 1, y: 5))
yVals.append(BarChartDataEntry(x: 2, y: 30))
yVals.append(BarChartDataEntry(x: 3, y: 10))
yVals.append(BarChartDataEntry(x: 4, y: 50))
yVals.append(BarChartDataEntry(x: 5, y: 15))
yVals.append(BarChartDataEntry(x: 6, y: 70))
yVals.append(BarChartDataEntry(x: 7, y: 20))
yVals.append(BarChartDataEntry(x: 8, y: 90))
yVals.append(BarChartDataEntry(x: 9, y: 25))
yVals.append(BarChartDataEntry(x: 10, y: 110))
yVals.append(BarChartDataEntry(x: 11, y: 30))
yVals.append(BarChartDataEntry(x: 12, y: 130))
yVals.append(BarChartDataEntry(x: 13, y: 35))
yVals.append(BarChartDataEntry(x: 14, y: 150))
yVals.append(BarChartDataEntry(x: 15, y: 40))
yVals.append(BarChartDataEntry(x: 16, y: 170))
yVals.append(BarChartDataEntry(x: 17, y: 50))
yVals.append(BarChartDataEntry(x: 18, y: 190))
let barChartDataSet = BarChartDataSet(values: yVals, label: "")
barChartDataSet.colors = [UIColor.violetBlue]
let barChartData = BarChartData(dataSet: barChartDataSet)
barChartData.barWidth = 0.4
barChartData.setDrawValues(false)
self.vwChart.data = barChartData
}

Please try to add the below line to line up the bars :
self.vwChart.leftAxis.axisMinimum = 0.0

You can use the spaceBottom/spaceTop Property for removing space.
self.vwChart.leftAxis.spaceBottom = 0.0
self.vwChart.rightAxis.spaceBottom = 0.0
Thanks.
Hope this will help.

Related

How do I use an NSImage as material of an SCNGeometry shape correctly?

I got a task in the university to add a picture as texture to the SCNGeometry Octahedron. It's my first project in Swift.
There are lot's of advices for the UIKit with UIImage class, but I'm using AppKit for macos and NSImage class. And none of the options I found in the web haven't worked for me yet. Probably I misunderstand something fundamental.
Well, firstly I dragndroped a picture named "sims.jpg" to my project folder and to art.scnassets folder. And also added them with File → Add files to "art.scnassets" and general folder. And did nothing with Assets.xcassets.
Then here is how the shape is created:
func createOctahedron() {
let vertices: [SCNVector3] = [
SCNVector3(0, 1, 0),
SCNVector3(-0.5, 0, 0.5),
SCNVector3(0.5, 0, 0.5),
SCNVector3(0.5, 0, -0.5),
SCNVector3(-0.5, 0, -0.5),
SCNVector3(0, -1, 0)
]
let source = SCNGeometrySource(vertices: vertices)
let indices: [UInt16] = [
0, 1, 2,
2, 3, 0,
3, 4, 0,
4, 1, 0,
1, 5, 2,
2, 5, 3,
3, 5, 4,
4, 5, 1
]
let element = SCNGeometryElement(indices: indices, primitiveType: .triangles)
let geometry = SCNGeometry(sources: [source], elements: [element])
let node = SCNNode(geometry: geometry)
node.geometry?.firstMaterial?.diffuse.contents = NSColor.green // назначаем цвет октаэдру
let scnView = self.view as! SCNView
scnView.scene?.rootNode.addChildNode(node)
let rotateAction = SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: .pi, z: 0, duration: 5))
node.runAction(rotateAction)
}
Just in case let me left a full code
So, I would add the image like this
let imageMaterial = SCNMaterial()
let image = NSImage.Name("sims")
imageMaterial.diffuse.contents = image
geometry.materials = [imageMaterial, imageMaterial, imageMaterial, imageMaterial, imageMaterial, imageMaterial, imageMaterial, imageMaterial]
Or maybe like that?
node.geometry?.firstMaterial?.diffuse.contents = NSImage.Name("sims")
Or should I additionally map it somehow? Help me please because I really do not get it. Xcode outputs just a rotating octahedron with no additional texture, no errors either
This line here:
let image = NSImage.Name("sims")
Only declares the name. You need:
let image = NSImage(named: NSImage.Name("sims"))
The reason your code compiles is that the contents property has a type of Any? so you can put any old goo in the property. It fails silently.
I found out what the deal was about. There was no texture appearing because of no UV mapping. I should have declared an array of 2d coordinates on the segment [0, 1] with the help of CGPoint and then add it to the source array.
Here is how it roughly looks like:
let width:CGFloat = 1/8
let coordinates: [CGPoint] = [
CGPoint(x: 0, y: 0),// BAC
CGPoint(x: width, y: 0),
CGPoint(x: width, y: 1),
CGPoint(x: 0, y: 1),// BAE
CGPoint(x: width * 7, y: 0),
CGPoint(x: 1, y: 0),
CGPoint(x: 1, y: 1),// EDA
CGPoint(x: width * 7, y: 1),
CGPoint(x: width * 6, y: 0),
CGPoint(x: width * 7, y: 0),// DAC
CGPoint(x: width, y: 0),
CGPoint(x: width * 4, y: 0),
CGPoint(x: width * 7, y: 1),// DFC
CGPoint(x: width * 6, y: 1),
CGPoint(x: width * 4, y: 1),
CGPoint(x: width, y: 1),// BFC
CGPoint(x: width * 4, y: 0),
CGPoint(x: width * 5, y: 0),
CGPoint(x: width * 5, y: 1),// BFE
CGPoint(x: width * 6, y: 1),
CGPoint(x: width * 5, y: 0),
CGPoint(x: width * 6, y: 0),// EFD
CGPoint(x: width * 4, y: 1),
CGPoint(x: width * 5, y: 1),
]
let source = [
SCNGeometrySource(vertices: vertices),
SCNGeometrySource(textureCoordinates: coordinates)
]
let element = SCNGeometryElement(indices: indices, primitiveType: .triangles)
let octahedron = SCNGeometry(sources: source, elements: [element])
After we have specified the coordinates it's enough to wright the following:
let image = NSImage(named: NSImage.Name("sims"))
octahedron.firstMaterial?.diffuse.contents = image
And the image will be stretched on faces of our octahedron.
The full code attaching

Create a UIView with rounded bottom edge

I want make view this Bottom roundedenter image description here
I think this is really close to what you want:
The rectView is your initial view;
You can play with the + 50 of quad curve height to adjust the curve
let rectView = UIView(frame: CGRect(x: 50, y: 100, width: 200, height: 200))
rectView.backgroundColor = .red
view.addSubview(rectView)
let arcBezierPath = UIBezierPath()
arcBezierPath.move(to: CGPoint(x: 0, y: rectView.frame.height))
arcBezierPath.addQuadCurve(to: CGPoint(x: rectView.frame.width, y: rectView.frame.height), controlPoint: CGPoint(x: rectView.frame.width / 2 , y: rectView.frame.height + 50 ))
arcBezierPath.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = arcBezierPath.cgPath
shapeLayer.fillColor = UIColor.red.cgColor
rectView.layer.insertSublayer(shapeLayer, at: 0)
rectView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
rectView.layer.cornerRadius = 10
rectView.layer.shadowRadius = 3
rectView.layer.shadowColor = UIColor.black.cgColor
rectView.layer.shadowOffset = CGSize(width: 0, height: 0)
rectView.layer.shadowOpacity = 0.25
Maybe, even better:
You can create your view:
let rectView = UIView(frame: CGRect(x: 50, y: 100, width: 200, height: 200))
view.addSubview(rectView)
Extend UIView
extension UIView {
func addBottomArc(ofHeight height: CGFloat, topCornerRadius: CGFloat) {
let arcBezierPath = UIBezierPath()
arcBezierPath.move(to: CGPoint(x: 0, y: frame.height))
arcBezierPath.addQuadCurve(to: CGPoint(x: frame.width, y: frame.height), controlPoint: CGPoint(x: frame.width / 2 , y: frame.height + height ))
arcBezierPath.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = arcBezierPath.cgPath
shapeLayer.fillColor = UIColor.red.cgColor
layer.insertSublayer(shapeLayer, at: 0)
layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
layer.cornerRadius = topCornerRadius
}
}
So you can set the height and the corner radius like this:
rectView.addBottomArc(ofHeight: 50, topCornerRadius: 15)
and than add the shadow you need to your view:
rectView.layer.shadowRadius = 3
rectView.layer.shadowColor = UIColor.black.cgColor
rectView.layer.shadowOffset = CGSize(width: 0, height: 0)
rectView.layer.shadowOpacity = 0.25

Applying a transformation to UIBezierPath makes drawing disappear

maybe this is a stupid question, but I'm trying to apply a transformation to a path as simple as this:
let path = UIBezierPath(rect: CGRect(x: 10, y: 10, width: 20, height: 20))
path.apply(CGAffineTransform(rotationAngle: 2.0))
"colorLiteral".setFill()
path.fill()
And seems like the fact of adding the "apply" line, completely erases the shape on the view, whereas if I don't include that line, the shape appears on its place correctly.
I'm quite new at Swift so I guess I'm missing an important step on this?
Thanks all!
Try this and remember rotationAngle takes Radians.
let bounds = CGRect(x: 10, y: 10, width: 20, height: 20)
let path = UIBezierPath(rect: bounds)
path.apply(CGAffineTransform(translationX: -bounds.midX, y: -bounds.midY))
path.apply(CGAffineTransform(rotationAngle: CGFloat.pi / 4))
path.apply(CGAffineTransform(translationX: bounds.midX, y: bounds.midY))
Using CATransform3D
shapeLayer.transform = CATransform3DMakeScale(1, -1, 1)
Transforming path,
let shapeBounds = shapeLayer.bounds
let mirror = CGAffineTransform(scaleX: 1,
y: -1)
let translate = CGAffineTransform(translationX: 0,
y: shapeBounds.size.height)
let concatenated = mirror.concatenating(translate)
bezierPath.apply(concatenated)
shapeLayer.path = bezierPath.cgPath
Transforming layer,
let shapeFrame = CGRect(x: -120, y: 120, width: 350, height: 350)
let mirrorUpsideDown = CGAffineTransform(scaleX: 1,
y: -1)
shapeLayer.setAffineTransform(mirrorUpsideDown)
shapeLayer.frame = shapeFrame

Multiple NSTextField in an NSAlert - MacOS

I am putting together a login dialog using an NSAlert in Swift 4 on MacOS. Here is the code I have so far:
func dialogOKCancel(question: String, text: String) -> (String, String) {
let alert = NSAlert()
alert.messageText = question
alert.informativeText = text
alert.alertStyle = .warning
alert.addButton(withTitle: "Login")
alert.addButton(withTitle: "Cancel")
let unameField = NSTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 24))
let passField = NSSecureTextField(frame: NSRect(x: 0, y: 0, width: 200, height: 24))
let stackViewer = NSStackView()
stackViewer.addSubview(unameField)
alert.accessoryView = stackViewer
let response: NSApplication.ModalResponse = alert.runModal()
if (response == NSApplication.ModalResponse.alertFirstButtonReturn) {
return (unameField.stringValue, passField.stringValue)
} else {
return ("", "")
}
}
This works just fine to show either the unameField or passField when I do alert.accessoryView = passField. But I want to show both fields in the same dialog. As you can see I've experimented with NSStackView (and others), but I have not found a solution to show both elements.
Hope will help you ...
You can use NSStackView and addSubview 2 item : unameField and passField.
But you must set frame for NSStackView and 2 item on NSStackView.
This is my code, you can refer:
let unameField = NSTextField(frame: NSRect(x: 0, y: 2, width: 200, height: 24))
let passField = NSSecureTextField(frame: NSRect(x: 0, y: 28, width: 200, height: 24))
let stackViewer = NSStackView(frame: NSRect(x: 0, y: 0, width: 200, height: 58))
stackViewer.addSubview(unameField)
stackViewer.addSubview(passField)
alert.accessoryView = stackViewer
And this is my result:
my result
My code: https://github.com/nhhthuanck/CustomizeNSAlertMacOS

UIBezierPath Rounded corners

I am trying to make this image appear with some rounded corners, dictated in code below
My code for this is as follows. I want path1,path[4], path[5] rounded. I am open to a different approach. Please dont recommend UIBezierPath(roundedRect:..) as I dont need corenrs 0,2 rounded. This is tricky!
let width = self.view.frame.size.width
let trianglePath = UIBezierPath()
var pts = [CGPoint(x: 2 * width / 16, y: width / 16),
CGPoint(x: width / 32, y: width / 16 + width / 16),
CGPoint(x: 2 * width / 16 , y: width / 16 + width / 8),
CGPoint(x: width / 5 + 2 * width / 16, y: width / 8 + width / 16),
CGPoint(x: width / 5 + 2 * width / 16, y: width / 16 ),
CGPoint(x: 2 * width / 16, y: width / 16 )
]
// this path replaces this, because i cannot easily add rectangle
//var path = UIBezierPath(roundedRect: rect, cornerRadius: width / 37.5).cgPath
trianglePath.move(to: pts[0])
trianglePath.addLine(to: pts[1]) // needs to be rounded
trianglePath.addLine(to: pts[2])
trianglePath.addLine(to: pts[3])
trianglePath.addLine(to: pts[4]) // needs to be rounded
trianglePath.addLine(to: pts[5]) // needs to be rounded
trianglePath.close()
let layer = CAShapeLayer()
layer.path = trianglePath.cgPath
layer.fillColor = UIColor.blue.cgColor
layer.lineCap = kCALineCapRound
layer.lineJoin = kCALineJoinRound
layer.zPosition = 4
layer.isHidden = false
view.layer.addSublayer(layer)
You can create a clipping path as explained here: https://www.raywenderlich.com/162313/core-graphics-tutorial-part-2-gradients-contexts
Specifically this bit:
let path = UIBezierPath(roundedRect: rect,
byRoundingCorners: .allCorners,
cornerRadii: CGSize(width: 8.0, height: 8.0))
path.addClip()
If you want to make rounded shapes you must use
trianglePath.AddArcToPoint(...);
See documentation here: https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/BezierPaths/BezierPaths.html#//apple_ref/doc/uid/TP40010156-CH11-SW5
To be extra helpful, here is an entire subclass which you can use to learn how to draw custom views. Hope this helps.
import Foundation
import UIKit
final class BorderedView:UIView
{
var drawTopBorder = false
var drawBottomBorder = false
var drawLeftBorder = false
var drawRightBorder = false
var topBorderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4)
var leftBorderColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4)
var rightBorderColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
var bottomBorderColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
var upperLeftCornerRadius:CGFloat = 0
var upperRightCornerRadius:CGFloat = 0
var lowerLeftCornerRadius:CGFloat = 0
var lowerRightCornerRadius:CGFloat = 0
var subview:UIView?
fileprivate var visibleView:UIView!
fileprivate var _backgroundColor:UIColor!
override init(frame: CGRect)
{
super.init(frame: frame)
super.backgroundColor = UIColor.clear
}
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
super.backgroundColor = UIColor.clear
}
func setVisibleBackgroundColor(_ color:UIColor)
{
_backgroundColor = color
}
func setBackgroundGradient(_ gradient:CAGradientLayer)
{
gradient.frame = visibleView.bounds
gradient.masksToBounds = true
visibleView.layer.insertSublayer(gradient, at: 0)
}
func drawView()
{
visibleView = UIView(frame: self.frame)
visibleView.backgroundColor = _backgroundColor
visibleView.clipsToBounds = true
if let v = subview
{
visibleView.addSubview(v)
}
}
override func draw(_ rect: CGRect)
{
// Drawing code
let width = rect.size.width - 0.5;
let height = rect.size.height - 0.5;
guard let context = UIGraphicsGetCurrentContext() else { return }
let w = self.frame.size.width;
let h = self.frame.size.height;
// Create clipping area as path.
let path = CGMutablePath();
path.move(to: CGPoint(x: 0, y: upperLeftCornerRadius))
path.addArc(tangent1End: CGPoint(x: 0, y: 0), tangent2End: CGPoint(x: upperLeftCornerRadius, y: 0), radius: upperLeftCornerRadius)
path.addLine(to: CGPoint(x: w - upperRightCornerRadius, y: 0))
path.addArc(tangent1End: CGPoint(x: w, y: 0), tangent2End: CGPoint(x: w, y: upperRightCornerRadius), radius: upperRightCornerRadius)
path.addLine(to: CGPoint(x: w, y: h - lowerRightCornerRadius))
path.addArc(tangent1End: CGPoint(x: w, y: h), tangent2End: CGPoint(x: w - lowerRightCornerRadius, y: h), radius: lowerRightCornerRadius)
path.addLine(to: CGPoint(x: lowerLeftCornerRadius, y: h))
path.addArc(tangent1End: CGPoint(x: 0, y: h), tangent2End: CGPoint(x: 0, y: h - lowerLeftCornerRadius), radius: lowerLeftCornerRadius)
path.closeSubpath();
// Add clipping area to path
context.addPath(path);
// Clip to the path and draw the image
context.clip ();
self.drawView()
visibleView.layer.render(in: context)
// ********** Your drawing code here **********
context.setLineWidth(0.5);
var stroke = false
if (drawTopBorder)
{
context.setStrokeColor(topBorderColor.cgColor);
context.move(to: CGPoint(x: 0, y: 0.5)); //start at this point
context.addLine(to: CGPoint(x: width, y: 0.5)); //draw to this point
stroke = true
}
if (drawLeftBorder)
{
context.setStrokeColor(leftBorderColor.cgColor);
context.move(to: CGPoint(x: 0.5, y: 0.5)); //start at this point
context.addLine(to: CGPoint(x: 0.5, y: height)); //draw to this point
stroke = true
}
if (drawBottomBorder)
{
context.setStrokeColor(bottomBorderColor.cgColor);
context.move(to: CGPoint(x: 0.5, y: height)); //start at this point
context.addLine(to: CGPoint(x: width, y: height)); //draw to this point
stroke = true
}
if (drawRightBorder)
{
context.setStrokeColor(rightBorderColor.cgColor);
context.move(to: CGPoint(x: width, y: 0.5)); //start at this point
context.addLine(to: CGPoint(x: width, y: height)); //draw to this point
stroke = true
}
// and now draw the Path!
if stroke
{
context.strokePath();
}
}
}