diff --git a/examples/main.tsx b/examples/main.tsx
index db29f90c..59c47fd6 100644
--- a/examples/main.tsx
+++ b/examples/main.tsx
@@ -184,6 +184,26 @@ function GobanTestPage(): JSX.Element {
/>
+
+ Stone font scale:
+ {
+ let ss = parseFloat(ev.target.value);
+ if (!ss) {
+ ss = 1;
+ }
+ base_config.stone_font_scale = ss;
+ forceUpdate();
+ fiddler.emit("setStoneFontScale", ss);
+ }}
+ />
+
+
Top labels:
(
console.log("SSS time: ", end - start);
});
+ fiddler.on("setStoneFontScale", (ss) => {
+ const start = Date.now();
+ goban.setStoneFontScale(ss);
+ const end = Date.now();
+ console.log("SFS time: ", end - start);
+ });
+
fiddler.on("redraw", () => {
const start = Date.now();
goban.draw_top_labels = !!base_config.draw_top_labels;
diff --git a/src/Goban/Goban.ts b/src/Goban/Goban.ts
index d6e921df..c5feae9c 100644
--- a/src/Goban/Goban.ts
+++ b/src/Goban/Goban.ts
@@ -289,6 +289,15 @@ export abstract class Goban extends OGSConnectivity {
this.redraw(true);
}
}
+
+ public setStoneFontScale(new_ss: number, suppress_redraw = false): void {
+ const redraw = this.stone_font_scale !== new_ss && !suppress_redraw;
+ this.stone_font_scale = new_ss;
+ if (redraw) {
+ this.redraw(true);
+ }
+ }
+
public computeMetrics(): GobanMetrics {
if (!this.square_size || this.square_size <= 0) {
this.square_size = 12;
diff --git a/src/Goban/InteractiveBase.ts b/src/Goban/InteractiveBase.ts
index fbdd3f29..c3d88c96 100644
--- a/src/Goban/InteractiveBase.ts
+++ b/src/Goban/InteractiveBase.ts
@@ -220,6 +220,12 @@ export abstract class GobanInteractive extends GobanBase {
this.emit("review_controller_id", this.review_controller_id);
}
+ public config: GobanConfig;
+ public last_move_radius: number;
+ public circle_radius: number;
+ public square_size: number = 10;
+ public stone_font_scale: number;
+
protected __board_redraw_pen_layer_timer: any = null;
protected __clock_timer?: ReturnType;
protected __draw_state: string[][];
@@ -231,7 +237,7 @@ export abstract class GobanInteractive extends GobanBase {
protected bounded_width: number;
protected bounds: GobanBounds;
protected conditional_path: string = "";
- public config: GobanConfig;
+
protected current_cmove?: ConditionalMoveTree;
protected currently_my_cmove: boolean = false;
protected dirty_redraw: any = null; // timer
@@ -239,8 +245,7 @@ export abstract class GobanInteractive extends GobanBase {
protected display_width?: number;
protected done_loading_review: boolean = false;
protected dont_draw_last_move: boolean;
- public last_move_radius: number;
- public circle_radius: number;
+
protected edit_color?: "black" | "white";
protected errorHandler: (e: Error) => void;
protected heatmap?: NumberMatrix;
@@ -274,7 +279,6 @@ export abstract class GobanInteractive extends GobanBase {
protected shift_key_is_down: boolean;
//protected show_move_numbers: boolean;
protected show_variation_move_numbers: boolean;
- public square_size: number = 10;
protected stone_placement_enabled: boolean;
protected sendLatencyTimer?: ReturnType;
@@ -407,6 +411,7 @@ export abstract class GobanInteractive extends GobanBase {
"draw_bottom_labels" in config ? !!config.draw_bottom_labels : true;
//this.show_move_numbers = this.getShowMoveNumbers();
this.show_variation_move_numbers = this.getShowVariationMoveNumbers();
+ this.stone_font_scale = this.getStoneFontScale();
if (this.bounds.left > 0) {
this.draw_left_labels = false;
@@ -490,6 +495,13 @@ export abstract class GobanInteractive extends GobanBase {
}
return false;
}
+ // scale relative to the "OGS default"
+ protected getStoneFontScale(): number {
+ if (callbacks.getStoneFontScale) {
+ return callbacks.getStoneFontScale();
+ }
+ return 1.0;
+ }
public static getMoveTreeNumbering(): string {
if (callbacks.getMoveTreeNumbering) {
return callbacks.getMoveTreeNumbering();
diff --git a/src/Goban/SVGRenderer.ts b/src/Goban/SVGRenderer.ts
index 1d7d4f84..ec1dd234 100644
--- a/src/Goban/SVGRenderer.ts
+++ b/src/Goban/SVGRenderer.ts
@@ -1834,13 +1834,12 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
if (letter) {
letter_was_drawn = true;
draw_last_move = false;
- cell.letter(
- letter,
- text_color,
- subscript ? this.square_size * 0.4 : this.square_size * 0.5,
- transparent ? 0.6 : 1.0,
- !!subscript,
- );
+
+ let fontSize = this.square_size * 0.5 * this.stone_font_scale;
+ if (subscript) {
+ fontSize *= 0.8;
+ }
+ cell.letter(letter, text_color, fontSize, transparent ? 0.6 : 1.0, !!subscript);
} else {
cell.clearLetter();
}
@@ -1851,7 +1850,7 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
cell.subscript(
subscript,
text_color,
- this.square_size * 0.4,
+ this.square_size * 0.4 * this.stone_font_scale,
transparent ? 0.6 : 1.0,
!!letter,
!!pos.sub_triangle,
@@ -2744,19 +2743,23 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
}
}
+ console.log("letter", letter, "subscript", subscript);
+
if (letter) {
letter_was_drawn = true;
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("class", "letter");
text.setAttribute("fill", text_color);
- text.setAttribute(
- "font-size",
- subscript ? `${this.square_size * 0.4}px` : `${this.square_size * 0.5}px`,
- );
+
+ let fontSize = this.square_size * 0.5 * this.stone_font_scale;
+ if (subscript) {
+ fontSize *= 0.8;
+ }
+ text.setAttribute("font-size", `${fontSize}px`);
text.setAttribute("text-anchor", "middle");
text.setAttribute("x", cx.toString());
- let yy = cy;
- yy += this.square_size / 6;
+
+ let yy = cy + fontSize * 0.35;
if (subscript) {
yy -= this.square_size * 0.15;
}
@@ -2774,7 +2777,8 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("class", "subscript");
text.setAttribute("fill", text_color);
- text.setAttribute("font-size", `${this.square_size * 0.4}px`);
+ const fontSize = this.square_size * 0.4 * this.stone_font_scale;
+ text.setAttribute("font-size", `${fontSize}px`);
text.setAttribute("text-anchor", "middle");
text.setAttribute("x", cx.toString());
let yy = cy;
@@ -2787,6 +2791,7 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
if (pos.sub_triangle) {
yy -= this.square_size * 0.08;
}
+ yy += fontSize * 0.35;
text.setAttribute("y", yy.toString());
text.textContent = subscript;
if (transparent) {
@@ -2830,12 +2835,18 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
circ.setAttribute("class", "circle");
circ.setAttribute("fill", "none");
circ.setAttribute("stroke", symbol_color);
- circ.setAttribute("stroke-width", `${this.square_size * 0.075}px`);
+ circ.setAttribute(
+ "stroke-width",
+ `${this.square_size * 0.075 * this.stone_font_scale}px`,
+ );
circ.setAttribute("cx", cx.toString());
circ.setAttribute("cy", cy.toString());
circ.setAttribute(
"r",
- Math.max(0.1, this.square_size * this.circle_radius).toFixed(2),
+ Math.max(
+ 0.1,
+ this.square_size * this.circle_radius * this.stone_font_scale,
+ ).toFixed(2),
);
if (transparent) {
circ.setAttribute("stroke-opacity", "0.6");
@@ -2850,11 +2861,11 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
alt_marking === "triangle" ||
hover_mark === "triangle"
) {
- let scale = 1.0;
+ let scale = 1.0 * this.stone_font_scale;
let oy = 0.0;
- let line_width = this.square_size * 0.075;
+ let line_width = this.square_size * 0.075 * scale;
if (pos.sub_triangle) {
- scale = 0.5;
+ scale = 0.5 * scale;
oy = this.square_size * 0.3;
transparent = false;
line_width *= 0.5;
@@ -2886,11 +2897,14 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
draw_last_move = false;
}
if (pos.cross || hover_mark === "cross") {
- const r = Math.max(1, this.metrics.mid * 0.35);
+ const r = Math.max(1, this.metrics.mid * 0.35 * this.stone_font_scale);
const cross = document.createElementNS("http://www.w3.org/2000/svg", "path");
cross.setAttribute("class", "cross");
cross.setAttribute("stroke", symbol_color);
- cross.setAttribute("stroke-width", `${this.square_size * 0.075}px`);
+ cross.setAttribute(
+ "stroke-width",
+ `${this.square_size * 0.075 * this.stone_font_scale}px`,
+ );
cross.setAttribute("fill", "none");
cross.setAttribute(
"d",
@@ -2916,8 +2930,11 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
square.setAttribute("class", "square");
square.setAttribute("fill", "none");
square.setAttribute("stroke", symbol_color);
- square.setAttribute("stroke-width", `${this.square_size * 0.075}px`);
- const r = Math.max(1, this.metrics.mid * 0.4);
+ square.setAttribute(
+ "stroke-width",
+ `${this.square_size * 0.075 * this.stone_font_scale}px`,
+ );
+ const r = Math.max(1, this.metrics.mid * 0.4 * this.stone_font_scale);
square.setAttribute("x", (cx - r).toFixed(2));
square.setAttribute("y", (cy - r).toFixed(2));
square.setAttribute("width", (r * 2).toFixed(2));
@@ -2955,14 +2972,18 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
if (this.submit_move) {
draw_last_move = false;
- const r = Math.max(1, this.metrics.mid * 0.35) * 0.8;
+ const r =
+ Math.max(1, this.metrics.mid * 0.35) * 0.8 * this.stone_font_scale;
const cross = document.createElementNS(
"http://www.w3.org/2000/svg",
"path",
);
cross.setAttribute("class", "last-move");
cross.setAttribute("stroke", color);
- cross.setAttribute("stroke-width", `${this.square_size * 0.075}px`);
+ cross.setAttribute(
+ "stroke-width",
+ `${this.square_size * 0.075 * this.stone_font_scale}px`,
+ );
cross.setAttribute("fill", "none");
cross.setAttribute("opacity", this.last_move_opacity.toString());
cross.setAttribute(
@@ -2990,7 +3011,10 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
);
text.setAttribute("class", "letter");
text.setAttribute("fill", color);
- text.setAttribute("font-size", `${this.square_size * 0.5}px`);
+ text.setAttribute(
+ "font-size",
+ `${this.square_size * 0.5 * this.stone_font_scale}px`,
+ );
text.setAttribute("text-anchor", "middle");
text.setAttribute("x", cx.toString());
let yy = cy;
@@ -3008,11 +3032,14 @@ export class SVGRenderer extends Goban implements GobanSVGInterface {
r = this.square_size * 0.3;
}
- r = Math.max(0.1, r);
+ r = Math.max(0.1, r * this.stone_font_scale);
circ.setAttribute("class", "last-move");
circ.setAttribute("fill", "none");
circ.setAttribute("stroke", color);
- circ.setAttribute("stroke-width", `${this.square_size * 0.075}px`);
+ circ.setAttribute(
+ "stroke-width",
+ `${this.square_size * 0.075 * this.stone_font_scale}px`,
+ );
circ.setAttribute("cx", cx.toString());
circ.setAttribute("cy", cy.toString());
circ.setAttribute("opacity", this.last_move_opacity.toString());
@@ -5246,11 +5273,13 @@ class GCell {
text.setAttribute("font-size", `${font_size}px`);
text.setAttribute("text-anchor", "middle");
text.setAttribute("x", cx.toString());
- let yy = cy;
- yy += ss / 6;
+
+ // Adjust the y-coordinate to account for vertical centering based on the font size
+ let yy = cy + font_size * 0.35;
if (room_for_subscript) {
yy -= ss * 0.15;
}
+
text.setAttribute("y", yy.toString());
text.textContent = letter;
if (opacity < 1) {
@@ -5319,21 +5348,25 @@ class GCell {
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("class", "subscript");
text.setAttribute("fill", color);
+
text.setAttribute("font-size", `${font_size}px`);
text.setAttribute("text-anchor", "middle");
text.setAttribute("x", cx.toString());
- let yy = cy;
- yy -= ss / 6;
+
+ // Adjust baseline based on the provided font size
+ let yy = cy + font_size * 0.3;
+
if (room_for_letter) {
- yy += ss * 0.6;
- } else {
- yy += ss * 0.31;
+ yy += ss * 0.3;
}
+
if (room_for_sub_triangle) {
yy -= ss * 0.08;
}
+
text.setAttribute("y", yy.toString());
text.textContent = subscript;
+
if (opacity < 1) {
text.setAttribute("fill-opacity", opacity.toString());
}
@@ -5382,7 +5415,7 @@ class GCell {
const mid = this.renderer.metrics.mid;
const cx = mid;
const cy = mid;
- const ss = this.renderer.square_size;
+ const ss = this.renderer.square_size * this.renderer.stone_font_scale;
const circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circ.setAttribute("class", "circle");
@@ -5391,7 +5424,13 @@ class GCell {
circ.setAttribute("stroke-width", `${ss * 0.075}px`);
circ.setAttribute("cx", cx.toString());
circ.setAttribute("cy", cy.toString());
- circ.setAttribute("r", Math.max(0.1, ss * this.renderer.circle_radius).toFixed(2));
+ circ.setAttribute(
+ "r",
+ Math.max(
+ 0.1,
+ ss * this.renderer.circle_radius * this.renderer.stone_font_scale,
+ ).toFixed(2),
+ );
if (opacity < 1.0) {
circ.setAttribute("stroke-opacity", opacity.toString());
}
@@ -5433,11 +5472,11 @@ class GCell {
const cy = mid;
const ss = this.renderer.square_size;
- let scale = 1.0;
+ let scale = 1.0 * this.renderer.stone_font_scale;
let oy = 0.0;
- let line_width = ss * 0.075;
+ let line_width = ss * 0.075 * scale;
if (as_subscript) {
- scale = 0.5;
+ scale = 0.5 * scale;
oy = ss * 0.3;
opacity = 1.0;
line_width *= 0.5;
@@ -5505,8 +5544,8 @@ class GCell {
const mid = this.renderer.metrics.mid;
const cx = mid;
const cy = mid;
- const ss = this.renderer.square_size;
- const r = Math.max(1, mid * 0.35);
+ const ss = this.renderer.square_size * this.renderer.stone_font_scale;
+ const r = Math.max(1, mid * 0.35 * this.renderer.stone_font_scale);
const cross = document.createElementNS("http://www.w3.org/2000/svg", "path");
cross.setAttribute("class", "cross");
@@ -5562,8 +5601,8 @@ class GCell {
const mid = this.renderer.metrics.mid;
const cx = mid;
const cy = mid;
- const ss = this.renderer.square_size;
- const r = Math.max(1, mid * 0.4);
+ const ss = this.renderer.square_size * this.renderer.stone_font_scale;
+ const r = Math.max(1, mid * 0.4 * this.renderer.stone_font_scale);
const square = document.createElementNS("http://www.w3.org/2000/svg", "rect");
square.setAttribute("class", "square");
@@ -5616,12 +5655,12 @@ class GCell {
const mid = this.renderer.metrics.mid;
const cx = mid;
const cy = mid;
- const ss = this.renderer.square_size;
+ const ss = this.renderer.square_size * this.renderer.stone_font_scale;
switch (symbol) {
case "+":
{
- const r = Math.max(1, mid * 0.35) * 0.8;
+ const r = Math.max(1, mid * 0.35) * 0.8 * this.renderer.stone_font_scale;
const cross = document.createElementNS("http://www.w3.org/2000/svg", "path");
cross.setAttribute("class", "last-move");
cross.setAttribute("stroke", color);
@@ -5662,7 +5701,7 @@ class GCell {
case "o":
{
const circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
- let r = ss * this.renderer.last_move_radius;
+ let r = ss * this.renderer.last_move_radius * this.renderer.stone_font_scale;
if (ss) {
r = ss * 0.3;
}
@@ -5718,7 +5757,7 @@ class GCell {
const mid = this.renderer.metrics.mid;
const cx = mid;
const cy = mid;
- const ss = this.renderer.square_size;
+ const ss = this.renderer.square_size * this.renderer.stone_font_scale;
const r = ss * 0.2 * Math.abs(estimate);
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
diff --git a/src/Goban/callbacks.ts b/src/Goban/callbacks.ts
index b570d264..8ff2857c 100644
--- a/src/Goban/callbacks.ts
+++ b/src/Goban/callbacks.ts
@@ -27,6 +27,7 @@ export interface GobanCallbacks {
getLocation?: () => string;
// getShowMoveNumbers?: () => boolean;
getShowVariationMoveNumbers?: () => boolean;
+ getStoneFontScale?: () => number;
getShowUndoRequestIndicator?: () => boolean;
getMoveTreeNumbering?: () => "move-coordinates" | "none" | "move-number";
getCDNReleaseBase?: () => string;
diff --git a/src/GobanBase.ts b/src/GobanBase.ts
index cc160e02..e0f46ece 100644
--- a/src/GobanBase.ts
+++ b/src/GobanBase.ts
@@ -96,6 +96,7 @@ export interface GobanConfig extends GobanEngineConfig, PuzzleConfig {
one_click_submit?: boolean;
double_click_submit?: boolean;
variation_stone_opacity?: number;
+ stone_font_scale?: number;
//
auth?: string;
diff --git a/webpack.config.js b/webpack.config.js
index ca7fa19f..cc6dadf5 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -6,6 +6,8 @@ const webpack = require("webpack");
const pkg = require("./package.json");
const TerserPlugin = require("terser-webpack-plugin");
+const DEV_SERVER_PORT = 9000;
+
let plugins = [];
plugins.push(
@@ -162,7 +164,7 @@ module.exports = (env, argv) => {
devServer: {
compress: true,
host: "0.0.0.0",
- port: 9000,
+ port: DEV_SERVER_PORT,
allowedHosts: ["all"],
static: [
@@ -182,6 +184,14 @@ module.exports = (env, argv) => {
writeToDisk: true,
},
hot: false,
+ setupMiddlewares: (middlewares, devServer) => {
+ console.log("------------------");
+ console.log("Demo board is served at http://localhost:" + DEV_SERVER_PORT);
+
+ console.log("Check your changes there!");
+ console.log("------------------");
+ return middlewares;
+ },
},
}),
];