首页 \ 问答 \ 核心图x轴标签不可见 - 边界的影响?(core-plot x-axis label not visible - bounding rects?)

核心图x轴标签不可见 - 边界的影响?(core-plot x-axis label not visible - bounding rects?)

使用垂直条形图示例作为开始,我创建了一个图表,其y值为0..1,x值为1..n但是没有出现为我的数据源的CPTBarPlotFieldBarLocation单元格提供的x标签索引; 我不使用y轴标签。

我怀疑我正在削减它们。 是否有一种方法,比如在旧的IB中,绘制各种图形区域的边界矩形?

x轴绘图标签是非数字字符串,如示例中所示。 我打破了什么? 这是我的设置

//
//  InfoBarView.m

#import "InfoBarView.h"

//  Item index to color mapping for legend symbols not item related
static NSUInteger fldMapping[] = { 5, 6, 7, 0 };

static const BOOL kUseHorizontalBars = NO;

static NSArray <__kindof NSString *> const* kTargets = nil;
static NSArray <__kindof NSString *> const* kGetters = nil;

@interface BarChart()
@property (nonatomic, readwrite, strong, nullable) CPTPlotSpaceAnnotation * symbolTextAnnotation;
@end

@implementation BarChart
@synthesize symbolTextAnnotation;
@synthesize plotData;

+ (void)initialize
{
    kTargets = [@[ @"grpA" , @"grpB", @"grpC", @"grpD" ] retain];
    kGetters = [@[ @"fldA", @"fldB", @"fldC", @"fldD" ] retain];
}

- (void)awakeFromNib
{
    //  Get our orig scaling
    [super awakeFromNib];
}

- (void)killGraph
{
    if ( self.graphs.count )
    {
        CPTGraph * graph = self.defaultGraph;

        CPTPlotSpaceAnnotation *annotation = self.symbolTextAnnotation;
        if ( annotation )
        {
            [graph.plotAreaFrame.plotArea removeAnnotation:annotation];
            self.symbolTextAnnotation = nil;
        }
    }

    [super killGraph];
}

- (void)generateData
{
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    NSUInteger rndx = controller.barDataRanking;
    NSArray * rankings = @[ @"Rank", @"Runs" ];
    GroupItem * group = controller.group;
    CPTGraph * graph = [self defaultGraph];

    CPTPlotSpaceAnnotation * annotation = self.symbolTextAnnotation;
    if ( annotation )
    {
        if (graph)
        {
            [graph.plotAreaFrame.plotArea removeAnnotation:annotation];
            self.symbolTextAnnotation = nil;
        }
    }

    //  Update X title with new controller index
    if (graph)
    {
        graph.title = [NSString stringWithFormat:@"Past Performances by %@", rankings[rndx]];
    }

    //  Figure out our rank selector
    NSString * rankSelectorName = [NSString stringWithFormat:@"%@%@Compare:",
                                   kTargets[controller.barDataIndex],
                                   rankings[rndx]];
    SEL dataRanking = NSSelectorFromString(rankSelectorName);

    self.plotData = (id)[group.items sortedArrayUsingSelector:dataRanking];
}

