Estoy tratando de implementar un renderizador del lado del servidor para HighCharts. Todo parece funcionar bien, excepto que al marcado SVG resultante le faltan los valores x, y, ancho y alto en todo el lugar. A través de algunas depuraciones, creo que he identificado el problema en el hecho de que offsetWidth, offsetHeight, offsetTop y offsetLeft no están definidos para cada elemento.
¿Están estas propiedades programadas para incluirse en una versión futura? Además, ¿hay alguna solución alternativa que pueda implementar en este momento?
Creo que sería necesario implementar http://www.w3.org/TR/cssom-view/ .
hemos comenzado a integrar cssom que debería resolver algunos de los problemas de SVG.
De hecho, sería genial si pudiéramos acceder a las propiedades de compensación *, las necesitaríamos para un proyecto relacionado con el lienzo.
¿Cómo está el avance en este tema? También agradecería una característica de este tipo para el renderizado de sag de backend con Highcharts.
Me encantaría tener esto también :)
¿Tienen bicicletas de repuesto para ayudar? Personalmente, no necesito svg 1.1, pero estaría dispuesto a ayudar a conseguirlo si ustedes están lo suficientemente animados para trabajar en él también.
@tmpvar : Me gustaría ayudar, pero soy bastante nuevo en esas cosas JS del lado del servidor.
Tal vez puedas indicarme por dónde empezar y podría hacer todo lo posible para que algo funcione :)
También estoy muy interesado en SVG 1.1, para habilitar highcharts en el servidor. Me gustaría ofrecer ayuda, pero primero necesito familiarizarme con SVG 1.0 y su implementación actual en jsdom, lo que puede llevar un tiempo;)
Creo que el primer paso aquí es tomar una copia del conjunto de pruebas (http://www.w3.org/Graphics/SVG/WG/wiki/Test_Suite_Overview) y convertirlo para que no tenga cabeza (lo que puede ser una gran empresa)
Luego podemos agregar level2/svg.js
y comenzar a implementar.
Probablemente llegaré a esto eventualmente, pero no es una prioridad en mi lista de prioridades de jsdom en este momento.
@href, la implementación de svg 1.0 es bastante simple. Pasa las pruebas en level1/core
pero en realidad no implementa nada específico de svg.
Creo que getBoundingCLientRect no se implementa correctamente.
Tengo este código para calcular un elemento svg específico:
var html = '<!DOCTYPE html><html><head><title></title></head><body style="margin: 0; padding: 0;"><svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" style="margin: 0; padding: 0;"><rect style="" x="10" y="10" width="100" height="100" rx="0" ry="0"/></svg></body></html>';
jsdom.env({
html : html,
src: [jquery],
done: function (errors, window) {
var $ = window.$;
var clientBox = $("#svg").find(type)[0].getBoundingClientRect();
console.log(clientBox);
}
});
Y el resultado es:
{ bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }
Pero, si pruebo el mismo html en el navegador web, el resultado es este:
{ bottom: 110, height: 100, left: 10, right: 110, top: 10, width: 100 }
@ throrin19 : Lea el n. ° 653.
¿Entonces es imposible de lograr? Hasta ahora logré evitar esta preocupación a través de phantomJS, pero es extremadamente lento y si tengo un SVG grande, se bloquea.
Quiero decir, no es imposible, pero tendríamos que escribir un motor de diseño completo y nadie ha tenido tiempo para hacerlo.
Lo he pensado, pero luego mi cerebro sufre espasmos y tengo que alejarme.
¿Hay pruebas más allá del ácido que se puedan seguir?
+1 al considerar que esta es una característica muy deseable
Utilizo este fragmento como soporte, que funciona para mi caso. Tenga en cuenta que está lejos de ser una implementación adecuada. Tenga en cuenta que window
debe ser su document.parentWindow
.
Si necesita una mejor implementación, amplíe el código usando la especificación:
http://dev.w3.org/csswg/cssom-view/#dom -htmlelement-offsetleft
Object.defineProperties(window.HTMLElement.prototype, {
offsetLeft: {
get: function() { return parseFloat(window.getComputedStyle(this).marginLeft) || 0; }
},
offsetTop: {
get: function() { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
},
offsetHeight: {
get: function() { return parseFloat(window.getComputedStyle(this).height) || 0; }
},
offsetWidth: {
get: function() { return parseFloat(window.getComputedStyle(this).width) || 0; }
}
});
¿Alguien más ha tenido éxito con lo que sugirió tobyhinloopen?
@tobyhinloopen : El fondo, el eje y las etiquetas de mi gráfico aparecen (aunque de forma sesgada), pero el resto todavía está muy confuso. ¿Pudiste obtener un gráfico completo?
Tuve un caso de uso diferente en el que funcionó mi implementación sugerida. Si no le funciona, extiéndalo. Probablemente OffsetHeight / width también debe incluir el relleno. Sugeriría algunas correcciones hacky para que funcione, porque una implementación perfecta es difícil de implementar.
La solución propuesta por @tobyhinloopen parece estar bien, pero cuando la uso obtengo "no se puede refinar la propiedad offsetLeft"
@zallek Creo que ya tienes soporte offsetLeft entonces :) ¿Qué devuelve window.HTMLElement.prototype.offsetLeft
? Si es cualquier cosa menos indefinida, mi solución no funcionará
Solo quería darte las gracias @tobyhinloopen , tu solución me fue muy útil. :)
@tobyhinloopen ¡ Muchas gracias por publicar la solución! Es muy útil y funciona siempre que use una variable para establecer el valor de compensación y excluir this
. this
sale indefinido, lo que tiene sentido dado que el contexto no es la clase real. ¿Es eso lo que esperabas?
@jordantomax esto está vinculado al elemento cuando se llama a la función, no cuando se define la función. 'this' debería ser el elemento cuando lo llame desde cualquier elemento html.
Si no es así, me gustaría ver un ejemplo.
@tobyhinloopen Gracias por la rápida respuesta. Eso es lo que esperaría. Cuando intento reproducir mi problema en codesandbox usando un entorno de navegador real, funciona correctamente. Pero cuando uso broma, veo this
como indefinido. Creé un pequeño repositorio de muestra para mostrarte lo que estoy experimentando, tal vez mi configuración sea incorrecta.
https://github.com/jordantomax/jest-htmlelement-prototype-sandbox
Relacionado, también tengo problemas para anular métodos como scrollIntoView
usando jest y jsdom. ¿Existe alguna forma recomendada de hacerlo?
¡Muchas gracias por su ayuda!
Creo que es porque usas get: () => {}
- La sintaxis de la función () => {}
confunde con tu this
. Si usa get() {}
(recomendado) o get: function() {}
(alternativa), funcionará. @jordantomax
También usa =>
en los it
/ describe
su suite de prueba. No sé sobre JEST, pero en MOCHA no se recomienda, ya que this
en su it
/ test
/ describe
tiene todo tipo de utilidades a las que no puede acceder si utiliza las funciones de flecha. Por ejemplo, el moca tiene cosas como this.slow()
, this.timeout(4000)
etc.
https://mochajs.org/#arrow -functions
Relacionado, también tengo problemas para anular métodos como scrollIntoView usando jest y jsdom. ¿Existe alguna forma recomendada de hacerlo?
Por lo general, hay algún tipo de polyfill disponible en MDN. De lo contrario, intente implementarlo según la especificación de una manera que se adapte a sus necesidades. Si todo falla, simplemente use un entorno de prueba diferente. JSDom tiene su lugar, pero en algún momento es posible que desee considerar un navegador real en su lugar. Muchos entornos de prueba permiten realizar pruebas en navegadores reales (incluso múltiples al mismo tiempo) al mismo tiempo que informan en tiempo real a su máquina de desarrollo. IIRC Karma hace esto -> https://karma-runner.github.io/latest/index.html
He tenido varios navegadores abiertos (firefox chrome safari internet explorer edge + móviles en simuladores) todos a la vez en mi máquina, y todos informaron en tiempo real usando Karma + Mocha.
@tobyhinloopen ¡Tienes razón en todas las cuentas! ¡¡Gracias!! Todavía no tengo claro por qué es necesario getComputedStyle
, y es posible escribir un setter dado ese método. Para mí, esto parece funcionar:
Object.defineProperties(window.HTMLElement.prototype, {
offsetTop: {
get () {
return this.marginTop
},
set (offset) {
this.marginTop = offset
}
}
})
Gracias de nuevo 🙏
@jordantomax getComputedStyle
obtiene el estilo real calculado para todas las propiedades CSS, sin importar dónde se haya aplicado (hoja de estilo, atributo style
o de JS). No estoy seguro de si this.marginTop
hace lo mismo, pero supongo que sí (pero solo para el margen, obviamente, no para todos los accesorios de CSS)
@tobyhinloopen Ah, lo tengo. ¡Gracias!
Gracias @tobyhinloopen . Yo uso una versión aún más corta. Creo que getComputedStyle
no es realmente necesario ya que personalmente nunca agrego ningún CSS a mis pruebas unitarias a menos que esté en línea, por lo que .style
es lo suficientemente bueno y rápido.
Object.defineProperties(window.HTMLElement.prototype, {
offsetLeft: {
get () { return parseFloat(this.style.marginLeft) || 0 }
},
offsetTop: {
get () { return parseFloat(this.style.marginTop) || 0 }
},
offsetHeight: {
get () { return parseFloat(this.style.height) || 0 }
},
offsetWidth: {
get () { return parseFloat(this.style.width) || 0 }
}
})
¿Se ha solucionado esto, obtengo offsetWidth = 0
const dom = new JSDOM(`<!DOCTYPE html><body></body>`);
let document = dom.window.document
let span = document.createElement("span");
span.innerHtml = 'test
span.style.fontSize = 150 + 'px';
span.style.fontFamily = 'Arial'
document.body.appendChild(span)
console.log(span.offsetWidth) // 0
¿Se ha solucionado esto, obtengo offsetWidth = 0
@petran no es realista esperar que jsdom calcule el ancho de su SPAN, ya que requiere conocer el tamaño de su fuente y todas las propiedades CSS heredadas. No creo que ese sea el objetivo de JSDOM. Si desea una simulación más precisa de un navegador, considere usar un navegador real.
Comentario más útil
Utilizo este fragmento como soporte, que funciona para mi caso. Tenga en cuenta que está lejos de ser una implementación adecuada. Tenga en cuenta que
window
debe ser sudocument.parentWindow
.Si necesita una mejor implementación, amplíe el código usando la especificación:
http://dev.w3.org/csswg/cssom-view/#dom -htmlelement-offsetleft