Raphael.path2curve не поддерживает первоначальный путь
У меня проблема с Raphael.path2curve(). Функция изменяет строку пути SVG, так что все команды пути преобразуются в абсолютные кубические кривые (C). Функция поддерживает все команды пути (mlcqahvstMLCQAHVST
см. SVG SPEC).
Raphael.path2curve() может обрабатывать пути скважин во многих случаях, например. Он может даже правильно преобразовать дуги в кубики, что не является простым вычислением. Я сделал много тестов и понял, что пути, которые состоят из команд QT
, CS
или же HT
хорошо конвертирует Нет проблем и со следующим:MS, HS, VS, LS, TC, TH, TL, TV, QA, TA
,
Но он не может обрабатывать команды QS, TS, AS, TT
(в этой последовательности).
Если мы, например. Иметь такой путь, преобразование не удается:
M 0 0 T 205.4 112.9 S 260.8 23.36 82.45 72.86
Но это преобразует правильно:
M 0 0 S 211.9 54.20 52.14 144.4 T 98.85 44.45
Итак, МТС не в порядке, но MST в порядке. Проблемными являются S и T, потому что они всегда под вопросом, когда что-то не получается.
Я создал генератор случайных путей (медленно, но для скорости использую jsbin), где вы можете получить случайный путь и преобразовать его в кубические команды, используя Raphael.path2curve(). В скрипте щелкните SVG или нажмите ввод в поле ввода, чтобы получить новый случайный путь. Повторяйте, пока не найдете неправильный. В jsfiddle в окне HTML есть параметр var list = "st";
где вы можете установить команды пути для рандомизации.
Это пример изображения. Синий - это исходный путь, а красный - преобразованный путь. Они должны быть идентичны.
Что я должен сделать с кодом Рафаэля, чтобы получить правильное преобразование?
(Я сделал сообщение об ошибке, но теперь пытался решить проблему несколько часов без удачи.
1 ответ
Кажется, я наконец-то все исправил. Пожалуйста, проверьте! Я сделал две версии JSBIN:
1) НЕ ФИКСИРОВАННАЯ версия, которая использует неизмененный Raphael lib: http://jsbin.com/oqojan/33.
2) ИСПРАВЛЕННАЯ версия, в которой модифицирована функция path2curve(): http://jsbin.com/oqojan/32.
В обеих версиях есть черный (оригинал) и белый (нормализованный) путь. Если все работает хорошо, вы не должны видеть белый путь ниже черного пути. Если вы видите белый путь, в коде lib есть ошибка (см. Ниже объяснение небольшого мерцания).
Пожалуйста, удерживайте кнопку ENTER в поле ввода около минуты. Код генерирует случайные пути многократно, пока ENTER не работает. Изменить атрибут var list = "mlcqahvstz";
изменить базовые буквы для рандомизации.
И вот объяснение того, что я должен был сделать с кодом lib. В оригинальном lib-коде Raphaël 2.1.0 есть функция path2curve(), которая имеет следующие строки:
case "S":
nx = d.x + (d.x - (d.bx || d.x));
ny = d.y + (d.y - (d.by || d.y));
path = ["C", nx, ny][concat](path.slice(1));
break;
case "T":
d.qx = d.x + (d.x - (d.qx || d.x));
d.qy = d.y + (d.y - (d.qy || d.y));
path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
break;
Когда я изменил их на:
case "S":
if (pcom == "C" || pcom == "S") { // In "S" case we have to take into
// account, if the previous command
// is C/S.
nx = d.x * 2 - d.bx; // And reflect the previous
ny = d.y * 2 - d.by; // command's control point relative
// to the current point.
}
else { // or some else or nothing
nx = d.x;
ny = d.y;
}
path = ["C", nx, ny][concat](path.slice(1));
break;
case "T":
if (pcom == "Q" || pcom == "T") { // In "T" case we have to take
// into account, if the
// previous command is Q/T.
d.qx = d.x * 2 - d.qx; // And make a reflection similar
d.qy = d.y * 2 - d.qy; // to case "S".
}
else { // or something else or nothing
d.qx = d.x;
d.qy = d.y;
}
path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
break;
функция работала как ожидалось (т.е. учитывает исходную форму пути при каждой возможной комбинации команд пути). pcom
Переменная относится к предыдущему сегменту ОРИГИНАЛЬНОГО пути, и мне пришлось также добавить способ получить pcom
, что было довольно легко, потому что в отношении всех других команд пути, кроме A, преобразование из исходного типа сегмента пути в кубическую кривую (C) дает только одну кубическую команду. В случае A функция может выдавать более одной команды C (короткие углы дают один или несколько сегментов C, а большие углы дают больше).
Единственное незначительное несоответствие исходит от команд Z, потому что Raphaël конвертирует каждый Z в C. Это влияет на визуальное отображение начала (или конца) пути, но разница невелика. Я предполагаю, что он конвертирует Z в C, чтобы сделать пути анимируемыми. Если анимация не нужна, то вы можете отредактировать функцию, чтобы оставить Z:s неконвертированным, и в этом случае точность преобразования будет превосходной.
Я поражен, что все команды пути могут быть представлены в виде кубических кривых так надежно!
Я надеюсь, что эта ошибка будет исправлена в будущем выпуске Raphaël.
РЕДАКТИРОВАТЬ: Сделал испытательный стенд также для анимации пути:
1) НЕ УСТАНОВЛЕНО: http://jsbin.com/oqojan/44
2) ИСПРАВЛЕНО: http://jsbin.com/oqojan/42
После тщательного тестирования с неанимированными и анимированными путями я могу подтвердить, что мое исправление функции path2curve стабильно и может быть реализовано в рабочем коде. Если вы хотите быть уверены, пожалуйста, используйте вышеупомянутые испытательные стенды.