Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: print fix ios #1658

Merged
merged 6 commits into from
Jan 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions package-lock.json

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

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@
"@glidejs/glide": "^3.5.2",
"awesomplete": "^1.1.5",
"cuid": "^2.1.8",
"dom-to-image-more": "2.8.0",
"downloadjs": "^1.4.7",
"elm-pep": "^1.0.6",
"html2canvas": "^1.4.0",
"html2canvas": "^1.4.1",
"ol-mapbox-style": "9.4.0",
"jspdf": "^2.5.0",
"ol": "^7.2.2",
Expand Down
4 changes: 4 additions & 0 deletions scss/externs/_ol.scss
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ button.ol-zoom-out {
text-align: center;
}

.ol-scale-bar-inner {
display: flex;
}

.ol-scale-singlebar-even{
background-color: #000000;
}
Expand Down
58 changes: 47 additions & 11 deletions src/controls/print/print-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { afterRender, beforeRender } from './download-callback';
import maputils from '../../maputils';
import PrintResize from './print-resize';
import { withLoading } from '../../loading';
import isOnIos from '../../utils/browser';

const PrintComponent = function PrintComponent(options = {}) {
const {
Expand All @@ -41,7 +42,6 @@ const PrintComponent = function PrintComponent(options = {}) {
sizeCustomMaxHeight,
sizeCustomMinWidth,
sizeCustomMaxWidth,
resolutions,
scaleInitial,
createdPrefix,
rotation,
Expand All @@ -60,6 +60,7 @@ const PrintComponent = function PrintComponent(options = {}) {
size,
orientation,
resolution,
resolutions,
scales,
showMargins,
showCreated,
Expand All @@ -76,18 +77,35 @@ const PrintComponent = function PrintComponent(options = {}) {
let titleAlign = `text-align-${titleAlignment}`;
let descriptionAlign = `text-align-${descriptionAlignment}`;
let viewerMapTarget;
const printMarginClass = 'print-margin';
let today = new Date(Date.now());
let printScale = 0;
let widthImage = 0;
let heightImage = 0;
const originalResolutions = viewer.getResolutions().map(item => item);
const originalGrids = new Map();
const deviceOnIos = isOnIos();

if (!Array.isArray(scales) || scales.length === 0) {
scales = originalResolutions.map(currRes => maputils.resolutionToFormattedScale(currRes, viewer.getProjection()));
}

const calcMaxRes = function calcMaxRes() {
const devicePixelRatio = window.devicePixelRatio;
const maxSize = 16777216;
const maxRes = Math.floor((Math.sqrt(maxSize / (sizes[size][1] * sizes[size][0])) * 25.4) / devicePixelRatio);
return maxRes;
};

const setMaxRes = function setMaxRes() {
const res = calcMaxRes();
resolutions = [{ label: 'Hög', value: res }];
resolution = res;
};

if (deviceOnIos) {
setMaxRes();
}

/**
* Recalulates a resoultions array to reflect dpi changes
* @param {number []} src the array of resolutions
Expand Down Expand Up @@ -196,6 +214,10 @@ const PrintComponent = function PrintComponent(options = {}) {
}
};

const getPrintPadding = function getPrintPadding() {
return showMargins ? `${(10 * resolution) / 150}mm ${(10 * resolution) / 150}mm` : '';
};

const created = function created() {
return showCreated ? `${createdPrefix}${today.toLocaleDateString()} ${today.toLocaleTimeString()}` : '';
};
Expand Down Expand Up @@ -259,9 +281,10 @@ const PrintComponent = function PrintComponent(options = {}) {
pageElement.style.width = `${widthImage}px`;
pageElement.style.height = `${heightImage}px`;
// Scale the printed map to make it fit in the preview
const scaleWidth = orientation === 'portrait' ? widthImage : heightImage;
const scaleFactor = `;transform: scale(${((widthInMm * 3.779527559055) / scaleWidth)});transform-origin: top left;`;
pageElement.setAttribute('style', pageElement.getAttribute('style') + scaleFactor);
const scaleWidth = widthImage;
pageElement.style.transform = `scale(${((widthInMm * 3.779527559055) / scaleWidth)})`;
pageElement.style.transformOrigin = 'top left';
pageElement.style.padding = getPrintPadding();
map.updateSize();
map.getView().setResolution(scaleResolution);
};
Expand Down Expand Up @@ -362,10 +385,16 @@ const PrintComponent = function PrintComponent(options = {}) {
},
changeSize(evt) {
size = evt.size;
if (deviceOnIos) {
setMaxRes();
}
this.updatePageSize();
},
changeCustomSize(evt) {
setCustomSize(evt);
if (deviceOnIos) {
setMaxRes();
}
this.updatePageSize();
},
changeOrientation(evt) {
Expand Down Expand Up @@ -404,11 +433,7 @@ const PrintComponent = function PrintComponent(options = {}) {
changeScale(evt) {
setScale(evt.scale);
},
printMargin() {
return showMargins ? 'print-margin' : '';
},
toggleMargin() {
pageElement.classList.toggle(printMarginClass);
showMargins = !showMargins;
this.updatePageSize();
},
Expand Down Expand Up @@ -507,6 +532,7 @@ const PrintComponent = function PrintComponent(options = {}) {
}
widthImage = orientation === 'portrait' ? Math.round((sizes[size][1] * resolution) / 25.4) : Math.round((sizes[size][0] * resolution) / 25.4);
heightImage = orientation === 'portrait' ? Math.round((sizes[size][0] * resolution) / 25.4) : Math.round((sizes[size][1] * resolution) / 25.4);

await withLoading(() => printToScalePDF({
el: pageElement,
filename,
Expand Down Expand Up @@ -540,6 +566,16 @@ const PrintComponent = function PrintComponent(options = {}) {
updatePageSize() {
pageContainerElement.style.height = orientation === 'portrait' ? `${sizes[size][0]}mm` : `${sizes[size][1]}mm`;
pageContainerElement.style.width = orientation === 'portrait' ? `${sizes[size][1]}mm` : `${sizes[size][0]}mm`;
const qH = (window.innerHeight - 78) / pageContainerElement.clientHeight;
const qW = (window.innerWidth - 32) / pageContainerElement.clientWidth;
pageContainerElement.style.transform = `scale(${qH > qW ? qW : qH})`;
if (window.innerWidth <= 1000) {
pageContainerElement.style.transformOrigin = 'top left';
pageContainerElement.style.marginLeft = '16px';
pageContainerElement.style.marginRight = '16px';
} else {
pageContainerElement.style.transformOrigin = 'top center';
}
this.updateMapSize();
if (printScale > 0) {
this.changeScale({ scale: printScale });
Expand Down Expand Up @@ -568,8 +604,8 @@ const PrintComponent = function PrintComponent(options = {}) {
style="margin-bottom: 4rem;">
<div
id="${pageId}"
class="o-print-page flex column no-shrink no-margin width-full height-full bg-white ${this.printMargin()}"
style="margin-bottom: 4rem;">
class="o-print-page flex column no-shrink no-margin width-full height-full bg-white}"
style="margin-bottom: 4rem; ${showMargins ? `padding: ${getPrintPadding()}` : ''}">
<div class="flex column no-margin width-full height-full overflow-hidden">
${pageTemplate({
descriptionComponent, printMapComponent, titleComponent, footerComponent
Expand Down
2 changes: 1 addition & 1 deletion src/controls/print/print-legend.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ export default function PrintLegend(options = {}) {

return `
<div id="legendContainer">
<div class="control overflow-hidden flex row o-legend">
<div class="control overflow-hidden flex row o-legend o-no-boxshadow">
<div class="flex column overflow-hidden relative">
${await overlaysCmp.render()}
</div>
Expand Down
11 changes: 7 additions & 4 deletions src/controls/print/print-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ const PrintSettings = function PrintSettings(options = {}) {
});
const marginControl = MarginControl({ checked: showMargins });
const createdControl = CreatedControl({ checked: showCreated });
const resolutionControl = ResolutionControl({
const resolutionControl = resolutions.length > 1 ? ResolutionControl({
initialResolution: resolution,
resolutions
});
}) : undefined;
const showScaleControl = ShowScaleControl({ checked: showScale });
northArrowControl = NorthArrowControl({ showNorthArrow });
printLegendControl = PrintLegendControl({ showPrintLegend });
Expand Down Expand Up @@ -204,8 +204,9 @@ const PrintSettings = function PrintSettings(options = {}) {
});
}
});
const components = [customSizeControl, marginControl, orientationControl, sizeControl, titleControl, descriptionControl, createdControl, northArrowControl, printLegendControl, setScaleControl, resolutionControl, showScaleControl];
const components = [customSizeControl, marginControl, orientationControl, sizeControl, titleControl, descriptionControl, createdControl, northArrowControl, printLegendControl, setScaleControl, showScaleControl];
if (rotationControl) { components.push(rotationControl); }
if (resolutions.length > 1) { components.push(resolutionControl); }
contentComponent.addComponents(components);
printSettingsContainer = Collapse({
cls: 'flex column',
Expand All @@ -232,7 +233,9 @@ const PrintSettings = function PrintSettings(options = {}) {
createdControl.on('change:check', (evt) => this.dispatch('change:created', evt));
northArrowControl.on('change:check', (evt) => this.dispatch('change:northarrow', evt));
printLegendControl.on('change:check', (evt) => this.dispatch('change:printlegend', evt));
resolutionControl.on('change:resolution', (evt) => this.dispatch('change:resolution', evt));
if (resolutionControl) {
resolutionControl.on('change:resolution', (evt) => this.dispatch('change:resolution', evt));
}
setScaleControl.on('change:scale', (evt) => this.dispatch('change:scale', evt));
showScaleControl.on('change:check', (evt) => this.dispatch('change:showscale', evt));
},
Expand Down
4 changes: 1 addition & 3 deletions src/controls/print/print-settings.template.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ export default function printTemplate({
<div class="padding-top"></div>
<h6>Orientering</h6>
${orientationControl.render()}
<div class="padding-top"></div>
<h6>Upplösning</h6>
${resolutionControl.render()}
${resolutionControl ? `<div class="padding-top"></div><h6>Upplösning</h6>${resolutionControl.render()}` : ''}
<div class="padding-top"></div>
${setScaleControl.render()}
<div class="padding-top-large"></div>
Expand Down
13 changes: 13 additions & 0 deletions src/utils/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const isOnIos = function isOnIos() {
return [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
].includes(navigator.platform)
|| (navigator.userAgent.includes('Mac') && 'ontouchend' in document);
};

export default isOnIos;
90 changes: 42 additions & 48 deletions src/utils/download.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import convertHtml2canvas from 'html2canvas';
import { jsPDF } from 'jspdf';
import domtoimage from 'dom-to-image-more';

let url;

Expand Down Expand Up @@ -54,24 +53,26 @@ export const html2canvas = function html2canvas(el) {
return convertHtml2canvas(el, {
useCORS: true,
allowTaint: true,
backgroundColor: null,
backgroundColor: '#FFFFFF',
logging: false,
height: el.offsetHeight,
width: el.offsetWidth
});
};

export const dom2image = function dom2image(el, exportOptions) {
return domtoimage.toJpeg(el, exportOptions);
};

export const getImageBlob = async function getImageBlob(el) {
if (el) {
const transformScale = el.style.transform;
const printEl = el;
printEl.style.transform = 'scale(1)';
const canvas = await html2canvas(printEl);
printEl.style.transform = transformScale;
const mapEl = el;
const parentEl = mapEl.parentElement;
const styleAttributes = mapEl.getAttribute('style');
const parentStyleAttributes = parentEl.getAttribute('style');
mapEl.style.transform = 'unset';
mapEl.style.transformOrigin = 'unset';
parentEl.style.transform = 'unset';
parentEl.style.transformOrigin = 'unset';
const canvas = await html2canvas(mapEl);
mapEl.setAttribute('style', styleAttributes); // Restore scaling
parentEl.setAttribute('style', parentStyleAttributes); // Restore scaling
const blob = await canvasToBlob(canvas);
return blob;
}
Expand Down Expand Up @@ -121,46 +122,39 @@ export const printToScalePDF = async function printToScalePDF({
orientation,
size,
width,
printScale,
widthImage,
heightImage
}) {
// export options for html-to-image.
// See: https://github.com/bubkoo/html-to-image#options
const exportOptions = {
filter(element) {
let className = element.className || '';
if (typeof className === 'object' && element.classList) {
className = `${element.classList}`;
}
return (
className.indexOf('o-print') === -1
|| className.indexOf('o-print-header') > -1
|| className.indexOf('print-scale-line') > -1
|| className.indexOf('padding-right-small') > -1
|| className.indexOf('padding-bottom-small') > -1
|| className.indexOf('o-print-description') > -1
|| className.indexOf('o-print-footer') > -1
|| className.indexOf('o-print-footer-left') > -1
|| className.indexOf('o-print-created') > -1
|| (className.indexOf('print-attribution') > -1
&& className.indexOf('ol-uncollapsible'))
);
const mapEl = el;
let orient = orientation;
if (size === 'custom') {
if (width > height) {
orient = widthImage < heightImage ? 'portrait' : 'landscape';
}
};

const format = size === 'custom' ? [mm2Pt(width), mm2Pt(height)] : size;
if (printScale !== 0) {
exportOptions.width = widthImage;
exportOptions.height = heightImage;
}

const pdf = new jsPDF({ orientation, format, unit: 'mm', compress: true });
const styleAttributes = el.getAttribute('style');
el.setAttribute('style', styleAttributes.split('transform: scale')[0]); // Remove scaling to get correct print size of image
let image = await dom2image(el, exportOptions);
image = await dom2image(el, exportOptions); // Fix for iPhone
pdf.addImage(image, 'JPEG', 0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight());
el.setAttribute('style', styleAttributes); // Restore scaling
pdf.save(`${filename}.pdf`);
const format = size === 'custom' ? [mm2Pt(height), mm2Pt(width)] : size;
const pdf = new jsPDF({ orientation: orient, format, unit: 'mm', compress: true });
const parentEl = mapEl.parentElement;
const styleAttributes = mapEl.getAttribute('style');
const parentStyleAttributes = parentEl.getAttribute('style');
mapEl.style.transform = 'unset';
mapEl.style.transformOrigin = 'unset';
parentEl.style.transform = 'unset';
parentEl.style.transformOrigin = 'unset';
convertHtml2canvas(mapEl, {
useCORS: true,
allowTaint: true,
backgroundColor: '#FFFFFF',
logging: false,
height: heightImage,
width: widthImage
})
.then((dataUrl) => {
pdf.addImage(dataUrl, 'JPEG', 0, 0, pdf.internal.pageSize.getWidth(), pdf.internal.pageSize.getHeight());
})
.then(() => {
pdf.save(`${filename}.pdf`);
mapEl.setAttribute('style', styleAttributes); // Restore scaling
parentEl.setAttribute('style', parentStyleAttributes); // Restore scaling
});
};