Skip to content

Commit

Permalink
Merge pull request #919 from Eastern-Research-Group/bugfix/647_print-…
Browse files Browse the repository at this point in the history
…map-issue

Bugfix/647 print map issue
  • Loading branch information
maxdiebold-erg authored Dec 29, 2023
2 parents 9a9ed37 + 2ef1494 commit f468547
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 125 deletions.
11 changes: 11 additions & 0 deletions app/client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion app/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"glossary-panel": "github:Eastern-Research-Group/glossary",
"highcharts": "11.1.0",
"highcharts-react-official": "3.2.1",
"html-to-image": "1.11.11",
"papaparse": "5.4.1",
"pdf-lib": "1.17.1",
"react": "17.0.2",
Expand Down Expand Up @@ -120,4 +121,4 @@
"last 1 safari version"
]
}
}
}
24 changes: 13 additions & 11 deletions app/client/src/components/shared/MapLegend.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,17 +575,19 @@ function MapLegendContent({ view, layer, additionalLegendInfo }: CardProps) {
// jsx
const healthIndexLegend = (
<li className="hmw-legend__item">
<div className="hmw-legend__symbol" css={legendItemStyles}>
<GradientIcon
id="health-index-gradient"
stops={[
{ label: '1', color: 'rgb(10, 8, 145)' },
{ label: '0.75', color: 'rgb(30, 61, 181)' },
{ label: '0.5', color: 'rgb(54, 140, 225)' },
{ label: '0.25', color: 'rgb(124, 187, 234)' },
{ label: '0', color: 'rgb(180, 238, 239)' },
]}
/>
<div css={legendItemStyles}>
<div className="hmw-legend__symbol">
<GradientIcon
id="health-index-gradient"
stops={[
{ label: '1', color: 'rgb(10, 8, 145)' },
{ label: '0.75', color: 'rgb(30, 61, 181)' },
{ label: '0.5', color: 'rgb(54, 140, 225)' },
{ label: '0.25', color: 'rgb(124, 187, 234)' },
{ label: '0', color: 'rgb(180, 238, 239)' },
]}
/>
</div>
<span className="hmw-legend__info" css={labelStyles}>
State Watershed Health Index Layer
</span>
Expand Down
149 changes: 38 additions & 111 deletions app/client/src/components/shared/MapWidgets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,8 @@ function MapWidgets({

return function cleanup() {
popupWatcher.remove();
}
}, [getHucBoundaries, view]);
};
}, [getHucBoundaries, view]);

