<commit_before>/**
 * Created by Michael on 13/04/2016.
 */
var graphs;

alert(test)

var svgContainers = {};
var averages = {};

jQuery("country-list").click(function () {
    var contentPanelId = jQuery(this).attr("id");
    alert(contentPanelId);
});

function addGraphPlaceholders(years) {
    const noOfColumns = 4;
    const columnWidth = 12 / noOfColumns;
    var container = document.getElementById('container');
    for (var i = 0; i < years.length; i++) {
        var year = years[i];
        if (i % noOfColumns === 0) {
            var newRow = document.createElement('div');
            newRow.className = 'row-fluid';
            container.appendChild(newRow);
        }
        container.lastChild.innerHTML += '

';
        document.getElementById('graph-' + year).innerHTML += '
' +
            year +
            ' Score: ' +
            '<button type="button" class="smallButton" id="giveButton-' + year + '">given</button>' +
            '<button type="button" class="smallButton" id="receiveButton-' + year + '">received</button>' +
            '<button type="button" class="smallButton" id="bothButton-' + year + '">both</button>' +
            '
';
        document.getElementById('graph-' + year).innerHTML += '

';
        if (i % noOfColumns == 0 || i == 0) {
            document.getElementById('container').innerHTML += '
'
        }
    }
}

var years = [];
for (yearCounter = 1957; yearCounter < 2016; yearCounter++) {
    years.push(yearCounter);
}

var selectedCountryIndex = 0;
var selectedCountryCode = "BE";

addGraphPlaceholders(years);

years.forEach(function (d) {
    drawCluster(d, 0);
});

function removeEverything() {
    years.forEach(function (year) {
        d3.selectAll("#receiveMid-" + year).remove();
        d3.selectAll("#receive-" + year).remove();
        d3.selectAll("#giveMid-" + year).remove();
        d3.selectAll("#give-" + year).remove();

    });
    d3.selectAll(".node").remove();
}

document.getElementById("allReceived").addEventListener("click", selectAllReceived);
function selectAllReceived() {

    removeEverything();
    years.forEach(function (d) {
        drawCluster(d, 1);
    });
}

document.getElementById("allGiven").addEventListener("click", selectAllGiven);
function selectAllGiven() {
    removeEverything();
    years.forEach(function (d) {
        drawCluster(d, 0);
    });
}

function drawCluster(chartYear, visibility2) {
    var chartId = "#draw-" + chartYear;
    //var width = $(document).width();
    var width = d3.select(chartId).node().getBoundingClientRect().width;
    //var height = $(document).height();
    var height = d3.select(chartId).node().getBoundingClientRect().height;
    console.log("Row - Width: " + width + " height: " + height);
    var middlePoint = {X: width / 2, Y: height / 2};

    var countries = [];
    var nodesData = [];
    var selectedCountry;
    var scores = [[]];

    const giveColour = "#082f6d";
    const receiveColour = "#cd0027";
    const radiusCenter = 15;
    const radiusOuter = 10;
    const buffer1 = 25; // buffer between outer nodes
    const buffer2 = 25; // buffer between mid circle and outer circles
    var radius = radiusOuter + radiusCenter + buffer2; // radius of circle on which outer nodes should be drawn

    var countriesData;
    var scoresData;

    if (!(chartYear in svgContainers)) {
        var tempSvg = d3.select(chartId)
            .append("svg")
            .attr("width", width)
            .attr("height", height);
        svgContainers[chartYear] = tempSvg;
    }

    var svgContainer = svgContainers[chartYear];

    var sortMethod = 1; //0 = none; 1 = neighbours ; 2 = score

    //load data from multiple json files async
    d3_queue.queue()
        .defer(d3.json, 'data/countries.json')
        .defer(d3.json, 'data/scores.json')
        .await(makeGraph);

    function calcGivenAverage(scoresData) {
        var total = 0;
        var amount = 0;
        scoresData.scores.forEach(function (generalScoreInfo) {
            generalScoreInfo.scores.forEach(function (arrayWithScores) {
                arrayWithScores.forEach(function (score) {
                    // if (score != 0) {
                    total += parseInt(score);
                    amount += 1;
                    //}
                })
            });
            averages[chartYear] = total / amount;
            //console.log(chartYear + ": " + total / amount)
            total = 0;
            amount = 0;
        })

    }

    function makeGraph(error, countriesData, scoresData) {
        if (error) throw error;

        var makeGraph = false;

        //Get the results for the given year
        var yearResult = scoresData.scores.find(function (s) {
            return s.year == chartYear;
        });

        //Get the countries that participate this year
        countries = [];
        countriesData.countries.forEach(function (c) {
            var index = yearResult.participants.indexOf(c.countryCode);
            if (index > -1) {
                countries[index] = c;
                if (c.countryCode == selectedCountryCode) {
                    selectedCountryIndex = index;
                    makeGraph = true;
                }
            }
        });

        if (makeGraph) {
            if (typeof averages !== 'undefined') {
                calcGivenAverage(scoresData);
            }

            scores = yearResult.scores;

            //aantal gegeven punten
            var pointsCount = countries.length - 1;

            // hoek tussen landen
            var slice = 2 * Math.PI / pointsCount;

            //dynamically changes the radius
            var temp = pointsCount * (buffer1 + radiusOuter * 2);
            while (radius * Math.PI * 2 < temp) {
                radius += 20;
            }

            var links = [];

            //function sortCountries() {
            //    if (sortMethod == 0)
            //        countries.sort();
            //    else
            //        countries.sort(function (c1, c2) {
            //            if (sortMethod == 1) {
            //                //neighbours
            //                return selectedCountry.country.neighbours.indexOf(c1.countryCode) > -1 ? -1 : 1
            //            } else {
            //                //score
            //                //TODO
            //            }
            //        });
            //}
            //
            //sortCountries();

            selectedCountry = {
                index: selectedCountryIndex,
                country: countries[selectedCountryIndex],
                X: middlePoint.X,
                Y: middlePoint.Y,
                R: radiusCenter
            };

            nodesData.push(selectedCountry);

            var i = 0, j = 0;

            var temp = countries.slice();
            temp.splice(selectedCountryIndex, 1);

            temp.sort(function (c) {
                //sorteren op neighbors
                if (selectedCountry.country.neighbours.indexOf(c.countryCode) > -1) {
                    return -1;
                }
                return 1;
            }).forEach(
                function (c) {
                    if (i == selectedCountryIndex)
                        i++;

                    var angle = slice * (j);
                    var isNeighour = selectedCountry.country.neighbours.indexOf(c.countryCode) > -1;

                    var outerCenterX = middlePoint.X + (isNeighour ? radius * .6 : radius) * Math.cos(angle);
                    var outerCenterY = middlePoint.Y + (isNeighour ? radius * .6 : radius) * Math.sin(angle);

                    var outerLinkX = middlePoint.X + ((isNeighour ? radius * .6 : radius) - radiusOuter) * Math.cos(angle);
                    var outerLinkY = middlePoint.Y + ((isNeighour ? radius * .6 : radius) - radiusOuter) * Math.sin(angle);

                    var innerLinkX = middlePoint.X + radiusCenter * Math.cos(angle);
                    var innerLinkY = middlePoint.Y + radiusCenter * Math.sin(angle);

                    // center between 2 links; x = (x1+x2)/2; y = (y1+y2)/2
                    var centerLinkX = (innerLinkX + outerLinkX) / 2;
                    var centerLinkY = (innerLinkY + outerLinkY) / 2;

                    nodesData.push({index: i, country: countries[i], X: outerCenterX, Y: outerCenterY, R: radiusOuter});

                    links.push({
                        innerLinkX: innerLinkX,
                        innerLinkY: innerLinkY,
                        outerLinkX: outerLinkX,
                        outerLinkY: outerLinkY,
                        centerLinkX: centerLinkX,
                        centerLinkY: centerLinkY,
                        scoreGiven: scores[j][selectedCountryIndex],
                        scoreReceived: scores[selectedCountryIndex][j],
                        isNeighbor: isNeighour
                    });

                    j++;
                    i++;
                });

            var lineFunction = d3.svg.line()
                .x(function (d) {
                    return d.X;
                })
                .y(function (d) {
                    return d.Y;
                });

            var layer1 = svgContainer.append('g');

            function drawLinks(visibility) {
                //remove the current lines
                d3.selectAll("#receiveMid-" + chartYear).remove();
                d3.selectAll("#receive-" + chartYear).remove();
                d3.selectAll("#giveMid-" + chartYear).remove();
                d3.selectAll("#give-" + chartYear).remove();

                switch (visibility) {
                    //give
                    case 0:
                        links.forEach(function (item, index) {
                            if (item.scoreGiven != 0) {
                                layer1.append("path")
                                    .attr("id", "give-" + chartYear)
                                    .attr("d", lineFunction([
                                        {X: item.innerLinkX, Y: item.innerLinkY},
                                        {X: item.outerLinkX, Y: item.outerLinkY}
                                    ]))
                                    .attr("stroke", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreGiven) < averages[chartYear]) {
                                            //rood
                                            return "#C05746";
                                        } else {
                                            return "#69995D";
                                        }
                                    })
                                    .attr("stroke-width", 4)
                                    .attr("fill", "none")
                                    .attr("marker-end", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreGiven) < averages[chartYear]) {
                                            //rood
                                            return "url(#giveArrowHeadRed)";
                                        } else {
                                            return "url(#giveArrowHeadGreen)";
                                        }
                                    })
                                    .on("mouseover", function () {
                                        document.getElementById("scoreText-" + chartYear).innerHTML = item.scoreGiven;
                                    })
                            }
                        });

                        break;
                    //receive
                    case 1:
                        links.forEach(function (item, index) {
                            if (item.scoreReceived != 0) {
                                layer1.append("path")
                                    .attr("id", "receive-" + chartYear)
                                    .attr("d", lineFunction([
                                        {X: item.outerLinkX, Y: item.outerLinkY},
                                        {X: item.innerLinkX, Y: item.innerLinkY}
                                    ]))
                                    .attr("stroke", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreReceived) < averages[chartYear]) {
                                            //rood
                                            return "#C05746";
                                        } else {
                                            return "#69995D";
                                        }
                                    })
                                    .attr("stroke-width", 4)
                                    .attr("fill", "none")
                                    .attr("marker-end", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreReceived) < averages[chartYear]) {
                                            //rood
                                            return "url(#receiveArrowHeadRed)";
                                        } else {
                                            return "url(#receiveArrowHeadGreen)";
                                        }
                                    })
                                    .on("mouseover", function () {
                                        document.getElementById("scoreText-" + chartYear).innerHTML = item.scoreGiven;
                                    });
                            }
                        });
                        break;
                    //both
                    case  2:
                        links.forEach(function (item, index) {
                            //give
                            layer1.append("path")
                                .attr("id", "give-" + chartYear)
                                .attr("d", lineFunction([
                                    {X: item.innerLinkX, Y: item.innerLinkY},
                                    {X: item.centerLinkX, Y: item.centerLinkY}
                                ]))
                                .attr("stroke", giveColour)
                                .attr("stroke-width", 4)
                                .attr("fill", "none")
                                .attr("marker-end", "url(#giveArrowHead)");
                            //receive
                            layer1.append("path")
                                .attr("id", "receive-" + chartYear)
                                .attr("d", lineFunction([
                                    {X: item.outerLinkX, Y: item.outerLinkY},
                                    {X: item.centerLinkX, Y: item.centerLinkY}
                                ]))
                                .attr("stroke", receiveColour)
                                .attr("stroke-width", 4)
                                .attr("fill", "none")
                                .attr("marker-end", "url(#receiveArrowHead)");
                        });
                        break;
                }

            }

            drawLinks(visibility2);//draws the links; default is given

            var nodes = svgContainer.selectAll("node")
                .data(nodesData);

            var defs = nodes.enter().append('defs');

            defs.append('pattern')
                .attr('id', function (d) {
                    return (d.country.countryCode + "-icon");
                })
                .attr('class', "countryNodes")
                .attr('width', 1)
                .attr('height', 1)
                .attr('patternContentUnits', 'objectBoundingBox')
                .append("image")
                .attr("xlink:xlink:href", function (d) {
                    return ("./images/flags/" + d.country.image);
                })
                .attr("height", 1)
                .attr("width", 1)
                .attr("preserveAspectRatio", "xMinYMin slice");

            //rood
            createMaker("#C05746", "giveArrowHeadRed")
            //groen
            createMaker("#69995D", "giveArrowHeadGreen")
            //rood
            createMaker("#C05746", "receiveArrowHeadRed")
            //groen
            createMaker("#69995D", "receiveArrowHeadGreen")

            function createMaker(color, id) {
                defs.append("marker")
                    .attr("id", id)
                    .attr("refX", 4) /*must be smarter way to calculate shift*/
                    .attr("refY", 0)
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 4)
                    .attr("orient", "auto")
                    .attr("viewBox", "-5 -5 10 10")
                    .append("path")
                    .attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z")
                    .attr("fill", color);
            }

            nodes.enter().append("circle")
                .attr("class", "node")
                .attr("cx", function (d) {
                    return d.X
                })
                .on("click", switchSelectedOnClick)
                .attr("cy", function (d) {
                    return d.Y
                })
                .attr("r", function (d) {
                    return d.R + 3.5
                })
                .style("fill", function (d) {
                    return ("url(#" + d.country.countryCode + "-icon)");
                })
                .attr("box-shadow", "0px 0px 50px green")
                .attr("border-style", "solid")
                .attr("border-width", "20px")
            ;

            //calcAndDraw(selectedCountryIndex);

            function switchSelectedOnClick(flag) {
                /* VB:
                 country = Object {countryCode: "IT", name: "Italië", neighbours: Array[6], image: "Italy.png"}
                 */
                selectedCountryCode = flag.country.countryCode;
                removeEverything();
                years.forEach(function (d) {
                    drawCluster(d, 0);
                });
            }

            var getCountryIndex = function (countryCode) {
                for (var intIndex = 0; intIndex < countries.length; intIndex++) {
                    if (countries[intIndex].countryCode == countryCode) {
                        return intIndex;
                    }
                }
                return 5000;
            };

            //adds the buttons to choose the visible lines
            document.getElementById("giveButton-" + chartYear).onclick = function () {
                drawLinks(0);
            };
            document.getElementById("receiveButton-" + chartYear).onclick = function () {
                drawLinks(1);
            };
            document.getElementById("bothButton-" + chartYear).onclick = function () {
                drawLinks(2);
            };
        }
    }

}<commit_msg>ff ne commit om te teste<commit_after>/**
 * Created by Michael on 13/04/2016.
 */
