Массив объявлен как константа, все еще манипулируемая в JavaScript - PullRequest
0 голосов
/ 12 мая 2018

Итак, я построил утилиту круглого случайного выбора цвета в javascript и HTML5 Canvas, и все компоненты являются динамическими, размер объектов подстраивается под размер экрана, а расстояние также подстраивается под размер экрана.Кроме того, если пользователь изменяет размеры дисплея, утилита также динамически изменяет размеры.

Я использую массив для хранения цветов для кругов.Когда создаются круги, они используют первый цвет в массиве, удаляют этот цвет из массива, а затем перетасовывают массив.

Проблема заключается в том, что, когда пользователь изменяет размер дисплея, массиву цветов не хватаетЦвета остались нарисовать все круги, потому что код удаляет используемые цвета, чтобы не было дубликатов.Однако я попытался исправить это, объявив постоянный массив цветов с именем origColours и установив массив цветов, равный массиву origColours.

Ниже приведен кодЯ написал.Я не могу понять, как или почему манипулируют массивом origColours , надеюсь, вы поможете

:)

//########//SETUP
var canvas = document.getElementById("myCanvas");
var c = canvas.getContext("2d");

canvas.height = innerHeight;
canvas.width = innerWidth;

document.documentElement.style.overflow = 'hidden';  // firefox, chrome
document.body.scroll = "no"; // ie only


//########//COLORS
const origColours = ["#1c2133", "#2b6ea8", "#5d99bf", "#333968", "#000000", "#b000b0", "#0000aa", "#ff0000", "#00aaaa", "#7CFC00", "#00FF7F", "#8B0000", "#F0E68C"];
var colours = ["#1c2133", "#2b6ea8", "#5d99bf", "#333968", "#000000", "#b000b0", "#0000aa", "#ff0000", "#00aaaa", "#7CFC00", "#00FF7F", "#8B0000", "#F0E68C"];



//########//VARIABLES
var backgroundColour = 0;

var mouse = {
    x: undefined,
    y: undefined,
}; 

var key = {
    keyCode: undefined,
}

var mainRadius = 0;
var smallRadius = 0;

var pointerCircle;
var circles = [];



//########//EVENTS
window.addEventListener("mousemove", function(event) {
    mouse.x = event.x;
    mouse.y = event.y;
})

window.addEventListener("keypress", function(event) {
    key.keyCode = event.keyCode;
    if (key.keyCode == 32) {
        switchBg();
    }
})

window.addEventListener('resize', function(event) {
    canvas.width = innerWidth
    canvas.height = innerHeight

    setup();
})



//########//OBJECTS
function Circle(x, y, radius, colour) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    //this.n = Math.floor(Math.random()*colours.length);

    if (colour == undefined) {
        //this.fill = colours[this.n];
        this.fill = colours[0];
        this.orignalFill = this.fill;
        colours.shift();
        colours = shuffleArray(colours);
    } else {
        this.fill = colour;
        this.orignalFill = this.fill;
    } 


    this.draw = function() {
        c.fillStyle = this.fill;
        c.strokeStyle = this.colour;
        c.beginPath();
        c.arc(this.x,this.y,this.radius,0,Math.PI*2);
        c.fill();
    }

    this.update = function() {

        //Bounce off the edges
//        if (this.x + this.radius > innerWidth || this.x - this.radius < 0) {
//            this.dx = -this.dx;
//        }
//        if (this.y + this.radius > innerHeight || this.y - this.radius < 0) {
//            this.dy = -this.dy;
//        }

        //Move circle
//        this.x += this.dx;
//        this.y += this.dy;



        //Draw the circle after all calculations have been made
        this.draw();

    }
}



//########//UTILITY FUNCTIONS
function shuffleArray(arr) {
    var j, x, i;
    for (i = arr.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        x = arr[i];
        arr[i] = arr[j];
        arr[j] = x;
    }
    return arr;
}

function checkCollisions(obj1, objs) {
    for (var i = 0; i < objs.length; i++) {
        if (checkCollision(obj1, objs[i])) {
            return objs[i]
        }
    }

}
function renderCircles(arr) {
    for (var i = 0; i < arr.length; i++) {
        arr[i].update();
    }
}

function checkCollision(object1, object2) {
    var obj_s = getDistance(object1.x, object1.y, object2.x, object2.y);

    if (obj_s < object1.radius + object2.radius) {
        return true;
    } else {
        return false;
    }
}

function getDistance(x1, y1, x2, y2) {
    xs = x2 - x1;
    ys = y2 - y1;

    return Math.sqrt(Math.pow(xs, 2) + Math.pow(ys, 2));
}

