SVG Interactivo usando <object>?

Estoy intentando incrustar una visualización de datos interactiva basada en SVG. Estoy generando el SVG desde un sistema separado (pero aún en el mismo dominio de segundo nivel que mi instalación de Discourse). He intentado cargar el SVG usando una etiqueta OBJECT…

<object type="image/svg+xml" data="URL_completa_a_foo.svg">
(se muestra si falla la carga del objeto)
</object>

Si simplemente cargo ese SVG (se genera dinámicamente cada vez) con una etiqueta IMG, la imagen aparece, pero (como esperaba) no hay interactividad…

<img src="URL_completa_a_foo.svg">

¿Alguna idea o indicación sobre dónde puedo encontrar pistas sobre SVGs y Discourse? :slight_smile:

La forma más sencilla de hacer que esto funcione es mediante un iframe. Agrega el dominio del SVG a la configuración del sitio allowed_iframes e inclúyelo en una publicación usando HTML.

Hmm, así que esa es la forma fácil.

¿Existe una forma difícil que pueda probar?

…porque quiero tener enlaces en el SVG que cambien la ubicación del navegador. Los enlaces en el SVG, dentro de un IFRAME, cambian lo que se muestra en el IFRAME…

Sospecho que incrustar JavaScript en el tema, justo antes del IFRAME, y llamar a una función de JavaScript en la página al hacer clic en el SVG… tampoco va a funcionar.

¿Tengo sentido? ¿Debería agregar algo de código JavaScript ligero, como en Mitigate XSS Attacks with Content Security Policy, y luego intentar llamarlo desde el SVG dentro del IFRAME? …¿o “dentro del IFRAME” es una fortaleza hermética?

¿Quizás debería preguntar cómo puedo incrustar directamente el SVG en la página? ¿Y luego usar JavaScript inyectado por un componente del tema para interactuar con mi otro servidor y actualizar dinámicamente el SVG?

¡Por favor, un poco de ayuda! :slight_smile:

Colocar el SVG en la publicación marcada con un div especial circundante y usar un componente de tema para convertirlo en una etiqueta object mediante la función de callback decorateCooked podría funcionar. Consulta la Guía para desarrolladores de temas de Discourse.

…en caso de que alguien esté siguiendo, decorateCooked() está obsoleto. Estoy experimentando con decorateCookedElement() en su lugar.

Estoy teniendo problemas con CORS (Access-Control-Allow-Origin). No estoy familiarizado con cómo funciona…

Tengo dos sitios: el sitio de Discourse alojado (forum.moversmindset.com) y un sitio de WordPress basado en Apache (moversmindset.com). Cabe mencionar que no hay contenido evidente en el sitio de WordPress; todo se trata de generar feeds RSS, servir medios, etc. Si accedes al dominio, simplemente te redirigirá al foro.

Tengo un directorio que responde a solicitudes GET devolviendo archivos SVG. Por ejemplo (no es la URL real): https://moversmindset.com/foo/bar.php

En mi tema de Discourse estoy experimentando con código de script (eventualmente será un plugin adecuado). Llama a api.decorateCooked() en ciertos DIVs que tienen algún atributo data-custom añadido. Así que dentro de la función llamada por decorateCooked() estoy haciendo algo como:

$.get(‘https://moversmindset.com/foo/bar.php’ … bla bla blah

Quiero obtener el SVG y luego agregarlo al DOM. Pero la consola de errores de mi navegador dice:

Pregunta:

¿Eso significa que debo configurar CORS en la instalación de Discourse o en el servidor Apache/WordPress?

Sí, tengo configurado https://moversmindset.com como permitido en CORS en Discourse.

Creo que está en este lado. ¿Podrías echar un vistazo a Access-Control-Allow-Origin header - HTTP | MDN si aún no lo has hecho y ver si te da alguna pista?

pasitos muy pequeños, ¡pero SÍ!

Tuve que añadir un encabezado Access-Control-Allow-Origin en el servidor apache/WP. Eso dejó contenta a la j/s (procedente de la plataforma Discourse). Gracias.

He seguido descubriendo esto poco a poco. Esto requiere mucha configuración para plantear mi pregunta:

SVG

Tengo un servidor web que genera SVG. Para esta pregunta, genera un SVG de prueba muy simple…

<svg xmlns="http://www.w3.org/2000/svg" stroke-linejoin="round" viewBox="0 0 100 100">
<path d="M50,4L4,50L50,96L96,50Z" stroke="#40638C" stroke-width="3"></path>
<path d="M50,5L5,50L50,95L95,50Z" stroke="#333" fill="#40638C" stroke-width="3"></path>
<path d="M37,42c-1,0,11-20,13-20c1,0,15,20,13,20h-9c0,8,9,22,12,25l-4,4l-8,-7v13h-10v-35z" stroke="#40495E" fill="#40495E"></path>
<path d="M35,40c-1,0,11-20,13-20c1,0,15,20,13,20h-9c0,8,9,22,12,25l-4,4l-8,-7v13h-10v-35z" stroke="#333" fill="#555"></path>
</svg>

Es simplemente un signo de “fusionar” con un aspecto elegante. Ten en cuenta que tiene cuatro elementos PATH.

Incrustación

Para insertar el SVG en una publicación, estoy utilizando algún JavaScript añadido a través de mi tema.

El objetivo final sería crear un plugin adecuado. Pero solo estoy intentando construir una prueba de concepto. Así que simplemente lo he pegado en la sección <head> de la personalización de mi tema:

<script type="text/discourse-plugin" version="0.8">
var UMB = {
    svgload: function(base, target) {
        var url = base + $(target).text();
        $(target).html('');
        $.ajax({
            method: "GET",
            url: url,
            async: false,
            dataType: "text",
            success: function(data) { $(target).append(data); }
        });
        alert('loaded!');
        $(target).children('path').each(function(){alert('here is a path element');});
    },
}
$.fn.umbdv = function() {
    this.each(
        function() {
            UMB.svgload('__URL_REDACTED__', this);
        }
    );
    return this;
};
api.decorateCooked(
  $elem => $elem.children('.cooked div[data-custom="umbdv"]').umbdv(),
  { id: 'umbdv' }
);
</script>

Donde…

var UMB = { es simplemente una variable global que me evita tener funciones anónimas gigantes por todas partes.

$.fn.umbdv = es [lo que creo que se llama] un “plugin” que extiende JQuery.

api.decorateCooked( me permite manipular la publicación antes de que se envíe al navegador.

Encantamiento

En un tema, luego escribo…

<div data-custom="umbdv">/vtest</div>

UMB.svgload('__URL_REDACTED__', this) se llama para ese DIV.

UMB.svgload() entiende correctamente la cadena /vtest, compone una URL y realiza la solicitud AJAX. Realiza con éxito el append(data) y boop, mi SVG está incrustado…

Mi alert() dentro de UMB.svgload() se dispara, tal como se esperaba. (Obviamente es un truco de depuración, ¿verdad? :)

La pregunta (finalmente)

Tengo un tema SOLO PARA PERSONAL en mi foro alojado en Discourse donde puedes ver esto en acción. (Estoy hablando con el personal de soporte de Discourse que puede entrar en mi instalación como usuarios Administradores.)

https://forum.moversmindset.com/t/svg-experimentation-in-progress/1109

¿Por qué no…

$(target).children('path').each(function(){alert('here is a path element');});

…selecciona ninguno de los elementos PATH?

No hace nada: ningún error. Nada.

Siguiente

A dónde iré si logro que esta trivial prueba de concepto con alert() funcione…

Soy consciente de que el fragmento del DOM con el que “estoy trabajando” aún no está conectado al DOM real del documento (en el punto donde se llama a UMB.svgload()). Por eso espero que $(target)… sea lo que necesito.

En última instancia, estoy incrustando SVGs mucho más complejos y necesitaré usar selectores JQuery más complejos. Quiero encontrar muchos elementos dentro de $(target) y adjuntar manipuladores de eventos (onclick, por ejemplo) que llamarán a otras funciones globales UMB.….

Los iframes pueden cambiar la navegación de nivel superior si lo deseas

http://w3c-test.org/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation_by_user_activation-manual.html

¡Gracias por el consejo!

Pero definitivamente prefiero ahora el SVG en línea.

De todas formas. Semanas después. Esto no funciona.

No parece posible manipular los elementos del DOM de SVG una vez que están incrustados en el documento principal. Así que no puedo averiguar cómo agregar disparadores o acciones de eventos (lo cual se podría hacer fácilmente con onclick, etc., si el SVG se carga en un iframe).

({{no usar un iframe era todo mi objetivo.}})

¯\_(ツ)_/¯