var graphs;

var svgContainers = {};
var averages = {};

jQuery("country-list").click(function () {
    var contentPanelId = jQuery(this).attr("id");
    alert(contentPanelId);
});

function addGraphPlaceholders(years) {
    const noOfColumns = 4;
    const columnWidth = 12 / noOfColumns;
    var container = document.getElementById('container');
    for (var i = 0; i < years.length; i++) {
        var year = years[i];
        if (i % noOfColumns === 0) {
            var newRow = document.createElement('div');
            newRow.className = 'row-fluid';
            container.appendChild(newRow);
        }
        container.lastChild.innerHTML += '

';
        document.getElementById('graph-' + year).innerHTML += '
' +
            year +
            ' Score: ' +
            '<button type="button" class="smallButton" id="giveButton-' + year + '">given</button>' +
            '<button type="button" class="smallButton" id="receiveButton-' + year + '">received</button>' +
            '<button type="button" class="smallButton" id="bothButton-' + year + '">both</button>' +
            '
';
        document.getElementById('graph-' + year).innerHTML += '

';
        if (i % noOfColumns == 0 || i == 0) {
            document.getElementById('container').innerHTML += '
'
        }
    }
}

var years = [];
for (yearCounter = 1957; yearCounter < 2016; yearCounter++) {
    years.push(yearCounter);
}

var selectedCountryIndex = 0;
var selectedCountryCode = "BE";

addGraphPlaceholders(years);

years.forEach(function (d) {
    drawCluster(d, 0);
});

function removeEverything() {
    years.forEach(function (year) {
        d3.selectAll("#receiveMid-" + year).remove();
        d3.selectAll("#receive-" + year).remove();
        d3.selectAll("#giveMid-" + year).remove();
        d3.selectAll("#give-" + year).remove();

    });
    d3.selectAll(".node").remove();
}

document.getElementById("allReceived").addEventListener("click", selectAllReceived);
function selectAllReceived() {

    removeEverything();
    years.forEach(function (d) {
        drawCluster(d, 1);
    });
}

document.getElementById("allGiven").addEventListener("click", selectAllGiven);
function selectAllGiven() {
    removeEverything();
    years.forEach(function (d) {
        drawCluster(d, 0);
    });
}

