Search code examples
macoscocoaosx-mavericksquartz-2d

Need sample code to swing needle in Cocoa/Quartz 2d Speedometer for Mac App


I'm building this to run on the Mac, not iOS - which is quit different. I'm almost there with the speedo, but the math of making the needle move up and down the scale as data is input eludes me. I'm measuring wind speed live, and want to display it as a gauge - speedometer, with the needle moving as the windspeed changes. I have the fundamentals ok. I can also - and will - load the images into holders, but later. For now I want to get it working ...

    - (void)drawRect:(NSRect)rect
{


    NSRect myRect = NSMakeRect ( 21, 21, 323, 325 ); // set the Graphics class square size to match the guage image
    [[NSColor blueColor] set]; // colour it in in blue - just because you can...
    NSRectFill ( myRect );



    [[NSGraphicsContext currentContext]                     // set up the graphics context
     setImageInterpolation: NSImageInterpolationHigh];      // highres image

    //-------------------------------------------

    NSSize viewSize  = [self bounds].size;
    NSSize imageSize = { 320, 322 };                        // the actual image rectangle size. You can scale the image here if you like. x and y remember

    NSPoint viewCenter;
    viewCenter.x = viewSize.width  * 0.50;                  // set the view center, both x & y
    viewCenter.y = viewSize.height * 0.50;

    NSPoint imageOrigin = viewCenter;
    imageOrigin.x -= imageSize.width  * 0.50;               // set the origin of the first point
    imageOrigin.y -= imageSize.height * 0.50;

    NSRect destRect;
    destRect.origin = imageOrigin;                          // set the image origin
    destRect.size = imageSize;                              // and size

    NSString * file = @"/Users/robert/Documents/XCode Projects/xWeather Graphics/Gauge_mph_320x322.png";  // stuff in the image
    NSImage * image = [[NSImage alloc] initWithContentsOfFile:file];

    //-------------------------------------------

    NSSize view2Size  = [self bounds].size;
    NSSize image2Size = { 149, 17 };                          // the orange needle
    NSPoint view2Center;
    view2Center.x = view2Size.width  * 0.50;                  // set the view center, both x & y
    view2Center.y = view2Size.height * 0.50;

    NSPoint image2Origin = view2Center;
    //image2Origin.x -= image2Size.width  * 0.50;               // set the origin of the first point
    image2Origin.x = 47;
    image2Origin.y -= image2Size.height * 0.50;

    NSRect dest2Rect;
    dest2Rect.origin = image2Origin;                          // set the image origin
    dest2Rect.size = image2Size;                              // and size now is needle size


    NSString * file2  = @"/Users/robert/Documents/XCode Projects/xWeather Graphics/orange-needle01.png";
    NSImage * image2 = [[NSImage alloc] initWithContentsOfFile:file2];


                                                            // do image 1
    [image setFlipped:YES];                                 // flip it because everything else is in this exerecise
                                                            // do image 2
    [image2 setFlipped:YES];                                // flip it because everything else is in this exerecise


    [image drawInRect: destRect
             fromRect: NSZeroRect
            operation: NSCompositeSourceOver
             fraction: 1.0];


    [image2 drawInRect: dest2Rect
             fromRect: NSZeroRect
            operation: NSCompositeSourceOver
             fraction: 1.0];





    NSBezierPath * path = [NSBezierPath bezierPathWithRect:destRect]; // draw a red border around the whole thing
    [path setLineWidth:3];
    [[NSColor redColor] set];
    [path stroke];


}

// flip the ocords - (BOOL) isFlipped { return YES; }

@end

The result is here. The gauge part that is. Now all I have to do is make the needle move in response to input.


Solution

  • Apple has some sample code, called SpeedometerView, which does exactly what you're asking. It'll surely take some doing to adapt it for your use, but it's probably a decent starting point.