Идеи для рендеринга HTML * в формах Raphael (SVG/VML)
Я работаю над приложением, которое использует Raphael для рисования примитивных фигур (прямоугольников, эллипсов, треугольников и т.д.) и линий, но позволяет пользователь может перемещать/изменять размер этих объектов. Одним из основных требований является то, что лицо форм может иметь форматированный текст. Фактический текст - это подмножество Markdown (простые вещи, такие как жирный шрифт, курсив, списки) и отображается как HTML.
FWIW - Я использую Backbone.js для модуляции логики формы.
Подход 1
Моя первоначальная мысль заключалась в использовании комбинации foreignObject
для SVG и прямого HTML с VML для IE. Однако IE9 не поддерживает foreignObject
, и поэтому этот подход пришлось отказаться.
Подход 2
Рядом с объектом canvas добавьте div
, который содержит фактический HTML. Затем поместите их поверх фактической фигуры с прозрачным фоном. Я создал представление формы, которое имеет ссылки как на фактическую форму Рафаэля, так и на "наложение" div
. Существует несколько проблем с этим подходом:
-
Использование оверлей, которые не являются дочерними элементами контейнера SVG/VML, кажется неправильным. Имеет ли этот элемент оверлея другие проблемы при рендеринге по дороге?
-
События, которые обычно захватываются Рафаэлем (перетаскивание, клик и т.д.), необходимо перенаправить из оверлея в объект Рафаэля. Для браузеров, поддерживающих pointer-events
, это легко сделать:
div.shape-text-overlay {
position: absolute;
background: none;
pointer-events: none;
}
Однако другие браузеры (например, IE8 и ниже) нуждаются в пересылке событий:
var forwardedEvents = 'mousemove mousedown mouseup click dblclick mouseover mouseout';
this.$elText.on(forwardedEvents, function(e) {
var original = e.originalEvent;
var event;
if (document.createEvent) {
event = document.createEvent('HTMLEvents');
event.initEvent(e.type, true, true);
}
else {
event = document.createEventObject();
event.eventType = e.type;
}
// FYI - This is the most simplistic approach to event forwarding.
// My real implementation is much larger and uses MouseEvents and UIEvents separately.
event.eventName = e.type;
_.extend(event, original);
if (document.createEvent) {
that.el.node.dispatchEvent(event);
}
else {
that.el.node.fireEvent('on' + event.eventType, event);
}
});
-
Перекрывающиеся фигуры заставляют текст перекрываться, потому что текст/фигуры находятся на разных уровнях. Хотя перекрывающиеся формы не будут распространены, это выглядит плохо:
![overlap]()
Этот подход - это то, что я сейчас использую, но он просто чувствует себя как огромный хак.
Подход 3
Почти как Подход 1, но это касается непосредственного ввода текстовых узлов/узлов VML. Самая большая проблема с этим - это необходимое количество ручного преобразования. Нарушение API Raphael кажется, что это может вызвать проблемы стабильности с другими объектами Рафаэля.
Вопрос
Кто-нибудь еще должен был сделать что-то подобное (визуализация HTML внутри SVG/VML)? Если да, то как вы решили эту проблему? Учитывались ли события?
Ответы
Ответ 1
Если другой ответ не может быть предоставлен и превзойти мое решение, я продолжил дополнительный слой div. Пересылка событий была самой трудной частью (если кому-то требуется код пересылки событий, я могу опубликовать его здесь). Опять же, самый большой недостаток этого решения заключается в том, что перекрывающиеся фигуры заставят их текст перекрываться над фактической фигурой.
Ответ 2
Я построил этот проект (больше не живет), используя Raphael. Я действительно отказался от идеи использования HTML внутри SVG, потому что это было слишком грязно. Вместо этого я абсолютно позиционировал слой HTML поверх слоя SVG и перемещал их вместе. Когда мне захотелось показать HTML, я просто угаснул его и угасал соответствующий объект SVG. Если он рассчитан правильно и правильно выстроен, это не заметно для неподготовленного глаза.
Хотя это может и не быть тем, что вы ищете, возможно, это заставит ваш разум думать о новых способах решения вашей проблемы! Не стесняйтесь смотреть на JS на этой странице, так как она не была анонимной;)
PS, проект является приложением для сбора свинца. Если вы просто хотите посмотреть, как это работает, выберите "Друг" в первом выпадающем меню, и вам не нужно предоставлять какую-либо информацию.