I'm interested in how to draw onto the gcodeviewer (or a canvas overlay of the gcodeviewer) to provide some clickable functions. I'm a bit at a loss for how to convert tracked gcode coordinates into pixel positions in the gcodeviewer. Obviously there needs to be some transformation based on zoom level, etc., but I lack the knowledge to accomplish this. Can someone point me to examples for how to do this?

Imagine a `G0 X60 Y60`

on my printer (which would be centered on my 120x120 bed). The canvas for the viewer is 568x568 in width/height, so that means that there should be a dot in the center of that at (568/2, 568/2). We should be able to ignore that the units in one system are millimeters and the new system are pixels.

For my printer, it homes in the back/left corner so a bigger value of Y means that the hotend assembly comes toward me.

Without factoring in the zoom aspect of this, it seems like the math then is...

## Map the four outermost corners and the center

From coordinates | => | To Canvas |
---|---|---|

G0 X0 Y0 | => | left: 0, top: 0 |

G0 X120 Y120 | => | left: 568, top: 568 |

G0 X0 Y120 | => | left: 0, top: 568 |

G0 X120 Y0 | => | left: 568, top: 0 |

G0 X60 Y60 | => | left: 284, top: 284 |

There's a common method of transforming between two systems by setting things up to "cross multiply":

```
60 x
--- = ---
120 568
```

Here, we know that 60:120 is the ratio of the X coordinate versus the maximum X coordinate. The destination system is from 0 to 568 so we're looking for the corresponding value x which is the canvas offset equivalent to the original value of 60 on the bed.

To find x, multiply (60 * 568) / 120 and solve. So the midway point in the new system is 284 which we knew intuitively before. But now we have the math for anything else.

(originalX * 568) / bedXmaximum = canvas left coordinate

(originalY * 568) / bedYmaximum = canvas top coordinate

It's been ages since I list fiddled around in this, but after a quick look just now and a bit of jogging my memory I think the secret was that gcode coordinates translate 1:1 on pixel position (so one pixel distance equals one mm distance), and zoom and offset are just done through the transformation.

The interesting bits are `applyOffsets`

and `applyZoom`

(plus `applyInversion`

in case of a coordinate swap) in https://github.com/foosel/OctoPrint/blob/61431c0df3fb571bd5fdaa6a910e4366a2145c51/src/octoprint/static/gcodeviewer/js/renderer.js. Transforms get tracked by wrapping the context and overloading the transform modifying operations (see `trackTransforms`

in the same file).

Thanks for the info. I am slowly making some progress on this. I'm trying to mark positions of objects in CancelObject plugin so they can be cancelled directly in the gcodeviewer.