function drawCluster(chartYear, visibility2) {
    var chartId = "#draw-" + chartYear;
    //var width = $(document).width();
    var width = d3.select(chartId).node().getBoundingClientRect().width;
    //var height = $(document).height();
    var height = d3.select(chartId).node().getBoundingClientRect().height;
    console.log("Row - Width: " + width + " height: " + height);
    var middlePoint = {X: width / 2, Y: height / 2};

    var countries = [];
    var nodesData = [];
    var selectedCountry;
    var scores = [[]];

    const giveColour = "#082f6d";
    const receiveColour = "#cd0027";
    const radiusCenter = 15;
    const radiusOuter = 10;
    const buffer1 = 25; // buffer between outer nodes
    const buffer2 = 25; // buffer between mid circle and outer circles
    var radius = radiusOuter + radiusCenter + buffer2; // radius of circle on which outer nodes should be drawn

    var countriesData;
    var scoresData;

    if (!(chartYear in svgContainers)) {
        var tempSvg = d3.select(chartId)
            .append("svg")
            .attr("width", width)
            .attr("height", height);
        svgContainers[chartYear] = tempSvg;
    }

    var svgContainer = svgContainers[chartYear];

    var sortMethod = 1; //0 = none; 1 = neighbours ; 2 = score

    //load data from multiple json files async
    d3_queue.queue()
        .defer(d3.json, 'data/countries.json')
        .defer(d3.json, 'data/scores.json')
        .await(makeGraph);

    function calcGivenAverage(scoresData) {
        var total = 0;
        var amount = 0;
        scoresData.scores.forEach(function (generalScoreInfo) {
            generalScoreInfo.scores.forEach(function (arrayWithScores) {
                arrayWithScores.forEach(function (score) {
                    // if (score != 0) {
                    total += parseInt(score);
                    amount += 1;
                    //}
                })
            });
            averages[chartYear] = total / amount;
            //console.log(chartYear + ": " + total / amount)
            total = 0;
            amount = 0;
        })

    }

    function makeGraph(error, countriesData, scoresData) {
        if (error) throw error;

        var makeGraph = false;

        //Get the results for the given year
        var yearResult = scoresData.scores.find(function (s) {
            return s.year == chartYear;
        });

        //Get the countries that participate this year
        countries = [];
        countriesData.countries.forEach(function (c) {
            var index = yearResult.participants.indexOf(c.countryCode);
            if (index > -1) {
                countries[index] = c;
                if (c.countryCode == selectedCountryCode) {
                    selectedCountryIndex = index;
                    makeGraph = true;
                }
            }
        });

        if (makeGraph) {
            if (typeof averages !== 'undefined') {
                calcGivenAverage(scoresData);
            }

            scores = yearResult.scores;

            //aantal gegeven punten
            var pointsCount = countries.length - 1;

            // hoek tussen landen
            var slice = 2 * Math.PI / pointsCount;

            //dynamically changes the radius
            var temp = pointsCount * (buffer1 + radiusOuter * 2);
            while (radius * Math.PI * 2 < temp) {
                radius += 20;
            }

            var links = [];

            //function sortCountries() {
            //    if (sortMethod == 0)
            //        countries.sort();
            //    else
            //        countries.sort(function (c1, c2) {
            //            if (sortMethod == 1) {
            //                //neighbours
            //                return selectedCountry.country.neighbours.indexOf(c1.countryCode) > -1 ? -1 : 1
            //            } else {
            //                //score
            //                //TODO
            //            }
            //        });
            //}
            //
            //sortCountries();

            selectedCountry = {
                index: selectedCountryIndex,
                country: countries[selectedCountryIndex],
                X: middlePoint.X,
                Y: middlePoint.Y,
                R: radiusCenter
            };

            nodesData.push(selectedCountry);

            var i = 0, j = 0;

            var temp = countries.slice();
            temp.splice(selectedCountryIndex, 1);

            temp.sort(function (c) {
                //sorteren op neighbors
                if (selectedCountry.country.neighbours.indexOf(c.countryCode) > -1) {
                    return -1;
                }
                return 1;
            }).forEach(
                function (c) {
                    if (i == selectedCountryIndex)
                        i++;

                    var angle = slice * (j);
                    var isNeighour = selectedCountry.country.neighbours.indexOf(c.countryCode) > -1;

                    var outerCenterX = middlePoint.X + (isNeighour ? radius * .6 : radius) * Math.cos(angle);
                    var outerCenterY = middlePoint.Y + (isNeighour ? radius * .6 : radius) * Math.sin(angle);

                    var outerLinkX = middlePoint.X + ((isNeighour ? radius * .6 : radius) - radiusOuter) * Math.cos(angle);
                    var outerLinkY = middlePoint.Y + ((isNeighour ? radius * .6 : radius) - radiusOuter) * Math.sin(angle);

                    var innerLinkX = middlePoint.X + radiusCenter * Math.cos(angle);
                    var innerLinkY = middlePoint.Y + radiusCenter * Math.sin(angle);

                    // center between 2 links; x = (x1+x2)/2; y = (y1+y2)/2
                    var centerLinkX = (innerLinkX + outerLinkX) / 2;
                    var centerLinkY = (innerLinkY + outerLinkY) / 2;

                    nodesData.push({index: i, country: countries[i], X: outerCenterX, Y: outerCenterY, R: radiusOuter});

                    links.push({
                        innerLinkX: innerLinkX,
                        innerLinkY: innerLinkY,
                        outerLinkX: outerLinkX,
                        outerLinkY: outerLinkY,
                        centerLinkX: centerLinkX,
                        centerLinkY: centerLinkY,
                        scoreGiven: scores[j][selectedCountryIndex],
                        scoreReceived: scores[selectedCountryIndex][j],
                        isNeighbor: isNeighour
                    });

                    j++;
                    i++;
                });

            var lineFunction = d3.svg.line()
                .x(function (d) {
                    return d.X;
                })
                .y(function (d) {
                    return d.Y;
                });

            var layer1 = svgContainer.append('g');

            function drawLinks(visibility) {
                //remove the current lines
                d3.selectAll("#receiveMid-" + chartYear).remove();
                d3.selectAll("#receive-" + chartYear).remove();
                d3.selectAll("#giveMid-" + chartYear).remove();
                d3.selectAll("#give-" + chartYear).remove();

                switch (visibility) {
                    //give
                    case 0:
                        links.forEach(function (item, index) {
                            if (item.scoreGiven != 0) {
                                layer1.append("path")
                                    .attr("id", "give-" + chartYear)
                                    .attr("d", lineFunction([
                                        {X: item.innerLinkX, Y: item.innerLinkY},
                                        {X: item.outerLinkX, Y: item.outerLinkY}
                                    ]))
                                    .attr("stroke", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreGiven) < averages[chartYear]) {
                                            //rood
                                            return "#C05746";
                                        } else {
                                            return "#69995D";
                                        }
                                    })
                                    .attr("stroke-width", 4)
                                    .attr("fill", "none")
                                    .attr("marker-end", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreGiven) < averages[chartYear]) {
                                            //rood
                                            return "url(#giveArrowHeadRed)";
                                        } else {
                                            return "url(#giveArrowHeadGreen)";
                                        }
                                    })
                                    .on("mouseover", function () {
                                        document.getElementById("scoreText-" + chartYear).innerHTML = item.scoreGiven;
                                    })
                            }
                        });

                        break;
                    //receive
                    case 1:
                        links.forEach(function (item, index) {
                            if (item.scoreReceived != 0) {
                                layer1.append("path")
                                    .attr("id", "receive-" + chartYear)
                                    .attr("d", lineFunction([
                                        {X: item.outerLinkX, Y: item.outerLinkY},
                                        {X: item.innerLinkX, Y: item.innerLinkY}
                                    ]))
                                    .attr("stroke", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreReceived) < averages[chartYear]) {
                                            //rood
                                            return "#C05746";
                                        } else {
                                            return "#69995D";
                                        }
                                    })
                                    .attr("stroke-width", 4)
                                    .attr("fill", "none")
                                    .attr("marker-end", function () {
                                        var avg = averages[chartYear];
                                        if (parseFloat(item.scoreReceived) < averages[chartYear]) {
                                            //rood
                                            return "url(#receiveArrowHeadRed)";
                                        } else {
                                            return "url(#receiveArrowHeadGreen)";
                                        }
                                    })
                                    .on("mouseover", function () {
                                        document.getElementById("scoreText-" + chartYear).innerHTML = item.scoreGiven;
                                    });
                            }
                        });
                        break;
                    //both
                    case  2:
                        links.forEach(function (item, index) {
                            //give
                            layer1.append("path")
                                .attr("id", "give-" + chartYear)
                                .attr("d", lineFunction([
                                    {X: item.innerLinkX, Y: item.innerLinkY},
                                    {X: item.centerLinkX, Y: item.centerLinkY}
                                ]))
                                .attr("stroke", giveColour)
                                .attr("stroke-width", 4)
                                .attr("fill", "none")
                                .attr("marker-end", "url(#giveArrowHead)");
                            //receive
                            layer1.append("path")
                                .attr("id", "receive-" + chartYear)
                                .attr("d", lineFunction([
                                    {X: item.outerLinkX, Y: item.outerLinkY},
                                    {X: item.centerLinkX, Y: item.centerLinkY}
                                ]))
                                .attr("stroke", receiveColour)
                                .attr("stroke-width", 4)
                                .attr("fill", "none")
                                .attr("marker-end", "url(#receiveArrowHead)");
                        });
                        break;
                }

            }

            drawLinks(visibility2);//draws the links; default is given

            var nodes = svgContainer.selectAll("node")
                .data(nodesData);

            var defs = nodes.enter().append('defs');

            defs.append('pattern')
                .attr('id', function (d) {
                    return (d.country.countryCode + "-icon");
                })
                .attr('class', "countryNodes")
                .attr('width', 1)
                .attr('height', 1)
                .attr('patternContentUnits', 'objectBoundingBox')
                .append("image")
                .attr("xlink:xlink:href", function (d) {
                    return ("./images/flags/" + d.country.image);
                })
                .attr("height", 1)
                .attr("width", 1)
                .attr("preserveAspectRatio", "xMinYMin slice");

            //rood
            createMaker("#C05746", "giveArrowHeadRed")
            //groen
            createMaker("#69995D", "giveArrowHeadGreen")
            //rood
            createMaker("#C05746", "receiveArrowHeadRed")
            //groen
            createMaker("#69995D", "receiveArrowHeadGreen")

            function createMaker(color, id) {
                defs.append("marker")
                    .attr("id", id)
                    .attr("refX", 4) /*must be smarter way to calculate shift*/
                    .attr("refY", 0)
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 4)
                    .attr("orient", "auto")
                    .attr("viewBox", "-5 -5 10 10")
                    .append("path")
                    .attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z")
                    .attr("fill", color);
            }

            nodes.enter().append("circle")
                .attr("class", "node")
                .attr("cx", function (d) {
                    return d.X
                })
                .on("click", switchSelectedOnClick)
                .attr("cy", function (d) {
                    return d.Y
                })
                .attr("r", function (d) {
                    return d.R + 3.5
                })
                .style("fill", function (d) {
                    return ("url(#" + d.country.countryCode + "-icon)");
                })
                .attr("box-shadow", "0px 0px 50px green")
                .attr("border-style", "solid")
                .attr("border-width", "20px")
            ;

            //calcAndDraw(selectedCountryIndex);

            function switchSelectedOnClick(flag) {
                /* VB:
                 country = Object {countryCode: "IT", name: "Italië", neighbours: Array[6], image: "Italy.png"}
                 */
                selectedCountryCode = flag.country.countryCode;
                removeEverything();
                years.forEach(function (d) {
                    drawCluster(d, 0);
                });
            }

            var getCountryIndex = function (countryCode) {
                for (var intIndex = 0; intIndex < countries.length; intIndex++) {
                    if (countries[intIndex].countryCode == countryCode) {
                        return intIndex;
                    }
                }
                return 5000;
            };

            //adds the buttons to choose the visible lines
            document.getElementById("giveButton-" + chartYear).onclick = function () {
                drawLinks(0);
            };
            document.getElementById("receiveButton-" + chartYear).onclick = function () {
                drawLinks(1);
            };
            document.getElementById("bothButton-" + chartYear).onclick = function () {
                drawLinks(2);
            };
        }
    }

}<|endoftext|>


