mainwindows文件修正

This commit is contained in:
shuaikangzhou
2023-05-22 11:32:12 +08:00
parent 01f16c1168
commit 64c1cb7c49
21 changed files with 18716 additions and 0 deletions

View File

@@ -0,0 +1 @@
from .snapshot import make_snapshot

View File

@@ -0,0 +1,62 @@
from ..types import Optional, Sequence, Union
class HTML:
def __init__(self, data: Optional[str] = None):
self.data = data
def _repr_html_(self):
return self.data
def __html__(self):
return self._repr_html_()
_lib_t1 = """new Promise(function(resolve, reject) {
var script = document.createElement("script");
script.onload = resolve;
script.onerror = reject;
script.src = "%s";
document.head.appendChild(script);
}).then(() => {
"""
_lib_t2 = """
});"""
_css_t = """var link = document.createElement("link");
link.ref = "stylesheet";
link.type = "text/css";
link.href = "%s";
document.head.appendChild(link);
"""
class Javascript:
def __init__(
self,
data: Optional[str] = None,
lib: Optional[Union[str, Sequence]] = None,
css: Optional[Union[str, Sequence]] = None,
):
if isinstance(lib, str):
lib = [lib]
elif lib is None:
lib = []
if isinstance(css, str):
css = [css]
elif css is None:
css = []
self.lib = lib
self.css = css
self.data = data or ""
def _repr_javascript_(self):
r = ""
for c in self.css:
r += _css_t % c
for d in self.lib:
r += _lib_t1 % d
r += self.data
r += _lib_t2 * len(self.lib)
return r

121
resource/render/engine.py Normal file
View File

@@ -0,0 +1,121 @@
import os
try:
from collections.abc import Iterable
except ImportError:
from collections import Iterable
from jinja2 import Environment
from ..commons import utils
from ..datasets import EXTRA, FILENAMES
from ..globals import CurrentConfig, NotebookType
from ..types import Any, Optional
from .display import HTML, Javascript
def write_utf8_html_file(file_name: str, html_content: str):
with open(file_name, "w+", encoding="utf-8") as html_file:
html_file.write(html_content)
class RenderEngine:
def __init__(self, env: Optional[Environment] = None):
self.env = env or CurrentConfig.GLOBAL_ENV
@staticmethod
def generate_js_link(chart: Any) -> Any:
if not chart.js_host:
chart.js_host = CurrentConfig.ONLINE_HOST
links = []
for dep in chart.js_dependencies.items:
# TODO: if?
if dep.startswith("https://api.map.baidu.com"):
links.append(dep)
if dep in FILENAMES:
f, ext = FILENAMES[dep]
links.append("{}{}.{}".format(chart.js_host, f, ext))
else:
for url, files in EXTRA.items():
if dep in files:
f, ext = files[dep]
links.append("{}{}.{}".format(url, f, ext))
break
chart.dependencies = links
return chart
def render_chart_to_file(self, template_name: str, chart: Any, path: str, **kwargs):
"""
Render a chart or page to local html files.
:param chart: A Chart or Page object
:param path: The destination file which the html code write to
:param template_name: The name of template file.
"""
tpl = self.env.get_template(template_name)
html = utils.replace_placeholder(
tpl.render(chart=self.generate_js_link(chart), **kwargs)
)
write_utf8_html_file(path, html)
def render_chart_to_template(self, template_name: str, chart: Any, **kwargs) -> str:
tpl = self.env.get_template(template_name)
return utils.replace_placeholder(
tpl.render(chart=self.generate_js_link(chart), **kwargs)
)
def render_chart_to_notebook(self, template_name: str, **kwargs) -> str:
tpl = self.env.get_template(template_name)
return utils.replace_placeholder(tpl.render(**kwargs))
def render(
chart, path: str, template_name: str, env: Optional[Environment], **kwargs
) -> str:
RenderEngine(env).render_chart_to_file(
template_name=template_name, chart=chart, path=path, **kwargs
)
return os.path.abspath(path)
def render_embed(
chart, template_name: str, env: Optional[Environment], **kwargs
) -> str:
return RenderEngine(env).render_chart_to_template(
template_name=template_name, chart=chart, **kwargs
)
def render_notebook(self, notebook_template, lab_template):
instance = self if isinstance(self, Iterable) else (self,)
if CurrentConfig.NOTEBOOK_TYPE == NotebookType.JUPYTER_NOTEBOOK:
require_config = utils.produce_require_dict(self.js_dependencies, self.js_host)
return HTML(
RenderEngine().render_chart_to_notebook(
template_name=notebook_template,
charts=instance,
config_items=require_config["config_items"],
libraries=require_config["libraries"],
)
)
if CurrentConfig.NOTEBOOK_TYPE == NotebookType.JUPYTER_LAB:
return HTML(
RenderEngine().render_chart_to_notebook(
template_name=lab_template, charts=instance
)
)
if CurrentConfig.NOTEBOOK_TYPE == NotebookType.NTERACT:
return HTML(self.render_embed())
if CurrentConfig.NOTEBOOK_TYPE == NotebookType.ZEPPELIN:
print("%html " + self.render_embed())
def load_javascript(chart):
scripts = []
for dep in chart.js_dependencies.items:
f, ext = FILENAMES[dep]
scripts.append("{}{}.{}".format(CurrentConfig.ONLINE_HOST, f, ext))
return Javascript(lib=scripts)