- (void)renderInGraphHostingView:(nonnull CPTGraphHostingView *)hostingView
                       withTheme:(nullable CPTTheme *)theme
                        animated:(BOOL)animated
{
#if TARGET_OS_SIMULATOR || TARGET_OS_IPHONE
    CGRect bounds = hostingView.bounds;
#else
    CGRect bounds = NSRectToCGRect(hostingView.bounds);
#endif
    InfoController * controller = ((InfoBarView *)hostingView.superview).controller;
    CPTGraph * graph = [[[CPTXYGraph alloc] initWithFrame:bounds] autorelease];
    NSString * titles = @"fldA  fldB  fldC  fldD";
    GroupItem * group = controller.group;
    CPTBarPlot * barPlot;

    //  Initially we default by rank
    self.title = @"Past Performances by Rank";

    [self addGraph:graph toHostingView:hostingView];

    graph.plotAreaFrame.masksToBorder = NO;
    if ( kUseHorizontalBars )
    {
        graph.plotAreaFrame.paddingBottom += self.titleSize;
    }
    else
    {
        graph.plotAreaFrame.paddingLeft += self.titleSize;
    }

    //  Add plot space for bar charts
    CPTXYPlotSpace * barPlotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    [barPlotSpace setScaleType:CPTScaleTypeCategory forCoordinate:CPTCoordinateX];
    if ( kUseHorizontalBars )
    {
        barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:@(-10.0) length:@120.0];
        barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:@(-1.0) length:@11.0];
    }
    else
    {
        barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
        barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:@(-0.05) length:@1.0];
    }
    barPlotSpace.allowsUserInteraction = YES;
    [graph addPlotSpace:barPlotSpace];
    barPlotSpace.delegate = self;

    // Create grid line styles
    CPTMutableLineStyle * majorGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorGridLineStyle.lineWidth = 1.0;
    majorGridLineStyle.lineColor = [[CPTColor grayColor] colorWithAlphaComponent:0.75];

    CPTMutableLineStyle * minorGridLineStyle = [CPTMutableLineStyle lineStyle];
    minorGridLineStyle.lineWidth = 1.0;
    minorGridLineStyle.lineColor = [[CPTColor whiteColor] colorWithAlphaComponent:0.25];

    // Create axes
    CPTXYAxisSet * axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis * x = axisSet.xAxis;
    {
        x.majorIntervalLength           = (kUseHorizontalBars ? @10.0 : @1.0);
        x.minorTicksPerInterval         = (kUseHorizontalBars ? 9 : 0);
        x.orthogonalPosition            = (kUseHorizontalBars ? @(-0.5) : @0.0);

        x.majorGridLineStyle            = majorGridLineStyle;
        x.minorGridLineStyle            = minorGridLineStyle;
        x.axisLineStyle                 = nil;
        x.majorTickLineStyle            = nil;
        x.minorTickLineStyle            = nil;

        x.labelOffset = self.titleSize * CPTFloat(2.5);
        if ( kUseHorizontalBars )
        {
            x.visibleRange   = [CPTPlotRange plotRangeWithLocation:@0.0 length:@10.0];
            x.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
        }
        else
        {
            x.visibleRange   = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
            x.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@0.0 length:@(1.0)];
        }
        x.plotSpace                     = barPlotSpace;
    }

    CPTXYAxis * y = axisSet.yAxis;
    {
        y.majorIntervalLength           = (kUseHorizontalBars ? @1.0 : @10.0);
        y.minorTicksPerInterval         = (kUseHorizontalBars ? 0 : 9);
        y.orthogonalPosition            = (kUseHorizontalBars ? @0.0 : @(-0.5) );

        y.preferredNumberOfMajorTicks   = 8;
        y.majorGridLineStyle            = majorGridLineStyle;
        y.minorGridLineStyle            = minorGridLineStyle;
        y.axisLineStyle                 = nil;
        y.majorTickLineStyle            = nil;
        y.minorTickLineStyle            = nil;
        y.labelOffset                   = self.titleSize * CPTFloat(0.175);
        y.titleLocation                 = (kUseHorizontalBars ? @55.0 : @(group.itemCount-1));

        if ( kUseHorizontalBars )
        {
            y.visibleRange   = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@10.0];
            y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@0.0 length:@100.0];
        }
        else
        {
            y.visibleRange   = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
            y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
        }
        y.title                         = titles;
        y.titleOffset                   = self.titleSize * CPTFloat(0.25);
        [barPlotSpace addCategory:title[seg] forCoordinate:CPTCoordinateY];
        y.plotSpace                     = barPlotSpace;
    }

    //  Set axes
    graph.axisSet.axes = @[x, y];

    //  Create a shared bar line style
    CPTMutableLineStyle * barLineStyle  = [[[CPTMutableLineStyle alloc] init] autorelease];
    barLineStyle.lineWidth = 1.0;
    barLineStyle.lineColor = [CPTColor whiteColor];

    //  Marshall Y axis into individual plot identifiers
    NSArray * title = [titles componentsSeparatedByString:@"  "];

    CPTMutableTextStyle * blackTextStyle = [CPTMutableTextStyle textStyle];
    blackTextStyle.color = [CPTColor blackColor];

    //  Create bar plot(s)
    for (int seg=0; seg<title.count; seg++)
    {
        barPlot = [[[CPTBarPlot alloc] init] autorelease];

        barPlot.lineStyle           = barLineStyle;
        barPlot.fill                = [CPTFill fillWithColor:[CPTColor colorAtIndex:seg]];
        barPlot.barBasesVary        = YES;
        barPlot.barCornerRadius     = 4.0;
        barPlot.barWidth            = @0.5;
        barPlot.barsAreHorizontal   = kUseHorizontalBars;
        barPlot.dataSource          = self;
        barPlot.delegate            = self;
        barPlot.identifier          = [NSString stringWithFormat:@"%@,%d",title[seg],seg],
        barPlot.labelTextStyle      = blackTextStyle;
        barPlot.labelOffset         = 0.0;
        [graph addPlot:barPlot toPlotSpace:barPlotSpace];
        NSLog(@"render:%@", barPlot.identifier);
    }

    //  Add X category per slot
    for (Item * item in plotData)
    {
        [barPlotSpace addCategory:item.numb forCoordinate:CPTCoordinateX];
    }
}