<commit_before>class Cell {
  constructor(key, role, gridElement) {
    this.key = key;
    this.role = role;
    this.gridElement = gridElement;
    this.offsetLeft = null;
    this.offsetTop = null;
    this.width = null;
    this.height = null;
    this.offsetRight = null;
    this.offsetBottom = null;
    this.row = null;
    this.column = null;

    // Elements owned by this cell, keyed by layer.
    this.elements_ = new Map();

    // Exposed to be used by text gestures.
    this.textHeight = null;

    // Initialization.
    this.neighborKeys_ = new Map();
    this.wireInteractions_();
  }

  getLayerContent(layer) {
    if (layer.getShadowingLayer) {
      return this.getLayerContent(layer.getShadowingLayer());
    }
    return state.getLayerContent(this.key, layer);
  }

  setLayerContent(layer, content, recordChange) {
    const oldContent = this.getLayerContent(layer);
    state.setLayerContent(this.key, layer, content);
    const newContent = this.getLayerContent(layer);
    if (!sameContent(oldContent, newContent)) {
      if (recordChange) {
        state.opCenter.
            recordCellChange(this.key, layer, oldContent, newContent);
      }
      this.updateElement_(layer, oldContent, newContent);
      if (layer.getShadowLayer) {
        this.updateElement_(layer.getShadowLayer(), oldContent, newContent);
      }
    }
  }

  hasLayerContent(layer) {
    return !!this.getLayerContent(layer);
  }

  isKind(layer, kind) {
    const content = this.getLayerContent(layer);
    return content ? content[ck.kind] === kind.id : false;
  }

  isVariation(layer, kind, variation) {
    const content = this.getLayerContent(layer);
    if (!content) return false;
    if (content[ck.kind] !== kind.id) return false;
    if (content[ck.variation] !== variation.id) return false;
    return true;
  }

  getVal(layer, contentKey) {
    const content = this.getLayerContent(layer);
    return content ? content[contentKey] : null;
  }

  createElementFromContent(layer, content) {
    if (!this.contentShouldHaveElement_(content)) return null;
    const element = createAndAppendDivWithClass(
        document.getElementById(layer.name + 'Layer'));
    this.populateElementFromContent_(element, layer, content);
    this.elements_.set(layer, element);
    return element;
  }

  // Returns all the cells in a square between this cell and 'cell', in row
  // and then col order.
  getPrimaryCellsInSquareTo(cell) {
    if (!cell || !this.role == 'primary' || !cell.role == 'primary') return [];

    const startCellKey =
        TheMap.primaryCellKey(
            Math.min(this.row, cell.row), Math.min(this.column, cell.column));
    const endCellKey =
        TheMap.primaryCellKey(
            Math.max(this.row, cell.row), Math.max(this.column, cell.column));
    const startCell = state.theMap.cells.get(startCellKey);
    if (!startCell) return [];
    const endCell = state.theMap.cells.get(endCellKey);
    if (!endCell) return [];
    const width = 1 + endCell.column - startCell.column;
    const height = 1 + endCell.row - startCell.row;

    const result = [];
    let rowStart = startCell;
    for (let i = 0; i < height; i++) {
      let currCell = rowStart;
      for (let j = 0; j < width; j++) {
        result.push(currCell);
        currCell = currCell.getNeighbors('right').cells[0];
        if (!currCell) break;
      }
      rowStart = rowStart.getNeighbors('bottom').cells[0];
      if (!rowStart) break;
    }
    return result;
  }

  populateElementFromContent_(element, layer, content) {
    this.modifyElementClasses_(layer, content, element, 'add');
    this.setElementGeometryToGridElementGeometry_(element, content);
    element.innerHTML = '';
    this.setText_(element, content[ck.text]);
    this.setImage_(element, content[ck.image], content[ck.variation]);
    this.setImageHash_(element, content[ck.imageHash], content[ck.variation]);
    this.setImageFromVariation_(element, layer, content);
    this.setClip_(
        element, content[ck.clipInclude], content[ck.clipExclude]);
  }

  setClip_(element, clipInclude, clipExclude) {
    if (!element || (!clipInclude && !clipExclude)) return;
    const shapes = [];
    if (clipInclude) {
      clipInclude.split('|').forEach(clipShape => {
        shapes.push(this.clipToSvgShape_(clipShape, 'white'));
      });
    } else {
      // If there are no inclusions, include the whole element.
      shapes
          .push("<rect x='0' y='0' width='100%' height='100%' fill='white'/>");
    }
    if (clipExclude) {
      clipExclude.split('|').forEach(clipShape => {
        shapes.push(this.clipToSvgShape_(clipShape, 'black'));
      });
    }
    const svg =
        "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'>" +
        `<defs><mask id='m'>${shapes.join('')}</mask></defs>` +
        "<rect x='0' y='0' width='100%' height='100%' mask='url(#m)' /></svg>";
    element.style['-webkit-mask'] = `url("${svg}")`;
    element.style['mask'] = `url("${svg}")`;
  }

  clipToSvgShape_(clipShape, color) {
    switch (clipShape[0]) {
      case 'e':
        const [rx, ry, cx, cy] =
            clipShape.substr(2).split(',').map(s => Number.parseFloat(s));
        return `<ellipse rx='${rx}' ry='${ry}' cx='${cx}' cy='${cy}' ` +
            `fill='${color}' />`;
    }
  }

//  setShadow_(element, layer, content) {
//    const shadowLayer = layer.getShadowLayer();
//    if (!shadowLayer) return;
//    let shadowElement = this.elements_.get(shadowLayer);
//    if (!element && !shadowElement) {
//      return;
//    }
//    if (!element && shadowElement) {
//      this.removeElement(shadowLayer);
//      return;
//    };
//    if (element && !shadowElement) {
//      this.getOrCreateLayerElement(shadowLayer, content);
//      return;
//    }
//
//
//    const shadowElement = element.cloneNode(true);
//    this.elements_[shadowLayer].set(shadowElement);
//    document.getElementById(shadowLayer.name + 'Layer')
//        .appendChild(shadowElement);
//    this.elements_[shadowLayer].set(shadowElement);
//  }

  setText_(element, text) {
    if (!element || !text) return;
    const offsetWidth = element.offsetWidth;
    const offsetHeight = element.offsetHeight;
    const theMapElement = document.getElementById('theMap');
    const sizingElement = createAndAppendDivWithClass(
        theMapElement, element.className);
    sizingElement.style.visibility = 'hidden';
    sizingElement.style.display = 'inline-block';
    sizingElement.style.width = offsetWidth;
    sizingElement.textContent = text;
    let fontSize = 14;
    sizingElement.style.fontSize = fontSize + 'pt';
    while (sizingElement.scrollWidth <= offsetWidth &&
        sizingElement.scrollHeight <= offsetHeight) {
      fontSize++;
      sizingElement.style.fontSize = fontSize + 'pt';
    }
    while (fontSize > 1 &&
        (sizingElement.scrollWidth > offsetWidth ||
         sizingElement.scrollHeight > offsetHeight)) {
      fontSize--;
      sizingElement.style.fontSize = fontSize + 'pt';
    }
    this.textHeight = sizingElement.scrollHeight;
    theMapElement.removeChild(sizingElement);
    element.style.fontSize = fontSize + 'pt';
    element.textContent = text;
  }

  setImage_(element, imageUrl, variation) {
    if (!element || !imageUrl) return;
    const width = element.offsetWidth;
    const height = element.offsetHeight;
    const classNames = variation.classNames || [];
    element.innerHTML = `<img class="image ${classNames.join(' ')}" src=` +
        `"${imageUrl}" style="width: ${width}px; height: ${height}px; alt="">`;
    if (imageUrl.endsWith('.svg')) {
      // Asynchronously replace <img> with <svg>, which then supports
      // 1. Styling
      // 2. Exporting to PNG / SVG
      var xhr = new XMLHttpRequest();
      xhr.open('get', imageUrl, true);
      xhr.onreadystatechange = () => {
        if (xhr.readyState != 4) return;
        const svgElement = xhr.responseXML.documentElement;
        svgElement.classList.add('image');
        svgElement.classList.add(...classNames);
        svgElement.style.width = width;
        svgElement.style.height = height;
        element.innerHTML = '';
        element.appendChild(svgElement);
      };
      xhr.send();
    }
  }

  setImageHash_(element, imageHash, variation) {
    if (!element || !imageHash) return;
    const imageUrl =
        gameIcons.find(gameIcon => gameIcon.hash == imageHash).path;
    if (imageUrl) {
      this.setImage_(element, imageUrl.replace('public/app/', ''), variation);
    }
  }

  setImageFromVariation_(element, layer, content) {
    if (!element) return;
    const kind = ct.children[layer.id].children[content[ck.kind]];
    const variation = kind.children[content[ck.variation]];
    if (!variation.imagePath) return;
    this.setImage_(element, variation.imagePath, variation);
  }

  getOrCreateLayerElement(layer, initialContent) {
    let element = this.elements_.get(layer);
    if (!element) {
      element = this.createElementFromContent(layer, initialContent);
    }
    return element;
  }

  removeElement(layer) {
    let element = this.elements_.get(layer);
    if (!element) return;
    element.parentElement.removeChild(element);
    this.elements_.delete(layer);
  }

  contentShouldHaveElement_(content) {
    // Either there's no content, or the content has a start cell, signalling
    // it should be rendered in another cell.
    return content && !content[ck.startCell];
  }

  updateElement_(layer, oldContent, newContent) {
    if (!this.contentShouldHaveElement_(newContent)) {
      this.removeElement(layer);
      return null;
    }
    const element = this.getOrCreateLayerElement(layer, newContent);
    this.modifyElementClasses_(layer, oldContent, element, 'remove');
    this.populateElementFromContent_(element, layer, newContent);
//    if (layer.getShadowLayer) {
//      this.updateElement_(layer.getShadowLayer(), oldContent, newContent);
//    }
    return element;
  }

  updateLayerElementToCurrentContent_(layer) {
    const element = this.elements_.get(layer);
    const content = this.getLayerContent(layer);
    if (!element) {
      this.createElementFromContent(layer, content);
    } else {
      if (this.contentShouldHaveElement_(content)) {
        element.className = '';
        this.populateElementFromContent_(element, layer, content);
      } else {
        this.removeElement(layer);
      }
    }
  }

  updateAllElementsToCurrentContent() {
    ct.children.forEach(layer => {
      this.updateLayerElementToCurrentContent_(layer);
    });
  }

  resetToDefault() {
    ct.children.forEach(layer => {
      const hasShadowingLayer = !!layer.getShadowingLayer;
      this.setLayerContent(layer, null, !hasShadowingLayer);
    });
  }

//  setShadowElement_(shadowLayer, element) {
//    if (!element) {
//      this.removeElement(shadowLayer);
//      return;
//    }
//    let shadowElement = this.elements_.get(shadowLayer);
//    if (!shadowElement) {
//      shadowElement = createAndAppendDivWithClass()
//    }
//    if (!element && shadowElement) {
//      this.elements_[];
//      element.parentElement.removeChild(element);
//      XXX
//    }
//  }

  onMouseEnter(e) {
    if (!state.gesture) return;
    if (e.buttons == 0) {
      state.gesture.startHover(this);
    } else if (e.buttons == 1) {
      state.gesture.continueGesture(this);
    }
    e.stopPropagation();
  }

  onMouseLeave(e) {
    if (!state.gesture) return;
    if (e.buttons == 0) {
      state.gesture.stopHover();
    }
    e.stopPropagation();
  }

  onMouseDown(e) {
    if (!state.gesture) return;
    if (e.buttons == 1) {
      state.gesture.startGesture();
    }
    e.stopPropagation();
  }

  onMouseUp(e) {
    if (!state.gesture) return;
    if (e.button == 0) {
      state.gesture.stopGesture();
    }
    state.gesture.startHover(this);
    e.stopPropagation();
  }

  wireInteractions_() {
    // All grid element interactions stop the event from bubbling up.
    this.gridElement.onmouseenter = e => this.onMouseEnter(e);
    this.gridElement.onmouseleave = e => this.onMouseLeave(e);
    this.gridElement.onmousedown = e => this.onMouseDown(e);
    this.gridElement.onmouseup = e => this.onMouseUp(e);
  }

  setElementGeometryToGridElementGeometry_(element, content) {
    const endCellKey = content[ck.endCell];
    const endCell = endCellKey ? state.theMap.cells.get(endCellKey) : this;
    element.style.top = this.offsetTop;
    element.style.right = endCell.offsetRight;
    element.style.bottom = endCell.offsetBottom;
    element.style.left = this.offsetLeft;
  }

  addNeighborKey(direction, dividerKey, cellKeys) {
    this.neighborKeys_.set(direction, {
      dividerKey: dividerKey,
      cellKeys : cellKeys,
    });
  }

  getNeighbors(direction) {
    const neighborKeysInDirection = this.neighborKeys_.get(direction);
    if (!neighborKeysInDirection) return null;
    return {
      dividerCell:
          state.theMap.cells.get(neighborKeysInDirection.dividerKey),
      cells: neighborKeysInDirection.cellKeys
          .map(cellKey => { return state.theMap.cells.get(cellKey); })
          .filter(cell => !!cell),
    }
  }

  getNeighbor(direction, divider) {
    const neighbors = this.getNeighbors(direction);
    if (!neighbors) return null;
    if (divider) {
      return neighbors.dividerCell;
    }
    if (!neighbors.cells || neighbors.cells.length == 0) return null;
    return neighbors.cells[0];
  }

  getAllNeighbors() {
    const neighbors = [];
    for (let direction of this.neighborKeys_.keys()) {
      const neighborsOfDirection = this.getNeighbors(direction);
      neighbors.push({
        direction,
        dividerCell: neighborsOfDirection.dividerCell,
        cells: neighborsOfDirection.cells,
      });
    };
    return neighbors;
  }

  modifyElementClasses_(layer, content, element, addOrRemove) {
    if (!content) return;
    const kind = ct.children[layer.id].children[content[ck.kind]];
    const variation = kind.children[content[ck.variation]];
    const classNames = [].concat(
        layer.classNames || [],
        kind.classNames || [],
        variation.classNames || []);
    classNames.forEach(className => {
      let renamed = className.replace(/_ROLE_/g, this.role);
      if (content.hasOwnProperty(ck.connections)) {
        renamed = renamed.replace(/_CONNECTIONS_/g, content[ck.connections]);
      }
      element.classList[addOrRemove](renamed);
    });
  }

  showHighlight(layer, content) {
    const existingContent = this.getLayerContent(layer);
    const action = existingContent && content ? 'editing' :
        (existingContent ? 'removing' : 'adding');
    const element = content ?
        this.updateElement_(layer, this.getLayerContent(layer), content) :
        this.elements_.get(layer);
    if (!element) return;
    if (action == 'adding') {
      element.className = element.className
          .replace(/_ADDING-REMOVING_/g, 'adding')
          .replace(/_ADDING_/g, 'adding');
    } else if (action == 'removing') {
      element.className = element.className
          .replace(/_ADDING-REMOVING_/g, 'removing')
          .replace(/_REMOVING_/g, 'removing');
    } else if (action == 'editing') {
      element.className = element.className.replace(/_EDITING_/g, 'editing');
    }
  }

  hideHighlight(layer) {
    this.updateLayerElementToCurrentContent_(layer);
  }
}
<commit_msg>Ellipses now show up fine in Firefox.<commit_after>class Cell {
  constructor(key, role, gridElement) {
    this.key = key;
    this.role = role;
    this.gridElement = gridElement;
    this.offsetLeft = null;
    this.offsetTop = null;
    this.width = null;
    this.height = null;
    this.offsetRight = null;
    this.offsetBottom = null;
    this.row = null;
    this.column = null;

    // Elements owned by this cell, keyed by layer.
    this.elements_ = new Map();

    // Exposed to be used by text gestures.
    this.textHeight = null;

    // Initialization.
    this.neighborKeys_ = new Map();
    this.wireInteractions_();
  }

  getLayerContent(layer) {
    if (layer.getShadowingLayer) {
      return this.getLayerContent(layer.getShadowingLayer());
    }
    return state.getLayerContent(this.key, layer);
  }

  setLayerContent(layer, content, recordChange) {
    const oldContent = this.getLayerContent(layer);
    state.setLayerContent(this.key, layer, content);
    const newContent = this.getLayerContent(layer);
    if (!sameContent(oldContent, newContent)) {
      if (recordChange) {
        state.opCenter.
            recordCellChange(this.key, layer, oldContent, newContent);
      }
      this.updateElement_(layer, oldContent, newContent);
      if (layer.getShadowLayer) {
        this.updateElement_(layer.getShadowLayer(), oldContent, newContent);
      }
    }
  }

  hasLayerContent(layer) {
    return !!this.getLayerContent(layer);
  }

  isKind(layer, kind) {
    const content = this.getLayerContent(layer);
    return content ? content[ck.kind] === kind.id : false;
  }

  isVariation(layer, kind, variation) {
    const content = this.getLayerContent(layer);
    if (!content) return false;
    if (content[ck.kind] !== kind.id) return false;
    if (content[ck.variation] !== variation.id) return false;
    return true;
  }

  getVal(layer, contentKey) {
    const content = this.getLayerContent(layer);
    return content ? content[contentKey] : null;
  }

  createElementFromContent(layer, content) {
    if (!this.contentShouldHaveElement_(content)) return null;
    const element = createAndAppendDivWithClass(
        document.getElementById(layer.name + 'Layer'));
    this.populateElementFromContent_(element, layer, content);
    this.elements_.set(layer, element);
    return element;
  }

  // Returns all the cells in a square between this cell and 'cell', in row
  // and then col order.
  getPrimaryCellsInSquareTo(cell) {
    if (!cell || !this.role == 'primary' || !cell.role == 'primary') return [];

    const startCellKey =
        TheMap.primaryCellKey(
            Math.min(this.row, cell.row), Math.min(this.column, cell.column));
    const endCellKey =
        TheMap.primaryCellKey(
            Math.max(this.row, cell.row), Math.max(this.column, cell.column));
    const startCell = state.theMap.cells.get(startCellKey);
    if (!startCell) return [];
    const endCell = state.theMap.cells.get(endCellKey);
    if (!endCell) return [];
    const width = 1 + endCell.column - startCell.column;
    const height = 1 + endCell.row - startCell.row;

    const result = [];
    let rowStart = startCell;
    for (let i = 0; i < height; i++) {
      let currCell = rowStart;
      for (let j = 0; j < width; j++) {
        result.push(currCell);
        currCell = currCell.getNeighbors('right').cells[0];
        if (!currCell) break;
      }
      rowStart = rowStart.getNeighbors('bottom').cells[0];
      if (!rowStart) break;
    }
    return result;
  }

  populateElementFromContent_(element, layer, content) {
    this.modifyElementClasses_(layer, content, element, 'add');
    this.setElementGeometryToGridElementGeometry_(element, content);
    element.innerHTML = '';
    this.setText_(element, content[ck.text]);
    this.setImage_(element, content[ck.image], content[ck.variation]);
    this.setImageHash_(element, content[ck.imageHash], content[ck.variation]);
    this.setImageFromVariation_(element, layer, content);
    this.setClip_(
        element, content[ck.clipInclude], content[ck.clipExclude]);
  }

  setClip_(element, clipInclude, clipExclude) {
    if (!element || (!clipInclude && !clipExclude)) return;
    const shapes = [];
    if (clipInclude) {
      clipInclude.split('|').forEach(clipShape => {
        shapes.push(this.clipToSvgShape_(clipShape, 'white'));
      });
    } else {
      // If there are no inclusions, include the whole element.
      shapes
          .push("<rect x='0' y='0' width='100%' height='100%' fill='white'/>");
    }
    if (clipExclude) {
      clipExclude.split('|').forEach(clipShape => {
        shapes.push(this.clipToSvgShape_(clipShape, 'black'));
      });
    }
    const svg =
        "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'>" +
        `<defs><mask id='m'>${shapes.join('')}</mask></defs>` +
        "<rect x='0' y='0' width='100%' height='100%' mask='url(%23m)' /></svg>";
    element.style['-webkit-mask'] = `url("${svg}")`;
    element.style['mask'] = `url("${svg}")`;
  }

  clipToSvgShape_(clipShape, color) {
    switch (clipShape[0]) {
      case 'e':
        const [rx, ry, cx, cy] =
            clipShape.substr(2).split(',').map(s => Number.parseFloat(s));
        return `<ellipse rx='${rx}' ry='${ry}' cx='${cx}' cy='${cy}' ` +
            `fill='${color}' />`;
    }
  }

//  setShadow_(element, layer, content) {
//    const shadowLayer = layer.getShadowLayer();
//    if (!shadowLayer) return;
//    let shadowElement = this.elements_.get(shadowLayer);
//    if (!element && !shadowElement) {
//      return;
//    }
//    if (!element && shadowElement) {
//      this.removeElement(shadowLayer);
//      return;
//    };
//    if (element && !shadowElement) {
//      this.getOrCreateLayerElement(shadowLayer, content);
//      return;
//    }
//
//
//    const shadowElement = element.cloneNode(true);
//    this.elements_[shadowLayer].set(shadowElement);
//    document.getElementById(shadowLayer.name + 'Layer')
//        .appendChild(shadowElement);
//    this.elements_[shadowLayer].set(shadowElement);
//  }

  setText_(element, text) {
    if (!element || !text) return;
    const offsetWidth = element.offsetWidth;
    const offsetHeight = element.offsetHeight;
    const theMapElement = document.getElementById('theMap');
    const sizingElement = createAndAppendDivWithClass(
        theMapElement, element.className);
    sizingElement.style.visibility = 'hidden';
    sizingElement.style.display = 'inline-block';
    sizingElement.style.width = offsetWidth;
    sizingElement.textContent = text;
    let fontSize = 14;
    sizingElement.style.fontSize = fontSize + 'pt';
    while (sizingElement.scrollWidth <= offsetWidth &&
        sizingElement.scrollHeight <= offsetHeight) {
      fontSize++;
      sizingElement.style.fontSize = fontSize + 'pt';
    }
    while (fontSize > 1 &&
        (sizingElement.scrollWidth > offsetWidth ||
         sizingElement.scrollHeight > offsetHeight)) {
      fontSize--;
      sizingElement.style.fontSize = fontSize + 'pt';
    }
    this.textHeight = sizingElement.scrollHeight;
    theMapElement.removeChild(sizingElement);
    element.style.fontSize = fontSize + 'pt';
    element.textContent = text;
  }

  setImage_(element, imageUrl, variation) {
    if (!element || !imageUrl) return;
    const width = element.offsetWidth;
    const height = element.offsetHeight;
    const classNames = variation.classNames || [];
    element.innerHTML = `<img class="image ${classNames.join(' ')}" src=` +
        `"${imageUrl}" style="width: ${width}px; height: ${height}px; alt="">`;
    if (imageUrl.endsWith('.svg')) {
      // Asynchronously replace <img> with <svg>, which then supports
      // 1. Styling
      // 2. Exporting to PNG / SVG
      var xhr = new XMLHttpRequest();
      xhr.open('get', imageUrl, true);
      xhr.onreadystatechange = () => {
        if (xhr.readyState != 4) return;
        const svgElement = xhr.responseXML.documentElement;
        svgElement.classList.add('image');
        svgElement.classList.add(...classNames);
        svgElement.style.width = width;
        svgElement.style.height = height;
        element.innerHTML = '';
        element.appendChild(svgElement);
      };
      xhr.send();
    }
  }

  setImageHash_(element, imageHash, variation) {
    if (!element || !imageHash) return;
    const imageUrl =
        gameIcons.find(gameIcon => gameIcon.hash == imageHash).path;
    if (imageUrl) {
      this.setImage_(element, imageUrl.replace('public/app/', ''), variation);
    }
  }

  setImageFromVariation_(element, layer, content) {
    if (!element) return;
    const kind = ct.children[layer.id].children[content[ck.kind]];
    const variation = kind.children[content[ck.variation]];
    if (!variation.imagePath) return;
    this.setImage_(element, variation.imagePath, variation);
  }

  getOrCreateLayerElement(layer, initialContent) {
    let element = this.elements_.get(layer);
    if (!element) {
      element = this.createElementFromContent(layer, initialContent);
    }
    return element;
  }

  removeElement(layer) {
    let element = this.elements_.get(layer);
    if (!element) return;
    element.parentElement.removeChild(element);
    this.elements_.delete(layer);
  }

  contentShouldHaveElement_(content) {
    // Either there's no content, or the content has a start cell, signalling
    // it should be rendered in another cell.
    return content && !content[ck.startCell];
  }

  updateElement_(layer, oldContent, newContent) {
    if (!this.contentShouldHaveElement_(newContent)) {
      this.removeElement(layer);
      return null;
    }
    const element = this.getOrCreateLayerElement(layer, newContent);
    this.modifyElementClasses_(layer, oldContent, element, 'remove');
    this.populateElementFromContent_(element, layer, newContent);
//    if (layer.getShadowLayer) {
//      this.updateElement_(layer.getShadowLayer(), oldContent, newContent);
//    }
    return element;
  }

  updateLayerElementToCurrentContent_(layer) {
    const element = this.elements_.get(layer);
    const content = this.getLayerContent(layer);
    if (!element) {
      this.createElementFromContent(layer, content);
    } else {
      if (this.contentShouldHaveElement_(content)) {
        element.className = '';
        this.populateElementFromContent_(element, layer, content);
      } else {
        this.removeElement(layer);
      }
    }
  }

  updateAllElementsToCurrentContent() {
    ct.children.forEach(layer => {
      this.updateLayerElementToCurrentContent_(layer);
    });
  }

  resetToDefault() {
    ct.children.forEach(layer => {
      const hasShadowingLayer = !!layer.getShadowingLayer;
      this.setLayerContent(layer, null, !hasShadowingLayer);
    });
  }

//  setShadowElement_(shadowLayer, element) {
//    if (!element) {
//      this.removeElement(shadowLayer);
//      return;
//    }
//    let shadowElement = this.elements_.get(shadowLayer);
//    if (!shadowElement) {
//      shadowElement = createAndAppendDivWithClass()
//    }
//    if (!element && shadowElement) {
//      this.elements_[];
//      element.parentElement.removeChild(element);
//      XXX
//    }
//  }

  onMouseEnter(e) {
    if (!state.gesture) return;
    if (e.buttons == 0) {
      state.gesture.startHover(this);
    } else if (e.buttons == 1) {
      state.gesture.continueGesture(this);
    }
    e.stopPropagation();
  }

  onMouseLeave(e) {
    if (!state.gesture) return;
    if (e.buttons == 0) {
      state.gesture.stopHover();
    }
    e.stopPropagation();
  }

  onMouseDown(e) {
    if (!state.gesture) return;
    if (e.buttons == 1) {
      state.gesture.startGesture();
    }
    e.stopPropagation();
  }

  onMouseUp(e) {
    if (!state.gesture) return;
    if (e.button == 0) {
      state.gesture.stopGesture();
    }
    state.gesture.startHover(this);
    e.stopPropagation();
  }

  wireInteractions_() {
    // All grid element interactions stop the event from bubbling up.
    this.gridElement.onmouseenter = e => this.onMouseEnter(e);
    this.gridElement.onmouseleave = e => this.onMouseLeave(e);
    this.gridElement.onmousedown = e => this.onMouseDown(e);
    this.gridElement.onmouseup = e => this.onMouseUp(e);
  }

  setElementGeometryToGridElementGeometry_(element, content) {
    const endCellKey = content[ck.endCell];
    const endCell = endCellKey ? state.theMap.cells.get(endCellKey) : this;
    element.style.top = this.offsetTop;
    element.style.right = endCell.offsetRight;
    element.style.bottom = endCell.offsetBottom;
    element.style.left = this.offsetLeft;
  }

  addNeighborKey(direction, dividerKey, cellKeys) {
    this.neighborKeys_.set(direction, {
      dividerKey: dividerKey,
      cellKeys : cellKeys,
    });
  }

  getNeighbors(direction) {
    const neighborKeysInDirection = this.neighborKeys_.get(direction);
    if (!neighborKeysInDirection) return null;
    return {
      dividerCell:
          state.theMap.cells.get(neighborKeysInDirection.dividerKey),
      cells: neighborKeysInDirection.cellKeys
          .map(cellKey => { return state.theMap.cells.get(cellKey); })
          .filter(cell => !!cell),
    }
  }

  getNeighbor(direction, divider) {
    const neighbors = this.getNeighbors(direction);
    if (!neighbors) return null;
    if (divider) {
      return neighbors.dividerCell;
    }
    if (!neighbors.cells || neighbors.cells.length == 0) return null;
    return neighbors.cells[0];
  }

  getAllNeighbors() {
    const neighbors = [];
    for (let direction of this.neighborKeys_.keys()) {
      const neighborsOfDirection = this.getNeighbors(direction);
      neighbors.push({
        direction,
        dividerCell: neighborsOfDirection.dividerCell,
        cells: neighborsOfDirection.cells,
      });
    };
    return neighbors;
  }

  modifyElementClasses_(layer, content, element, addOrRemove) {
    if (!content) return;
    const kind = ct.children[layer.id].children[content[ck.kind]];
    const variation = kind.children[content[ck.variation]];
    const classNames = [].concat(
        layer.classNames || [],
        kind.classNames || [],
        variation.classNames || []);
    classNames.forEach(className => {
      let renamed = className.replace(/_ROLE_/g, this.role);
      if (content.hasOwnProperty(ck.connections)) {
        renamed = renamed.replace(/_CONNECTIONS_/g, content[ck.connections]);
      }
      element.classList[addOrRemove](renamed);
    });
  }

  showHighlight(layer, content) {
    const existingContent = this.getLayerContent(layer);
    const action = existingContent && content ? 'editing' :
        (existingContent ? 'removing' : 'adding');
    const element = content ?
        this.updateElement_(layer, this.getLayerContent(layer), content) :
        this.elements_.get(layer);
    if (!element) return;
    if (action == 'adding') {
      element.className = element.className
          .replace(/_ADDING-REMOVING_/g, 'adding')
          .replace(/_ADDING_/g, 'adding');
    } else if (action == 'removing') {
      element.className = element.className
          .replace(/_ADDING-REMOVING_/g, 'removing')
          .replace(/_REMOVING_/g, 'removing');
    } else if (action == 'editing') {
      element.className = element.className.replace(/_EDITING_/g, 'editing');
    }
  }

  hideHighlight(layer) {
    this.updateLayerElementToCurrentContent_(layer);
  }
}
<|endoftext|>


