Una pregunta que escuchamos de quienes evalúan sgcHTML: incluye muchos componentes ya preparados, pero ¿qué pasa si ya tengo una biblioteca JavaScript que me gusta? Quizás prefiera los gráficos de D3.js o Chart.js, o haya pagado por un Grid de DevExtreme y quiera usarlo. La respuesta corta es que sgcHTML se diseñó para ser abierto. Genera páginas completas en el servidor a partir de código Delphi, C++Builder o .NET, y cualquier biblioteca que se ejecute en un navegador se integra con tres pequeños puntos de enganche. Si recurre a la misma biblioteca a menudo, puede envolverla en un componente reutilizable para que el resto de su aplicación nunca vea el JavaScript.
Los tres puntos de enganche
Todo widget de terceros necesita las mismas tres cosas en la página: la biblioteca debe cargarse, debe existir un elemento en el que renderizar, y debe ejecutarse una línea de código de inicialización una vez que el DOM esté listo. El componente TsgcHTMLComponent_Site le ofrece una propiedad o método para cada una.
CustomHeadinyecta marcado en<head>, el lugar natural para un<script>o<link>que cargue la biblioteca.AddContentemite el elemento de destino en el cuerpo de la página.BodyEndHTMLejecuta su código de inicialización justo antes de</body>, después de que la biblioteca se haya cargado.
Aquí tiene un ejemplo completo con D3.js. Cargue la biblioteca, incorpore un contenedor y deje que D3 dibuje en él.
uses
sgcHTML_Component_Site;
var
oSite: TsgcHTMLComponent_Site;
begin
oSite := TsgcHTMLComponent_Site.Create(nil);
try
oSite.Title := 'Sales Dashboard';
// 1) Load the library (a public CDN, or a file you serve yourself)
oSite.CustomHead := '<script src="https://d3js.org/d3.v7.min.js"></script>';
// 2) Emit the element your library renders into
oSite.AddContent('<div id="chart"></div>');
// 3) Run your init code at the end of the body
oSite.BodyEndHTML :=
'<script>' +
' const data = [4, 8, 15, 16, 23, 42];' +
' d3.select("#chart").selectAll("div").data(data).enter()' +
' .append("div").attr("class", "bar")' +
' .style("width", d => (d * 12) + "px").text(d => d);' +
'</script>';
WebModule.Response := oSite.HTML;
finally
oSite.Free;
end;
end;
Ese es todo el patrón. Cambie la URL y el código de inicialización, y esas mismas tres líneas sirven para Chart.js, un widget de DevExtreme, un calendario, un mapa o cualquier otra cosa.
CDN o alojamiento propio
El ejemplo anterior apunta a una CDN pública, la forma más rápida de probar algo. Para una aplicación de intranet, una implementación sin conexión, o cuando quiera fijar una versión exacta, sirva usted mismo el archivo de la biblioteca desde el servidor sgc y referéncielo con una ruta local. Varios componentes integrados ya hacen esto: el componente Chart incluido carga Chart.js desde un /chart.umd.min.js local en lugar de una CDN, de modo que la página no tiene ninguna dependencia externa.
// The .js and .css files sit next to your server executable and are
// served as static files, so the page references them by local path:
oSite.CustomHead :=
'<link rel="stylesheet" href="/assets/mylib.min.css">' +
'<script src="/assets/mylib.min.js"></script>';
Si prefiere construir el head como nodos en lugar de una cadena sin procesar, la capa de plantillas expone las listas HeadNodes y BodyEndNodes con los métodos auxiliares AddScript y AddStylesheet, además de los nodos TsgcHTMLScript (con Src, Code, Defer, Async) y TsgcHTMLStylesheet. Las cadenas sin procesar y los nodos tipados son intercambiables, use la que resulte más legible en su código.
Chart.js en pocas líneas
Chart.js es una petición habitual, así que aquí está usando los mismos tres puntos de enganche. Cargue la biblioteca, emita un <canvas> y luego construya el gráfico.
oSite.CustomHead := '<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>';
oSite.AddContent('<canvas id="revenue" width="600" height="300"></canvas>');
oSite.BodyEndHTML :=
'<script>' +
' new Chart(document.getElementById("revenue"), {' +
' type: "bar",' +
' data: {' +
' labels: ["Q1", "Q2", "Q3", "Q4"],' +
' datasets: [{ label: "Revenue", data: [12, 19, 7, 15] }]' +
' }' +
' });' +
'</script>';
Si solo quiere gráficos y no necesita una biblioteca específica, tenga en cuenta que sgcHTML ya incluye un componente TsgcHTMLComponent_Chart que es Chart.js ya conectado para usted, con una propiedad CustomOptions que pasa directamente cualquier configuración sin procesar de Chart.js. Esta sección es para cuando quiera manejar la biblioteca usted mismo.
Un Grid de DevExtreme
DevExtreme es un buen ejemplo de una suite comercial más pesada. El DataGrid necesita su hoja de estilos y su paquete cargados, un elemento donde montarse y un objeto de configuración. El enfoque no cambia en nada.
oSite.CustomHead :=
'<link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/23.2.3/css/dx.light.css">' +
'<script src="https://cdn3.devexpress.com/jslib/23.2.3/js/dx.all.js"></script>';
oSite.AddContent('<div id="grid"></div>');
oSite.BodyEndHTML :=
'<script>' +
' new DevExpress.ui.dxDataGrid(document.getElementById("grid"), {' +
' dataSource: [' +
' { id: 1, name: "Widget", price: 9.90 },' +
' { id: 2, name: "Gadget", price: 14.50 }' +
' ],' +
' columns: ["id", "name", "price"],' +
' showBorders: true' +
' });' +
'</script>';
La parte interesante es de dónde viene dataSource. Puede serializar un conjunto de datos a JSON en el servidor e incluirlo en línea como se muestra, o apuntar el grid a un endpoint que exponga su servidor sgc y dejar que lo cargue en vivo. Hay un ejemplo listo de Grid de DevExtreme en la carpeta de demos que alimenta un grid desde un servidor sgc WebSocket, de modo que los datos se actualizan en tiempo real sin recargar la página.
Envuélvalo en un componente reutilizable
Pasar cadenas sin procesar está bien para algo puntual. Cuando se encuentre usando la misma biblioteca página tras página, promuévala a un componente: cree una subclase de TsgcHTMLComponent y sobrescriba GetHTML para devolver su propio marcado más el código de enlace de la biblioteca. En el resto de su aplicación, simplemente establece una propiedad y llama a HTML, exactamente igual que un componente integrado.
uses
sgcHTML_Component;
type
TsgcHTMLComponent_D3Bars = class(TsgcHTMLComponent)
private
FData: string; // a JSON array, e.g. '[4,8,15,16,23,42]'
published
property Data: string read FData write FData;
public
function GetHTML: string; override;
end;
function TsgcHTMLComponent_D3Bars.GetHTML: string;
begin
Result :=
'<div id="d3bars"></div>' +
'<script src="https://d3js.org/d3.v7.min.js"></script>' +
'<script>' +
' const data = ' + FData + ';' +
' d3.select("#d3bars").selectAll("span").data(data).enter()' +
' .append("span").style("padding-right", d => d + "px").text(d => d);' +
'</script>';
end;
Esto no es un caso especial, así es como están construidos varios de los componentes incluidos. El componente Map envuelve Leaflet, el RichEditor envuelve Quill, el KanbanBoard envuelve SortableJS, y el PDFViewer envuelve pdf.js, cada uno de ellos cargando su biblioteca y emitiendo su código de inicialización exactamente a través de estos puntos de enganche. Su propio wrapper se sitúa junto a ellos como un componente de primera clase, y puede agregar una sobrescritura equivalente de GetCSS si la biblioteca necesita estilos, que sgcHTML recopila y deduplica en toda la página por usted.
Pruébelo
La conclusión es que sgcHTML nunca lo encasilla. Los componentes integrados cubren mucho terreno, y cuando necesite algo específico, D3.js, Chart.js, un Grid o Chart de DevExtreme, cualquier biblioteca de navegador que sea, son tres puntos de enganche para incorporarla y una pequeña subclase para hacerla reutilizable.
¿Preguntas o comentarios? Póngase en contacto, recibirá una respuesta de las personas que escribieron el código.
