ShinobiCharts selecting a column - ios

I'm trying to make the columns in my chart to be selectable and show more details of the selected column when clicked. Every column is represented by one series (you will understand in a second).
this is how i build each series:
-(SChartSeries *)sChart:(ShinobiChart *)chart seriesAtIndex:(int)index {
SChartColumnSeries *series = [SChartColumnSeries new];
series.style.showAreaWithGradient = NO;
series.stackIndex = [NSNumber numberWithInt:0];
series.selectedStyle.showAreaWithGradient = NO;
CHART_COLOR_TYPE dataType = [TestGraphDataManager getDataType:index];
series.style.areaColor = (dataType == ACCOUNT)?
[UIColor colorWithRed:227.0f/255.0f green:179.0f/255.0f blue:0.0f/255.0f alpha:0.5f]:
[UIColor colorWithRed:0.0f/255.0f green:172.0f/255.0f blue:235.0f/255.0f alpha:0.5f];
series.selectedStyle.areaColor = [UIColor colorWithRed:129.0f/255.0f green:0.0f/255.0f blue:82.0f/255.0f alpha:0.5f];
series.selectionMode = SChartSelectionSeries;
series.style.lineColor = [UIColor clearColor];
series.selectedStyle.lineColor = [UIColor clearColor];
return series;
}
The problem I'm currently having is that only the first series is selectable. Also i made each bar represented by a different series so that i can toggle its color easly with series.selectionMode = SChartSelectionSeries
Finally I have this delegate event so that i can load the extra data but it's also being called only for the first series
- (void)sChart:(ShinobiChart *)chart toggledSelectionForSeries:(SChartSeries *)series nearPoint:(SChartDataPoint *)dataPoint atPixelCoordinate:(CGPoint)pixelPoint{
NSLog(#"click event called");
//Display data
}
Does anyone know why this is happening? It's been driving me insane all day.
Thank you, in advance for any help give.
EDIT:
I found the major problem as i do series.stackIndex = [NSNumber numberWithInt:0]; it makes all the bars with the same name stack (as nome of the names repeat its not a problem in my point of view), i do this so that all the bars are at the same distance from the tick marker and so that the bars aren't very tine. But i believe that shinobi places invisible bars for those values and they are over the other, making only the first series selectable because its over the others. If i remove that line the graphic look horrible but all are clickable.
Any idea on how to bypass this or to avoid this problem?
how it should look (using stacking indexes) but it breaks the click events:
without stacking indexes all bars are clickable but it doesn't look as good, and it gets worse the more bars i have this is using only 4 bars:

Rob here from Shinobi - thanks for getting in touch!
This can be solved by using subclassing, and returning zero for the column offset, like so:
#interface MyColumnSeries : SChartColumnSeries
#end
#implementation MyColumnSeries
- (double) offsetOfStackInChart:(ShinobiChart *)chart forDatapointIndex:(const int)pointIndex withPointSelector:(SEL)pointSelector
{
return 0.0;
}
#end

Related

Add gradient background for only last 2 section on UITableView

I'm creating a UITableView have 3 sections with custom cells. At 1st section I set it to white background color. Now I wanna set a gradient background like image below for only section 2nd and 3rd (this background will start from section 2 and end at last row of section 3):
How can I do that? Can someone give me a solution? Thanks.
This is actually pretty easy.
First, make sure each cell has a transparent background color. The default is opaque white. You can set this in your storyboard, or you can do it in your tableView:cellForRowAtIndexPath: method like this:
cell.backgroundColor = [UIColor clearColor];
Next, make a subclass of UITableView and override layoutSubviews. Be sure to call [super layoutSubviews].
In your override of layoutSubviews, the first time it's called, make a CAGradientLayer with your chosen gradient and add it as a sublayer of the table view's layer at index 0 (so it's behind all of the table view's other sublayers). On every call, update the frame of the gradient layer to be the union of [self rectForSection:1] and [self rectForSection:2].
Also, remember to set the custom class of the table view in your storyboard.
Here's the table view subclass I used to make the demo.
GradientTableView.h
#import <UIKit/UIKit.h>
#interface GradientTableView : UITableView
#end
GradientTableView.m
#import "GradientTableView.h"
#implementation GradientTableView {
CAGradientLayer *gradientLayer;
}
- (void)layoutSubviews {
[super layoutSubviews];
[self layoutGradient];
}
- (void)layoutGradient {
[self createGradientLayerIfNeeded];
[self updateGradientLayerFrame];
}
- (void)createGradientLayerIfNeeded {
if (gradientLayer != nil) {
return;
}
gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = #[
(__bridge id)[UIColor redColor].CGColor,
(__bridge id)[UIColor orangeColor].CGColor
];
gradientLayer.locations = #[ #0, #1 ];
gradientLayer.startPoint = CGPointZero;
gradientLayer.endPoint = CGPointMake(0, 1);
gradientLayer.type = kCAGradientLayerAxial;
[self.layer insertSublayer:gradientLayer atIndex:0];
}
- (void)updateGradientLayerFrame {
CGRect frame = [self rectForSection:1];
frame = CGRectUnion(frame, [self rectForSection:2]);
gradientLayer.frame = frame;
}
#end
Edit:
This answer contains some general information on table views and an easy solution to your question if a coarse gradient as shown in the screenshot below suffices. If you need a more fine-grained solution please refer to Rob's answer.
Apart from the fact that it's really hard to recognize that your background image has a gradient at all (it looks like a plain red image to me and you should consider just using a red background color instead) there is no way to just set an image as the background of a whole section using the standard UIKit API. And there's a reason for that:
A UITableView doesn't load all its cells when it appears on screen. Instead it only loads those cells that are visible at the moment plus a couple of buffer cells below (and above) in order to enable smooth scrolling. A table view section is rather an abstract concept that's intended to help you present your data in a structured fashion as it gives you headers and footers for each section and the ability to give your cells a different format (e.g. a different background color) depending on the section index. However, a table view section is not a view that is placed behind your cells. And thus you cannot apply a background image or a color to it.
You can see that when you look at an arbitrary table view in Xcode's view debugger:
The selected light blue view is the table view's wrapper view. The upper next view layer is already the table view cells. So there's no "section view" or something in between.
As you can see from the screenshot it's possible and quite easy to get a rough gradient effect by simply setting the cell's background color depending on its index path. I achieved this effect with the following two lines of code in the cellForRowAtIndexPath method:
Swift:
let redColorValue = CGFloat(indexPath.row)/CGFloat(tableView.numberOfRowsInSection(indexPath.section))
cell.backgroundColor = UIColor.init(red: redColorValue, green: 0.5, blue: 0.8, alpha: 1)
Objective-C:
CGFloat redColorValue = (CGFloat)(indexPath.row) / aSection;
cell.backgroundColor = [UIColor colorWithRed:redColorValue green:0.5 blue:0.8 alpha:1];
This way the first and the last cell in the section will always have the same color so the gradient will dynamically change its height depending on the number of cells in your section.
I think you need to set the background to the cell, so it moves with scrolling. You need to know where your sections begins (0, 5, 10):
if (indexPath.row < 5)
{
[cell setBackgroundColor:[UIColor whiteColor]];
}
if (indexPath.row > 5 && < 10)
{
[cell setBackgroundColor:[UIColor gradientColor]];
}
if (indexPath.row > 10)
{
[cell setBackgroundColor:[UIColor gradientColor2]];
}