function switchBg() {
    if (backgroundColour == 0) {
        document.body.style.backgroundColor = "black"
        backgroundColour = 1
    } else if (backgroundColour == 1) {
        document.body.style.backgroundColor = "white"
        backgroundColour = 0
    }
}



//########//ANIMATION
function animate() {
    requestAnimationFrame(animate);
    c.clearRect(0,0,innerWidth,innerHeight);

    pointerCircle.x = mouse.x;
    pointerCircle.y = mouse.y;

    var result = checkCollisions(pointerCircle, circles);

    if (result != undefined) {
        circles[0].fill = result.fill;
    } else {
        circles[0].fill = circles[0].orignalFill;
    }

    pointerCircle.update();
    renderCircles(circles);

}

//########//RUNNING CODE


function setup() {
    if (innerHeight >= innerWidth) {
        mainRadius = innerWidth/6;
    } else {
        mainRadius = innerHeight/6;
    }

    smallRadius = mainRadius/2;

    c.clearRect(0,0,innerWidth,innerHeight);

    circles = [];
    colours = origColours

    pointerCircle = new Circle(0,0,1, "rgba(0,0,0,0)");
    circles.push(new Circle(innerWidth/2, innerHeight/2, mainRadius, "white"));

    circles.push(new Circle((innerWidth/2)-mainRadius*2, innerHeight/2, smallRadius));
    circles.push(new Circle((innerWidth/2)+mainRadius*2, innerHeight/2, smallRadius));
    circles.push(new Circle((innerWidth/2), (innerHeight/2)-mainRadius*2, smallRadius));
    circles.push(new Circle((innerWidth/2), (innerHeight/2)+mainRadius*2, smallRadius));

    var angCoE = mainRadius / 2 * 3;

    circles.push(new Circle((innerWidth/2)+angCoE, (innerHeight/2)-angCoE, smallRadius));
    circles.push(new Circle((innerWidth/2)+angCoE, (innerHeight/2)+angCoE, smallRadius));
    circles.push(new Circle((innerWidth/2)-angCoE, (innerHeight/2)-angCoE, smallRadius));
    circles.push(new Circle((innerWidth/2)-angCoE, (innerHeight/2)+angCoE, smallRadius));

}

setup();
animate();

Ответы [ 4 ]

0 голосов
/ 12 мая 2018

Примечание: так что я был немного поспешным и недостаточно внимательно прочитал ваш вопрос.Реальное решение было опубликовано Hey24sheep и pooyan ниже - я оставляю это здесь, чтобы объяснить другой аспект вопроса.

Объявление переменной как const означает, что вы не можете изменить ее значение.Если рассматриваемая переменная содержит ссылку на объект (например, массив), это означает, что вы не можете заставить переменную ссылаться на другой объект.

Например, если вы попытались это сделать:

const colors = [ 'red', 'green', 'blue' ];
colors = [ 'yellow', 'cyan', 'magenta' ];

Это не получится, потому что вы пытаетесь изменить то, к чему относится colors.Однако сам массив является отдельной сущностью от вашей переменной, и его свойства по-прежнему свободны для манипулирования.

В данном случае вы ищете Object.freeze():

const colors = Object.freeze([ 'red', 'green', 'blue' ]);

Теперь вы обнаружите, что не можете добавлять, удалять или изменять какие-либо элементы массива.И, поскольку вы удалили его с помощью const, вы также не можете переназначить переменную colors.

Дополнительная информация:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

0 голосов
/ 12 мая 2018

Вы должны клонировать свой массив вместо colours = origColours. Один из способов клонировать ваш массив - это colours = origColours.slice(0);, иначе при изменении массива colours будет действовать и ваш origColours.

0 голосов
/ 12 мая 2018

вы можете сделать копию массива, и исходный массив останется нетронутым, так как вы можете скопировать массив несколькими способами

colours = origColours.slice();

или если вы используете es7 polyfills

colours = [...origColours]

const означает, что вы не можете изменить назначение, но вы можете изменить внутреннюю часть присвоения

//you can do this
const a = [1, 2]; // [1]
a.pop()
console.log(a)

// but you cant do this
const i = 5;
i = 4; // erro
0 голосов
/ 12 мая 2018

В JavaScript объекты передаются и присваиваются по ссылке (точнее, по значению ссылки), поэтому цвета являются ссылкой на один и тот же объект.

Потому что вы делаете это в функции настройки.

colours = origColours

Вам нужно создать копию, если вам нужно изменить одну, а не другую. По сути, операция slice () клонирует массив и возвращает ссылку на новый массив

.
colours = origColours.slice();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...