Commit 79827d1a authored by Kento HASEGAWA's avatar Kento HASEGAWA
Browse files

Support for the problem viewer and dragging blocks in viewers

parent fb0ef6af
Loading
Loading
Loading
Loading
+3 −3
Changes for main.py: 3 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -16,9 +16,9 @@ def webui_index():
    # return adc2019system.role.role
    return render_template('index.html')

@webui.route('/view/solution')
def webui_view_solution():
    return render_template('view-solution.html')
@webui.route('/viewer')
def webui_viewer():
    return render_template('viewer.html')

@webui.route('/part/problems')
def webui_part_problems():
+6 −5
Changes for roles/host.py: 6 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -106,15 +106,16 @@ class Host(object):
        else:
            return {'status': 'unknown request'}
    
    def get_solution_for_viewer(self, problem_key, solution_id):
    def get_viewer_data(self, problem_key, solution_id):
        problem = self.get_problem(problem_key)
        if problem is None:
            return None
        problem_data = problem.get_d3json()

        if solution_id is None:
            solution_data = None
        else:
            solution = problem.get_solution(solution_id)
        if solution is None:
            return None
            solution_data = solution.get_d3json()
        
        return {
@@ -146,10 +147,10 @@ class Host(object):
        elif cmd == 'stop':
            self.worker_manager.request_stop()
            return {}
        elif cmd == 'view/solution':
        elif cmd == 'view':
            problem_key = params['problem']
            solution_id = params['solution']
            return self.get_solution_for_viewer(problem_key, solution_id)
            return self.get_viewer_data(problem_key, solution_id)
        elif cmd == 'adccli/login':
            with open('path-to-adccli-login', 'r') as fp:
                d = json.load(fp)
+77 −92
Changes for static/js/adc2019-viewer.js: 77 added lines, 92 removed lines.
Original line number Diff line number Diff line
@@ -103,6 +103,7 @@ class ADC2019BoardViewer {
        let cubeResolution = this.cubeResolution;

        // Draw outer box
        if(('solution' in data) && (data['solution'] != null)){
            let _width = data['solution']['w'] * this.cubeResolution;
            let _height = data['solution']['h'] * this.cubeResolution;
            this.view.append("g")
@@ -128,6 +129,7 @@ class ADC2019BoardViewer {
                .attr("y2", function (d) { return d; })
                .attr("stroke", "#d00")
                .attr("stroke-width", 2);
        }

        let colors = d3.schemeCategory10

@@ -138,11 +140,18 @@ class ADC2019BoardViewer {

        // Create data
        var blocks = data['problem']['block'];
        var block_nums = Object.keys(blocks).length;
        var block_row = Math.ceil(Math.sqrt(block_nums));
        var block_idx = 0;
        for(var bi in blocks){
            let bw = blocks[bi]['w'];
            let bh = blocks[bi]['h'];
            let bx = data['solution']['block'][bi]['x'];
            let by = data['solution']['block'][bi]['y'];
            var bx = (block_idx % block_row) * 3;
            var by = (Math.floor(block_idx / block_row)) * 3;
            if(('solution' in data) && (data['solution'] != null)){
                bx = data['solution']['block'][bi]['x'];
                by = data['solution']['block'][bi]['y'];
            }

            blocks[bi]['cellpos'] = Array();
            for(var _h=0; _h<bh; _h++){
@@ -161,6 +170,34 @@ class ADC2019BoardViewer {

            blocks[bi]['x'] = bx;
            blocks[bi]['y'] = by;
            block_idx++;
        }

        function snapToGrid(p, r) {
            return Math.round(p / r) * r;
        }

        var __view = this.view;

        function dragged(d) {
            var el = d3.select(this);
            var _x = parseInt(el.attr('data-x'), 10) + d3.event.x;
            var _y = parseInt(el.attr('data-y'), 10) + d3.event.y;
            el.attr("transform", (d) => {
                    return 'translate(' + snapToGrid(_x, cubeResolution) + ',' + snapToGrid(_y, cubeResolution) + ')'
                })
        }
        function dragended(d) {
            var el = d3.select(this).classed("dragging", false);
            var _x = parseInt(el.attr('data-x'), 10) + d3.event.x;
            var _y = parseInt(el.attr('data-y'), 10) + d3.event.y;
            d3.select(this)
                .attr('data-x', snapToGrid(_x, cubeResolution))
                .attr('data-y', snapToGrid(_y, cubeResolution));
        }
        function dragstarted(d) {
            var el = d3.select(this);
            el.raise().classed("dragging", true);
        }

        var itemContainer = this.view.selectAll("g.itemContainer")
@@ -168,15 +205,19 @@ class ADC2019BoardViewer {
            .enter()
            .append('g')
            .attr('class', 'itemContainer')
            .attr("transform", (d) => 'translate(' + d.x + ',' + d.y + ')')
            .attr("transform", (d) => 'translate(' + 0 + ',' + 0 + ')')
            .attr('data-x', (d) => d.x)
            .attr('data-y', (d) => d.y);
            .attr('data-y', (d) => d.y)
            .call(d3.drag()
                .on("start", dragstarted)
                .on("drag", dragged)
                .on("end", dragended));

        var cellContainer = itemContainer.append('g')
            .attr('class', 'cellContainer')
            .attr('data-color', (d, i) => colors[i % colors.length])
            .attr('x', 0)
            .attr('y', 0)
            .attr('y', 0);

        cellContainer.selectAll('g')
            .data((d) => d.cellpos)
@@ -191,6 +232,7 @@ class ADC2019BoardViewer {
                return d3.select(nodes[i].parentNode).attr('data-color');
            });

        if(('solution' in data) && (data['solution'] != null)){
            cellContainer.selectAll('g')
                .data((d) => d.cellpos)
                .enter()
@@ -203,8 +245,24 @@ class ADC2019BoardViewer {
                .attr('fill', 'white')
                .attr('font-size', '20px')
                .attr('cursor', 'move');
            // .text((d) => d[2]);
        }else{
            cellContainer.selectAll('g')
                .data((d) => d.cellpos)
                .enter()
                .append('text')
                .attr('x', (d) => d[0] * this.cubeResolution + 0.5 * this.cubeResolution)
                .attr('y', (d) => d[1] * this.cubeResolution + 0.5 * this.cubeResolution)
                .attr('width', this.cubeResolution)
                .attr('height', this.cubeResolution)
                .attr('text-anchor', 'middle')
                .attr('fill', 'white')
                .attr('font-size', '20px')
                .attr('cursor', 'move')
                .text((d) => d[2]);
        }

        if(('solution' in data) && (data['solution'] != null)){
            // Draw lines
            let sw = data['solution']['w'];
            let sh = data['solution']['h'];
            var lines = Object();
@@ -265,91 +323,9 @@ class ADC2019BoardViewer {
                .attr('fill', 'black')
                .attr('font-size', '16px')
                .text((d) => d[2]);
        }

    }
    // _draw_blocks(blocks){

    //     let cubeResolution = this.cubeResolution;

    //     function snapToGrid(p, r) {
    //         return Math.round(p / r) * r;
    //     }

    //     function dragged(d) {
    //         var el = d3.select(this);
    //         var _x = parseInt(el.attr('data-x'), 10) + d3.event.x;
    //         var _y = parseInt(el.attr('data-y'), 10) + d3.event.y;
    //         el.attr("transform", (d) => {
    //                 return 'translate(' + snapToGrid(_x, cubeResolution) + ',' + snapToGrid(_y, cubeResolution) + ')'
    //             })
    //     }
    //     function dragended(d) {
    //         var el = d3.select(this).classed("dragging", false);
    //         var _x = parseInt(el.attr('data-x'), 10) + d3.event.x;
    //         var _y = parseInt(el.attr('data-y'), 10) + d3.event.y;
    //         d3.select(this)
    //             .attr('data-x', snapToGrid(_x, cubeResolution))
    //             .attr('data-y', snapToGrid(_y, cubeResolution));
    //     }
    //     function dragstarted(d) {
    //         var el = d3.select(this);
    //         el.raise().classed("dragging", true);
    //     }

    //     let colors = d3.schemeCategory10

    //     // Reference 
    //     // Grid: https://bl.ocks.org/ngminhtrung/7c5721a1504f3e29a36da9ddd9e5039b
    //     // Snap: https://bl.ocks.org/evanjmg/ea3e59e67b4256c8831d3fc80f71294b
    //     // Nested data structure: https://codeday.me/jp/qa/20190428/720184.html

    //     var itemContainer = this.view.selectAll("g.itemContainer")
    //         .data(blocks)
    //         .enter()
    //         .append('g')
    //         .attr('class', 'itemContainer')
    //         .attr("transform", (d) => 'translate(' + d.x + ',' + d.y + ')')
    //         .attr('data-x', (d) => d.x)
    //         .attr('data-y', (d) => d.y)
    //         .call(d3.drag()
    //             .on("start", dragstarted)
    //             .on("drag", dragged)
    //             .on("end", dragended));

    //     var cellContainer = itemContainer.append('g')
    //         .attr('class', 'cellContainer')
    //         .attr('data-color', (d, i) => colors[i])
    //         .attr('x', 0)
    //         .attr('y', 0)

    //     cellContainer.selectAll('g')
    //         .data((d) => d.cells)
    //         .enter()
    //         .append('rect')
    //         .attr('x', (d) => d[0] * this.cubeResolution)
    //         .attr('y', (d) => d[1] * this.cubeResolution)
    //         .attr('width', this.cubeResolution)
    //         .attr('height', this.cubeResolution)
    //         .attr('cursor', 'move')
    //         .attr('fill', (d, i, nodes) => {
    //             return d3.select(nodes[i].parentNode).attr('data-color');
    //         });

    //     cellContainer.selectAll('g')
    //         .data((d) => d.cells)
    //         .enter()
    //         .append('text')
    //         .attr('x', (d) => d[0] * this.cubeResolution + 0.5 * this.cubeResolution)
    //         .attr('y', (d) => d[1] * this.cubeResolution + 0.5 * this.cubeResolution)
    //         .attr('width', this.cubeResolution)
    //         .attr('height', this.cubeResolution)
    //         .attr('text-anchor', 'middle')
    //         .attr('fill', 'white')
    //         .attr('font-size', '20px')
    //         .attr('cursor', 'move')
    //         .text((d) => d[2]);

    // }
}

$(function(){
@@ -359,17 +335,26 @@ $(function(){
    hash = location.hash.replace("#", "");
    params = hash.split('/');

    problem_name = params[0];
    if(params.length > 1){
        solution_id = params[1];
    }else{
        solution_id = null;
    }

    $.ajax({
        type: "POST",
        dataType: "json",
        url: "/api/view/solution",
        url: "/api/view",
        data: JSON.stringify({
            "problem": params[0],
            "solution": params[1]
            "problem": problem_name,
            "solution": solution_id
        }),
        contentType: 'application/json'
    }).done((d) => {
        board.draw(d);
    }).fail((d) => {
        console.log(d);
    });

});
+1 −1
Changes for static/js/adc2019.js: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ class StatusView {
            _this.container.find('.solution-detail-row.valid-solution td').click((e) => {
                var solution_id = $(e.target).parent("tr").data("solution-id");
                var problem_name = $(e.target).parent("tr").data("problem");
                var viewer_url = "/view/solution#" + problem_name + "/" + solution_id;
                var viewer_url = "/viewer#" + problem_name + "/" + solution_id;
                window.open(viewer_url, "_blank");
            });

+1 −0
Changes for templates/part_problem_status.html: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
<div>
    <h4 class='inline-heading' id='problem-status-title'>{{problem.name}}</h4>
    <a href="/viewer#{{problem.name}}" target="_blank">Viewer</a>
    {#% # if localmode %#}
    <button class="btn btn-primary btn-lg start-button" type="button" data-qname="{{problem.name}}">Start</button>
    <!-- <button class="btn btn-danger btn-lg stop-button" type="button" data-qname="all">Stop</button> -->
Loading