<commit_before>var Main = function(game){

};

Main.prototype = {

	create: function() {
	    var me = this;

	    // Set the background colour to blue
	    me.game.stage.backgroundColor = '#ccddff';
		// background
		me.game.add.sprite(0, -300, 'bg');

	    // Start the P2 Physics Engine
	    me.game.physics.startSystem(Phaser.Physics.P2JS);

	    // Create collision groups
	    me.playerCollisionGroup = me.game.physics.p2.createCollisionGroup();
	    me.webCollisionGroup = me.game.physics.p2.createCollisionGroup();
	    me.blockCollisionGroup = me.game.physics.p2.createCollisionGroup();

		game.physics.p2.setImpactEvents(true);

		// Set the gravity
	    me.game.physics.p2.gravity.y = 1000;

	    // Create a random generator
	    var seed = Date.now();
	    me.random = new Phaser.RandomDataGenerator([seed]);

		// Register keys
		me.registerKeys();

		me.createPlatforms();

	    // Create the ceiling
	    me.createBlock();

	    // Create the player
	    me.createPlayer();

	    // arrow
    	me.arrow = game.add.sprite(me.player.x, me.player.y, 'arrow');
    	me.arrow.anchor.setTo(0.5, 1.2);

	    // Create rope
	    me.createRope();
	},

	playerStanding: function() {
	    var me = this;

		var yAxis = p2.vec2.fromValues(0, 1);
		var result = false;
		function checkConstraint(c) {
			if (c.bodyA === me.player.body.data || c.bodyB === me.player.body.data) {
				var d = p2.vec2.dot(c.normalA, yAxis); // Normal dot Y-axis
				if (c.bodyA === me.player.body.data) d *= -1;
				if (d > 0.5) result = true; // cos(60 degrees) = 0.5, so we can lean 30 degrees
			}
		}
		game.physics.p2.world.narrowphase.contactEquations.forEach(checkConstraint);
		return result;
	},

	update: function() {
	    var me = this;

	    // let arrow follow player
   		me.arrow.x = me.player.x;
    	me.arrow.y = me.player.y;

		me.standing = me.playerStanding();//me.player.body.touching && me.player.body.touching.down;
		me.extraWeb = false;

		if (me.spaceKey.justUp) {
			if (!me.player.swinging || me.extraWeb) {
				me.fire();
			}
			else {
				me.cutRope();
			}
		}

		if (me.cursors.up.justUp && me.player.swinging) {
			me.pullRope();
		}

		if (me.cursors.left.isDown) {
			if (me.cursors.left.shiftKey===true)
			{
				// aim
				me.arrow.rotation -= 0.05;
			} else if (me.standing) {
				// move
				me.player.body.velocity.x = -50;
			}
		}
		if (me.cursors.right.isDown) {
			if (me.cursors.right.shiftKey===true)
			{
				// aim
				me.arrow.rotation += 0.05;
			} else if (me.standing) {
				// move
				me.player.body.velocity.x = 50;
			}
		}

	    //Update the position of the rope
		if (me.player.swinging) {
		    me.drawRope();
		}
//		me.platform[0].key.render();
	},

	registerKeys: function() {
		var me = this;

		me.spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
    	// stop the following keys from propagating up to the browser
        me.game.input.keyboard.addKeyCapture([Phaser.Keyboard.SPACEBAR]);

	    me.cursors = game.input.keyboard.createCursorKeys();
		//me.cursors.up.onInputDown(me.pullRope);
	},

	createPlatforms: function () {
	    var me = this;

		function createPlatform(data, index) {
			// // Define a block using bitmap data rather than an image sprite
			var blockShape = me.game.add.bitmapData(data.width, data.height);

			// Fill the block with black color
			blockShape.ctx.rect(0, 0, data.width, data.height);
			blockShape.ctx.fillStyle = '#abc';
			blockShape.ctx.fill();

			// // Create a new sprite using the bitmap data
			me.platform[index] = me.game.add.sprite(data.x, data.y, blockShape);
// 			me.platform[index] = me.game.add.sprite(data.x, data.y, 'ground');

			// // Enable P2 Physics and set the block not to move
			me.game.physics.p2.enable([me.platform[index]], true);
			me.platform[index].body.static = true;
			me.platform[index].anchor.setTo(data.x, data.y);
			me.platform[index].body.setCollisionGroup(me.blockCollisionGroup);
			me.platform[index].body.collides([
				me.playerCollisionGroup,
				me.webCollisionGroup,
			]);
			// me.platform[index].inputEnabled = true;
			// me.platform[index].events.onInputDown.add(me.changeRope, this);

			//me.platform[index] = me.platforms.create(data.x, data.y, 'ground');
			//me.platform[index].body.immovable = true;
		}

		var platformData = [
			{ x: me.game.world.width/2, y: me.game.world.height - 32, width: me.game.world.width, height: 64 },
			{ x: me.game.world.width-100, y: 400, width: 200, height: 32 },
			{ x: 100, y: 200, width: 200, height: 32 }
		]

		me.platform = [];
		platformData.forEach(createPlatform);
	},

	createBlock: function() {
	    var me = this;

	    // Define a block using bitmap data rather than an image sprite
	    var blockShape = me.game.add.bitmapData(me.game.world.width, 20);

	    // Fill the block with black color
	    blockShape.ctx.rect(0, 0, me.game.world.width, 20);
	    blockShape.ctx.fillStyle = '#2b3';
	    blockShape.ctx.fill();

	    // Create a new sprite using the bitmap data
	    me.block = me.game.add.sprite(0, 0, blockShape);

	    // Enable P2 Physics and set the block not to move
	    me.game.physics.p2.enable(me.block);
	    me.block.body.static = true;
	    me.block.anchor.setTo(0, 0);

	    // Enable clicking on block and trigger a function when it is clicked
    	me.block.inputEnabled = true;
	    me.block.events.onInputDown.add(me.changeRope, this);
	},

	newRope: function(body, point) {
	    var me = this;

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);

	    //Create new spring at pointer x and y
		var len = Phaser.Point.distance(me.player, point, false);
		var pull = 1
	    me.rope = me.game.physics.p2.createSpring(body, me.player, len*pull, 100, 3, [-point.x, -point.y]);
		me.player.swinging = true;
		console.log('New rope with length', len);
		console.log('Rope now has length', me.rope.data.restLength);
	    me.ropeAnchorX = point.x;
	    me.ropeAnchorY = point.y
	},

	changeRope: function(sprite, pointer) {
	    var me = this;

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);

	    //Create new spring at pointer x and y
		var len = Phaser.Point.distance(me.player, pointer, false);
		var pull = 1
	    me.rope = me.game.physics.p2.createSpring(me.block, me.player, len*pull, 100, 3, [-pointer.x, -pointer.y]);
		me.player.swinging = true;
		console.log('Changed to rope with length', len);
		console.log('Rope now has length', me.rope.data.restLength);
	    me.ropeAnchorX = pointer.x;
	    me.ropeAnchorY = pointer.y
	},

	pullRope: function() {
	    console.log('pull');
		var me = this;

	    //Create new spring with shorter rest length
		//var len = me.rope.data.restLength;
		var len = Phaser.Point.distance(me.player, { x: me.ropeAnchorX, y: me.ropeAnchorY }, false);
		console.log('Rope had length', len);
		var step = 30;
		var newLen = Math.max(len-step, 3);
		console.log('Pulled to rope with length', newLen);
		console.log('Rope now has length', me.rope.data.restLength);

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);

	    me.rope = me.game.physics.p2.createSpring(me.block, me.player, newLen, 100, 3, [-me.ropeAnchorX, -me.ropeAnchorY]);
	},

	cutRope: function() {
		var me = this;

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);
		me.player.swinging = false;
	},

	fire: function() {
		console.log('Fire!');
		var me = this;

		if (me.web) me.web.kill();
		// instantiate web
		me.web = game.add.sprite(me.player.x, me.player.y, 'projectile');
		me.web.anchor.set(0.5, 0.5);
		me.game.physics.p2.enable([me.web]);
		me.web.body.gravity.y = 300;
	    me.web.body.setCollisionGroup(me.webCollisionGroup);
	    me.web.body.collides([
	        me.blockCollisionGroup,
	    ]);
		// collide the web projectile and the platforms
		me.web.body.createGroupCallback(me.blockCollisionGroup, me.webHit, me);

		var magnitude = 900;
		var firingAngle = (me.arrow.angle - 90) * Math.PI / 180;
		me.web.body.velocity.x = magnitude * Math.cos(firingAngle) + me.player.body.velocity.x;
		me.web.body.velocity.y = magnitude * Math.sin(firingAngle) + me.player.body.velocity.y;
		if (!me.standing) {
			me.player.body.velocity.x -= 0.1 * magnitude * Math.cos(firingAngle);
			me.player.body.velocity.y -= 0.1 * magnitude * Math.sin(firingAngle);
		}
	},

	webHit: function(web, block, webShape, blockShape) {
	    var me = this;

		console.log('web hit', web.x, web.y);
		me.newRope(block, me.web);
		// remove the projectile - the rope remains
		me.web.body.removeNextStep = true;
		me.web.destroy();
	},

	createPlayer: function() {
	    var me = this;

	    // Add the player to the game
	    me.player = me.game.add.sprite(200, 400, 'spider');

	    // Enable physics, use "true" to enable debug drawing
	    me.game.physics.p2.enable([me.player], false);

	    // Get rid of current bounding box
	    //me.player.body.clearShapes();

	    // Add our PhysicsEditor bounding shape
	    //me.player.body.loadPolygon("sprite_physics", "betty");
	    // Define the players collision group and make it collide with the block and fruits
	    me.player.body.setCollisionGroup(me.playerCollisionGroup);
	    me.player.body.collides([
	        me.blockCollisionGroup,
	    ]);

		me.player.swinging = false;
	},

	createRope: function() {
	    var me = this;

	    // Add bitmap data to draw the rope
	    me.ropeBitmapData = game.add.bitmapData(me.game.world.width, me.game.world.height);

	    me.ropeBitmapData.ctx.beginPath();
	    me.ropeBitmapData.ctx.lineWidth = "4";
	    me.ropeBitmapData.ctx.strokeStyle = "#ffffff";
	    me.ropeBitmapData.ctx.stroke();

	    // Create a new sprite using the bitmap data
	    me.line = game.add.sprite(0, 0, me.ropeBitmapData);

	    // Keep track of where the rope is anchored
	    me.ropeAnchorX = (me.block.world.x + 500);
	    me.ropeAnchorY = (me.block.world.y + me.block.height);

	    // Create a spring between the player and block to act as the rope
	    me.rope = me.game.physics.p2.createSpring(
	        me.block,  // sprite 1
	        me.player, // sprite 2
	        300,       // length of the rope
	        10,        // stiffness
	        3,         // damping
	        [-(me.block.world.x + 500), -(me.block.world.y + me.block.height)]
	    );
		me.player.swinging = true;

	    // Draw a line from the player to the block to visually represent the spring
	    me.line = new Phaser.Line(me.player.x, me.player.y,
	        (me.block.world.x + 500), (me.block.world.y + me.block.height));
	},

	drawRope: function() {
	    var me = this;

	    // Change the bitmap data to reflect the new rope position
	    me.ropeBitmapData.clear();
	    me.ropeBitmapData.ctx.beginPath();
	    me.ropeBitmapData.ctx.beginPath();
	    me.ropeBitmapData.ctx.moveTo(me.player.x, me.player.y);
	    me.ropeBitmapData.ctx.lineTo(me.ropeAnchorX, me.ropeAnchorY);
	    me.ropeBitmapData.ctx.lineWidth = 4;
	    me.ropeBitmapData.ctx.stroke();
	    me.ropeBitmapData.ctx.closePath();
	    me.ropeBitmapData.render();
    },

	gameOver: function(){
		this.game.state.start('GameOver');
	},
};<commit_msg>only show arrow when you can shoot web<commit_after>var Main = function(game){

};

