diff --git a/deployment/Dockerfile b/deployment/Dockerfile index d39027aa..b2a2b06f 100644 --- a/deployment/Dockerfile +++ b/deployment/Dockerfile @@ -82,22 +82,6 @@ RUN apt-get update -y && \ RUN curl -L https://github.com/plotly/plotly.js/archive/master.tar.gz \ | tar -xvzf - --strip-components=3 plotly.js-master/dist/extras/mathjax -#################### -# Copy and set up Orca - -RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ - sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \ - apt-get update -y && \ - apt-get install -y google-chrome-stable xvfb poppler-utils git && \ - rm -rf /var/lib/apt/lists/* && apt-get clean - -COPY package.json /var/www/image-exporter/ -COPY bin /var/www/image-exporter/bin -COPY src /var/www/image-exporter/src - -WORKDIR /var/www/image-exporter -RUN npm install && mkdir build - #################### # Install and configure monit COPY deployment/monitrc /etc @@ -127,6 +111,22 @@ RUN wget https://raw.githubusercontent.com/plotly/plotly.js/master/dist/plotly-g COPY deployment/ImageMagickPolicy.xml /etc/ImageMagick-6/policy.xml +#################### +# Copy and set up Orca + +RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \ + sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list' && \ + apt-get update -y && \ + apt-get install -y google-chrome-stable xvfb poppler-utils git && \ + rm -rf /var/lib/apt/lists/* && apt-get clean + +COPY package.json /var/www/image-exporter/ +COPY package-lock.json /var/www/image-exporter/ +WORKDIR /var/www/image-exporter +RUN npm install && mkdir build +COPY bin /var/www/image-exporter/bin +COPY src /var/www/image-exporter/src + #################### # Add entrypoint script COPY deployment/entrypoint.sh / diff --git a/deployment/run_server b/deployment/run_server index 6b1657b7..23b7fdd6 100755 --- a/deployment/run_server +++ b/deployment/run_server @@ -40,7 +40,7 @@ pkill -9 Xvfb pkill -9 node pkill -9 electron -xvfb-run --auto-servernum --server-args '-screen 0 640x480x24' /var/www/image-exporter/bin/orca.js serve $REQUEST_LIMIT --safe-mode --verbose $PLOTLYJS_ARG $ORCA_IGNORECERTERRORS_ARG $@ & +xvfb-run --auto-servernum --server-args '-screen 0 1024x768x24' /var/www/image-exporter/bin/orca.js serve $REQUEST_LIMIT --safe-mode --verbose $PLOTLYJS_ARG $ORCA_IGNORECERTERRORS_ARG $@ & echo \$! > \$PIDFILE EOF diff --git a/src/component/plotly-dash-preview/parse.js b/src/component/plotly-dash-preview/parse.js index 83a62bf2..3f26c191 100644 --- a/src/component/plotly-dash-preview/parse.js +++ b/src/component/plotly-dash-preview/parse.js @@ -36,17 +36,25 @@ function parse (body, req, opts, sendToRenderer) { result.timeOut = body.timeout result.tries = Number(result.timeOut * 1000 / cst.minInterval) - if (cst.sizeMapping[result.pdfOptions.pageSize]) { - result.browserSize = cst.sizeMapping[result.pdfOptions.pageSize] - } else if (body.pageSize && isPositiveNumeric(body.pageSize.width) && - isPositiveNumeric(body.pageSize.height)) { + var pageSize + if (result.pdfOptions.pageSize) { + pageSize = result.pdfOptions.pageSize + } else if (body.pageSize) { + pageSize = body.pageSize + } + + if (cst.sizeMapping[pageSize]) { + result.browserSize = cst.sizeMapping[pageSize] + result.pdfOptions.pageSize = pageSize + } else if (pageSize && isPositiveNumeric(pageSize.width) && + isPositiveNumeric(pageSize.height)) { result.browserSize = { - width: body.pageSize.width * cst.pixelsInMicron, - height: body.pageSize.height * cst.pixelsInMicron + width: pageSize.width * cst.pixelsInMicron, + height: pageSize.height * cst.pixelsInMicron } result.pdfOptions.pageSize = { - width: Math.ceil(body.pageSize.width), - height: Math.ceil(body.pageSize.height) + width: Math.ceil(pageSize.width), + height: Math.ceil(pageSize.height) } } else { return errorOut( @@ -57,6 +65,10 @@ function parse (body, req, opts, sendToRenderer) { ) } + // BrowserWindow only accepts integer values: + result.browserSize['width'] = Math.ceil(result.browserSize['width']) + result.browserSize['height'] = Math.ceil(result.browserSize['height']) + sendToRenderer(null, result) } diff --git a/src/component/plotly-dash-preview/render.js b/src/component/plotly-dash-preview/render.js index 090cda62..bef71541 100644 --- a/src/component/plotly-dash-preview/render.js +++ b/src/component/plotly-dash-preview/render.js @@ -15,6 +15,8 @@ function render (info, opts, sendToMain) { const result = {} let createBrowserWindowOpts = info.browserSize ? info.browserSize : {} + createBrowserWindowOpts['enableLargerThanScreen'] = true + createBrowserWindowOpts['useContentSize'] = true createBrowserWindowOpts['show'] = opts.debug let win = remote.createBrowserWindow(createBrowserWindowOpts) diff --git a/test/unit/plotly-dash-preview_test.js b/test/unit/plotly-dash-preview_test.js index 30756d25..d2695f9a 100644 --- a/test/unit/plotly-dash-preview_test.js +++ b/test/unit/plotly-dash-preview_test.js @@ -2,6 +2,7 @@ const tap = require('tap') const sinon = require('sinon') const _module = require('../../src/component/plotly-dash-preview') +const constants = require('../../src/component/plotly-dash-preview/constants') const remote = require('../../src/util/remote') const { createMockWindow } = require('../common') @@ -30,49 +31,79 @@ tap.test('parse:', t => { t.end() }) }) - t.test('should error when pageSize is not given', t => { - fn({ + t.test('pageSize options:', t => { + const mock = () => ({ url: 'https://dash-app.com', selector: 'dummy' - }, {}, {}, (errorCode, result) => { - t.equal(errorCode, 400) - t.same(result.msg, 'pageSize must either be A3, A4, A5, Legal, Letter, ' + - 'Tabloid or an Object containing height and width in microns.') - t.end() }) - }) - t.test('should parse properly when pageSize is given', t => { - fn({ - url: 'https://dash-app.com', - selector: 'dummy', - pageSize: { height: 1000, width: 1000 } - }, {}, {}, (errorCode, result) => { - t.equal(errorCode, null) - - // height/width are converted from microns to pixels: - t.same(result.browserSize, { - height: 3.779527559055118, - width: 3.779527559055118 + + t.test('should error when not given', t => { + fn(mock(), {}, {}, (errorCode, result) => { + t.equal(errorCode, 400) + t.same(result.msg, 'pageSize must either be A3, A4, A5, Legal, Letter, ' + + 'Tabloid or an Object containing height and width in microns.') + t.end() }) - t.same(result.pdfOptions.pageSize, { - height: 1000, - width: 1000 + }) + + function assertEqualSize (browserSize, pageSize) { + // Browser size is always integer pixels + var bW = browserSize.width + var bH = browserSize.height + t.ok(Number.isInteger(bW), 'browserSize.width is not an integer') + t.ok(Number.isInteger(bH), 'browserSize.height is not an integer') + var pW, pH + if (constants.sizeMapping[pageSize]) { + var equivalentPixelSize = constants.sizeMapping[pageSize] + pW = equivalentPixelSize.width + pH = equivalentPixelSize.height + } else { + pW = pageSize.width * constants.pixelsInMicron + pH = pageSize.height * constants.pixelsInMicron + } + // Round + pW = Math.ceil(pW) + pH = Math.ceil(pH) + t.equal(bW, pW, 'browser and page should have the same width') + t.equal(bH, pH, 'browser and page should have the same height') + } + + // Browser size and page size should be the same assuming a DPI of 96 + // to make sure plotly.js figures are appropriately sized right away for print + [ + [true, { height: 1000, width: 1000 }], + [true, 'Letter'], + [false, { height: 1000, width: 1000 }], + [false, 'Letter'] + ].forEach(arg => { + var toplevel = arg[0] + var pageSize = arg[1] + t.test(`should size window and page properly when ${toplevel ? '' : 'pdf_options.'}pageSize is given`, t => { + var body = mock() + if (toplevel) { + body.pageSize = pageSize + } else { + body.pdf_options = { pageSize: pageSize } + } + fn(body, {}, {}, (errorCode, result) => { + t.equal(errorCode, null) + t.same(result.pdfOptions.pageSize, pageSize) + assertEqualSize(result.browserSize, result.pdfOptions.pageSize) + t.end() + }) }) - t.end() }) - }) - t.test('should parse properly when pdf_options are given', t => { - fn({ - url: 'https://dash-app.com', - selector: 'dummy', - pdf_options: { pageSize: 'Letter', marginsType: 1 } - }, {}, {}, (errorCode, result) => { - t.equal(errorCode, null) - // height/width are converted to pixels from page-type: - t.same(result.browserSize, { height: 1056, width: 816 }) - t.same(result.pdfOptions, { pageSize: 'Letter', marginsType: 1 }) - t.end() + + t.test('should passthrough pdf_options', t => { + var body = mock() + body.pdf_options = { pageSize: 'Letter', marginsType: 1, crazyOptions: true } + fn(body, {}, {}, (errorCode, result) => { + t.equal(errorCode, null) + t.same(result.pdfOptions, { pageSize: 'Letter', marginsType: 1, crazyOptions: true }) + t.end() + }) }) + t.end() }) t.end()