View File

@@ -0,0 +1,99 @@
import base64
import codecs
import logging
import os
from io import BytesIO
from ..types import Any
logger = logging.getLogger(__name__)
PNG_FORMAT = "png"
JPG_FORMAT = "jpeg"
GIF_FORMAT = "gif"
PDF_FORMAT = "pdf"
SVG_FORMAT = "svg"
EPS_FORMAT = "eps"
B64_FORMAT = "base64"
def make_snapshot(
engine: Any,
file_name: str,
output_name: str,
delay: float = 2,
pixel_ratio: int = 2,
is_remove_html: bool = False,
**kwargs,
):
logger.info("Generating file ...")
file_type = output_name.split(".")[-1]
content = engine.make_snapshot(
html_path=file_name,
file_type=file_type,
delay=delay,
pixel_ratio=pixel_ratio,
**kwargs,
)
if file_type in [SVG_FORMAT, B64_FORMAT]:
save_as_text(content, output_name)
else:
# pdf, gif, png, jpeg
content_array = content.split(",")
if len(content_array) != 2:
raise OSError(content_array)
image_data = decode_base64(content_array[1])
if file_type in [PDF_FORMAT, GIF_FORMAT, EPS_FORMAT]:
save_as(image_data, output_name, file_type)
elif file_type in [PNG_FORMAT, JPG_FORMAT]:
save_as_png(image_data, output_name)
else:
raise TypeError(f"Not supported file type '{file_type}'")
if "/" not in output_name:
output_name = os.path.join(os.getcwd(), output_name)
if is_remove_html and not file_name.startswith("http"):
os.unlink(file_name)
logger.info(f"File saved in {output_name}")
def decode_base64(data: str) -> bytes:
"""Decode base64, padding being optional.
:param data: Base64 data as an ASCII byte string
:returns: The decoded byte string.
"""
missing_padding = len(data) % 4
if missing_padding != 0:
data += "=" * (4 - missing_padding)
return base64.decodebytes(data.encode("utf-8"))
def save_as_png(image_data: bytes, output_name: str):
with open(output_name, "wb") as f:
f.write(image_data)
def save_as_text(image_data: str, output_name: str):
with codecs.open(output_name, "w", encoding="utf-8") as f:
f.write(image_data)
def save_as(image_data: bytes, output_name: str, file_type: str):
try:
from PIL import Image
m = Image.open(BytesIO(image_data))
m.load()
color = (255, 255, 255)
b = Image.new("RGB", m.size, color)
# BUG for Mac:
# b.paste(m, mask=m.split()[3])
b.paste(m)
b.save(output_name, file_type, quality=100)
except ModuleNotFoundError:
raise Exception(f"Please install PIL for {file_type} image type")

View File

@@ -0,0 +1,13 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ chart.page_title }}</title>
</head>
<body>
{{ macro.gen_components_content(chart) }}
</body>
</html>

View File

