Numbering Annotations For Shapes (Rect, Ellipse, Cloud)

PDF.js Express Version

Detailed description of issue
Hi there. This is a follow up question to providing a number at the corner of an annotation using setCustomDrawHandler. StickyAnnotation works well in a sense with the number at the bottom right and it stays there when the note is moved. The issue I am running into is with shapes, specifically Ellipse, Rectangle and Cloud. The number does not start at the bottom right and resizing the shapes does not help either. In addition when I move the annotation the number does not follow. I figured that matching the same width and height as the annotation with the ctx.fillText would work but this is not the case. Appreciate the help!

Expected behaviour

THIS WORKS!

        Annotations.setCustomDrawHandler(Annotations.StickyAnnotation, function(
          ctx, //canvas context
          pageMatrix,
          rotation,
          options
        ) {
          options.originalDraw(ctx, pageMatrix);
          const annot = options.annotation;
          const number = 1;
          const width = annot.Width;
          const height = annot.Height;
          const padding = 1;

          if (number) {
            //circle styles
            ctx.fillStyle = '#37A000';
            ctx.beginPath();
            ctx.arc(width - 6, height - 10, 9, 0, 2 * Math.PI);
            ctx.fill();
            //number styles
            ctx.fillStyle = '#FFFFFF';
            ctx.fillText(`${1}`, width - 8, height - 6);
          }
        });

THIS DOES NOT WORK!

  Annotations.setCustomDrawHandler(
          Annotations.EllipseAnnotation,
          function(
            ctx, //canvas context
            pageMatrix,
            rotation,
            options
          ) {
            const annot = options.annotation;
            const width = annot.Width;
            const height = annot.Height;
            const padding = 10;
            const number = 1;
            if (number) {
              //circle styles
              ctx.fillStyle = '#37A000';
              ctx.beginPath();
              ctx.arc(width + padding, height + padding, 9, 0, 2 * Math.PI);
              ctx.fill();
              //number styles
              ctx.fillStyle = '#FFFFFF';
              ctx.fillText(`${number}`, width + padding, height + padding);
            }
            options.originalDraw(ctx, pageMatrix);
          }
        );

Does your issue happen with every document, or just one?
{Answer here}

Link to document
{Provide a link to the document in question if possible}

Code snippet
{Provide a relevant code snippet}

Hello, I’m Ron, an automated tech support bot :robot:

While you wait for one of our customer support representatives to get back to you, please check out some of these documentation pages:

Guides:APIs:Forums:

Hey there,

The CTX passed in for the Rectangle and Ellipse annotations is a bit different than the one passed in for for sticky note (its hard to explain why but its for a good reason - has to do with zooming behaviour for sticky notes).

The CTX passed for shapes is the size of the entire page, instead of just the annotation, so you need to adjust accordingly.

Here’s some code to get you started (all im doing is using annot.X + width for my x pos instead of just width, and same for height):

  Annotations.setCustomDrawHandler(
    Annotations.RectangleAnnotation,
    function (
      ctx, //canvas context
      pageMatrix,
      rotation,
      options
    ) {
      const annot = options.annotation;
      const width = annot.Width;
      const height = annot.Height;
      const padding = 10;
      const number = 1;
      if (number) {
        const x = annot.X + width
        const y = annot.Y + height

        //circle styles
        ctx.fillStyle = '#37A000';
        ctx.beginPath();

        ctx.arc(x + padding, y + padding, 9, 0, 2 * Math.PI);
        ctx.fill();
        //number styles
        ctx.fillStyle = '#FFFFFF';
        ctx.fillText(`${number}`, x + padding, y + padding);
      }
      options.originalDraw(ctx, pageMatrix);
    }
  );

Thanks,
Logan

Also one more little tip to help you out:

When drawing the number icon on the Ellipse annotation, you will run into issues where the number is not on the actual circle, and its because of this:

Using just width and height for a circular annotation doesn’t work for this reason ^

To fix this We need to calculate the point on the ellispe:

That being said, here’s some code to calculate the X and Y positions on the ellipse:

Annotations.setCustomDrawHandler(
    Annotations.EllipseAnnotation,
    function (
      ctx, //canvas context
      pageMatrix,
      rotation,
      options
    ) {
      const annot = options.annotation;
      const padding = 10;
      const number = 1;
      if (number) {

        const rx = annot.Width / 2;
        const ry = annot.Height / 2;
        let angle = 45;
        const t = Math.tan(angle++ / 360 * Math.PI);
        const x = (rx * (1 - t ** 2) / (1 + t ** 2)) + annot.X + rx;
        const y = (ry * 2 * t / (1 + t ** 2)) + annot.Y + ry;

        ctx.fillStyle = '#37A000';
        ctx.beginPath();

        ctx.arc(x + padding, y + padding, 9, 0, 2 * Math.PI);
        ctx.fill();
        //number styles
        ctx.fillStyle = '#FFFFFF';
        ctx.fillText(`${number}`, x + padding, y + padding);
      }
      options.originalDraw(ctx, pageMatrix);
    }
  );

Thanks,
Logan

Great! This is very helpful. Thanks Logan.

Hi Logan,

Another question related to numbering annotations. The method above is achieved through redrawing the canvas but that does not actually modify the xfdf file, correct? So when we “merge”, we are taking the pdf file and the xfdf file and creating downloadable file. Will the numbered annotations be present in that file? If so, do you see a way to include these numbered annotations only when exporting the pdf?

Thanks,
Ryan

Hi Logan,

You can close out this topic. I created a new one. See link: Do annotations from setCustomDrawHandler make it to the downloadable file?

1 Like