#pragma mark -
#pragma mark Plot Delegate

- (void)Plot:(nonnull CPTPlot *)plot dataLabelWasSelectedAtRecordIndex:(NSUInteger)index
{
//  NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];

    NSLog(@"Data label for '%@' was selected at record %d.", plot.identifier, (int)index);
}

- (CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index;
{
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle];
    textStyle.color = [CPTColor colorAtIndex:item.foreRGB];
    textStyle.textAlignment = CPTTextAlignmentCenter;
    textStyle.fontSize = 24;
    plot.labelOffset = 0;

    CPTMutableShadow * shadow = [CPTMutableShadow shadow];
    shadow.shadowColor = [CPTColor blackColor];//colorAtIndex:item.backRGB];
    shadow.shadowOffset = CGSizeMake(1,-1);
    shadow.shadowBlurRadius = 2.0f;
    plot.labelShadow = shadow;

    CPTTextLayer * textLayer = [[CPTTextLayer alloc] initWithText:item.numb.squish style:textStyle];

    return [textLayer autorelease];
}

- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index
{
    CGFloat floor = [[self valueForPlot:plot field:CPTBarPlotFieldBarBase recordIndex:index] doubleValue];
    CGFloat value = [[self valueForPlot:plot field:CPTBarPlotFieldBarTip recordIndex:index] doubleValue];
    CGFloat runs = 0;

    NSString * barID = (NSString *)[[(id)plot.identifier
                                     componentsSeparatedByString:@","] lastObject];
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int fndx = [barID intValue];
    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
    DataItem * data = [item performSelector:dataItem];
    runs = [[data fldD] doubleValue];

    NSLog(@"BarSelected %@ %@ record:%lu. base:%.2f value:%.2f",
          plot.identifier, data.name, index, floor, value);

    CPTGraph * graph = [self defaultGraph];

    CPTPlotSpaceAnnotation * annotation = self.symbolTextAnnotation;
    if ( annotation )
    {
        [graph.plotAreaFrame.plotArea removeAnnotation:annotation];
        self.symbolTextAnnotation = nil;
    }

    // Setup a style for the annotation
    CPTMutableTextStyle * hitAnnotationTextStyle = [CPTMutableTextStyle textStyle];
    hitAnnotationTextStyle.color    = [CPTColor colorAtIndex:fldMapping[fndx]];
    hitAnnotationTextStyle.fontSize = 16.0;
    hitAnnotationTextStyle.fontName = @"Helvetica-Bold";

    // Determine point of symbol in plot coordinates
    NSNumber * x = @(index);
    NSNumber * y = @(0.03 + (floor / runs));

    CPTNumberArray * anchorPoint = (kUseHorizontalBars ? @[y, x] : @[x, y]);

    // Add annotation
    // First make a string for the y value
    NSString * yString = [[NSNumberFormatter withFormat:@"#,###"] stringFromNumber:@(value)];

    // Now add the annotation to the plot area
    CPTPlotSpace * space = plot.plotSpace;
    if ( space )
    {
        CPTTextLayer * textLayer    = [[CPTTextLayer alloc] initWithText:yString style:hitAnnotationTextStyle];

        annotation                  = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:space anchorPlotPoint:anchorPoint];
        annotation.contentLayer     = [textLayer autorelease];
        annotation.displacement     = CGPointMake(0.0, 0.0);
        self.symbolTextAnnotation   = annotation;

        [graph.plotAreaFrame.plotArea addAnnotation:[annotation autorelease]];
    }
}

#pragma mark Plot DataSource

- (NSUInteger)numberOfRecordsForPlot:(nonnull CPTPlot *)plot
{
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    return group.itemCount;
}

- (nullable id)numberForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int fndx = [barID intValue];
    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
    NSString * getName = kGetters[fndx];
    SEL getter = NSSelectorFromString(getName);
    SEL fldD = @selector(fldD);
    CGFloat runs, base=0, value=0;
    DataItem * data;
    id num=nil;

    //  First get which data data item we're after
    data = [item performSelector:dataItem];
    runs = [[data performSelector:fldD] floatValue];

    //  Now fetch its getter
    switch ( fieldEnum )
    {
        case CPTBarPlotFieldBarLocation:
            num = item.numb;
            break;

        case CPTBarPlotFieldBarTip:
            //  Build base for this tip
            for (int seg=0; seg < fndx; seg++)
            {
                value += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
            }

            //  Add this 'tip' value unless it's the total
            if (fndx == 3)
                num = @(1.0f);
            else
            {
                value += [[data performSelector:getter] floatValue];
                num = @(value/runs);
            }
            break;

        case CPTBarPlotFieldBarBase:
            //  Calc base by sum prior fields
            for (int seg=0; seg < fndx; seg++)
            {
                base += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
            }
            num = @(base/runs);
    }

    return num;
}