@@ -0,0 +1,231 @@
{%- macro render_chart_content(c) -%}
<div id="{{ c.chart_id }}" class="chart-container" style="width:{{ c.width }}; height:{{ c.height }}; {{ c.horizontal_center }}"></div>
{% if c._geo_json_name and c._geo_json %}
<script>
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports', 'echarts'], factory);
} else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
// CommonJS
factory(exports, require('echarts'));
} else {
// Browser globals
factory({}, root.echarts);
}
}(this, function (exports, echarts) {
var log = function (msg) {
if (typeof console !== 'undefined') {
console && console.error && console.error(msg);
}
}
if (!echarts) {
log('ECharts is not Loaded');
return;
}
if (!echarts.registerMap) {
log('ECharts Map is not loaded')
return;
}
echarts.registerMap('{{ c._geo_json_name }}', {{ c._geo_json }});
}));
</script>
{% endif %}
<script>
{% if c._is_tab_chart %}
document.getElementById('{{ c.chart_id }}').style.width = document.getElementById('{{ c.chart_id }}').parentNode.clientWidth + 'px';
{% endif %}
var chart_{{ c.chart_id }} = echarts.init(
document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}'});
{% for js in c.js_functions.items %}
{{ js }}
{% endfor %}
var option_{{ c.chart_id }} = {{ c.json_contents }};
chart_{{ c.chart_id }}.setOption(option_{{ c.chart_id }});
{% if c._is_geo_chart %}
var bmap = chart_{{ c.chart_id }}.getModel().getComponent('bmap').getBMap();
{% if c.bmap_js_functions %}
{% for fn in c.bmap_js_functions.items %}
{{ fn }}
{% endfor %}
{% endif %}
{% endif %}
{% if c.width.endswith('%') %}
window.addEventListener('resize', function(){
chart_{{ c.chart_id }}.resize();
})
{% endif %}
</script>
{%- endmacro %}
{%- macro render_notebook_charts(charts, libraries) -%}
<script>
require([{{ libraries | join(', ') }}], function(echarts) {
{% for c in charts %}
{% if c._component_type not in ("table", "image") %}
var chart_{{ c.chart_id }} = echarts.init(
document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}'});
{% for js in c.js_functions.items %}
{{ js }}
{% endfor %}
var option_{{ c.chart_id }} = {{ c.json_contents }};
chart_{{ c.chart_id }}.setOption(option_{{ c.chart_id }});
{% if c._is_geo_chart %}
var bmap = chart_{{ c.chart_id }}.getModel().getComponent('bmap').getBMap();
bmap.addControl(new BMap.MapTypeControl());
{% endif %}
{% endif %}
{% endfor %}
});
</script>
{%- endmacro %}
{%- macro render_chart_dependencies(c) -%}
{% for dep in c.dependencies %}
<script type="text/javascript" src="{{ dep }}"></script>
{% endfor %}
{%- endmacro %}
{%- macro render_chart_css(c) -%}
{% for dep in c.css_libs %}
<link rel="stylesheet" href="{{ dep }}">
{% endfor %}
{%- endmacro %}
{%- macro display_tablinks(chart) -%}
<div class="tab">
{% for c in chart %}
<button class="tablinks" onclick="showChart(event, '{{ c.chart_id }}')">{{ c.tab_name }}</button>
{% endfor %}
</div>
{%- endmacro %}
{%- macro switch_tabs() -%}
<script>
(function() {
containers = document.getElementsByClassName("chart-container");
if(containers.length > 0) {
containers[0].style.display = "block";
}
})()
function showChart(evt, chartID) {
let containers = document.getElementsByClassName("chart-container");
for (let i = 0; i < containers.length; i++) {
containers[i].style.display = "none";
}
let tablinks = document.getElementsByClassName("tablinks");
for (let i = 0; i < tablinks.length; i++) {
tablinks[i].className = "tablinks";
}
document.getElementById(chartID).style.display = "block";
evt.currentTarget.className += " active";
}
</script>
{%- endmacro %}
{%- macro generate_tab_css() %}
<style>
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 12px 16px;
transition: 0.3s;
}
.tab button:hover {
background-color: #ddd;
}
.tab button.active {
background-color: #ccc;
}
.chart-container {
display: block;
}
.chart-container:nth-child(n+2) {
display: none;
}
</style>
{%- endmacro %}
{%- macro gen_components_content(chart) %}
{% if chart._component_type == "table" %}
<style>
.fl-table {
margin: 20px;
border-radius: 5px;
font-size: 12px;
border: none;
border-collapse: collapse;
max-width: 100%;
white-space: nowrap;
word-break: keep-all;
}
.fl-table th {
text-align: left;
font-size: 20px;
}
.fl-table tr {
display: table-row;
vertical-align: inherit;
border-color: inherit;
}
.fl-table tr:hover td {
background: #00d1b2;
color: #F8F8F8;
}
.fl-table td, .fl-table th {
border-style: none;
border-top: 1px solid #dbdbdb;
border-left: 1px solid #dbdbdb;
border-bottom: 3px solid #dbdbdb;
border-right: 1px solid #dbdbdb;
padding: .5em .55em;
font-size: 15px;
}
.fl-table td {
border-style: none;
font-size: 15px;
vertical-align: center;
border-bottom: 1px solid #dbdbdb;
border-left: 1px solid #dbdbdb;
border-right: 1px solid #dbdbdb;
height: 30px;
}
.fl-table tr:nth-child(even) {
background: #F8F8F8;
}
</style>
<div id="{{ chart.chart_id }}" class="chart-container" style="">
<p class="title" {{ chart.title_opts.title_style }}> {{ chart.title_opts.title }}</p>
<p class="subtitle" {{ chart.title_opts.subtitle_style }}> {{ chart.title_opts.subtitle }}</p>
{{ chart.html_content }}
</div>
{% elif chart._component_type == "image" %}
<div id="{{ chart.chart_id }}" class="chart-container" style="">
<p class="title" {{ chart.title_opts.title_style }}> {{ chart.title_opts.title }}</p>
<p class="subtitle" {{ chart.title_opts.subtitle_style }}> {{ chart.title_opts.subtitle }}</p>
<img {{ chart.html_content }}/>
</div>
{% endif %}
{%- endmacro %}