Main.prototype = {

	create: function() {
	    var me = this;

	    // Set the background colour to blue
	    me.game.stage.backgroundColor = '#ccddff';
		// background
		me.game.add.sprite(0, -300, 'bg');

	    // Start the P2 Physics Engine
	    me.game.physics.startSystem(Phaser.Physics.P2JS);

	    // Create collision groups
	    me.playerCollisionGroup = me.game.physics.p2.createCollisionGroup();
	    me.webCollisionGroup = me.game.physics.p2.createCollisionGroup();
	    me.blockCollisionGroup = me.game.physics.p2.createCollisionGroup();

		game.physics.p2.setImpactEvents(true);

		// Set the gravity
	    me.game.physics.p2.gravity.y = 1000;

	    // Create a random generator
	    var seed = Date.now();
	    me.random = new Phaser.RandomDataGenerator([seed]);

		// Register keys
		me.registerKeys();

		me.createPlatforms();

	    // Create the ceiling
	    me.createBlock();

	    // Create the player
	    me.createPlayer();

	    // arrow
    	me.arrow = game.add.sprite(me.player.x, me.player.y, 'arrow');
    	me.arrow.anchor.setTo(0.5, 1.2);

	    // Create rope
	    me.createRope();
	},

	playerStanding: function() {
	    var me = this;

		var yAxis = p2.vec2.fromValues(0, 1);
		var result = false;
		function checkConstraint(c) {
			if (c.bodyA === me.player.body.data || c.bodyB === me.player.body.data) {
				var d = p2.vec2.dot(c.normalA, yAxis); // Normal dot Y-axis
				if (c.bodyA === me.player.body.data) d *= -1;
				if (d > 0.5) result = true; // cos(60 degrees) = 0.5, so we can lean 30 degrees
			}
		}
		game.physics.p2.world.narrowphase.contactEquations.forEach(checkConstraint);
		return result;
	},

	update: function() {
	    var me = this;

	    // let arrow follow player
   		me.arrow.x = me.player.x;
    	me.arrow.y = me.player.y;

		me.standing = me.playerStanding();//me.player.body.touching && me.player.body.touching.down;
		me.extraWeb = false;

		me.canShoot = !me.player.swinging || me.extraWeb;

		if (me.canShoot) {
			me.arrow.alpha = 1;
		} else {
			me.arrow.alpha = 0;
		}

		if (me.spaceKey.justUp) {
			if (me.canShoot) {
				me.fire();
			}
			else {
				me.cutRope();
			}
		}

		if (me.cursors.up.justUp && me.player.swinging) {
			me.pullRope();
		}

		if (me.cursors.left.isDown) {
			if (me.cursors.left.shiftKey===true)
			{
				// aim
				me.arrow.rotation -= 0.05;
			} else if (me.standing) {
				// move
				me.player.body.velocity.x = -50;
			}
		}
		if (me.cursors.right.isDown) {
			if (me.cursors.right.shiftKey===true)
			{
				// aim
				me.arrow.rotation += 0.05;
			} else if (me.standing) {
				// move
				me.player.body.velocity.x = 50;
			}
		}

	    //Update the position of the rope
		if (me.player.swinging) {
		    me.drawRope();
		}
//		me.platform[0].key.render();
	},

	registerKeys: function() {
		var me = this;

		me.spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);
    	// stop the following keys from propagating up to the browser
        me.game.input.keyboard.addKeyCapture([Phaser.Keyboard.SPACEBAR]);

	    me.cursors = game.input.keyboard.createCursorKeys();
		//me.cursors.up.onInputDown(me.pullRope);
	},

	createPlatforms: function () {
	    var me = this;

		function createPlatform(data, index) {
			// // Define a block using bitmap data rather than an image sprite
			var blockShape = me.game.add.bitmapData(data.width, data.height);

			// Fill the block with black color
			blockShape.ctx.rect(0, 0, data.width, data.height);
			blockShape.ctx.fillStyle = '#abc';
			blockShape.ctx.fill();

			// // Create a new sprite using the bitmap data
			me.platform[index] = me.game.add.sprite(data.x, data.y, blockShape);
// 			me.platform[index] = me.game.add.sprite(data.x, data.y, 'ground');

			// // Enable P2 Physics and set the block not to move
			me.game.physics.p2.enable([me.platform[index]], true);
			me.platform[index].body.static = true;
			me.platform[index].anchor.setTo(data.x, data.y);
			me.platform[index].body.setCollisionGroup(me.blockCollisionGroup);
			me.platform[index].body.collides([
				me.playerCollisionGroup,
				me.webCollisionGroup,
			]);
			// me.platform[index].inputEnabled = true;
			// me.platform[index].events.onInputDown.add(me.changeRope, this);

			//me.platform[index] = me.platforms.create(data.x, data.y, 'ground');
			//me.platform[index].body.immovable = true;
		}

		var platformData = [
			{ x: me.game.world.width/2, y: me.game.world.height - 32, width: me.game.world.width, height: 64 },
			{ x: me.game.world.width-100, y: 400, width: 200, height: 32 },
			{ x: 100, y: 200, width: 200, height: 32 }
		]

		me.platform = [];
		platformData.forEach(createPlatform);
	},

	createBlock: function() {
	    var me = this;

	    // Define a block using bitmap data rather than an image sprite
	    var blockShape = me.game.add.bitmapData(me.game.world.width, 20);

	    // Fill the block with black color
	    blockShape.ctx.rect(0, 0, me.game.world.width, 20);
	    blockShape.ctx.fillStyle = '#2b3';
	    blockShape.ctx.fill();

	    // Create a new sprite using the bitmap data
	    me.block = me.game.add.sprite(0, 0, blockShape);

	    // Enable P2 Physics and set the block not to move
	    me.game.physics.p2.enable(me.block);
	    me.block.body.static = true;
	    me.block.anchor.setTo(0, 0);

	    // Enable clicking on block and trigger a function when it is clicked
    	me.block.inputEnabled = true;
	    me.block.events.onInputDown.add(me.changeRope, this);
	},

	newRope: function(body, point) {
	    var me = this;

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);

	    //Create new spring at pointer x and y
		var len = Phaser.Point.distance(me.player, point, false);
		var pull = 1
	    me.rope = me.game.physics.p2.createSpring(body, me.player, len*pull, 100, 3, [-point.x, -point.y]);
		me.player.swinging = true;
		console.log('New rope with length', len);
		console.log('Rope now has length', me.rope.data.restLength);
	    me.ropeAnchorX = point.x;
	    me.ropeAnchorY = point.y
	},

	changeRope: function(sprite, pointer) {
	    var me = this;

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);

	    //Create new spring at pointer x and y
		var len = Phaser.Point.distance(me.player, pointer, false);
		var pull = 1
	    me.rope = me.game.physics.p2.createSpring(me.block, me.player, len*pull, 100, 3, [-pointer.x, -pointer.y]);
		me.player.swinging = true;
		console.log('Changed to rope with length', len);
		console.log('Rope now has length', me.rope.data.restLength);
	    me.ropeAnchorX = pointer.x;
	    me.ropeAnchorY = pointer.y
	},

	pullRope: function() {
	    console.log('pull');
		var me = this;

	    //Create new spring with shorter rest length
		//var len = me.rope.data.restLength;
		var len = Phaser.Point.distance(me.player, { x: me.ropeAnchorX, y: me.ropeAnchorY }, false);
		console.log('Rope had length', len);
		var step = 30;
		var newLen = Math.max(len-step, 3);
		console.log('Pulled to rope with length', newLen);
		console.log('Rope now has length', me.rope.data.restLength);

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);

	    me.rope = me.game.physics.p2.createSpring(me.block, me.player, newLen, 100, 3, [-me.ropeAnchorX, -me.ropeAnchorY]);
	},

	cutRope: function() {
		var me = this;

	    //Remove last spring
	    me.game.physics.p2.removeSpring(me.rope);
		me.player.swinging = false;
	},

	fire: function() {
		console.log('Fire!');
		var me = this;

		if (me.web) me.web.kill();
		// instantiate web
		me.web = game.add.sprite(me.player.x, me.player.y, 'projectile');
		me.web.anchor.set(0.5, 0.5);
		me.game.physics.p2.enable([me.web]);
		me.web.body.gravity.y = 300;
	    me.web.body.setCollisionGroup(me.webCollisionGroup);
	    me.web.body.collides([
	        me.blockCollisionGroup,
	    ]);
		// collide the web projectile and the platforms
		me.web.body.createGroupCallback(me.blockCollisionGroup, me.webHit, me);

		var magnitude = 900;
		var firingAngle = (me.arrow.angle - 90) * Math.PI / 180;
		me.web.body.velocity.x = magnitude * Math.cos(firingAngle) + me.player.body.velocity.x;
		me.web.body.velocity.y = magnitude * Math.sin(firingAngle) + me.player.body.velocity.y;
		if (!me.standing) {
			me.player.body.velocity.x -= 0.1 * magnitude * Math.cos(firingAngle);
			me.player.body.velocity.y -= 0.1 * magnitude * Math.sin(firingAngle);
		}
	},

	webHit: function(web, block, webShape, blockShape) {
	    var me = this;

		console.log('web hit', web.x, web.y);
		me.newRope(block, me.web);
		// remove the projectile - the rope remains
		me.web.body.removeNextStep = true;
		me.web.destroy();
	},

	createPlayer: function() {
	    var me = this;

	    // Add the player to the game
	    me.player = me.game.add.sprite(200, 400, 'spider');

	    // Enable physics, use "true" to enable debug drawing
	    me.game.physics.p2.enable([me.player], false);

	    // Get rid of current bounding box
	    //me.player.body.clearShapes();

	    // Add our PhysicsEditor bounding shape
	    //me.player.body.loadPolygon("sprite_physics", "betty");
	    // Define the players collision group and make it collide with the block and fruits
	    me.player.body.setCollisionGroup(me.playerCollisionGroup);
	    me.player.body.collides([
	        me.blockCollisionGroup,
	    ]);

		me.player.swinging = false;
	},

	createRope: function() {
	    var me = this;

	    // Add bitmap data to draw the rope
	    me.ropeBitmapData = game.add.bitmapData(me.game.world.width, me.game.world.height);

	    me.ropeBitmapData.ctx.beginPath();
	    me.ropeBitmapData.ctx.lineWidth = "4";
	    me.ropeBitmapData.ctx.strokeStyle = "#ffffff";
	    me.ropeBitmapData.ctx.stroke();

	    // Create a new sprite using the bitmap data
	    me.line = game.add.sprite(0, 0, me.ropeBitmapData);

	    // Keep track of where the rope is anchored
	    me.ropeAnchorX = (me.block.world.x + 500);
	    me.ropeAnchorY = (me.block.world.y + me.block.height);

	    // Create a spring between the player and block to act as the rope
	    me.rope = me.game.physics.p2.createSpring(
	        me.block,  // sprite 1
	        me.player, // sprite 2
	        300,       // length of the rope
	        10,        // stiffness
	        3,         // damping
	        [-(me.block.world.x + 500), -(me.block.world.y + me.block.height)]
	    );
		me.player.swinging = true;

	    // Draw a line from the player to the block to visually represent the spring
	    me.line = new Phaser.Line(me.player.x, me.player.y,
	        (me.block.world.x + 500), (me.block.world.y + me.block.height));
	},

	drawRope: function() {
	    var me = this;

	    // Change the bitmap data to reflect the new rope position
	    me.ropeBitmapData.clear();
	    me.ropeBitmapData.ctx.beginPath();
	    me.ropeBitmapData.ctx.beginPath();
	    me.ropeBitmapData.ctx.moveTo(me.player.x, me.player.y);
	    me.ropeBitmapData.ctx.lineTo(me.ropeAnchorX, me.ropeAnchorY);
	    me.ropeBitmapData.ctx.lineWidth = 4;
	    me.ropeBitmapData.ctx.stroke();
	    me.ropeBitmapData.ctx.closePath();
	    me.ropeBitmapData.render();
    },

	gameOver: function(){
		this.game.state.start('GameOver');
	},
};<|endoftext|>


