Skip to content

Commit

Permalink
make manual changes in html to accomplish the desired width and heigh…
Browse files Browse the repository at this point in the history
…t, add showtitle as option (only for png)
  • Loading branch information
Heiss committed Dec 29, 2023
1 parent efe5919 commit 02a3619
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 36 deletions.
2 changes: 1 addition & 1 deletion onlinewardleymaps/assets/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ logfile=/dev/null
logfile_maxbytes=0

[program:onlinewardleymaps]
command=yarn start
command=yarn start -H 0.0.0.0 -p 3000
directory=/server/frontend
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
Expand Down
19 changes: 12 additions & 7 deletions onlinewardleymaps/src/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// must be declared first
import { logger } from './logger.js'
import {logger} from './logger.js'
import http from 'node:http'
import {TimeoutError as PuppeteerTimeoutError} from 'puppeteer'
import micro from 'micro'
import Task from './task.js'
import { create } from './browser-instance.js'
import { SyntaxError, TimeoutError, Worker } from './worker.js'
import {create} from './browser-instance.js'
import {SyntaxError, TimeoutError, Worker} from './worker.js'

(async () => {
// QUESTION: should we create a pool of Chrome instances ?
Expand All @@ -19,11 +19,16 @@ import { SyntaxError, TimeoutError, Worker } from './worker.js'
const url = new URL(req.url, 'http://localhost') // create a URL object. The base is not important here
const outputType = url.pathname.match(/\/(png|svg)$/)?.[1]
if (outputType) {
const diagramSource = await micro.text(req, { limit: '1mb', encoding: 'utf8' })
const diagramSource = await micro.text(req, {limit: '1mb', encoding: 'utf8'})
if (diagramSource) {
try {
const isPng = outputType === 'png'
const output = await worker.convert(new Task(diagramSource, isPng))
const params = url.searchParams
const width = parseInt(params.get('width')) || 800
const height = parseInt(params.get('height')) || 600
const showTitle = params.has('showtitle')

const output = await worker.convert(new Task(diagramSource, isPng, width, height, showTitle))
res.setHeader('Content-Type', isPng ? 'image/png' : 'image/svg+xml')
return micro.send(res, 200, output)
} catch (err) {
Expand All @@ -44,7 +49,7 @@ import { SyntaxError, TimeoutError, Worker } from './worker.js'
}
})
} else {
logger.warn({ err }, 'Exception during convert')
logger.warn({err}, 'Exception during convert')
return micro.send(res, 500, {
error: {
message: `An error occurred while converting the diagram: ${err.message}`,
Expand Down Expand Up @@ -74,6 +79,6 @@ import { SyntaxError, TimeoutError, Worker } from './worker.js'
)
server.listen(8007)
})().catch(err => {
logger.error({ err }, 'Unable to start the service')
logger.error({err}, 'Unable to start the service')
process.exit(1)
})
6 changes: 5 additions & 1 deletion onlinewardleymaps/src/task.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export default class Task {
constructor (source, isPng = false) {
constructor(source, isPng, width, height, showTitle, background = "white") {
this.source = source
this.isPng = isPng
this.width = width
this.height = height
this.showTitle = showTitle
this.background = background
}
}
100 changes: 73 additions & 27 deletions onlinewardleymaps/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,94 @@ export class Worker {
}

async convert(task) {
console.debug("Connecting browser")
logger.debug("Connecting browser")
const browser = await puppeteer.connect({
browserWSEndpoint: this.browserWSEndpoint,
ignoreHTTPSErrors: true
})
// https://github.com/damonsk/onlinewardleymaps/pull/75
console.debug("Browser connected")
logger.debug("Browser connected")
const page = await browser.newPage()
page.setDefaultTimeout(parseInt(this.convertTimeout))

const editorSelector = '.ace_text-input';
const mapFrameSelector = '.contentLoaded';
const fullScreenButtonSelector = 'html body div#__next div#main.MuiGrid-root.MuiGrid-container.MuiGrid-spacing-xs-2.css-16divny div.MuiGrid-root.MuiGrid-item.MuiGrid-grid-xs-12.MuiGrid-grid-sm-8.map-view.css-1klpxdq div.noText div.plain button.MuiButtonBase-root.MuiIconButton-root.MuiIconButton-colorBlack.MuiIconButton-sizeMedium.css-y7xizo';
const footerSelector = "html body div#__next div.MuiGrid-root.MuiGrid-container.css-3iorlj";
const inputSelector = 'html body div#__next div#main.MuiGrid-root.MuiGrid-container.MuiGrid-spacing-xs-2.css-16divny div.MuiGrid-root.MuiGrid-item.MuiGrid-grid-xs-12.MuiGrid-grid-sm-4.css-owsoks div#htmPane div#htmEditor.ace_editor.ace_hidpi.ace_dark.ace-dracula';
const mapContentSelector = '#main > div.MuiGrid-root.MuiGrid-item.MuiGrid-grid-xs-12.MuiGrid-grid-sm-8.map-view.css-1klpxdq > div' // set position absolute, top:0, left:0, max-width:100%, max-height:100%, width:100%, height:100%
const bodySelector = 'body' // set background-color:transparent
const titleSvgSelector = '#title' // set display:none, if shoTitle is false
const helperSelector = "html body div.ace_editor.ace_hidpi.ace_autocomplete.ace_dark.ace-dracula div.ace_scroller div.ace_content"

try {
console.debug("Page loaded")
let evalResult
try {
await page.setViewport({height: 1024, width: 800})
await page.goto(this.pageUrl)
console.debug("Page loaded")
await page.setViewport({height: task.height, width: task.width})
logger.debug("Page loaded")

logger.debug("Prepare page")
await (await page.waitForSelector(fullScreenButtonSelector)).evaluate((e) => {
e.click();
e.style.display = 'none'
});
logger.debug(("Click and hide full screen button"))


if (!task.showTitle) {
await (await page.waitForSelector(titleSvgSelector)).evaluate((e) => e.style.display = 'none');
logger.debug("Delete title")
}

logger.debug("Hide input")
await (await page.waitForSelector(mapContentSelector)).evaluate((e) => {
});
logger.debug("Set map content position")
logger.debug("Preparation done")

const editorSelector = '.ace_text-input';
await page.waitForSelector(editorSelector);
console.debug("Editor selector found")
logger.debug("Editor selector found")

await page.$eval(
editorSelector,
(e, val) => {
e.value = val;
e.value = val + "\n";
e.dispatchEvent(new Event('input', {bubbles: true}));
e.dispatchEvent(new Event('change', {bubbles: true}));
},
task.source
);
console.debug("Editor Map content set")
const mapFrameSelector = '.contentLoaded';
await page.waitForSelector(mapFrameSelector);
console.debug("image content loaded")
logger.debug("Editor Map content set")
await (await page.waitForSelector(mapFrameSelector)).evaluate((e) => {
e.style.position = 'absolute';
e.style.top = '0';
e.style.left = '0';
e.style.maxWidth = '100%';
e.style.width = '101%';
e.style.backgroundColor = "white"
e.style.zIndex = '1000';
})
logger.debug("image content loaded")

await (await page.waitForSelector(inputSelector)).evaluate((e) => {
e.style.display = 'none';
})
await (await page.waitForSelector(bodySelector)).evaluate((e) => {
e.style.backgroundColor = "white"
})
await (await page.waitForSelector(footerSelector)).evaluate((e) => {
e.style.display = 'none';
})
logger.debug("Hide input and footer, set background transparent")

await page.setViewport({height: task.height + 1, width: task.width})
await page.waitForTimeout(1000)

const svgSelector = '#map';
const elem = await page.waitForSelector(svgSelector);
const svg = await elem.evaluate((e) => e.innerHTML.replaceAll(" ", " "));
console.debug("svg loaded", svg)
logger.debug("svg loaded", svg)
evalResult = {svg: svg, error: null}
} catch (err) {
logger.error({err}, 'Unable to load the map')
Expand All @@ -72,22 +122,18 @@ export class Worker {
}

if (task.isPng) {
console.debug("Converting to PNG")
await page.setContent(`<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
${evalResult.svg}
</body>
</html>`)

const container = await page.$('svg')
logger.debug("Converting to PNG")
const container = await page.$('body')
return await container.screenshot({
type: 'png',
omitBackground: true
omitBackground: true,
clip: {
x: 0,
y: 0,
width: task.width,
height: task.height - 10,
scale: 1
}
})
} else {
return evalResult.svg
Expand Down

0 comments on commit 02a3619

Please sign in to comment.