Градиентный штрих вдоль дуги холста исчезает, когда контекст перемещается в центр

Я очень новичок в рисовании на холсте. Я пытаюсь применить градиент по дуге окружности. Я могу заставить его выглядеть нормально, когда я рисую дугу со смещением центра от координат контекста. Допустим, centerX и centerY обозначают центр холста. Я могу получить дугу градиента, используя context.arc(centerX, centerY, radius, ......).

Working example: http://jsfiddle.net/m5Pmb/

Но когда я пытаюсь нарисовать дугу вокруг координат контекста, градиент исчезает. Например, я беру приведенный выше рабочий пример jsfiddle, делаю context.translate(centerX, centerY), затем делаю context.arc(0,0,radius,......), на полученной дуге нет никакого градиента.

Example here: http://jsfiddle.net/N6NMB/

В моем случае мне нужно повернуть полученный круг вокруг своей оси, используя context.rotate(), поэтому я должен перевести его в центр и нарисовать круг вокруг (0,0). Но я не могу понять, почему градиент исчезает при попытке нарисовать дугу вокруг точки контекста (0,0). Любое понимание было бы действительно полезно.


person elto    schedule 08.07.2014    source источник


Ответы (2)


Поскольку вы переводите контекст, centerX и centerY больше не совпадают с вашими мыслями.

Когда вы переводите контекст, вы говорите, что хотите, чтобы x и y были новыми 0,0. Итак, теперь ваш 0,0 находится в центре холста, поэтому centerX и centerY смещаются сами по себе, удаляя их от центра.

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

var grad = context.createLinearGradient(
    -radius,
    radius / 2,
    radius,
    radius / 2
);

демонстрация

Вышеприведенное работает, потому что оно вызывается после перевода контекста, поэтому centerX и centerY (как я уже говорил ранее) равны 0,0, что означает, что на них не нужно ссылаться в этой функции.

person Loktar    schedule 08.07.2014

Градиенты, которые вы создаете, будут окрашены фактически используемым преобразованием.

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

Если вы используете преобразование, вы должны думать о координатах градиента относительно точки/угла/масштаба, когда вы будете их использовать.

Чтобы объяснить далее, я изменил ваш пример и использовал радиальный градиент.
Я создал нормализованный градиент: он определен в диапазоне от 0,0 до 1,0 радиуса, что означает, что его x и y будут в [-1; 1].

var eyeGrad = context.createRadialGradient(0, 0, 0, 0, 0, 1.0);

Затем, чтобы использовать градиент, я должен:
1) перевести в центр фигуры, которую я хочу нарисовать.
2) масштабировать, чтобы иметь нормализованные координаты.

function drawEye(x, y, r) {
    context.save();
    //translate context to center
    context.translate(x, y);
    // scale to radius
    context.scale(r, r);
    context.beginPath();
    // draw an arc with radius of 1
    context.arc(0, 0, 1, 0, 2 * Math.PI, false);
    context.fillStyle = eyeGrad;
    context.fill();
    context.restore();
}

скрипка здесь:

   http://jsfiddle.net/gamealchemist/N6NMB/3/

Результат для:

drawEye(100, 100, 40);
drawEye(250, 120, 20);

введите здесь описание изображения

person GameAlchemist    schedule 09.07.2014
comment
Можете ли вы объяснить, почему вы использовали шкалу? Я попытался удалить масштаб и использовать радиус при рисовании дуги, например. context.arc(0,0,r,2*Math.PI,false). Но все, что он нарисовал, это круг радиусом 1 пиксель. Почему он рисует такой маленький круг, несмотря на большое значение радиуса? - person elto; 10.07.2014
comment
идея состоит в том, чтобы использовать ту же систему координат, что и градиент. Итак, сначала нужно центрировать, а затем масштабировать, чтобы использовать нормализованные ([0,1]) координаты. - person GameAlchemist; 10.07.2014
comment
ах, черт возьми, мне придется улучшить свою игру во всех моих новых ответах, @GameAlchemist включает скриншоты и более продуманный код: P +1 - person Loktar; 10.07.2014
comment
Спасибо, что так хорошо объяснили. +1 - person elto; 11.07.2014