核心图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
最满意答案
我的一般建议是保留一个“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'
相关问答
更多-
正如你所发现的, rebase不是你想用来将历史拼接在一起的命令(因为它实际上会重写历史记录)。 早期的Git有一个功能(黑客)专门为您要做的事情设计: 移植点 。 更好的是,从1.6.5开始,你可以使用git replace --graft代替: git checkout master git replace --graft $(git log RepoB/master --format=%H | tail -1) HEAD git replace --graft $(git log RepoA/mast ...
-
您可以使用git rebase --interactive来获取交互式rebase,您可以在其中重新排序提交并压缩它们。 你可以像git rebase -i 3d2a5a5一样调用它,你可能会看到类似的东西 pick 8ab463d add big picutres pick 503c2b6 make a useful commit pick 04f9ac3 replace big pictures with small pictures 您现在可以编辑此列表,因此它看起来像 pick 8ab463d a ...
-
您只需要为使用prod分支制定一些基本规则。 就像你说的那样,理想情况下你应该有另一个分支进行日常开发(主人)。 每个开发人员也应该从master中分支出来进行功能,然后合并并推送他们的更改。 至于上述场景中发生的事情: 场景1: 你的同事不应该做出改变然后拉,他应该反过来做。 这是功能分支派上用场的地方。 这样做的一个好方法是: 从掌握最新的变化 分支到新功能分支并在那里完成所有工作 看看大师 拉最新的变化 在master上,合并功能分支 将合并提交推送到远程 每个团队都有自己的方式来管理git生命周期, ...
-
首先,我们来讨论这个部分: 我是否使用了一种很好的方法来维护两个分支中的不同配置文件? (我刚刚看到使用.gitattributes的这种方法看起来好多了)。 至少在一般情况下,我不会推荐这些方法。 相反,如果你有一个控制事物的配置文件,根本不要检查它(至少不在这个存储库中),你可以将它检入到其他存储库中,然后使用这里使用的文件作为符号链接例如存储在其他存储库中的“真实”配置文件)。 将源代码控制文件作为示例或示例或启动器配置。 如有必要,让系统将此文件复制到实际配置文件(通过.gitignore )。 在 ...
-
我的一般建议是保留一个“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 ja ...
-
更容易清理git存储库是使用'BFG repo cleaner' https://rtyley.github.io/bfg-repo-cleaner/ (比git-filter-branch更容易,速度更快!) 但请注意,它将改变所有历史记录,修改提交的sha1并影响所有开发人员! The easier to clean a git repository is to use 'BFG repo cleaner' https://rtyley.github.io/bfg-repo-cleaner/ (easi ...
-
apenwarr的git子树有一个--squash选项,可能几乎可以做你想要的。 remote=libfoo branch=master prefix=helpers/libfoo git fetch "$remote" && git subtree add --prefix="$prefix" --squash "$remote/$branch" : Later, once there are changes to pick up. git subtree pull --prefix="$prefix ...
-
TL; DR(但未经测试) 作为shell脚本: git rev-list --merges HEAD | while read rev; do thistree=$(git rev-parse $rev^{tree}) p1tree=$(git rev-parse $rev^1^{tree}) if [ $thistree = $p1tree ]; then echo "commit $rev has the effect of -s ours" fi do ...
-
有趣的问题。 不幸的是,命令行工具显然不直接支持这个用例。 但是,您可以编写一个脚本,该脚本使用svn mergeinfo的输出并将其提供给svn log以获取此信息。 以下bash脚本可能是一个很好的起点。 #! /bin/bash source="^/trunk" url="$( svn info | sed -ne '/^URL: /s///p' )" mergeinfo=(svn mergeinfo --show-revs=merged "$source") revs=($( diff <( "${ ...
-
您可以使用预提交挂钩来检查未暂存的文件。 您可以列出未分级的新文件: git ls-files --others --exclude-standard 这是一篇关于如何添加自己的提交挂钩的简便帖子 You can list unstaged, new files with: git ls-files --others --exclude-standard A git commit hook for it this could look like this: #!/bin/sh if [[ `git ls ...