iOS Charts: Determine the positioning and color of the highlighted entry - ios-charts

I have a pie chart implemented with the Charts library. Now when an entry is tapped and becomes highlighted, I would like to show a tooltip that shows the value of the selected entry, positioned in the middle of the entry, and outlined in the same color of the selected piece of the pie.
In the delegate function chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) I can obtain the highlight's xPx and yPx, but this is the touch point where the user tapped to highlight this entry, not the center point of the entry itself, so centering the tooltip on these values results in the tooltip jumping around depending on where you tap the entry. And I don't see any way to get the color of the highlighted entry.
I am trying to obtain the following, and outline it in that pink color:

:: 1 :: Position of the Popup
Hmm... I've been looking and I don't think the ChartDataEntry has an available frame to use as a reference point for setting your popup's position.
I think doing it based on the tap location is a decent alternative, though. That at least gets the popup to show in the same general region as the pie segment. It should still be a good user experience, in my opinion. :)
:: 2 :: Color of the Currently Selected Segment
PieChartDataSet has a values property that has your ChartDataEntry objects in it. So you could find the index of the matching one since the chartValueSelected delegate method passes you the current ChartDataEntry object (entry).

PieChartView has the marker property which you can use for display marker when a value is clicked on the chart. In my opinion, using marker property and creating the custom marker class it is a preferred way of resolving your task.
The custom marker class must conform to IMarker protocol and can be instantiated from MarkerImage class. Pay attention to two functions:
draw(context: CGContext, point: CGPoint) function with two input params which pass position and context for drawing. So you have information about the position for your balloon.
refreshContent(entry: ChartDataEntry, highlight: Highlight). In this function, you can choose a color for the balloon. MarkerImage class has chartView property so you have access to datasets. If you use more than one dataset, you can use a value of highlight.dataSetIndex to define dataset which was clicked. When the dataset is chosen you can get a color from dataSet.colors property using index obtained by dataSet.entryIndex(entry: entry).
Example of color choosing:
open override func refreshContent(entry: ChartDataEntry, highlight: Highlight)
{
let dataSet = chartView!.data!.dataSets[highlight.dataSetIndex]
let colorIndex = dataSet.entryIndex(entry: entry) % dataSet.colors.count
color = dataSet.colors[colorIndex]
super.refreshContent(entry: entry, highlight: highlight)
}

Related

Add dynamically SKLabelNode to MKTVIew

I am working on metal view that shows the heart rate graph. between every peak of this graph, I need to add a label.
In this process, chart moving from right to left
I have an array that dynamically shows the x coordinate of this label
for example when one value should show in the screen, this array contain only element and if there are more, it contain more element, this array is named coordinates
I use a for loop to get every element
for coordinate in coordinates {
}
I also have another array that dynamically shows the text of the label, and it works same as coordinates. It's named rrIntervalData.
to define this label, I asked another question here: Render text with SKRenderer
here is my code
skScene.size = CGSize(width: CGFloat(viewportSize.x), height: CGFloat(viewportSize.y))
for coordinate in coordinates {
var index = 0
skLabel.text = "\(rrIntervalData[index].value)"
skLabel.position = CGPoint(x: Int(coordinate), y: 200)
skLabel.fontSize = 20
skLabel.fontColor = SKColor.red
index += 1
}
skLabel is a SKLabelNode.
I also have skScene.addChild(skLabel), that I added in the init of the parent class (I know this is not correct), If I add it here, the app get crashed because skLabel is already added to skScene.
In the current version, the label is created in every point, and it moves with graph (as expected), but when the coordinate of the new label comes to screen, the first label is gone and it shows in the second position, and If I zoom out the graph when it should show more than 20 label in a same time, it always show the label in the last label in the right side.
how can I create a dynamic number of labels that set set here and stick with every coordinate and value?
Your help will be appreciated, It has been more than a week that I couldn't deal with adding this label.

Change Background Color of Line Chart Entry on Selection in ios-charts

I'm using the iOS Charts framework and am trying to achieve this custom selection style.
Screenshot of Chart
In this screenshot, the blue circles are my line data entries, and the purple box that red arrow points to on the '15.2' entry represents what I'm trying to achieve. So basically, instead of the standard "crosshair" the framework provides when the user selects an entry, I'd like to draw a custom selection view under the user selected entry akin to the purple box.
I'm still new to this framework - is there an easy way to accomplish this I'm missing?
Well I've had a play and I couldn't find the iOS equivalent of the custom highlighter for android.
I have however changed the standard highlighter to match your requirements.
If you just disable the horizontal highlighter and adjust width then add colour/ alpha to your requirements you should be able to achieve what you need.
graphDataSet.setDrawHighlightIndicators(true)
graphDataSet.drawHorizontalHighlightIndicatorEnabled = false
graphDataSet.highlightLineWidth = 75
graphDataSet.highlightColor = UIColor.blue.withAlphaComponent(0.5)
graphDataSet is your LineChartDataSet
let graphDataSet = LineChartDataSet(values: someValue, label: "Label")

ARKIT - 3d text - state of the art