// add the layers to the map
useEffect(() => {
Expand Down Expand Up @@ -2088,23 +2088,29 @@ export async function generateAndDownloadPdf({
firstOnly?: boolean;
}) {
const image = !symbolClass ? null : await getImage(element, symbolClass);
let itemsAdded = 0;

// get captions
const textItems = element.getElementsByClassName(textClass);
// skip adding text if the png was generated from a div
const symbols = !symbolClass
? null
: element.getElementsByClassName(symbolClass);
if (!symbolClass || (symbols && symbols.length > 0)) {
// get captions
const textItems = element.getElementsByClassName(textClass);

for (let textItem of textItems) {
const text = textItem.textContent;
if (text) {
itemsAdded += 1;
legendItems.push({
image,
text,
type,
});
}

let itemsAdded = 0;
for (let textItem of textItems) {
const text = textItem.textContent;
if (text) {
itemsAdded += 1;
legendItems.push({
image,
text,
type,
});
if (firstOnly) break;
}

if (firstOnly) break;
}

if (itemsAdded === 0 && image) {
Expand Down Expand Up @@ -2147,7 +2153,7 @@ export async function generateAndDownloadPdf({
);
for (let legendService of legendServices) {
let hasHighestLevel = false;
const groups = Array.from(
let groups = Array.from(
legendService.getElementsByClassName('esri-legend__group-layer-child'),
);
if (groups.length === 0) groups.push(legendService);
Expand All @@ -2165,7 +2171,7 @@ export async function generateAndDownloadPdf({
// get main title
await addLegendItem({
legendItems,
element: legendService,
element: group,
textClass: 'esri-legend__service-label',
type: hasHighestLevel ? 'h2' : 'h1',
});
Expand Down Expand Up @@ -2382,25 +2388,22 @@ export async function generateAndDownloadPdf({
* @returns code as base64 PNG and height/width of image.
*/
async function getImage(parentElement: Element, searchClass: string) {
const htmltoimage = await import('html-to-image');
// get the symbol
const symbols = parentElement.getElementsByClassName(searchClass);
const symbol = symbols.length > 0 ? symbols[0] : null;
const svgs =
symbol?.tagName === 'SVG'
? [symbol as SVGSVGElement]
: symbol?.getElementsByTagName('svg');
const svgTemp = svgs && svgs.length > 0 ? svgs[0] : null;
const png = svgTemp ? await svgToPng(svgTemp) : null;
if (png) return png;

const imgs =
symbol?.tagName === 'IMG'
? [symbol as HTMLImageElement]
: symbol?.getElementsByTagName('img');
const img = imgs && imgs.length > 0 ? imgs[0] : null;
if (img) return { code: img.src, height: img.height, width: img.width };

return null;
const symbol = (
symbols.length > 0 ? symbols[0] : parentElement
) as HTMLElement;
// set div to visible to avoid blank image
const lastVisibility = symbol.style.visibility;
symbol.style.visibility = 'visible';
const img = await htmltoimage.toPng(symbol, { skipFonts: true });
symbol.style.visibility = lastVisibility;
return {
code: img,
height: symbol.offsetHeight,
width: symbol.offsetWidth,
};
}

/**
Expand Down Expand Up @@ -2463,82 +2466,6 @@ export async function generateAndDownloadPdf({
return numberOfIndents;
}

/**
* Converts an svg string to base64 png using the domUrl.
*
* @param svgText the string representation of the SVG.
* @return a promise to the bas64 png image.
*/
function svgToPng(svgElm: SVGSVGElement): Promise<PdfLegendImage> {
// convert an svg text to png using the browser
return new Promise(function (resolve, reject) {
try {
// can use the domUrl function from the browser
const domUrl = window.URL || window.webkitURL || window;
if (!domUrl) {
reject(new Error('Browser does not support converting SVG to PNG.'));
}

// figure out the height and width from svg text
const height = svgElm.height.baseVal.value;
const width = svgElm.width.baseVal.value;

let svgText = svgElm.outerHTML;
// remove "xlink:"" from "xlink:href" as it is not proper SVG syntax
svgText = svgText.replaceAll('xlink:', '');

// verify it has a namespace
if (!svgText.includes('xmlns="')) {
svgText = svgText.replace(
'<svg ',
'<svg xmlns="http://www.w3.org/2000/svg" ',
);
}

// create a canvas element to pass through
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');

// make a blob from the svg
const svg = new Blob([svgText], {
type: 'image/svg+xml;charset=utf-8',
});

// create a dom object for that image
const url = domUrl.createObjectURL(svg);

// create a new image to hold it the converted type
const img = new Image();

// when the image is loaded we can get it as base64 url
img.onload = function () {
if (!ctx) return;

// draw it to the canvas
ctx.drawImage(img, 0, 0);

// we don't need the original any more
domUrl.revokeObjectURL(url);
// now we can resolve the promise, passing the base64 url
resolve({ code: canvas.toDataURL(), width, height });
};

img.onerror = function (err) {
console.error(err);
reject(new Error('Failed to convert svg to png.'));
};

// load the image
img.src = url;
} catch (err) {
console.error(err);
reject(new Error('Failed to convert svg to png.'));
}
});
}

/**
* A wrapper for setTimeout, which allows async/await syntax.
*
Expand Down
4 changes: 4 additions & 0 deletions app/client/src/styles/mapStyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
box-shadow: 0 0 2px rgba(0, 0, 0, 0.3);
}

.esri-legend__symbol {
margin: unset;
}

.esri-print__header-title {
font-size: 1.25em;
font-weight: 500;
Expand Down
4 changes: 2 additions & 2 deletions app/client/src/utils/mapFunctions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -937,8 +937,8 @@ export function GradientIcon({
}) {
const divisions = stops.length - 1;
return (
<div css={{ display: 'flex', margin: 'auto' }}>
<div css={{ margin: '15px 0' }}>
<div style={{ display: 'flex', margin: 'auto' }}>
<div style={{ margin: '15px 0' }}>
<svg width={50} height={25 * divisions + 20}>
<defs>
<linearGradient
Expand Down

0 comments on commit f468547

Please sign in to comment.