Problems with clipping

I'm using SDK v3.1.9 on a Vivoactive 4s.  I've modified the Analog sample program to show both steps and heart rate.  That all works fine when the updates are done once a minute via onUpdate(). However I want them to update more frequently than that, so I've added the update code to onPartialUpdate() and am using clips to minimise the amount of screen to be updated.

If I redisplay these values every second it works but the power budget occasionally gets exceeded.  If I try and only redisplay these values when they change then on all subsequent seconds where the values do not change that part of the display is blacked out (Graphics.COLOR_BLACK), presumably because the clip(s) is/are being overwritten by the secondhand processing.

I've read elsewhere on this forum that the clips are additive when created within a single call to onPartialUpdate() however, I've tried creating all of the clips, then done a dc.clear() and then redisplayed each changed value but the clips are clearly not being properly recognised as the text displays are rubbish, although the second hand ticks without a problem.

Ideally, what I'd like to be able to do is to use a clip when necessary and then delete the instance of it in some way before recreating it for another display.  Is there any way to do that and, if not, will I have to calculate the whole clipping area myself or is there some other magical way in which I can update up to 3 completely separate areas in a single call to onPartialUpdate()?

For clarity, when I set a clip for each value and update it every second as a single block of code those values are displayed continuously.  When I set a clip and update each value only when it changes that value displays for one second and then disappears.  When I create all three clips (whenever required) and then redisplay all three displays together the secondhand is fine the other two displays (drawn before the secondhand) are rubbish and it looks as if the clipped area has been miscalculated.

  • One thing to note is if you set multiple clip regions, the are actually combined.

    So if you have a 20x20 region at the top of the screen, say at row 20, and another at the bottom, say at row 220, your combined clip region is actual 220 rows.

    Rows are important, as that's how the display actually gets updated.  The above will exceed the power budget, even though each clip region is only 20 rows high

    So, you need to consider the total number of rows when the clip regions are combined.

    In the Sim, if you select File>View Watchface Diagnostics you can see how you're doing with the  budget

  • Hi, thanks foe the quick answer and tip about the diagnostics.  It's a bit late here at the moment so I'll try it tomorrow.

    One thought I  have just had, though, is that it might be an issue with the clip instance not getting properly released.  The steps and heartrate displays get blacked out when those values do not change on a new call to onPartialUpdate() and, in those circumstances, I  don't  call setClip at all for those areas.  How does onPartialUpdate() even know about them then?

  • There are some tricks for 1hz, including "do nothing" is a value being displayed hasn't changed.

    See:

    https://forums.garmin.com/developer/connect-iq/f/discussion/5156/1hz-watch-faces---q-a

  • Thanks for the link which was extremely informative and interesting (I've yet to read to the end of it!).  I've made one or two changes to my code based on that article and there has been an improvement but it is still not working.  The code I'm using is derived from the Analog sample and the onPartialUpdate() portion is:-

        function onPartialUpdate( dc ) {
            // If we're not doing a full screen refresh we need to re-draw the background
            // before drawing the updated second hand position. Note this will only re-draw
            // the background in the area specified by the previously computed clipping region.
            if(!fullScreenRefresh) {
                drawBackground(dc);
            }
    
            var width = dc.getWidth();
            var height = dc.getHeight();
            
    //----------  Steps  --------------------
        	
        	var newSteps = ActivityMonitor.getInfo().steps;
       	
        	if (newSteps > Steps) {
    			dc.setClip(width*0.25-(StepsDims[0]/2),height*0.4,StepsDims[0],StepsDims[1]);
    	        dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_RED);
    	        dc.clear();
    //	    	dc.drawText(width*0.25, height*0.4, Graphics.FONT_TINY, Steps.toString(), Graphics.TEXT_JUSTIFY_CENTER);
    	    	Steps = newSteps;
    	    	dc.setColor(Graphics.COLOR_YELLOW, Graphics.COLOR_RED);
    	    	dc.drawText(width*0.25, height*0.4, Graphics.FONT_TINY, Steps.toString(), Graphics.TEXT_JUSTIFY_CENTER);
    	    	dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
    //        	dc.fillPolygon(hourPolyPoints);
    //        	dc.fillPolygon(minPolyPoints);
    //        	dc.clearClip();
    	    }
        	
    //----------   Heart Rate   ----------------
            var newHR = Activity.getActivityInfo().currentHeartRate;   
    /*
    		if (null != newHR  && newHR != HR) {
    //		if (null != newHR) {
    //	        dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_TRANSPARENT);
    			dc.setClip(width*0.62,height*0.4,HRDims[0],HRDims[1]);
    	     	dc.drawText(width*0.8,height*0.4, Graphics.FONT_TINY, HR.toString(), Graphics.TEXT_JUSTIFY_CENTER);
    	    	dc.setColor(Graphics.COLOR_YELLOW, Graphics.COLOR_TRANSPARENT);
    	    	HR = newHR;
    	     	dc.drawText(width*0.8,height*0.4, Graphics.FONT_TINY, HR.toString(), Graphics.TEXT_JUSTIFY_CENTER);
    	    	dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
    //        	dc.fillPolygon(hourPolyPoints);
    //        	dc.fillPolygon(minPolyPoints);
    //        	dc.clearClip();
    	     }
    */
            var clockTime = System.getClockTime();
    
            var secondHand = (clockTime.sec / 60.0) * Math.PI * 2;
            var secondHandPoints = generateHandCoordinates(screenCenterPoint, secondHand, 90, 20, 2);
            
            // Update the cliping rectangle to the new location of the second hand.
            curClip = getBoundingBox( secondHandPoints );
            var bboxWidth = curClip[1][0] - curClip[0][0] + 1;
            var bboxHeight = curClip[1][1] - curClip[0][1] + 1;
            dc.setClip(curClip[0][0], curClip[0][1], bboxWidth, bboxHeight);
    		
            // Draw the second hand to the screen.
            dc.setColor(Graphics.COLOR_RED, Graphics.COLOR_TRANSPARENT);
            dc.fillPolygon(secondHandPoints);
        }
    

    Here is a video of the result over 1 minute with steps set to 6 per minute.  On checking the Diagnostics I would say that it comes in at an average of about 25msecs per minute but I've not done a proper calculation yet.  It blanks out at the top of the minute because I've not yet added code in onUpdate().  I've added a red background to make it easier to see what is happening.  The variable StepDims is calculated from "888888" in onLayout().  It looks as though the secondhand is the culprit but I've checked the clip dimensions.  Here is a system print of those dimensions (as used in setClip()) starting where it starts to go wrong.

    X : 50.721447 - Y : 92.731880 - w : 72.343277 - h : 98.669792
    X : 42.586922 - Y : 93.967972 - w : 82.038841 - h : 90.846497
    X : 35.185516 - Y : 95.374245 - w : 90.846512 - h : 82.038811
    X : 28.598320 - Y : 96.935272 - w : 98.669800 - h : 72.343262
    X : 22.897453 - Y : 98.633972 - w : 105.423058 - h : 61.866028
    X : 18.145454 - Y : 100.451721 - w : 111.032188 - h : 50.721939
    X : 14.394348 - Y : 102.368599 - w : 115.435791 - h : 39.033104
    X : 11.685242 - Y : 104.363617 - w : 118.585617 - h : 26.927582
    X : 10.047806 - Y : 106.414909 - w : 120.447159 - h : 14.537926
    X : 9.500000 - Y : 108.500000 - w : 121.000000 - h : 3.000000  <=====  Horizontal at the 45 second point
    X : 10.047806 - Y : 99.047165 - w : 120.447159 - h : 14.537926
    X : 11.685242 - Y : 88.708809 - w : 118.585617 - h : 26.927574
    X : 14.394348 - Y : 78.598289 - w : 115.435791 - h : 39.033112
    X : 18.145454 - Y : 68.826332 - w : 111.032188 - h : 50.721947
    X : 22.897453 - Y : 59.500008 - w : 105.423058 - h : 61.866020
    X : 28.598320 - Y : 50.721451 - w : 98.669800 - h : 72.343277
    X : 35.185524 - Y : 42.586929 - w : 90.846504 - h : 82.038834
    X : 42.586945 - Y : 35.185516 - w : 82.038811 - h : 90.846512
    X : 50.721470 - Y : 28.598305 - w : 72.343246 - h : 98.669823

    Do you have any idea what is going wrong?

  • OK, I've just run this again after setting the secondhand background to blue and this video shows exactly what is happening.  The same was happening (except with a black background) when using setColor(Graphics.COLOR_RED,Graphics.COLOR_TRANSPARENT)

    So, it looks, on the face of it, as though Graphics.TRANSPARENT does not work in a clip - could that be right?