I want to show objects of NSMutableArray in two different colors

There is an NSMutableArray "onlinevalarr" in which i have offline and online as values.
I want to show offline in red colour and online value in green colour.
This is my code:
{
for (NSString * str in onlinevalarr)
{
if ([str isEqualToString:#"online"])
{
NSLog(#"online");
cell.online.textColor = [UIColor greenColor];
}
else if ([str isEqualToString:#"offline"])
{
NSLog(#"offline");
cell.online.textColor = [UIColor redColor];
}
}
}
But with this code either i am getting all the values in red or all in green.
Think about what your code is doing.
You have a for loop that loops through ALL The elements in your array and sets the current cell's color based on on the current array element. As you go through your for loop you set the current cell's color to different values, and then once you're done, the cell will have the color for the last entry in your array. That doesn't make sense.
If this code is from your cellForRowAtIndexPath method, then you want to get the row of the current cell, use it as an index into your array, and then use that to determine the color for the current cell.
Try using different cell identifiers for each cell.
Ex: "OnlineCellIdentifier" and "OfflineCellIdentifier
After updating the colour, reload the data for that cell
I think this is what you are trying to do:
if ([(NSString*)[onlinevarr objectAtIndex:indexPath.row] isEqualToString:#"online"]){
NSLog(#"online");
cell.online.textColor = [UIColor greenColor];
}else if ([[(NSString*)[onlinevarr objectAtIndex:indexPath.row] isEqualToString:#"offline"]){
NSLog(#"offline");
cell.online.textColor = [UIColor redColor];
}
P.S. This code is to be kept in the cellForRowAtIndexPath method.
And please, don't just paste the code, understand it. This is the code-version of #DuncanC's answer.

Setting x-axis of bar chart to show month

Hi everyone.
Problem: I'm trying to get my xAxis to show on the month from the NSdate that I obtained.
Desired output: Under each bar, it will show "Jan", "Feb", "Mar" etc... according to the event time.
I read throught serveral thread and tried the methods but none is of any help. I understand that I should post a question when I hit the wall and I have just hit it :( been trying out this for a few days.
Here are the resources I tried.
http://www.shinobicontrols.com/forum/shinobicontrols/2013/12/updating-date-format-on-an-axis-fails-except-on-chart-creation
http://www.shinobicontrols.com/forum/shinobicontrols/2014/7/x-axis-with-formatted-dates
http://stackoverflow.com/questions/13688920/how-to-change-the-xaxis-used-on-my-chart-shinobicharts
This is my current code for the chart
The chart itself is also set to the follow:
utilitiesBarChart = [[ShinobiChartalloc] initWithFrame:CGRectInset(cell.bounds, margin, margin) withPrimaryXAxisType:SChartAxisTypeDateTimewithPrimaryYAxisType:SChartAxisTypeNumber];
And this is my code for xvalue
This is the error
My chart continue to show in epoch time :(
any help would be awesome :D
Thank you people
I have a similar barchart with a date/time x-axis. Here is how I created the x-axis to show dates like "Jun 3":
// x-axis
_xAxis = [[SChartDateTimeAxis alloc] init];
_xAxis.style.lineColor = [UIColor colorWithWhite:0.5f alpha:1.0f];
_xAxis.style.lineWidth = #1;
_xAxis.style.majorTickStyle.showLabels = YES;
_xAxis.style.majorTickStyle.labelFont = [UIFont systemFontOfSize:9];
_xAxis.style.majorTickStyle.labelColor = [UIColor colorWithWhite:0.5f alpha:1.0f];
_xAxis.style.majorTickStyle.showTicks = YES;
_xAxis.style.majorTickStyle.lineWidth = #(1);
_xAxis.style.majorTickStyle.lineColor = COLOR_BACKGROUND;
_xAxis.labelFormatString = #"MMM d";
You can optionally implement the delegate to do additional formatting (like making the string uppercase in my case):
-(void)sChart:(ShinobiChart *)chart alterTickMark:(SChartTickMark *)tickMark beforeAddingToAxis:(SChartAxis *)axis {
tickMark.tickLabel.text = [tickMark.tickLabel.text uppercaseString];
}

CPTBarPlot: Do I need to call reloadData after changing bar fill color?

I have an iOS app that displays a CPTBarPlot. My bar plot responds to touches by changing the color of the touched bar. I do this by keeping track of the index of the last selected bar in barWasSelectedAtRecordIndex, and then I set the color of the selected bar in barFillForBarPlot to make it a different color from the others. This works fine, but it seems I have to call reloadData every time the selected bar changes in order for the new fill color to take effect. This takes too long because there is a lot of data, making the app feel sluggish.
It seems wasteful to have to reload all the data just to change the color of one bar, so I'm hoping there's a better way, or I'm just doing something stupid.
Here is a simplified version of the relevant code:
-(void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)idx
{
self.selectedIndex = idx
// Do I have to do this??
[self reloadData];
}
-(CPTFill *)barFillForBarPlot:(CPTBarPlot *)barPlot recordIndex:(NSUInteger)index
{
CPTFill *barFill = nil;
if (index == self.selectedIndex)
{
barFill = [CPTFill fillWithColor:redColor];
}
else
{
barFill = [CPTFill fillWithColor:blueColor];
}
return barFill;
}
Yes. The plot caches everything it loads from the datasource including the bar fills. You need to call -reloadData to tell it that new information is available to load.

iOS: how to set custom background colour with sliders?

First off I want to say I saw a couple of posts on this site about how to do this, although none seemed to work for me so please don't close this down until I get it working.
What I want to do is make the background of the view change depending on the value of the sliders are, so that the user can choose the background colour they want.
self->colorView.backgroundColor = [UIColor myColor];
myColor =
I figure I'll need a bit of code like that, although I don't know how to define what my colour will be something; like "red: redSlider / 255" and so on for the other colours? I also don't know where to implement the code above as I need it to continuously update when the use changes the values of the sliders.
I am quite basic at programming as you may have picked up because I'm only a teenager doing it as a hobby and I'd appreciate simple instructions telling me clearly where I need to put code etc.
p.s. It won't let me post an image of the view, sorry :(
In your ViewController.h file define
#property (nonatomic, strong) IBOutlet UISlider *mySlider;
In ViewController.m file, add this:
- (void) sliderValueChanged:(UISlider *)slider
{
// Handle your color changing logic here
myView.backgroundColor = [UIColor colorWithRed:0.4f green:0.5f blue:1.0f alpha:1.0f];
}
In Interface Builder,
Drag UISlider to view and set its "Value Changed" event outlet to sliderValueChanged method.
Now as you change the slider on screen, the color should changed based on your logic in the method sliderValueChanged
Below is the logic as per your requirement:
- (void) sliderValueChanged:(UISlider *)slider
{
// Assuming slider minimum is 0 and maximum is 1
CGFloat redVal = 0.0f;
CGFloat yellowVal = 0.0f;
CGFloat blueVal = 0.0f;
if (slider == redSlider)
{
redVal = slider.value;
}
else if (slider == yellowSlider)
{
yellowVal = slider.value;
}
else if (slider == blueSlider)
{
blueVal = slider.value;
}
myView.backgroundColor = [UIColor colorWithRed:redVal green:greenVal blue:blueVal alpha:1.0f];
}
As UISlider implements the UIAppearence protocol you can set its background color like:
mySlider.backgroundColor = [UIColor lightGrayColor]; // Or any other color
or:
[[mySlider appearance] setBackgroundColor:[UIColor lightGrayColor]];

Resources