- (nullable id)valueForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int fndx = [barID intValue];
    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
    NSString * getName = kGetters[fndx];
    SEL getter = NSSelectorFromString(getName);
    SEL fldD = @selector(fldD);
    CGFloat runs, value=0;
    DataItem * data;
    id num=nil;

    //  First get which data block we're after
    data = [item performSelector:dataItem];
    runs = [[data performSelector:fldD] floatValue];

    //  Now fetch its getter
    switch ( fieldEnum )
    {
        case CPTBarPlotFieldBarLocation:
            num = item.numb.squish;
            break;

        case CPTBarPlotFieldBarTip:
            value = [[data performSelector:getter] floatValue];
            num = @(value);
            break;

        case CPTBarPlotFieldBarBase:
            //  Calc base by sum prior fields
            for (int seg=0; seg < fndx; seg++)
            {
                value += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
            }
            num = @(value);
    }

    return num;
}

- (nullable NSString *)legendTitleForBarPlot:(nonnull CPTBarPlot *)plot recordIndex:(NSUInteger)index
{
    NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];
    int fndx = [barID intValue];

    return kGetters[fndx];
}

#pragma mark Plot Legend Delegate

- (void)legend:(CPTLegend *)legend legendEntryForPlot:(CPTPlot *)plot wasSelectedAtIndex:(NSUInteger)index
{
    NSLog(@"legend:%@ index:%lu", plot.identifier, index);
}

#pragma mark Plot Space Delegate

#pragma mark Plot Space Delegate

- (CPTPlotRange *)plotSpace:(CPTPlotSpace *)space
      willChangePlotRangeTo:(CPTPlotRange *)newRange
              forCoordinate:(CPTCoordinate)coordinate
{
    CGFloat newLocation = newRange.location.floatValue;
//  CGFloat newLength = newRange.length.floatValue;

    //  Range change to +2 point on data boundary
    if (CPTCoordinateX == coordinate)
    {
        if (newLocation < -0.5)
        {
            return [CPTPlotRange plotRangeWithLocation:@(-0.5) length:newRange.length];
        }
        else
        if (newLocation > (0.3))
        {
            return [CPTPlotRange plotRangeWithLocation:@(0.3) length:newRange.length];
        }
    }

    if (CPTCoordinateY == coordinate)
    {
        if (newLocation < (-0.1))
        {
            return [CPTPlotRange plotRangeWithLocation:@(-0.1) length:newRange.length];
        }
        else
        if (newLocation > (0.1))
        {
            return [CPTPlotRange plotRangeWithLocation:@(0.1) length:newRange.length];
        }
    }
//  CGRect chartBounds = self.defaultGraph.bounds;
//  NSLog(@"old:%@", NSStringFromRect(chartBounds));
//  NSLog(@"new:%@ %@", (coordinate == CPTCoordinateX ? @"X" : @"Y"),[newRange description]);
    return newRange;
}
@end

@implementation InfoBarView
@synthesize barChart;
@synthesize x_title;

- (void)awakeFromNib
{
    //  Get our orig scaling
    [super awakeFromNib];

    self.barChart = [[[BarChart alloc] init] autorelease];
}

- (void)drawRect:(NSRect)clip
{
    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
    NSImage * webImage = controller.group.track.webImage;
    GroupItem * group = controller.group;
    NSRect rect = [self frame];

    //  Save state so we can restore later
    CGContextSaveGState(context);

    //  Draw track image as our view's background
    if (webImage)
    {
        [webImage drawInRect:rect fromRect:[webImage alignmentRect]
                   operation:NSCompositeSourceOver fraction:0.25];
    }

    if (group && !barChart.graphs.count)
    {
        [barChart renderInView:self withTheme:nil animated:YES];
    }

    CGContextRestoreGState(context);
}

@end

如果有明显的线索 - 绘制了界限,我认为我们中的很多人都可以从中受益(我想念那些来自IB大约v3的人)。


Using the vertical bar chart sample as a start, I created a chart whose y values are 0..1, x values 1..n but the x label index supplied for CPTBarPlotFieldBarLocation cell of my data source doesn't appear; I don't use y-axis labels.

I suspect I'm clipping them. Is there a way, like in the old IB, to draw the various graph region's bounding rect?

The x-axis plot labels are a non-numeric string as in the example. What did I break? Here's my setup

//
//  InfoBarView.m

#import "InfoBarView.h"

