Skip to content
Merged
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
152 changes: 105 additions & 47 deletions DataPlotly/layouts/plot_layout_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,92 @@
from qgis.PyQt.QtWidgets import QGraphicsItem

from qgis.core import (
Qgis,
QgsLayoutItem,
QgsLayoutItemRegistry,
QgsLayoutItemAbstractMetadata,
QgsMessageLog,
QgsGeometry,
QgsPropertyCollection
)
from qgis.PyQt.QtWebEngineWidgets import QWebEngineView
from qgis.PyQt.QtWebEngineCore import QWebEnginePage

if Qgis.versionInt() >= 40000:
from qgis.PyQt.QtWebEngineWidgets import QWebEngineView
from qgis.PyQt.QtWebEngineCore import QWebEnginePage
else:
from qgis.PyQt.QtGui import QPalette
from qgis.PyQt.QtWebKitWidgets import QWebPage
from qgis.core import QgsNetworkAccessManager

from DataPlotly.core.plot_settings import PlotSettings
from DataPlotly.core.plot_factory import PlotFactory, FilterRegion
from DataPlotly.gui.gui_utils import GuiUtils

ITEM_TYPE = QgsLayoutItemRegistry.ItemType.PluginItem + 1337
if Qgis.versionInt() >= 40000:
ITEM_TYPE = QgsLayoutItemRegistry.ItemType.PluginItem + 1337
else:
ITEM_TYPE = QgsLayoutItemRegistry.PluginItem + 1337


if Qgis.versionInt() >= 40000:

class LoggingWebPage(QWebEnginePage):

def __init__(self, parent=None):
super().__init__(parent)

def javaScriptConsoleMessage(self, level, message, lineNumber, source):
QgsMessageLog.logMessage(f'{source}:{lineNumber} {message}', 'DataPlotly')

class LoggingWebPage(QWebEnginePage):
else:

def __init__(self, parent=None):
super().__init__(parent)
class LoggingWebPage(QWebPage):

def javaScriptConsoleMessage(self, level, message, lineNumber, source):
QgsMessageLog.logMessage(f'{source}:{lineNumber} {message}', 'DataPlotly')
def __init__(self, parent=None):
super().__init__(parent)

def javaScriptConsoleMessage(self, message, lineNumber, source):
QgsMessageLog.logMessage(f'{source}:{lineNumber} {message}', 'DataPlotly')


class PlotLayoutItem(QgsLayoutItem):

def __init__(self, layout):
super().__init__(layout)
self.setCacheMode(QGraphicsItem.CacheMode.NoCache)
if Qgis.versionInt() >= 40000:
self.setCacheMode(QGraphicsItem.CacheMode.NoCache)
else:
self.setCacheMode(QGraphicsItem.NoCache)
self.plot_settings = []
self.plot_settings.append(PlotSettings())
self.linked_map_uuid = ''
self.linked_map = None
self._loading = False
self._captured_pixmap = None

self.web_page = LoggingWebPage(self)
self.web_page.setBackgroundColor(Qt.GlobalColor.transparent)
if Qgis.versionInt() >= 40000:
self.web_page = LoggingWebPage(self)
self.web_page.setBackgroundColor(Qt.GlobalColor.transparent)

self.web_view = QWebEngineView()
self.web_view.setPage(self.web_page)
self.web_view.setAttribute(Qt.WidgetAttribute.WA_DontShowOnScreen)
self.web_view.setZoomFactor(10.0)
self.web_view.show()
self.web_view = QWebEngineView()
self.web_view.setPage(self.web_page)
self.web_view.setAttribute(Qt.WidgetAttribute.WA_DontShowOnScreen)
self.web_view.setZoomFactor(10.0)
self.web_view.show()
else:
self.web_page = LoggingWebPage(self)
self.web_page.setNetworkAccessManager(QgsNetworkAccessManager.instance())

# This makes the background transparent. (copied from QgsLayoutItemLabel)
palette = self.web_page.palette()
palette.setBrush(QPalette.Base, Qt.transparent)
self.web_page.setPalette(palette)
self.web_page.mainFrame().setZoomFactor(10.0)
self.web_page.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
self.web_page.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

self.web_page.loadFinished.connect(self.loading_html_finished)
self.html_loaded = False
self._loading = False
self._captured_pixmap = None
self.html_units_to_layout_units = self.calculate_html_units_to_layout_units()

self.sizePositionChanged.connect(self.refresh)
Expand All @@ -82,7 +119,9 @@ def calculate_html_units_to_layout_units(self):
# Hm - why is this? Something internal in Plotly which is auto-scaling the html content?
# we may need to expose this as a "scaling" setting