View File

@@ -0,0 +1,5 @@
{% import 'macro' as macro %}
{% for chart in charts %}
{{ macro.gen_components_content(chart) }}
{% endfor %}

View File

@@ -0,0 +1,49 @@
<script>
require.config({
paths: {
{{ config_items | join(', ') }}
}
});
</script>
{% for chart in charts %}
<div id="{{ chart.chart_id }}" style="width:{{ chart.width }}; height:{{ chart.height }};"></div>
{% endfor %}
<script>
require([{{ libraries | join(', ') }}], function(echarts) {
{% for c in charts %}
var canvas_{{ c.chart_id }} = document.createElement('canvas');
var mapChart_{{ c.chart_id }} = echarts.init(
canvas_{{ c.chart_id }}, '{{ c.theme }}', {width: 4096, height: 2048, renderer: '{{ c.renderer }}'});
var mapOption_{{ c.chart_id }} = {{ c.json_contents }};
mapChart_{{ c.chart_id }}.setOption(mapOption_{{ c.chart_id }});
var chart_{{ c.chart_id }} = echarts.init(
document.getElementById('{{ c.chart_id }}'), '{{ c.theme }}', {renderer: '{{ c.renderer }}'});
{% for js in c.js_functions.items %}
{{ js }}
{% endfor %}
var option_{{ c.chart_id }} = {
"globe": {
"show": true,
"baseTexture": mapChart_{{ c.chart_id }},
shading: 'lambert',
light: {
ambient: {
intensity: 0.6
},
main: {
intensity: 0.2
}
}
}};
chart_{{ c.chart_id }}.setOption(option_{{ c.chart_id }});
{% endfor %}
});
</script>

View File

@@ -0,0 +1,16 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
{% for chart in charts %}
{% if chart._component_type in ("table", "image") %}
{{ macro.gen_components_content(chart) }}
{% else %}
{{ macro.render_chart_content(chart) }}
{% endif %}
{% endfor %}
</body>
</html>

View File

@@ -0,0 +1,20 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
{{ macro.generate_tab_css() }}
{{ macro.display_tablinks(charts) }}
{% for chart in charts %}
{% if chart._component_type in ("table", "image") %}
{{ macro.gen_components_content(chart) }}
{% else %}
{{ macro.render_chart_content(chart) }}
{% endif %}
{% endfor %}
{{ macro.switch_tabs() }}
</body>
</html>

View File

@@ -0,0 +1,21 @@
{% import 'macro' as macro %}
<script>
require.config({
paths: {
{{ config_items | join(', ') }}
}
});
</script>
{% for chart in charts %}
{% if chart._component_type in ("table", "image") %}
{{ macro.gen_components_content(chart) }}
{% else %}
<div id="{{ chart.chart_id }}" style="width:{{ chart.width }}; height:{{ chart.height }};"></div>
{% endif %}
{% endfor %}
{{ macro.render_notebook_charts(charts, libraries) }}

View File