<commit_before>/**
 * Scrollbar constructor.
 * @constructor
 */

function scrollbar(parent, for_dom_obj, options){

    this.for_dom_obj = for_dom_obj;
    this.dom_obj = {};
    this.parent = parent;

    this.scroll_button = {};
    this.height = 0;

    if (options){
        if (options.height){
            this.height = options.height;
        }
    }

    this.init();
}

scrollbar.prototype.init = function(){
    _debug('scrollbar.init');

    this.dom_obj = create_block_element('mb_scroll', this.parent);

    var scroll_container = create_block_element('mb_scroll_t', this.dom_obj);

    scroll_container.style.height = this.height + 'px';

    this.scroll_button = create_block_element('mb_scroll_c', scroll_container);

    create_block_element('mb_scroll_b', this.dom_obj);
}

scrollbar.prototype.reset = function(){
    _debug('scrollbar.reset');

    this.scroll_button.style.top = 6 + 'px';
}

scrollbar.prototype.refresh = function(){
    _debug('scrollbar.refresh');

    //this.parent.scrollTop
    //this.parent.scrollHeight
    //this.parent.style.height
    var top = 6;
    var input_height = this.for_dom_obj.scrollHeight - parseInt(this.for_dom_obj.offsetHeight);

    _debug('this.for_dom_obj.scrollHeight', this.for_dom_obj.scrollHeight);
    _debug('this.for_dom_obj.offsetHeight', this.for_dom_obj.offsetHeight);
    _debug('input_height', input_height);
    _debug('this.height', this.height);
    _debug('this.parent.scrollTop', this.parent.scrollTop);

    if (input_height != 0){
        top = (this.for_dom_obj.scrollTop*(this.height - 32))/input_height + 6;
    }

    _debug('top', top);

    this.scroll_button.style.top = top + 'px';
}<commit_msg>"Add loader.next"<commit_after>/**
 * Scrollbar constructor.
 * @constructor
 */

