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.