return 8
if Qgis.versionInt() >= 40000:
return 8
return 72

def set_linked_map(self, map):
"""
Expand Down Expand Up @@ -162,11 +201,18 @@ def draw(self, context):
painter = context.renderContext().painter()
painter.save()

if self._captured_pixmap and not self._captured_pixmap.isNull():
sx = self.rect().width() * context.renderContext().scaleFactor() / self._captured_pixmap.width()
sy = self.rect().height() * context.renderContext().scaleFactor() / self._captured_pixmap.height()
painter.scale(sx, sy)
painter.drawPixmap(0, 0, self._captured_pixmap)
if Qgis.versionInt() >= 40000:
if self._captured_pixmap and not self._captured_pixmap.isNull():
sx = self.rect().width() * context.renderContext().scaleFactor() / self._captured_pixmap.width()
sy = self.rect().height() * context.renderContext().scaleFactor() / self._captured_pixmap.height()
painter.scale(sx, sy)
painter.drawPixmap(0, 0, self._captured_pixmap)
else:
# almost a direct copy from QgsLayoutItemLabel!
painter.scale(context.renderContext().scaleFactor() / self.html_units_to_layout_units,
context.renderContext().scaleFactor() / self.html_units_to_layout_units)
self.web_page.mainFrame().render(painter)

painter.restore()

def create_plot(self):
Expand Down Expand Up @@ -213,15 +259,22 @@ def get_polygon_filter(self, index=0):
return polygon_filter, visible_features_only

def load_content(self):
import tempfile
self._loading = True
self.html_loaded = False
self.web_view.resize(QSize(int(self.rect().width()) * self.html_units_to_layout_units,
int(self.rect().height()) * self.html_units_to_layout_units))
self._tmp_file = tempfile.NamedTemporaryFile(suffix='.html', delete=False)
self._tmp_file.write(self.create_plot().encode('utf-8'))
self._tmp_file.close()
self.web_page.load(QUrl.fromLocalFile(self._tmp_file.name))

if Qgis.versionInt() >= 40000:
import tempfile
self._loading = True
self.web_view.resize(QSize(int(self.rect().width()) * self.html_units_to_layout_units,
int(self.rect().height()) * self.html_units_to_layout_units))
self._tmp_file = tempfile.NamedTemporaryFile(suffix='.html', delete=False)
self._tmp_file.write(self.create_plot().encode('utf-8'))
self._tmp_file.close()
self.web_page.load(QUrl.fromLocalFile(self._tmp_file.name))
else:
base_url = QUrl.fromLocalFile(self.layout().project().absoluteFilePath())
self.web_page.setViewportSize(QSize(int(self.rect().width()) * self.html_units_to_layout_units,
int(self.rect().height()) * self.html_units_to_layout_units))
self.web_page.mainFrame().setHtml(self.create_plot(), base_url)

def writePropertiesToElement(self, element, document, _) -> bool:
for plot_setting in self.plot_settings:
Expand Down Expand Up @@ -261,22 +314,27 @@ def finalizeRestoreFromXml(self):
self.set_linked_map(map)

def loading_html_finished(self):
self.web_page.runJavaScript("document.documentElement.style.overflow='hidden'")
self._render_retries = 0
js = """(function() {
var plot = document.querySelector('.js-plotly-plot');
if (plot && typeof Plotly !== 'undefined') {
Plotly.toImage(plot, {format: 'png', scale: 2}).then(function(dataUrl) {
window._capturedImage = dataUrl;
}).catch(function() {
if Qgis.versionInt() >= 40000:
self.web_page.runJavaScript("document.documentElement.style.overflow='hidden'")
self._render_retries = 0
js = """(function() {
var plot = document.querySelector('.js-plotly-plot');
if (plot && typeof Plotly !== 'undefined') {
Plotly.toImage(plot, {format: 'png', scale: 2}).then(function(dataUrl) {
window._capturedImage = dataUrl;
}).catch(function() {
window._capturedImage = '';
});
} else {
window._capturedImage = '';
});
} else {
window._capturedImage = '';
}
})()"""
self.web_page.runJavaScript(js)
self._wait_for_image_capture()
}
})()"""
self.web_page.runJavaScript(js)
self._wait_for_image_capture()
else:
self.html_loaded = True
self.invalidateCache()
self.update()

def _wait_for_image_capture(self):
"""Poll until Plotly.toImage() has produced the image."""
Expand Down
Loading