//  Item index to color mapping for legend symbols not item related
static NSUInteger fldMapping[] = { 5, 6, 7, 0 };

static const BOOL kUseHorizontalBars = NO;

static NSArray <__kindof NSString *> const* kTargets = nil;
static NSArray <__kindof NSString *> const* kGetters = nil;

@interface BarChart()
@property (nonatomic, readwrite, strong, nullable) CPTPlotSpaceAnnotation * symbolTextAnnotation;
@end

@implementation BarChart
@synthesize symbolTextAnnotation;
@synthesize plotData;

+ (void)initialize
{
    kTargets = [@[ @"grpA" , @"grpB", @"grpC", @"grpD" ] retain];
    kGetters = [@[ @"fldA", @"fldB", @"fldC", @"fldD" ] retain];
}

- (void)awakeFromNib
{
    //  Get our orig scaling
    [super awakeFromNib];
}

- (void)killGraph
{
    if ( self.graphs.count )
    {
        CPTGraph * graph = self.defaultGraph;

        CPTPlotSpaceAnnotation *annotation = self.symbolTextAnnotation;
        if ( annotation )
        {
            [graph.plotAreaFrame.plotArea removeAnnotation:annotation];
            self.symbolTextAnnotation = nil;
        }
    }

    [super killGraph];
}

- (void)generateData
{
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    NSUInteger rndx = controller.barDataRanking;
    NSArray * rankings = @[ @"Rank", @"Runs" ];
    GroupItem * group = controller.group;
    CPTGraph * graph = [self defaultGraph];

    CPTPlotSpaceAnnotation * annotation = self.symbolTextAnnotation;
    if ( annotation )
    {
        if (graph)
        {
            [graph.plotAreaFrame.plotArea removeAnnotation:annotation];
            self.symbolTextAnnotation = nil;
        }
    }

    //  Update X title with new controller index
    if (graph)
    {
        graph.title = [NSString stringWithFormat:@"Past Performances by %@", rankings[rndx]];
    }

    //  Figure out our rank selector
    NSString * rankSelectorName = [NSString stringWithFormat:@"%@%@Compare:",
                                   kTargets[controller.barDataIndex],
                                   rankings[rndx]];
    SEL dataRanking = NSSelectorFromString(rankSelectorName);

    self.plotData = (id)[group.items sortedArrayUsingSelector:dataRanking];
}

