Skip to content
Snippets Groups Projects
primitives_jupyter.hpp 3.68 KiB
Newer Older
Nicolas M. Thiéry's avatar
Nicolas M. Thiéry committed
/**
   Variante de primitives.h pour dessiner dans Jupyter, sans la SFML

   CAVEAT: Ceci est une pure rustine, du genre que l'on bricole entre
   minuit et 3h du mat pour sauver un TP, en attendant une solution
   pérenne: backend Jupyter pour SFML, utilisation de xcanvas
   (https://github.com/martinRenou/xcanvas) l'équivalent de ipycanvas
   (https://ipycanvas.readthedocs.io/) pour C++, ou possibilité de
   lancer des applications graphiques sur JupyterHub.

   NE PRENNEZ PAS EXEMPLE DESSUS!
 **/

#include <iostream>
#include <sstream>
#include <xwidgets/xhtml.hpp>

/** Execute javascript code in the Jupyter window
 **/
void execute_javascript(std::string js) {
    nl::json mime_bundle;
    mime_bundle["application/javascript"] = js;
    ::xeus::get_interpreter().display_data(mime_bundle,
                                           nl::json::object(),
                                           nl::json::object());
}

void load_javascript_library() {
    execute_javascript(R"js(
document.primitives_get_context = function() {
    return document.primitives_canvas.getContext('2d');
}
document.primitives_draw_rectangle = function(x, y, width, height, color) {
    var ctx = document.primitives_get_context();
    ctx.strokeStyle = color;
    ctx.strokeRect(x, y, width, height);
}
document.primitives_draw_filled_rectangle = function(x, y, width, height, color) {
    var ctx = document.primitives_get_context();
    ctx.fillStyle = color;
    ctx.fillRect(x, y, width, height);
}
document.primitives_draw_point = function(x, y, color) {
    document.primitives_draw_rectangle(x, y, 1, 1, color);
}
)js");
}

namespace Color {
    using Color = std::string;
    Color White = "white";
    Color Red = "red";
    Color Yellow = "yellow";
    Color Green = "#00FF00";
    Color Black = "black";
}

class Point {
    public:
    int x;
    int y;
    Point(int _x, int _y): x(_x), y(_y) {};
    Point(double _x, double _y): x(_x), y(_y) {};
};

class VideoMode {
    public:
    int width;
    int height;
    VideoMode(int w, int h): width(w), height(h) {}
};

class RenderWindow {
    xw::html html;
    VideoMode vm;

    public:
    // A buffer of javascript commands to execute
    std::ostringstream buffer;
    RenderWindow(VideoMode _vm, std::string s) : vm(_vm) {
        std::ostringstream canvas;
        // canvas << "<canvas id='primitives_canvas'"
        //        << " width=" << vm.width << " height=" << vm.height
        //        << " style='border:1px solid #000000;'></canvas>";
        load_javascript_library();
	buffer << "document.primitives_canvas = document.getElementById('primitives_canvas');";
	buffer << "document.primitives_canvas.height = " << vm.height << ";";
	buffer << "document.primitives_canvas.width = " << vm.width << ";";
	buffer << "document.primitives_canvas.style = 'border:1px solid #000000';";
	display();
	// Disabled until xwidgets is functional again
	// For now, the canvas needs to be created in a markdown cell of the notebook
        // html.value = canvas.str();
        // html.display();
    }

    // Update the canvas by executing all javascript commands in the buffer
    void display() {
        execute_javascript(buffer.str());
        buffer = std::ostringstream();
    }

    // Clear the canvas with the given color
    void clear(Color::Color color) {
        buffer << "document.primitives_draw_filled_rectangle(0, 0, "
               << vm.width << ", "
               << vm.height <<  ", '"
               << color << "');";
        display();
    }
};

void draw_point(RenderWindow &window, Point p, Color::Color color) {
    window.buffer << "document.primitives_draw_point("
                  << p.x << ", "
                  << p.y << ", '"
                  << color << "');";
}