<commit_before>//
//  Place.js
//  -----------
//  Written by AppleBetas and nullpixel. Inspired by Reddit's /r/place.
//

const size = 1000;

var createCanvasController = function(canvas) {
    let ctx = canvas.getContext("2d");
    // Disable image smoothing
    ctx.mozImageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.msImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;
    
    return {
        canvas: canvas,
        ctx: ctx,
        isDisplayDirty: false,

        clearCanvas: function() {
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.isDisplayDirty = true;
        },

        drawImage: function(image) {
            this.ctx.drawImage(image, 0, 0, size, size);
            this.isDisplayDirty = true;
        },

        setPixel: function(colour, x, y) {
            this.ctx.fillStyle = colour;
            this.ctx.fillRect(x, y, 1, 1);
            this.isDisplayDirty = true;
        }
    }
}

var place = {
    zooming: {
        zoomedIn: false,
        zooming: false,
        zoomFrom: 0,
        zoomTo: 0,
        zoomTime: 0,
        zoomHandle: null
    },
    socket: null,
    zoomButton: null,
    dragStart: null,
    isMouseDown: false, shouldClick: true,
    panX: 0, panY: 0,
    DEFAULT_COLOURS: ["#FFFFFF", "#E4E4E4", "#888888", "#222222", "#FFA7D1", "#E50000", "#E59500", "#A06A42", "#E5D900", "#94E044", "#02BE01", "#00D3DD", "#0083C7", "#0000EA", "#CF6EE4", "#820080"],
    selectedColour: null, handElement: null, unlockTime: null, secondTimer: null,

    start: function(canvas, zoomController, cameraController, displayCanvas, colourPaletteElement) {
        this.canvas = canvas;
        this.canvasController = createCanvasController(canvas);
        this.displayCanvas = displayCanvas;
        this.setupDisplayCanvas(this.displayCanvas);

        this.colourPaletteElement = colourPaletteElement;
        this.setupColours();
        this.placingOverlay = $(this.colourPaletteElement).children("#placing-modal");
        this.placeTimer = $(this.colourPaletteElement).children("#place-timer");
        let app = this;
        $(this.colourPaletteElement).on("click", ".colour-option", function() {
            let colourID = parseInt($(this).data("colour"));
            if(colourID) app.selectColour(colourID);
        });
        $(this.colourPaletteElement).click(function(e) {
            if(e.target !== this) return;
            app.deselectColour();
        })
        this.updatePlaceTimer();

        let controller = $(zoomController).parent()[0];
        controller.onmousedown = (event) => this.handleMouseDown(event || window.event);
        controller.onmouseup = (event) => this.handleMouseUp(event || window.event);
        controller.onmouseout = (event) => { this.shouldClick = false; this.handleMouseUp(event || window.event) };
        controller.onmousemove = (event) => {
            if (this.isMouseDown) this.handleMouseDrag(event || window.event);
            this.handleMouseMove(event || window.event);
        }
        controller.addEventListener("touchstart", (event) => this.handleMouseDown(event.changedTouches[0]));
        controller.addEventListener("touchmove", (event) => { event.preventDefault(); if (this.isMouseDown) this.handleMouseDrag(event.changedTouches[0]); });
        controller.addEventListener("touchend", (event) => this.handleMouseUp(event.changedTouches[0]));
        controller.addEventListener("touchcancel", (event) => this.handleMouseUp(event.changedTouches[0]));

        window.onresize = () => this.handleResize();

        this.zoomController = zoomController;
        this.cameraController = cameraController;

        this.loadImage().then((image) => {
            this.canvasController.clearCanvas();
            this.canvasController.drawImage(image);
            this.updateDisplayCanvas();
            this.displayCtx.imageSmoothingEnabled = false;
        });

        this.socket = this.startSocketConnection()
    },

    startSocketConnection() {
        var socket = io();
        socket.on('error', function(e) {
            console.log('socket error: ' + e)
        })

        socket.on('connect', function() {
            console.log("socket successfully connected")
        })

        socket.on('tile_placed', this.liveUpdateTile.bind(this))
    },

    liveUpdateTile: function (data) {
        this.canvasController.setPixel(`rgb(${data.colour.r}, ${data.colour.g}, ${data.colour.b})`, data.x, data.y)
        this.updateDisplayCanvas();
    },

    setupColours: function() {
        $(this.colourPaletteElement).remove(".colour-option");
        this.colourPaletteOptionElements = [];
        this.DEFAULT_COLOURS.forEach((colour, index) => {
            let elem = $("<div class=\"colour-option" + (colour.toLowerCase() == "#ffffff" ? " is-white" : "") + "\" style=\"background-color: " + colour + ";\" data-colour=\"" + (index + 1) + "\"></div>").appendTo(this.colourPaletteElement)[0];
            this.colourPaletteOptionElements.push(elem);
        });
    },

    handleResize: function() {
        this.displayCanvas.height = window.innerHeight;
        this.displayCanvas.width = window.innerWidth;
        this.displayCtx.mozImageSmoothingEnabled = false;
        this.displayCtx.webkitImageSmoothingEnabled = false;
        this.displayCtx.msImageSmoothingEnabled = false;
        this.displayCtx.imageSmoothingEnabled = false;
        this.updateDisplayCanvas();
    },

    setupDisplayCanvas: function(canvas) {
        this.displayCtx = canvas.getContext("2d");
        this.handleResize();
        this.updateDisplayCanvas();
    },

    updateDisplayCanvas: function() {
        let dcanvas = this.displayCanvas;
        this.displayCtx.clearRect(0, 0, dcanvas.width, dcanvas.height);
        let zoom = this._getCurrentZoom();
        let mod = size / 2;
        this.displayCtx.drawImage(this.canvas, dcanvas.width / 2 + (this.panX - mod - 0.5) * zoom, dcanvas.height / 2 + (this.panY - mod - 0.5) * zoom, this.canvas.width * zoom, this.canvas.height * zoom);
    },

    _zoomLerp: function(from, to, time) {
        return from + time * (to - from)
    },

    _getCurrentZoom: function() {
        if (!this.zooming.zooming) return this._getZoomMultiplier()

        return this._zoomLerp(this.zooming.zoomFrom, this.zooming.zoomTo, this.zooming.zoomTime)
    },

    _getZoomMultiplier: function() {
        return this.zooming.zoomedIn ? 40 : 4;
    },

    loadImage: function() {
        return new Promise((resolve, reject) => {
            image = new Image();
            image.src = "/api/board-image";
            image.onload = () => {
                resolve(image);
            };
        });
    },

    animateZoom: function() {
        this.updateDisplayCanvas()
        this.zooming.zoomTime += 0.05

        if (this.zooming.zoomTime >= 1) {
            this.zooming.zooming = false
            clearInterval(this.zooming.zoomHandle)
            return
        }
    },

    setZoomedIn: function(zoomedIn) {
        this.zooming.zoomFrom = this._getCurrentZoom()<commit_msg>Fix zoom bug, start random spawn<commit_after>//
//  Place.js
//  -----------
//  Written by AppleBetas and nullpixel. Inspired by Reddit's /r/place.
//

const size = 1000;

var createCanvasController = function(canvas) {
    let ctx = canvas.getContext("2d");
    // Disable image smoothing
    ctx.mozImageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.msImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;
    
    return {
        canvas: canvas,
        ctx: ctx,
        isDisplayDirty: false,

        clearCanvas: function() {
            this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
            this.isDisplayDirty = true;
        },

        drawImage: function(image) {
            this.ctx.drawImage(image, 0, 0, size, size);
            this.isDisplayDirty = true;
        },

        setPixel: function(colour, x, y) {
            this.ctx.fillStyle = colour;
            this.ctx.fillRect(x, y, 1, 1);
            this.isDisplayDirty = true;
        }
    }
}

var place = {
    zooming: {
        zoomedIn: false,
        zooming: false,
        zoomFrom: 0,
        zoomTo: 0,
        zoomTime: 0,
        zoomHandle: null
    },
    socket: null,
    zoomButton: null,
    dragStart: null,
    isMouseDown: false, shouldClick: true,
    panX: 0, panY: 0,
    DEFAULT_COLOURS: ["#FFFFFF", "#E4E4E4", "#888888", "#222222", "#FFA7D1", "#E50000", "#E59500", "#A06A42", "#E5D900", "#94E044", "#02BE01", "#00D3DD", "#0083C7", "#0000EA", "#CF6EE4", "#820080"],
    selectedColour: null, handElement: null, unlockTime: null, secondTimer: null,

    start: function(canvas, zoomController, cameraController, displayCanvas, colourPaletteElement) {
        this.canvas = canvas;
        this.canvasController = createCanvasController(canvas);
        this.displayCanvas = displayCanvas;
        this.setupDisplayCanvas(this.displayCanvas);

        this.colourPaletteElement = colourPaletteElement;
        this.setupColours();
        this.placingOverlay = $(this.colourPaletteElement).children("#placing-modal");
        this.placeTimer = $(this.colourPaletteElement).children("#place-timer");
        let app = this;
        $(this.colourPaletteElement).on("click", ".colour-option", function() {
            let colourID = parseInt($(this).data("colour"));
            if(colourID) app.selectColour(colourID);
        });
        $(this.colourPaletteElement).click(function(e) {
            if(e.target !== this) return;
            app.deselectColour();
        })
        this.updatePlaceTimer();

        let controller = $(zoomController).parent()[0];
        controller.onmousedown = (event) => this.handleMouseDown(event || window.event);
        controller.onmouseup = (event) => this.handleMouseUp(event || window.event);
        controller.onmouseout = (event) => { this.shouldClick = false; this.handleMouseUp(event || window.event) };
        controller.onmousemove = (event) => {
            if (this.isMouseDown) this.handleMouseDrag(event || window.event);
            this.handleMouseMove(event || window.event);
        }
        controller.addEventListener("touchstart", (event) => this.handleMouseDown(event.changedTouches[0]));
        controller.addEventListener("touchmove", (event) => { event.preventDefault(); if (this.isMouseDown) this.handleMouseDrag(event.changedTouches[0]); });
        controller.addEventListener("touchend", (event) => this.handleMouseUp(event.changedTouches[0]));
        controller.addEventListener("touchcancel", (event) => this.handleMouseUp(event.changedTouches[0]));

        window.onresize = () => this.handleResize();

        this.zoomController = zoomController;
        this.cameraController = cameraController;

        this.loadImage().then((image) => {
            this.canvasController.clearCanvas();
            this.canvasController.drawImage(image);
            this.updateDisplayCanvas();
            this.displayCtx.imageSmoothingEnabled = false;
        });

        this.socket = this.startSocketConnection()
    },

    startSocketConnection() {
        var socket = io();
        socket.on('error', function(e) {
            console.log('socket error: ' + e)
        })

        socket.on('connect', function() {
            console.log("socket successfully connected")
        })

        socket.on('tile_placed', this.liveUpdateTile.bind(this))
    },

    getRandomSpawnPoint: function() {
        function getRandomTileNumber() {
            return Math.random() * (size - 1);
        }
        return {x: getRandomTileNumber(), y: getRandomTileNumber()};
    },

    liveUpdateTile: function (data) {
        this.canvasController.setPixel(`rgb(${data.colour.r}, ${data.colour.g}, ${data.colour.b})`, data.x, data.y)
        this.updateDisplayCanvas();
    },

    setupColours: function() {
        $(this.colourPaletteElement).remove(".colour-option");
        this.colourPaletteOptionElements = [];
        this.DEFAULT_COLOURS.forEach((colour, index) => {
            let elem = $("<div class=\"colour-option" + (colour.toLowerCase() == "#ffffff" ? " is-white" : "") + "\" style=\"background-color: " + colour + ";\" data-colour=\"" + (index + 1) + "\"></div>").appendTo(this.colourPaletteElement)[0];
            this.colourPaletteOptionElements.push(elem);
        });
    },

    handleResize: function() {
        this.displayCanvas.height = window.innerHeight;
        this.displayCanvas.width = window.innerWidth;
        this.displayCtx.mozImageSmoothingEnabled = false;
        this.displayCtx.webkitImageSmoothingEnabled = false;
        this.displayCtx.msImageSmoothingEnabled = false;
        this.displayCtx.imageSmoothingEnabled = false;
        this.updateDisplayCanvas();
    },

    setupDisplayCanvas: function(canvas) {
        this.displayCtx = canvas.getContext("2d");
        this.handleResize();
        this.updateDisplayCanvas();
    },

    updateDisplayCanvas: function() {
        let dcanvas = this.displayCanvas;
        this.displayCtx.clearRect(0, 0, dcanvas.width, dcanvas.height);
        let zoom = this._getCurrentZoom();
        let mod = size / 2;
        this.displayCtx.drawImage(this.canvas, dcanvas.width / 2 + (this.panX - mod - 0.5) * zoom, dcanvas.height / 2 + (this.panY - mod - 0.5) * zoom, this.canvas.width * zoom, this.canvas.height * zoom);
    },

    _zoomLerp: function(from, to, time) {
        return from + time * (to - from)
    },

    _getCurrentZoom: function() {
        if (!this.zooming.zooming) return this._getZoomMultiplier()

        return this._zoomLerp(this.zooming.zoomFrom, this.zooming.zoomTo, this.zooming.zoomTime)
    },

    _getZoomMultiplier: function() {
        return this.zooming.zoomedIn ? 40 : 4;
    },

    loadImage: function() {
        return new Promise((resolve, reject) => {
            image = new Image();
            image.src = "/api/board-image";
            image.onload = () => {
                resolve(image);
            };
        });
    },

    animateZoom: function() {
        this.zooming.zoomTime += 0.05
        this.updateDisplayCanvas()

        if (this.zooming.zoomTime >= 1) {
            this.zooming.zooming = false
            clearInterval(this.zooming.zoomHandle)
            return
        }
    },

    setZoomedIn: function(zoomedIn) {
        this.zooming.zoomFrom = this._getCurrentZoom()
{'fraction_non_alphanumeric': 0.14223722275795564, 'fraction_numerical': 0.014395922303347568, 'mean_word_length': 2.5690757128810224, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1830524', 'n_tokens_mistral': 4419, 'n_tokens_neox': 4219, 'n_words': 747}