diff --git a/.gitignore b/.gitignore index 59bdf5854..d885dff6c 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,5 @@ site/ .yarn ui-tests/.yarn + +js/less/bqplot.tmp.less diff --git a/js/less/bqplot.less b/js/less/bqplot.less index 74b953460..aed588ba6 100644 --- a/js/less/bqplot.less +++ b/js/less/bqplot.less @@ -113,11 +113,11 @@ --bq-plotarea-background-fill: var(--jp-layout-color1); } -[data-jp-theme-light='false'] .bqplot .linkarrow { +[data-jp-theme-light='false'] .bqplot_@{version} .linkarrow { fill: var(--bq-linkarrow-fill-light); } -[data-jp-theme-light='false'] .bqplot .network .node .label { +[data-jp-theme-light='false'] .bqplot_@{version} .network .node .label { --bq-network-node-label-text-fill: #727272; } @@ -142,25 +142,25 @@ .common(); } -.bqplot { +.bqplot_@{version} { box-sizing: border-box; display: flex; width: auto; height: 480px; } -.bqplot > .svg-background { +.bqplot_@{version} > .svg-background { position: absolute; width: 100%; height: 100%; z-index: 0; } -.bqplot > canvas { +.bqplot_@{version} > canvas { position: absolute; pointer-events: none; z-index: 0; } -.bqplot > svg { +.bqplot_@{version} > svg { z-index: 0; font: 11px sans-serif; user-select: none; @@ -333,16 +333,16 @@ } } -.bqplot .toolbar_div { +.bqplot_@{version} .toolbar_div { position: absolute; transition: visibility 0.5s linear, opacity 0.5s linear; } -.bqplot_tooltip_div { +.bqplot_@{version}_tooltip_div { z-index: 1001; } -.bqplot_mark_tooltip { +.bqplot_@{version}_mark_tooltip { pointer-events: none; z-index: 1001; color: var(--bq-content-font-color); @@ -354,29 +354,29 @@ -moz-user-select: var(--bq-mark-tooltip--moz-user-select); } -.bqplot_mark_tooltip > .bqplot.figure { +.bqplot_@{version}_mark_tooltip > .bqplot_@{version}.figure { width: 427px; height: 320px; } -.bqplot_mark_tooltip .tooltiptext { +.bqplot_@{version}_mark_tooltip .tooltiptext { text-align: center; padding: 0.5em; } -.bqplot .world_map path { +.bqplot_@{version} .world_map path { stroke: var(--bq-world-map-path-stroke); stroke-width: var(--bq-world-map-path-stroke-width); fill: var(--bq-world-map-path-fill); } -.bqplot .world_map .hovered { +.bqplot_@{version} .world_map .hovered { fill: Orange; stroke: Orange; stroke-width: 2.5px; } -.bqplot .world_map #container { +.bqplot_@{version} .world_map #container { margin: 10px 10%; border: 2px solid #000; border-radius: 5px; @@ -385,52 +385,52 @@ background: #f0f8ff; } -.bqplot .world_map .graticule { +.bqplot_@{version} .world_map .graticule { fill: none; stroke: #bbb; stroke-width: 0.5px; stroke-opacity: 0.5; } -.bqplot .g_legend { +.bqplot_@{version} .g_legend { fill: none; } -.bqplot .pie polyline { +.bqplot_@{version} .pie polyline { opacity: var(--bq-pie-polyline-opacity); stroke: var(--bq-pie-polyline-stroke); stroke-width: var(--bq-pie-polyline-stroke-width); fill: var(--bq-pie-polyline-fill); } -.bqplot .pie_label { +.bqplot_@{version} .pie_label { fill: var(--bq-content-font-color); } -.bqplot .bar_label, -.bqplot .curve_label { +.bqplot_@{version} .bar_label, +.bqplot_@{version} .curve_label { fill: var(--bq-content-font-color); } -.bqplot .network .node .element { +.bqplot_@{version} .network .node .element { fill: var(--bq-network-node-element-fill); stroke: var(--bq-network-node-element-stroke); stroke-width: var(--bq-network-node-element-stroke-width); } -.bqplot .network .link { +.bqplot_@{version} .network .link { fill: var(--bq-network-link-fill); stroke: var(--bq-network-link-stroke); stroke-width: var(--bq-network-link-stroke-width); } -.bqplot .network .node .label { +.bqplot_@{version} .network .node .label { font: var(--bq-network-node-label-font); pointer-events: var(--bq-network-node-label-pointer-events); text-shadow: var(--bq-network-node-label-text-shadow); fill: var(--bq-network-node-label-text-fill); } -.bqplot .linkarrow { +.bqplot_@{version} .linkarrow { fill: var(--bq-linkarrow-fill-dark); } diff --git a/js/package.json b/js/package.json index 336cd4be1..2dbbf26cd 100644 --- a/js/package.json +++ b/js/package.json @@ -21,7 +21,7 @@ }, "scripts": { "build": "jlpm run build:css && jlpm run build:js && jlpm run build:labextension && webpack --mode=production", - "build:css": "lessc less/bqplot.less css/bqplot.css", + "build:css": "python scripts/build_css.py", "build:js": "tsc --build src", "build:labextension": "jupyter labextension build .", "watch": "npm-run-all -p watch:*", diff --git a/js/scripts/build_css.py b/js/scripts/build_css.py new file mode 100644 index 000000000..dc59f9fa6 --- /dev/null +++ b/js/scripts/build_css.py @@ -0,0 +1,37 @@ +import re +import json +import subprocess +from pathlib import Path + +# paths +root = Path(__file__).parent.parent +package_json = root / "package.json" +less_input = root / "less" / "bqplot.less" +tmp_less_input = root / "less" / "bqplot.tmp.less" +css_output = root / "css" / "bqplot.css" + +# load version from package.json +with package_json.open() as f: + pkg = json.load(f) + +version = pkg.get('version') +clean_version = re.sub(r'[^0-9A-Za-z]+', '_', version) + +with open(less_input, 'r') as fobj: + less_code = fobj.read().replace('@{version}', clean_version) + +with open(tmp_less_input, 'w') as fobj: + fobj.write(less_code) + +cmd = [ + "lessc", + str(tmp_less_input), + str(css_output), +] + +print(f"Run command {' '.join(cmd)}") + +# run lessc with modify-var +subprocess.run(cmd, check=True) + +print(f"Built CSS for bqplot version {version} {clean_version}") diff --git a/js/src/Axis.ts b/js/src/Axis.ts index e837d4343..5e0ee6fd8 100644 --- a/js/src/Axis.ts +++ b/js/src/Axis.ts @@ -285,7 +285,7 @@ export class Axis extends WidgetView { const tickLabels = this.model.get('tick_labels'); if (tickLabels && Object.keys(tickLabels).length > 0) { const formatter = (data) => { - let value = tickLabels[data]; + const value = tickLabels[data]; if (value === undefined) { return default_formatter(data); } else { @@ -855,7 +855,7 @@ export class Axis extends WidgetView { if (!(isLinearScale(this.axis_scale) || isColorScale(this.axis_scale))) { return -1; } - let ticks: any[] = this.axis.tickValues(); + const ticks: any[] = this.axis.tickValues(); // Case where all data is concentrated into one point. if (ticks.length === 1) { return 1; @@ -895,7 +895,7 @@ export class Axis extends WidgetView { if (!isDateScale(this.axis_scale)) { return; } - let ticks: any[] = this.axis.tickValues(); + const ticks: any[] = this.axis.tickValues(); // diff is the difference between ticks in milliseconds const diff = Math.abs(ticks[1] - ticks[0]); @@ -974,7 +974,7 @@ export class Axis extends WidgetView { if (!isLogScale(this.axis_scale)) { return -1; } - let ticks: any[] = this.axis.tickValues(); + const ticks: any[] = this.axis.tickValues(); const ratio = Math.abs(Math.log10(ticks[1] / ticks[0])); if (ratio >= 0.301) { @@ -1055,7 +1055,7 @@ export class Axis extends WidgetView { this.autoOffset = autoOffset; } - autoOffset: number = 0; + autoOffset = 0; axis_scale: Scale; axis: d3.Axis; d3el: d3.Selection; diff --git a/js/src/BarsModel.ts b/js/src/BarsModel.ts index b5fdf27e8..c545ceb01 100644 --- a/js/src/BarsModel.ts +++ b/js/src/BarsModel.ts @@ -155,7 +155,7 @@ export class BarsModel extends MarkModel { }; }); - let extremes = [this.baseValue, cumulativeNeg, cumulativePos]; + const extremes = [this.baseValue, cumulativeNeg, cumulativePos]; // posMax is the maximum positive value for a group of // bars. data.posMax = d3.max(extremes); diff --git a/js/src/Figure.ts b/js/src/Figure.ts index ff80ea0e3..abe18db7c 100644 --- a/js/src/Figure.ts +++ b/js/src/Figure.ts @@ -36,6 +36,12 @@ import { MarkModel } from './MarkModel'; import { Interaction } from './Interaction'; import { FigureModel } from './FigureModel'; import { Axis } from './Axis'; +import { version } from './version'; + +export const FIGURE_CSS_CLASS = `bqplot_${version.replace( + /[^0-9A-Za-z]+/g, + '_' +)}`; interface IFigureSize { width: number; @@ -53,7 +59,7 @@ export class Figure extends DOMWidgetView { this.updateDecorators(); }, 100); // Internet Explorer does not support classList for svg elements - this.el.classList.add('bqplot'); + this.el.classList.add(FIGURE_CSS_CLASS); this.el.classList.add('figure'); this.el.classList.add('jupyter-widgets'); this.change_theme(); @@ -121,12 +127,12 @@ export class Figure extends DOMWidgetView { return domSize; } - let solver = new kiwi.Solver(); - var width = new kiwi.Variable(); - var height = new kiwi.Variable(); + const solver = new kiwi.Solver(); + const width = new kiwi.Variable(); + const height = new kiwi.Variable(); // calculate padding by summing up all auto sizes + fig_margins - var padding = { top: 0, bottom: 0, left: 0, right: 0 }; + const padding = { top: 0, bottom: 0, left: 0, right: 0 }; const fig_margin = this.model.get('fig_margin'); ['top', 'bottom', 'left', 'right'].forEach((side) => { padding[side] = this.decorators[side].reduce((total, decorator) => { @@ -174,8 +180,8 @@ export class Figure extends DOMWidgetView { y - padding.top - domSize.height/2 + height/2 + padding.bottom/2 + padding.top/2 = 0 y - padding.top/2 - domSize.height/2 + height/2 + padding.bottom/2 = 0 */ - var x = new kiwi.Variable(); - var y = new kiwi.Variable(); + const x = new kiwi.Variable(); + const y = new kiwi.Variable(); solver.addConstraint( new kiwi.Constraint( new kiwi.Expression( @@ -281,7 +287,7 @@ export class Figure extends DOMWidgetView { this.tooltip_div = d3 .select(document.createElement('div')) - .attr('class', 'bqplot_tooltip_div'); + .attr('class', `${FIGURE_CSS_CLASS}_tooltip_div`); this.popper_reference = new popperreference.PositionReference({ x: 0, y: 0, @@ -1364,7 +1370,7 @@ export class Figure extends DOMWidgetView { const image = new Image(); image.onload = () => { const canvas = document.createElement('canvas'); - canvas.classList.add('bqplot'); + canvas.classList.add(FIGURE_CSS_CLASS); canvas.width = this.width * scale; canvas.height = this.height * scale; canvas.style.width = this.width.toString(); @@ -1565,12 +1571,12 @@ export class Figure extends DOMWidgetView { fig_marks: d3.Selection; fig_background: d3.Selection; fig: d3.Selection; - figure_padding_x: number = 0; - figure_padding_y: number = 0; - width: number = 0; - height: number = 0; - offsetX: number = 0; - offsetY: number = 0; + figure_padding_x = 0; + figure_padding_y = 0; + width = 0; + height = 0; + offsetX = 0; + offsetY = 0; interaction_view: Interaction; interaction: d3.Selection; mark_views: ViewList; diff --git a/js/src/Mark.ts b/js/src/Mark.ts index 9efc27937..32ea33335 100644 --- a/js/src/Mark.ts +++ b/js/src/Mark.ts @@ -25,7 +25,7 @@ import { Widget } from '@lumino/widgets'; import { d3GetEvent, getLuminoWidget } from './utils'; import * as _ from 'underscore'; import { MarkModel } from './MarkModel'; -import { Figure } from './Figure'; +import { FIGURE_CSS_CLASS, Figure } from './Figure'; import { applyStyles } from './utils'; // Check that value is defined and not null @@ -76,7 +76,7 @@ export abstract class Mark extends widgets.WidgetView { } this.tooltip_div = d3 .select(document.createElement('div')) - .attr('class', 'bqplot_mark_tooltip') + .attr('class', `${FIGURE_CSS_CLASS}_mark_tooltip`) .attr('id', 'tooltip_' + this.uuid) .style('display', 'none') .style('opacity', 0); diff --git a/js/src/MarketMap.ts b/js/src/MarketMap.ts index d54f19905..9983fe57a 100644 --- a/js/src/MarketMap.ts +++ b/js/src/MarketMap.ts @@ -30,7 +30,7 @@ import { Scale } from 'bqscales'; import * as d3 from 'd3'; // var d3 =Object.assign({}, require("d3-array"), require("d3-format"), require("d3-selection"), require("d3-selection-multi"), require("d3-shape")); -import { Figure } from './Figure'; +import { Figure, FIGURE_CSS_CLASS } from './Figure'; import { MarketMapModel } from './MarketMapModel'; import { Tooltip } from './Tooltip'; import * as popperreference from './PopperReference'; @@ -84,7 +84,7 @@ export class MarketMap extends Figure { // code for tool tip to be displayed this.tooltip_div = d3 .select(document.createElement('div')) - .attr('class', 'bqplot_mark_tooltip'); + .attr('class', `${FIGURE_CSS_CLASS}_mark_tooltip`); applyStyles(this.tooltip_div, { opacity: 0, 'pointer-events': 'none' }); const freeze_tooltip_loc = this.model.get('freeze_tooltip_location'); diff --git a/js/src/index-embed.ts b/js/src/index-embed.ts index 03ec6ee77..af130f0c2 100644 --- a/js/src/index-embed.ts +++ b/js/src/index-embed.ts @@ -13,5 +13,5 @@ * limitations under the License. */ -require('../less/bqplot.less'); +require('../less/bqplot.tmp.less'); module.exports = require('./index'); diff --git a/js/src/version.ts b/js/src/version.ts index 50ef7f311..03b3eab89 100644 --- a/js/src/version.ts +++ b/js/src/version.ts @@ -15,4 +15,5 @@ import packageJson from '../package.json'; +export const version = packageJson.version; export const semver_range = '^' + packageJson.version;