function scrollbar(parent, for_dom_obj, options){

    this.for_dom_obj = for_dom_obj;
    this.dom_obj = {};
    this.parent = parent;

    this.scroll_button = {};
    this.height = 0;

    if (options){
        if (options.height){
            this.height = options.height;
        }
    }

    this.init();
}

scrollbar.prototype.init = function(){
    _debug('scrollbar.init');

    this.dom_obj = create_block_element('mb_scroll', this.parent);

    var scroll_container = create_block_element('mb_scroll_t', this.dom_obj);

    scroll_container.style.height = this.height + 'px';

    this.scroll_button = create_block_element('mb_scroll_c', scroll_container);

    create_block_element('mb_scroll_b', this.dom_obj);
}

scrollbar.prototype.reset = function(){
    _debug('scrollbar.reset');

    this.scroll_button.style.top = 6 + 'px';
}

scrollbar.prototype.refresh = function(){
    _debug('scrollbar.refresh');

    //this.parent.scrollTop
    //this.parent.scrollHeight
    //this.parent.style.height
    var top = 6;
    var input_height = this.for_dom_obj.scrollHeight - parseInt(this.for_dom_obj.offsetHeight);

    _debug('this.for_dom_obj.scrollHeight', this.for_dom_obj.scrollHeight);
    _debug('this.for_dom_obj.offsetHeight', this.for_dom_obj.offsetHeight);
    _debug('input_height', input_height);
    _debug('this.height', this.height);
    _debug('this.parent.scrollTop', this.parent.scrollTop);

    if (input_height != 0){
        top = (this.for_dom_obj.scrollTop*(this.height - 32))/input_height + 6;
    }

    _debug('top', top);

    this.scroll_button.style.top = top + 'px';
}

loader.next();<|endoftext|>