request is to be able to render in arkit test input from keyboard.
So far I have used SCNText, which is 3d render of plain 2D text. I am not satisfied with that result as the text is clearly a projection in 3D space of a 2D text in X/Y plane. Also applying effects like "neon" is not effective.
The only thing pops out from my mind at the moment is to:
a- Create for every char a .DAE object representing the character
b- Import the .DAEs and map them with the characters
This approach is very time consuming and don't even know possible complications. Also considering the different languages it will involve further work to adapt to the different languages.
Questions:
1- Is anyone familiar with that and has implemented that already?
2- Are there around better solutions to that problem?
3- Is there any way to have already build .DAEs for the single characters ?
Thanks.
You can set the extrusiondepth paramater of SCNText to make it look more '3D':
Apple: For example, if its extrusionDepth property is 1.0, the geometry extends from -0.5 to 0.5 along the z-axis. An extrusion depth of zero creates a flat, one-sided shape—the geometry is confined to the plane whose z-coordinate is 0.0, and viewable only from its front unless its material’s isDoubleSided property is true.
You can also use an NSAttributedString which would add some extra' effects'.
And finally you say that you want the SCNText to appear dynamically based on Keyboard input?
Create a TextField and add it to your view e.g:
let textField = UITextField(frame: self.view.bounds)
self.view.addSubview(textField)
textField.backgroundColor = .clear
textField.becomeFirstResponder()
textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
Respond to the input:
#objc func textFieldDidChange(_ textField: UITextField) {
//Set The SCNText Here
displayLabel.string = textField.text
}

Auto layout constraints not taking effect on child controls until parent container is resized (swift)

I have a program with an NSSplitView (containing two panes) filling the window. The left pane is an NSStackView and it contains three NSBoxes. The top two each contain an NSTextField for displaying a string of weather information that can change length every time it is updated by code in the background. I have added the relevant constraints to the top two NSBoxes (and their child NSTextFields) to make them expand or shrink to fit the size of the text fields inside them as the text changes length. The third NSBox fills up the remaining space in the stack view.
The problem is that when the window loads, the NSBoxes (as expected) display the correct size as designed in interface builder to fit the default string in the text fields. However, when the update code kicks in and changes the text of the text fields to the downloaded data, which is longer than the default string, the NSBoxes do not adjust their height to fit the larger text. They only change their height when the splitter of the split view is moved. This is annoying because I have to move the splitter every time the number of lines in the text fields changes. Why is this happening and how can I make the boxes update their height to fit the text when it is longer or shorter than before?
It is much like this question (the only source of information I found on my problem): NSScrollView with auto layout not resizing until first manual window resize, however the solution did not work for me.
Below is an image of the interface (again, the top two boxes should resize to fit their text but this only happens when the splitter is moved). It shows longer text than the boxes can display and they haven't resized:
One option is to create a subclass of NSBox and override the intrinsicContentSize property. In your implementation you'd measure the height of the text contained in the box's text field, take account of any vertical padding that exists between the vertical edges of the text field and the corresponding edges of the box, and return the result of your calculation as the height part of the NSSize return value. Then, any time you want the boxes to resize, you can call invalidateIntrinsicContentSize.
I created a sample app to see if I could get this to work which I've posted here. There are a couple of tricky parts which you should be aware of:
Calculating Text Height
The most involved bit of coding in this approach is calculating the height of the text. Fortunately, Apple has documentation that tells you exactly how to do it; here's how that looks in Swift:
// Properties of your NSBox subclass
var layoutManager: NSLayoutManager {
return textStorage.layoutManagers.first! as! NSLayoutManager
}
var textContainer: NSTextContainer {
return layoutManager.textContainers.first! as! NSTextContainer
}
var typesetter: NSTypesetter {
return layoutManager.typesetter
}
// The textStorage object lies at the heart of the text stack. Create this
// object first, the rest follows.
lazy var textStorage: NSTextStorage! = {
var initialString: String = ""
var ts = NSTextStorage(attributedString: self.textField.attributedStringValue)
var lm = NSLayoutManager()
lm.typesetterBehavior = NSTypesetterBehavior.Behavior_10_2_WithCompatibility
var tc = NSTextContainer()
lm.addTextContainer(tc)
ts.addLayoutManager(lm)
return ts
}()
Setting the hugging-resisting priorities for your NSBox subclass
To get the demo working correctly I found that I needed to set the vertical hugging priority and vertical compression resistance values of the NSBox objects to 900.

hide and show a polyline in leaflet?

I'm using leaflet for show raw itinerary to go to some markers.
I'm showing my itinerary with a leaflet polyline.
But I would like to be able to
How to hide and show a polyline in leaflet ?
I can do this :
$('.leaflet-overlay-pane').hide();
and
$('.leaflet-overlay-pane').show();
But this will show and hide all my polyline.
I would like to be able to hide and show them separately.
Thanks.
If you have a reference to the polyline
var polyline = L.polyline(...);
Then you can use
map.addLayer(polyline);//For show
map.removeLayer(polyline);// For hide
at the moment I think there is no native method to only hide/show, maybe in the 0.7 version
Other solution is to access to the object container, in a old commet from the maintainer
I don't think there's an easy solution, for tile layers at least. :( I'll try to handle this sooner.
For vectors, you can change path._container.style.display, and for markers - marker._image.style.display and marker._shadow.style.display.
Removing and adding objects on the map will also change the order of the layers (if you have more than one in your legend). The added objects will always be on top and not in the original order. I use setLatLng (markers) and setLatLngs (polylines and polygons) to do a quick trick without changing the order. Just change the latLngs to e.g.(1000,1000) outside your view.
var myLatLng0 = L.latLng(1000,1000);
var myObject = L.marker(myLatLng,{....});
myObject.latlng = myLatLng;
or
var myObject = L.polygon(myPath,{....});
myObject.path = myPath;
Hide / Show marker:
myObject.setLatLng(myLatLng0);
myObject.setLatLng(myObject.latlng);
Hide / Show polyline or polygon:
myObject.setLatLngs(myLatLng0);
myObject.setLatLngs(myObject.path);
Note: hiding polylines and polygons will also work with setLatLngs(false). setLatLng(false) for markers will give an error.