- (void)renderInGraphHostingView:(nonnull CPTGraphHostingView *)hostingView
                       withTheme:(nullable CPTTheme *)theme
                        animated:(BOOL)animated
{
#if TARGET_OS_SIMULATOR || TARGET_OS_IPHONE
    CGRect bounds = hostingView.bounds;
#else
    CGRect bounds = NSRectToCGRect(hostingView.bounds);
#endif
    InfoController * controller = ((InfoBarView *)hostingView.superview).controller;
    CPTGraph * graph = [[[CPTXYGraph alloc] initWithFrame:bounds] autorelease];
    NSString * titles = @"fldA  fldB  fldC  fldD";
    GroupItem * group = controller.group;
    CPTBarPlot * barPlot;

    //  Initially we default by rank
    self.title = @"Past Performances by Rank";

    [self addGraph:graph toHostingView:hostingView];

    graph.plotAreaFrame.masksToBorder = NO;
    if ( kUseHorizontalBars )
    {
        graph.plotAreaFrame.paddingBottom += self.titleSize;
    }
    else
    {
        graph.plotAreaFrame.paddingLeft += self.titleSize;
    }

    //  Add plot space for bar charts
    CPTXYPlotSpace * barPlotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    [barPlotSpace setScaleType:CPTScaleTypeCategory forCoordinate:CPTCoordinateX];
    if ( kUseHorizontalBars )
    {
        barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:@(-10.0) length:@120.0];
        barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:@(-1.0) length:@11.0];
    }
    else
    {
        barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
        barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:@(-0.05) length:@1.0];
    }
    barPlotSpace.allowsUserInteraction = YES;
    [graph addPlotSpace:barPlotSpace];
    barPlotSpace.delegate = self;

    // Create grid line styles
    CPTMutableLineStyle * majorGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorGridLineStyle.lineWidth = 1.0;
    majorGridLineStyle.lineColor = [[CPTColor grayColor] colorWithAlphaComponent:0.75];

    CPTMutableLineStyle * minorGridLineStyle = [CPTMutableLineStyle lineStyle];
    minorGridLineStyle.lineWidth = 1.0;
    minorGridLineStyle.lineColor = [[CPTColor whiteColor] colorWithAlphaComponent:0.25];

    // Create axes
    CPTXYAxisSet * axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis * x = axisSet.xAxis;
    {
        x.majorIntervalLength           = (kUseHorizontalBars ? @10.0 : @1.0);
        x.minorTicksPerInterval         = (kUseHorizontalBars ? 9 : 0);
        x.orthogonalPosition            = (kUseHorizontalBars ? @(-0.5) : @0.0);

        x.majorGridLineStyle            = majorGridLineStyle;
        x.minorGridLineStyle            = minorGridLineStyle;
        x.axisLineStyle                 = nil;
        x.majorTickLineStyle            = nil;
        x.minorTickLineStyle            = nil;

        x.labelOffset = self.titleSize * CPTFloat(2.5);
        if ( kUseHorizontalBars )
        {
            x.visibleRange   = [CPTPlotRange plotRangeWithLocation:@0.0 length:@10.0];
            x.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
        }
        else
        {
            x.visibleRange   = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
            x.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@0.0 length:@(1.0)];
        }
        x.plotSpace                     = barPlotSpace;
    }

    CPTXYAxis * y = axisSet.yAxis;
    {
        y.majorIntervalLength           = (kUseHorizontalBars ? @1.0 : @10.0);
        y.minorTicksPerInterval         = (kUseHorizontalBars ? 0 : 9);
        y.orthogonalPosition            = (kUseHorizontalBars ? @0.0 : @(-0.5) );

        y.preferredNumberOfMajorTicks   = 8;
        y.majorGridLineStyle            = majorGridLineStyle;
        y.minorGridLineStyle            = minorGridLineStyle;
        y.axisLineStyle                 = nil;
        y.majorTickLineStyle            = nil;
        y.minorTickLineStyle            = nil;
        y.labelOffset                   = self.titleSize * CPTFloat(0.175);
        y.titleLocation                 = (kUseHorizontalBars ? @55.0 : @(group.itemCount-1));

        if ( kUseHorizontalBars )
        {
            y.visibleRange   = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@10.0];
            y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@0.0 length:@100.0];
        }
        else
        {
            y.visibleRange   = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
            y.gridLinesRange = [CPTPlotRange plotRangeWithLocation:@(-0.5) length:@(group.itemCount)];
        }
        y.title                         = titles;
        y.titleOffset                   = self.titleSize * CPTFloat(0.25);
        [barPlotSpace addCategory:title[seg] forCoordinate:CPTCoordinateY];
        y.plotSpace                     = barPlotSpace;
    }

    //  Set axes
    graph.axisSet.axes = @[x, y];

    //  Create a shared bar line style
    CPTMutableLineStyle * barLineStyle  = [[[CPTMutableLineStyle alloc] init] autorelease];
    barLineStyle.lineWidth = 1.0;
    barLineStyle.lineColor = [CPTColor whiteColor];

    //  Marshall Y axis into individual plot identifiers
    NSArray * title = [titles componentsSeparatedByString:@"  "];

    CPTMutableTextStyle * blackTextStyle = [CPTMutableTextStyle textStyle];
    blackTextStyle.color = [CPTColor blackColor];

    //  Create bar plot(s)
    for (int seg=0; seg<title.count; seg++)
    {
        barPlot = [[[CPTBarPlot alloc] init] autorelease];

        barPlot.lineStyle           = barLineStyle;
        barPlot.fill                = [CPTFill fillWithColor:[CPTColor colorAtIndex:seg]];
        barPlot.barBasesVary        = YES;
        barPlot.barCornerRadius     = 4.0;
        barPlot.barWidth            = @0.5;
        barPlot.barsAreHorizontal   = kUseHorizontalBars;
        barPlot.dataSource          = self;
        barPlot.delegate            = self;
        barPlot.identifier          = [NSString stringWithFormat:@"%@,%d",title[seg],seg],
        barPlot.labelTextStyle      = blackTextStyle;
        barPlot.labelOffset         = 0.0;
        [graph addPlot:barPlot toPlotSpace:barPlotSpace];
        NSLog(@"render:%@", barPlot.identifier);
    }

    //  Add X category per slot
    for (Item * item in plotData)
    {
        [barPlotSpace addCategory:item.numb forCoordinate:CPTCoordinateX];
    }
}

#pragma mark -
#pragma mark Plot Delegate

- (void)Plot:(nonnull CPTPlot *)plot dataLabelWasSelectedAtRecordIndex:(NSUInteger)index
{
//  NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];

    NSLog(@"Data label for '%@' was selected at record %d.", plot.identifier, (int)index);
}