@@ -0,0 +1,26 @@
{% import 'macro' as macro %}
<script>
require.config({
paths: {
{{ config_items | join(', ') }}
}
});
</script>
{{ macro.generate_tab_css() }}
{{ macro.display_tablinks(charts) }}
{% for chart in charts %}
{% if chart._component_type in ("table", "image") %}
{{ macro.gen_components_content(chart) }}
{% else %}
<div id="{{ chart.chart_id }}" class="chart-container"
style="width:{{ chart.width }}; height:{{ chart.height }};"></div>
{% endif %}
{% endfor %}
{{ macro.render_notebook_charts(charts, libraries) }}
{{ macro.switch_tabs() }}

View File

@@ -0,0 +1,13 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{{ macro.render_chart_dependencies(chart) }}
</head>
<body>
{% for c in chart %}
{{ macro.render_chart_content(c) }}
{% endfor %}
</body>
</html>

View File

@@ -0,0 +1,12 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ chart.page_title }}</title>
{{ macro.render_chart_dependencies(chart) }}
</head>
<body {% if chart.fill_bg %}style="background-color: {{ chart.bg_color }}" {% endif %}>
{{ macro.render_chart_content(chart) }}
</body>
</html>

View File

@@ -0,0 +1,42 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ chart.page_title }}</title>
{{ macro.render_chart_dependencies(chart) }}
</head>
<body>
<div id="{{ chart.chart_id }}" style="width:{{ chart.width }}; height:{{ chart.height }};"></div>
<script>
var canvas_{{ chart.chart_id }} = document.createElement('canvas');
var mapChart_{{ chart.chart_id }} = echarts.init(
canvas_{{ chart.chart_id }}, '{{ chart.theme }}', {width: 4096, height: 2048, renderer: '{{ chart.renderer }}'});
{% for js in chart.js_functions.items %}
{{ js }}
{% endfor %}
var mapOption_{{ chart.chart_id }} = {{ chart.json_contents }};
mapChart_{{ chart.chart_id }}.setOption(mapOption_{{ chart.chart_id }});
var chart_{{ chart.chart_id }} = echarts.init(
document.getElementById('{{ chart.chart_id }}'), '{{ chart.theme }}', {renderer: '{{ chart.renderer }}'});
var options_{{ chart.chart_id }} = {
"globe": {
"show": true,
"baseTexture": mapChart_{{ chart.chart_id }},
shading: 'lambert',
light: {
ambient: {
intensity: 0.6
},
main: {
intensity: 0.2
}
}
}};
chart_{{ chart.chart_id }}.setOption(options_{{ chart.chart_id }});
</script>
</body>
</html>

View File

@@ -0,0 +1,34 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ chart.page_title }}</title>
{{ macro.render_chart_dependencies(chart) }}
{{ macro.render_chart_css(chart) }}
</head>
<body {% if chart.page_border_color !='' %}style="background-color: {{ chart.page_border_color }}" {% endif %}>
<style>.box { {{ chart.layout }} } </style>
{% if chart.download_button %}
<button onclick="downloadCfg()">Save Config</button>
{% endif %}
<div class="box">
{% for c in chart %}
{% if c._component_type in ("table", "image") %}
{{ macro.gen_components_content(c) }}
{% else %}
{{ macro.render_chart_content(c) }}
{% endif %}
{% for _ in range(chart.page_interval) %}
{% if chart.remove_br is false %}<br/>{% endif %}
{% endfor %}
{% endfor %}
</div>
<script>
{% for js in chart.js_functions.items %}
{{ js }}
{% endfor %}
</script>
</body>
</html>

View File

@@ -0,0 +1,36 @@
{% import 'macro' as macro %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ chart.page_title }}</title>
{{ macro.render_chart_dependencies(chart) }}
{{ macro.render_chart_css(chart) }}
</head>
<body {% if chart.bg_color !='' %}style="background-color: {{ chart.bg_color }}" {% endif %}>
{% if chart.use_custom_tab_css is not true %}
{{ macro.generate_tab_css() }}
{% else %}
<style>{{ chart.tab_custom_css }}</style>
{% endif %}
{{ macro.display_tablinks(chart) }}
<div class="box">
{% for c in chart %}
{% if c._component_type in ("table", "image") %}
{{ macro.gen_components_content(c) }}
{% else %}
{{ macro.render_chart_content(c) }}
{% endif %}
{% endfor %}
</div>
<script>
{% for js in chart.js_functions.items %}
{{ js }}
{% endfor %}
</script>
{{ macro.switch_tabs() }}
</body>
</html>