diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.css b/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.css index df9c55d0ace1..8b338fff11ce 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.css +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.css @@ -1,7 +1,3 @@ -::ng-deep #chart-demo { - height: 460px; -} - ::ng-deep #chart { position: absolute; top: 12px; @@ -10,7 +6,7 @@ height: 347px; } -::ng-deep .chart_environment { +::ng-deep .chart-environment { width: 820px; position: relative; margin: 0 auto; @@ -19,3 +15,18 @@ ::ng-deep .controls-pane { text-align: center; } + +::ng-deep .custom-markup-text { + fill: #fff; + font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif; +} + +::ng-deep .custom-markup-text-title { + font-size: 36px; + font-weight: bold; +} + +::ng-deep .custom-markup-text-subtitle { + font-size: 14px; + opacity: 0.8; +} diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.html b/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.html index 4d669c49873f..cf5542b767a6 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.html +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.html @@ -1,5 +1,5 @@ -
-
+
+
Export Custom @@ -31,13 +25,7 @@ Export a chart with custom elements diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.ts b/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.ts index 82d031e494cd..4029ce6e01ff 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.ts +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.ts @@ -54,13 +54,33 @@ export class AppComponent { } prepareMarkup() { + const sourceContainer = document.getElementById('custom-markup-container'); + const sourceElements = sourceContainer.querySelectorAll('*'); + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); svg.setAttribute('version', '1.1'); svg.setAttribute('width', '820px'); svg.setAttribute('height', '420px'); - svg.innerHTML = document.getElementById('custom_markup_container').innerHTML; + + const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement; + const clonedElements = clonedContainer.querySelectorAll('*'); + + clonedElements.forEach((clonedEl, index) => { + const sourceEl = sourceElements[index] as HTMLElement; + if (!sourceEl) return; + + const computed = window.getComputedStyle(sourceEl); + ['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => { + const value = computed.getPropertyValue(prop)?.trim(); + if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') { + (clonedEl as SVGElement).setAttribute(prop, value); + } + }); + }); + + svg.innerHTML = clonedContainer.innerHTML; const group = document.createElementNS('http://www.w3.org/2000/svg', 'g'); group.setAttribute('transform', 'translate(305,12)'); diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/React/App.tsx b/apps/demos/Demos/Charts/ExportCustomMarkup/React/App.tsx index c419d77ee303..2bab05e1c456 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/React/App.tsx +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/React/App.tsx @@ -16,15 +16,31 @@ import Form from './Form.tsx'; const barPadding = 0.3; -const prepareMarkup = (chartSVG: string, markup: string) => { +const prepareMarkup = (chartSVG: string, sourceContainer: HTMLElement) => { + const sourceElements = sourceContainer.querySelectorAll('*'); + const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); svg.setAttribute('version', '1.1'); svg.setAttribute('width', '820px'); svg.setAttribute('height', '420px'); - svg.innerHTML = markup; + const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement; + const clonedElements = clonedContainer.querySelectorAll('*'); + + clonedElements.forEach((clonedEl, index) => { + const sourceEl = sourceElements[index] as HTMLElement; + if (!sourceEl) return; + const computed = window.getComputedStyle(sourceEl); + ['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => { + const value = computed.getPropertyValue(prop)?.trim(); + if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') { + (clonedEl as SVGElement).setAttribute(prop, value); + } + }); + }); + svg.innerHTML = clonedContainer.innerHTML; const group = document.createElementNS('http://www.w3.org/2000/svg', 'g'); group.setAttribute('transform', 'translate(305,12)'); group.innerHTML = chartSVG; @@ -40,7 +56,7 @@ function App() { const onClick = useCallback(() => { exportFromMarkup( prepareMarkup(chartRef.current?.instance().svg() ?? '', - childRef.current?.innerHTML ?? ''), { + childRef.current ?? document.createElement('div')), { width: 820, height: 420, margin: 0, @@ -68,7 +84,7 @@ function App() { return (
-
+
((_, ref) => ( -
+
- + Export Custom Markup - + Export a chart with custom elements diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/React/styles.css b/apps/demos/Demos/Charts/ExportCustomMarkup/React/styles.css index d1c3833b7043..a8e4f5ab3fe5 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/React/styles.css +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/React/styles.css @@ -10,7 +10,7 @@ height: 347px; } -.chart_environment { +.chart-environment { width: 820px; position: relative; margin: 0 auto; @@ -19,3 +19,18 @@ .controls-pane { text-align: center; } + +.custom-markup-text { + fill: #fff; + font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif; +} + +.custom-markup-text-title { + font-size: 36px; + font-weight: bold; +} + +.custom-markup-text-subtitle { + font-size: 14px; + opacity: 0.8; +} diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/App.js b/apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/App.js index 0e8dfbf8e978..518953376cef 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/App.js +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/App.js @@ -14,14 +14,36 @@ import { dataSource } from './data.js'; import Form from './Form.js'; const barPadding = 0.3; -const prepareMarkup = (chartSVG, markup) => { +const prepareMarkup = (chartSVG, sourceContainer) => { + const sourceElements = sourceContainer.querySelectorAll('*'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); svg.setAttribute('version', '1.1'); svg.setAttribute('width', '820px'); svg.setAttribute('height', '420px'); - svg.innerHTML = markup; + const clonedContainer = sourceContainer.cloneNode(true); + const clonedElements = clonedContainer.querySelectorAll('*'); + clonedElements.forEach((clonedEl, index) => { + const sourceEl = sourceElements[index]; + if (!sourceEl) return; + const computed = window.getComputedStyle(sourceEl); + [ + 'fill', + 'font-family', + 'font-size', + 'font-weight', + 'opacity', + 'stroke', + 'stroke-width', + ].forEach((prop) => { + const value = computed.getPropertyValue(prop)?.trim(); + if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') { + clonedEl.setAttribute(prop, value); + } + }); + }); + svg.innerHTML = clonedContainer.innerHTML; const group = document.createElementNS('http://www.w3.org/2000/svg', 'g'); group.setAttribute('transform', 'translate(305,12)'); group.innerHTML = chartSVG; @@ -33,7 +55,10 @@ function App() { const chartRef = useRef(null); const onClick = useCallback(() => { exportFromMarkup( - prepareMarkup(chartRef.current?.instance().svg() ?? '', childRef.current?.innerHTML ?? ''), + prepareMarkup( + chartRef.current?.instance().svg() ?? '', + childRef.current ?? document.createElement('div'), + ), { width: 820, height: 420, @@ -55,7 +80,7 @@ function App() { }, []); return (
-
+
(
( > (
-
+
{ +const prepareMarkup = (chartSVG: string, sourceContainer: HTMLElement): SVGElement => { + const sourceElements = sourceContainer.querySelectorAll('*'); const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); svg.setAttribute('version', '1.1'); svg.setAttribute('width', '820px'); svg.setAttribute('height', '420px'); - svg.innerHTML = markup; - + const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement; + const clonedElements = clonedContainer.querySelectorAll('*'); + clonedElements.forEach((clonedEl, index) => { + const sourceEl = sourceElements[index] as HTMLElement; + if (!sourceEl) return; + const computed = window.getComputedStyle(sourceEl); + ['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => { + const value = computed.getPropertyValue(prop)?.trim(); + if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') { + (clonedEl as SVGElement).setAttribute(prop, value); + } + }); + }); + svg.innerHTML = clonedContainer.innerHTML; const group = document.createElementNS('http://www.w3.org/2000/svg', 'g'); group.setAttribute('transform', 'translate(305,12)'); group.innerHTML = chartSVG; svg.appendChild(group); - return svg; }; @@ -127,7 +139,7 @@ function onClick(): void { height: 347px; } -.chart_environment { +.chart-environment { width: 820px; position: relative; margin: 0 auto; diff --git a/apps/demos/Demos/Charts/ExportCustomMarkup/Vue/Form.vue b/apps/demos/Demos/Charts/ExportCustomMarkup/Vue/Form.vue index d81bd148391e..3650ad53fb12 100644 --- a/apps/demos/Demos/Charts/ExportCustomMarkup/Vue/Form.vue +++ b/apps/demos/Demos/Charts/ExportCustomMarkup/Vue/Form.vue @@ -1,5 +1,5 @@