- (CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index;
{
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    CPTMutableTextStyle * textStyle = [CPTMutableTextStyle textStyle];
    textStyle.color = [CPTColor colorAtIndex:item.foreRGB];
    textStyle.textAlignment = CPTTextAlignmentCenter;
    textStyle.fontSize = 24;
    plot.labelOffset = 0;

    CPTMutableShadow * shadow = [CPTMutableShadow shadow];
    shadow.shadowColor = [CPTColor blackColor];//colorAtIndex:item.backRGB];
    shadow.shadowOffset = CGSizeMake(1,-1);
    shadow.shadowBlurRadius = 2.0f;
    plot.labelShadow = shadow;

    CPTTextLayer * textLayer = [[CPTTextLayer alloc] initWithText:item.numb.squish style:textStyle];

    return [textLayer autorelease];
}

- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index
{
    CGFloat floor = [[self valueForPlot:plot field:CPTBarPlotFieldBarBase recordIndex:index] doubleValue];
    CGFloat value = [[self valueForPlot:plot field:CPTBarPlotFieldBarTip recordIndex:index] doubleValue];
    CGFloat runs = 0;

    NSString * barID = (NSString *)[[(id)plot.identifier
                                     componentsSeparatedByString:@","] lastObject];
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int fndx = [barID intValue];
    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
    DataItem * data = [item performSelector:dataItem];
    runs = [[data fldD] doubleValue];

    NSLog(@"BarSelected %@ %@ record:%lu. base:%.2f value:%.2f",
          plot.identifier, data.name, index, floor, value);

    CPTGraph * graph = [self defaultGraph];

    CPTPlotSpaceAnnotation * annotation = self.symbolTextAnnotation;
    if ( annotation )
    {
        [graph.plotAreaFrame.plotArea removeAnnotation:annotation];
        self.symbolTextAnnotation = nil;
    }

    // Setup a style for the annotation
    CPTMutableTextStyle * hitAnnotationTextStyle = [CPTMutableTextStyle textStyle];
    hitAnnotationTextStyle.color    = [CPTColor colorAtIndex:fldMapping[fndx]];
    hitAnnotationTextStyle.fontSize = 16.0;
    hitAnnotationTextStyle.fontName = @"Helvetica-Bold";

    // Determine point of symbol in plot coordinates
    NSNumber * x = @(index);
    NSNumber * y = @(0.03 + (floor / runs));

    CPTNumberArray * anchorPoint = (kUseHorizontalBars ? @[y, x] : @[x, y]);

    // Add annotation
    // First make a string for the y value
    NSString * yString = [[NSNumberFormatter withFormat:@"#,###"] stringFromNumber:@(value)];

    // Now add the annotation to the plot area
    CPTPlotSpace * space = plot.plotSpace;
    if ( space )
    {
        CPTTextLayer * textLayer    = [[CPTTextLayer alloc] initWithText:yString style:hitAnnotationTextStyle];

        annotation                  = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:space anchorPlotPoint:anchorPoint];
        annotation.contentLayer     = [textLayer autorelease];
        annotation.displacement     = CGPointMake(0.0, 0.0);
        self.symbolTextAnnotation   = annotation;

        [graph.plotAreaFrame.plotArea addAnnotation:[annotation autorelease]];
    }
}

#pragma mark Plot DataSource

- (NSUInteger)numberOfRecordsForPlot:(nonnull CPTPlot *)plot
{
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    return group.itemCount;
}

- (nullable id)numberForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int fndx = [barID intValue];
    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
    NSString * getName = kGetters[fndx];
    SEL getter = NSSelectorFromString(getName);
    SEL fldD = @selector(fldD);
    CGFloat runs, base=0, value=0;
    DataItem * data;
    id num=nil;

    //  First get which data data item we're after
    data = [item performSelector:dataItem];
    runs = [[data performSelector:fldD] floatValue];

    //  Now fetch its getter
    switch ( fieldEnum )
    {
        case CPTBarPlotFieldBarLocation:
            num = item.numb;
            break;

        case CPTBarPlotFieldBarTip:
            //  Build base for this tip
            for (int seg=0; seg < fndx; seg++)
            {
                value += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
            }

            //  Add this 'tip' value unless it's the total
            if (fndx == 3)
                num = @(1.0f);
            else
            {
                value += [[data performSelector:getter] floatValue];
                num = @(value/runs);
            }
            break;

        case CPTBarPlotFieldBarBase:
            //  Calc base by sum prior fields
            for (int seg=0; seg < fndx; seg++)
            {
                base += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
            }
            num = @(base/runs);
    }

    return num;
}

