Масштабирование точки X Y на холсте HTML5 в процентах

#javascript #animation #trigonometry

#javascript #Анимация #тригонометрия

Вопрос:

Я работаю над своим первым проектом canvas, и для этого требуется частичная карта США с масштабированием и центром по состоянию при нажатии.

Мне удалось найти массивы точек X Y для рисования страны, причем каждое государство является собственным массивом. Мне нужно было, чтобы состояния были вытянуты больше, чем эти размеры, поэтому я ввел переменную шкалу для умножения каждой точки.

Моя следующая проблема заключалась в том, что клиент хотел, чтобы было выделено только 13 состояний, но не размещалось для масштабирования друг против друга. (Например, поместите Огайо и Иллинойс рядом друг с другом на холсте и игнорируйте Индиану). Мое решение состояло в том, чтобы ввести фиксированную «константу» X, Y для каждого состояния, чтобы после масштабирования добавить значение X Y для этого состояния и сделать его местом для рисования.

 for ( var j = 0; j < state.myPolygons.length;   j) {
    context.beginPath();
    context.lineWidth = lineWidth;
    context.strokeStyle = stateStroke;
    context.fillStyle = stateFill;
    for ( var k = 0; k < state.myPolygons[j].myXVals.length;   k ) {
        var x = parseFloat(state.myPolygons[j].myXVals[k]*state.scale) state.posX;
        var y = parseFloat(state.myPolygons[j].myYVals[k]*state.scale) state.posY;
        y = canvas.height - y;
        if ( k == 0 ) 
            context.moveTo(x,y);
        else 
            context.lineTo(x,y);
    }
    context.closePath();
    context.fill();
    context.stroke();
}
  

Эффект нажатия на состояние, его увеличения и центрирования на холсте был достигнут путем определения целевого масштаба и количества шагов. Я получаю разницу между целевым масштабом и текущим масштабом и делю это на количество шагов, чтобы выяснить, сколько нужно добавить к масштабу состояния в каждом «кадре».
Пример: начальный масштаб Огайо равен 1,97 от найденных координат. Моя цель для шкалы Огайо — 3,75%. Я получаю разницу (1,78) и делю ее на 45 (определенный набор шагов) для рисования. Это дает мне 0,039 в качестве приращения к моему масштабу в каждом кадре. Затем я выполняю цикл, пока текущий масштаб моих состояний меньше целевого масштаба. Однако, опять же, поскольку мне нужно манипулировать Xy рендеринга, у меня есть константа zoomx и zoomy для каждого состояния, которое добавляется к вычисленному Xy, чтобы оно могло «скользить» к центру холста.

Все это работает отлично, и у меня есть калифорнийский масштаб / сдвиг слева направо, Огайо сдвиг справа налево и т.д. — Вот моя проблема.

У меня есть ряд точек для обозначения местоположения клиента в состоянии. Это простые Xy, на которых я рисую круг. Начальный рендеринг карты включает в себя цикл для выполнения через каждый набор состояний местоположений. Я применяю тот же масштабный коэффициент и переменные PosX, posY для настройки окончательного размещения точки по отношению к окончательному отображению состояния

 for (var loc in state.Locations) {
    var locx = parseFloat(state.Locations[loc].x*state.scale) state.posX
    var locy =parseFloat(state.Locations[loc].y*state.scale) state.posY;
    var txt=state.Locations[loc].text;
    var lnk=state.Locations[loc].link;
    context.beginPath();
    context.arc(locx,locy,locationSize,0,Math.PI*2,true);
    context.fillStyle = locationFill;
    context.closePath();
    context.fill();
    context.stroke();                           
}
  

Однако, когда состояние масштабируется, логика масштабирования для точек завершается сбоем. Применяется масштаб состояния для данного фрейма

 x = parseFloat(activeState.myPolygons[j].myXVals[k]*activeState.scale) activeState.posX;
y = parseFloat(activeState.myPolygons[j].myYVals[k]*activeState.scale) activeState.posY;
  

Когда я применяю это к заданному местоположению в состоянии с

 locx = parseFloat(activeState.Locations[loc].x*activeState.scale) activeState.posX;
locy = parseFloat(activeState.Locations[loc].y*activeState.scale) activeState.posY;
  

В итоге X следует довольно точно, но в примере с Огайо Y находится где-то рядом с Флоридой. В других штатах, таких как Калифорния, дела обстоят еще хуже, поскольку их точки начинают более «укладываться» друг на друга и в конечном итоге оказываются более «разбросанными» рядом друг с другом.

Я пытаюсь определить тригонометрические функции, необходимые для увеличения и уменьшения положения X Y в местоположении по отношению к текущему масштабу состояния, и сохранить его на том же пути, по которому состояние проходит через анимацию (как увеличение, так и уменьшение масштаба).

Моей последней попыткой перед тем, как прийти сюда, было получить начальный Xy местоположения и сравнить его расстояние с ПОСЛЕДНИМ Xy массива состояний. Затем я пытался найти угол линии, соединяющей эти 2 точки, а затем использовать все это для масштабирования. Я все еще чувствую, что могу быть на что-то с этим подходом, я просто не могу этого добиться.

Спасибо всем, что нашли время, чтобы прочитать это, я ценю любую помощь, которую вы можете предложить

Комментарии:

1. Вы вообще рассматривали возможность использования SVG для этого? Все это масштабирование и анимация встроены в SVG.

2. Спасибо, к сожалению, в этом проекте эти функции были расширены, и я слишком далеко продвинулся по этому пути, чтобы повернуть назад. Первоначально он должен был нарисовать состояние «маленький», а затем «большой» — анимация была введена где-то в середине этой цели. Я выбрал canvas для первоначальной цели как возможность получить опыт работы с ним, и теперь я сталкиваюсь с ГОРАЗДО большим опытом, чем предполагал 🙂

Ответ №1:

Вы могли бы просто взглянуть на бумагу, которую я положил на ваш стол, на ту, на которой написано уравнение. Однако SVGS был бы более оптимальным для проекта, поскольку вы могли бы легко группировать объекты вместе, используя тег g, а затем просто масштабировать всю группу.

Однако, поскольку на этом этапе вы вынуждены использовать canvas: вам придется масштабировать director вверх и вниз, используя тригонометрию, учитывая угол начальной точки до точки местоположения и РАЗНИЦУ пройденного влево или вправо от исходного расстояния. Я объясню более подробно, с реальными уравнениями, когда вы позволите мне вернуть мне эту бумагу. Однако единственная строка, которую вам действительно нужно изменить на этом этапе, это:

 locy = parseFloat(activeState.Locations[loc].y*activeState.scale) activeState.posY;