- (nullable id)valueForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];
    InfoBarView * barView = (id)[[self defaultLayerHostingView] superview];
    InfoController * controller = barView.controller;
    GroupItem * group = controller.group;

    int fndx = [barID intValue];
    int sndx = index % group.itemCount;
    Item * item = (Item *)[self.plotData objectAtIndex:sndx];

    SEL dataItem = NSSelectorFromString(kTargets[controller.barDataIndex]);
    NSString * getName = kGetters[fndx];
    SEL getter = NSSelectorFromString(getName);
    SEL fldD = @selector(fldD);
    CGFloat runs, value=0;
    DataItem * data;
    id num=nil;

    //  First get which data block we're after
    data = [item performSelector:dataItem];
    runs = [[data performSelector:fldD] floatValue];

    //  Now fetch its getter
    switch ( fieldEnum )
    {
        case CPTBarPlotFieldBarLocation:
            num = item.numb.squish;
            break;

        case CPTBarPlotFieldBarTip:
            value = [[data performSelector:getter] floatValue];
            num = @(value);
            break;

        case CPTBarPlotFieldBarBase:
            //  Calc base by sum prior fields
            for (int seg=0; seg < fndx; seg++)
            {
                value += [[data performSelector:NSSelectorFromString(kGetters[seg])] floatValue];
            }
            num = @(value);
    }

    return num;
}

- (nullable NSString *)legendTitleForBarPlot:(nonnull CPTBarPlot *)plot recordIndex:(NSUInteger)index
{
    NSString * barID = (NSString *)[[(id)plot.identifier componentsSeparatedByString:@","] lastObject];
    int fndx = [barID intValue];

    return kGetters[fndx];
}

#pragma mark Plot Legend Delegate

- (void)legend:(CPTLegend *)legend legendEntryForPlot:(CPTPlot *)plot wasSelectedAtIndex:(NSUInteger)index
{
    NSLog(@"legend:%@ index:%lu", plot.identifier, index);
}

#pragma mark Plot Space Delegate

#pragma mark Plot Space Delegate

- (CPTPlotRange *)plotSpace:(CPTPlotSpace *)space
      willChangePlotRangeTo:(CPTPlotRange *)newRange
              forCoordinate:(CPTCoordinate)coordinate
{
    CGFloat newLocation = newRange.location.floatValue;
//  CGFloat newLength = newRange.length.floatValue;

    //  Range change to +2 point on data boundary
    if (CPTCoordinateX == coordinate)
    {
        if (newLocation < -0.5)
        {
            return [CPTPlotRange plotRangeWithLocation:@(-0.5) length:newRange.length];
        }
        else
        if (newLocation > (0.3))
        {
            return [CPTPlotRange plotRangeWithLocation:@(0.3) length:newRange.length];
        }
    }

    if (CPTCoordinateY == coordinate)
    {
        if (newLocation < (-0.1))
        {
            return [CPTPlotRange plotRangeWithLocation:@(-0.1) length:newRange.length];
        }
        else
        if (newLocation > (0.1))
        {
            return [CPTPlotRange plotRangeWithLocation:@(0.1) length:newRange.length];
        }
    }
//  CGRect chartBounds = self.defaultGraph.bounds;
//  NSLog(@"old:%@", NSStringFromRect(chartBounds));
//  NSLog(@"new:%@ %@", (coordinate == CPTCoordinateX ? @"X" : @"Y"),[newRange description]);
    return newRange;
}
@end

@implementation InfoBarView
@synthesize barChart;
@synthesize x_title;

- (void)awakeFromNib
{
    //  Get our orig scaling
    [super awakeFromNib];

    self.barChart = [[[BarChart alloc] init] autorelease];
}

- (void)drawRect:(NSRect)clip
{
    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
    NSImage * webImage = controller.group.track.webImage;
    GroupItem * group = controller.group;
    NSRect rect = [self frame];

    //  Save state so we can restore later
    CGContextSaveGState(context);

    //  Draw track image as our view's background
    if (webImage)
    {
        [webImage drawInRect:rect fromRect:[webImage alignmentRect]
                   operation:NSCompositeSourceOver fraction:0.25];
    }

    if (group && !barChart.graphs.count)
    {
        [barChart renderInView:self withTheme:nil animated:YES];
    }

    CGContextRestoreGState(context);
}

@end

If there were visible clues - drawn bounding rects, I think a lot of us could benefit from them (I miss those from IB circa v3).


原文:https://stackoverflow.com/questions/38909147
更新时间:2022-10-13 19:10

最满意答案

我的一般建议是保留一个“dev”配置文件,该文件适用于大多数开发人员,然后使用不受版本控制的每个开发人员配置文件或使用环境变量来覆盖它。


Doing this will work:

git merge --no-ff --no-commit devEnv-Jake 

Follow it up with:

git reset 

to clear the files from the staging area.


I actually created an alias to do this:

alias jake-mergeDevEnv-git='git merge --no-ff --no-commit devEnv-Jake ; git reset'

相关问答

更多

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)