cm-chessboard 8.9.0 → 8.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/assets/extensions/markers/markers.css +89 -45
- package/assets/extensions/markers/markers.css.map +1 -9
- package/assets/extensions/markers/markers.scss +60 -6
- package/assets/extensions/markers/markers.svg +3 -0
- package/examples/extensions/markers-extension.html +1 -1
- package/examples/extensions/right-click-annotator.html +11 -1
- package/examples/validate-moves.html +3 -0
- package/index.html +24 -13
- package/package.json +1 -1
- package/src/extensions/arrows/Arrows.js +1 -0
- package/src/extensions/markers/Markers.js +1 -0
- package/src/extensions/right-click-annotator/RightClickAnnotator.js +63 -101
package/README.md
CHANGED
|
@@ -20,8 +20,9 @@ functionality](https://shaack.com/projekte/cm-chessboard/examples/extensions/arr
|
|
|
20
20
|
|
|
21
21
|
The core of cm-chessboard is small, fast and reduced to the essentials. You can easily extend its functionality with extensions.
|
|
22
22
|
|
|
23
|
-
- [Markers Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/markers-extension.html)
|
|
24
|
-
- [
|
|
23
|
+
- [RightClickAnnotator](https://shaack.com/projekte/cm-chessboard/examples/extensions/right-click-annotator.html) ⇨ Uses [Markers Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/markers-extension.html) and [Arrows Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/arrows-extension.html) and adds the handling mouse events to draw them on the board.
|
|
24
|
+
- [Markers Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/markers-extension.html) ⇨ create markers on specific squares
|
|
25
|
+
- [Arrows Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/arrows-extension.html) ⇨ renders arrows on the chessboard
|
|
25
26
|
- [Accessibility Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/accessibility-extension.html) ⇨ makes the chessboard more accessible
|
|
26
27
|
- [PromotionDialog Extension](https://shaack.com/projekte/cm-chessboard/examples/extensions/promotion-dialog-extension.html) ⇨ shows a dialog to select the piece to promote to
|
|
27
28
|
|
|
@@ -1,47 +1,91 @@
|
|
|
1
1
|
.cm-chessboard .markers {
|
|
2
|
-
pointer-events: none;
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
2
|
+
pointer-events: none;
|
|
3
|
+
}
|
|
4
|
+
.cm-chessboard .markers .marker.marker-frame {
|
|
5
|
+
stroke: black;
|
|
6
|
+
stroke-width: 1.8px;
|
|
7
|
+
opacity: 0.5;
|
|
8
|
+
}
|
|
9
|
+
.cm-chessboard .markers .marker.marker-frame-primary, .cm-chessboard .markers .marker.marker-frame-info {
|
|
10
|
+
stroke: blue;
|
|
11
|
+
stroke-width: 1.8px;
|
|
12
|
+
opacity: 0.4;
|
|
13
|
+
}
|
|
14
|
+
.cm-chessboard .markers .marker.marker-frame-danger {
|
|
15
|
+
stroke: red;
|
|
16
|
+
stroke-width: 1.8px;
|
|
17
|
+
opacity: 0.4;
|
|
18
|
+
}
|
|
19
|
+
.cm-chessboard .markers .marker.marker-frame-warning {
|
|
20
|
+
stroke: orange;
|
|
21
|
+
stroke-width: 1.8px;
|
|
22
|
+
opacity: 0.4;
|
|
23
|
+
}
|
|
24
|
+
.cm-chessboard .markers .marker.marker-circle {
|
|
25
|
+
stroke: black;
|
|
26
|
+
stroke-width: 3px;
|
|
27
|
+
opacity: 0.3;
|
|
28
|
+
}
|
|
29
|
+
.cm-chessboard .markers .marker.marker-circle-primary {
|
|
30
|
+
stroke: blue;
|
|
31
|
+
stroke-width: 3px;
|
|
32
|
+
opacity: 0.4;
|
|
33
|
+
}
|
|
34
|
+
.cm-chessboard .markers .marker.marker-circle-info {
|
|
35
|
+
stroke: blue;
|
|
36
|
+
stroke-width: 3px;
|
|
37
|
+
opacity: 0.4;
|
|
38
|
+
}
|
|
39
|
+
.cm-chessboard .markers .marker.marker-circle-info-filled {
|
|
40
|
+
stroke: blue;
|
|
41
|
+
fill: blue;
|
|
42
|
+
stroke-width: 3px;
|
|
43
|
+
opacity: 0.4;
|
|
44
|
+
}
|
|
45
|
+
.cm-chessboard .markers .marker.marker-circle-danger {
|
|
46
|
+
stroke: red;
|
|
47
|
+
stroke-width: 3px;
|
|
48
|
+
opacity: 0.4;
|
|
49
|
+
}
|
|
50
|
+
.cm-chessboard .markers .marker.marker-circle-danger-filled {
|
|
51
|
+
stroke: red;
|
|
52
|
+
fill: red;
|
|
53
|
+
stroke-width: 3px;
|
|
54
|
+
opacity: 0.4;
|
|
55
|
+
}
|
|
56
|
+
.cm-chessboard .markers .marker.marker-circle-warning {
|
|
57
|
+
stroke: orange;
|
|
58
|
+
stroke-width: 3px;
|
|
59
|
+
opacity: 0.4;
|
|
60
|
+
}
|
|
61
|
+
.cm-chessboard .markers .marker.marker-circle-warning-filled {
|
|
62
|
+
stroke: orange;
|
|
63
|
+
fill: orange;
|
|
64
|
+
stroke-width: 3px;
|
|
65
|
+
opacity: 0.4;
|
|
66
|
+
}
|
|
67
|
+
.cm-chessboard .markers .marker.marker-circle-success {
|
|
68
|
+
stroke: green;
|
|
69
|
+
stroke-width: 3px;
|
|
70
|
+
opacity: 0.4;
|
|
71
|
+
}
|
|
72
|
+
.cm-chessboard .markers .marker.marker-circle-success-filled {
|
|
73
|
+
stroke: green;
|
|
74
|
+
fill: green;
|
|
75
|
+
stroke-width: 3px;
|
|
76
|
+
opacity: 0.4;
|
|
77
|
+
}
|
|
78
|
+
.cm-chessboard .markers .marker.marker-square {
|
|
79
|
+
fill: black;
|
|
80
|
+
opacity: 0.11;
|
|
81
|
+
}
|
|
82
|
+
.cm-chessboard .markers .marker.marker-dot {
|
|
83
|
+
fill: black;
|
|
84
|
+
opacity: 0.2;
|
|
85
|
+
}
|
|
86
|
+
.cm-chessboard .markers .marker.marker-bevel {
|
|
87
|
+
fill: black;
|
|
88
|
+
opacity: 0.2;
|
|
89
|
+
}
|
|
36
90
|
|
|
37
|
-
|
|
38
|
-
.cm-chessboard .markers .marker.marker-circle-green {
|
|
39
|
-
stroke: #2e7d32; /* green */
|
|
40
|
-
stroke-width: 3px;
|
|
41
|
-
opacity: 0.4; }
|
|
42
|
-
.cm-chessboard .markers .marker.marker-circle-orange {
|
|
43
|
-
stroke: #ff9800; /* orange */
|
|
44
|
-
stroke-width: 3px;
|
|
45
|
-
opacity: 0.4; }
|
|
46
|
-
|
|
47
|
-
/*# sourceMappingURL=markers.css.map */
|
|
91
|
+
/*# sourceMappingURL=markers.css.map */
|
|
@@ -1,9 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"file": "markers.css",
|
|
4
|
-
"sources": [
|
|
5
|
-
"markers.scss"
|
|
6
|
-
],
|
|
7
|
-
"names": [],
|
|
8
|
-
"mappings": "AAIA,AACE,cADY,CACZ,QAAQ,CAAC;EACP,cAAc,EAAE,IAAI,GAuDrB;EAzDH,AAKM,cALQ,CACZ,QAAQ,CAGN,OAAO,AACJ,aAAa,CAAC;IACb,MAAM,EAVC,OAAO;IAWd,YAAY,EAAE,KAAK;IACnB,OAAO,EAAE,GAAG,GACb;EATP,AAWM,cAXQ,CACZ,QAAQ,CAGN,OAAO,AAOJ,qBAAqB,CAAC;IACrB,MAAM,EAfS,OAAO;IAgBtB,YAAY,EAAE,KAAK;IACnB,OAAO,EAAE,GAAG,GACb;EAfP,AAiBM,cAjBQ,CACZ,QAAQ,CAGN,OAAO,AAaJ,oBAAoB,CAAC;IACpB,MAAM,EApBQ,OAAO;IAqBrB,YAAY,EAAE,KAAK;IACnB,OAAO,EAAE,GAAG,GACb;EArBP,AAuBM,cAvBQ,CACZ,QAAQ,CAGN,OAAO,AAmBJ,cAAc,CAAC;IACd,MAAM,EA5BC,OAAO;IA6Bd,YAAY,EAAE,GAAG;IACjB,OAAO,EAAE,GAAG,GACb;EA3BP,AA6BM,cA7BQ,CACZ,QAAQ,CAGN,OAAO,AAyBJ,sBAAsB,CAAC;IACtB,MAAM,EAjCS,OAAO;IAkCtB,YAAY,EAAE,GAAG;IACjB,OAAO,EAAE,GAAG,GACb;EAjCP,AAmCM,cAnCQ,CACZ,QAAQ,CAGN,OAAO,AA+BJ,qBAAqB,CAAC;IACrB,MAAM,EAtCQ,OAAO;IAuCrB,YAAY,EAAE,GAAG;IACjB,OAAO,EAAE,GAAG,GACb;EAvCP,AAyCM,cAzCQ,CACZ,QAAQ,CAGN,OAAO,AAqCJ,cAAc,CAAC;IACd,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,IAAI,GACd;EA5CP,AA8CM,cA9CQ,CACZ,QAAQ,CAGN,OAAO,AA0CJ,WAAW,CAAC;IACX,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,GAAG,GACb;EAjDP,AAmDM,cAnDQ,CACZ,QAAQ,CAGN,OAAO,AA+CJ,aAAa,CAAC;IACb,IAAI,EAAE,KAAK;IACX,OAAO,EAAE,GAAG,GACb"
|
|
9
|
-
}
|
|
1
|
+
{"version":3,"sourceRoot":"","sources":["markers.scss"],"names":[],"mappings":"AAOE;EACE;;AAGE;EACE,QAZO;EAaP;EACA;;AAGF;EACE,QAjBY;EAkBZ;EACA;;AAGF;EACE,QAtBc;EAuBd;EACA;;AAGF;EACE,QA3Be;EA4Bf;EACA;;AAGF;EACE,QApCO;EAqCP;EACA;;AAGF;EACE,QAzCY;EA0CZ;EACA;;AAGF;EACE,QA/CY;EAgDZ;EACA;;AAGF;EACE,QArDY;EAsDZ,MAtDY;EAuDZ;EACA;;AAGF;EACE,QA3Dc;EA4Dd;EACA;;AAGF;EACE,QAjEc;EAkEd,MAlEc;EAmEd;EACA;;AAGF;EACE,QAvEe;EAwEf;EACA;;AAGF;EACE,QA7Ee;EA8Ef,MA9Ee;EA+Ef;EACA;;AAGF;EACE,QAnFe;EAoFf;EACA;;AAGF;EACE,QAzFe;EA0Ff,MA1Fe;EA2Ff;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA","file":"markers.css"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
$marker-color:
|
|
2
|
-
$marker-color-
|
|
3
|
-
$marker-color-danger:
|
|
1
|
+
$marker-color: black;
|
|
2
|
+
$marker-color-info: blue;
|
|
3
|
+
$marker-color-danger: red;
|
|
4
|
+
$marker-color-warning: orange;
|
|
5
|
+
$marker-color-success: green;
|
|
4
6
|
|
|
5
7
|
.cm-chessboard {
|
|
6
8
|
.markers {
|
|
@@ -13,8 +15,8 @@ $marker-color-danger: #aa0000;
|
|
|
13
15
|
opacity: 0.5;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
&.marker-frame-primary {
|
|
17
|
-
stroke: $marker-color-
|
|
18
|
+
&.marker-frame-primary, &.marker-frame-info {
|
|
19
|
+
stroke: $marker-color-info;
|
|
18
20
|
stroke-width: 1.8px;
|
|
19
21
|
opacity: 0.4;
|
|
20
22
|
}
|
|
@@ -25,6 +27,12 @@ $marker-color-danger: #aa0000;
|
|
|
25
27
|
opacity: 0.4;
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
&.marker-frame-warning {
|
|
31
|
+
stroke: $marker-color-warning;
|
|
32
|
+
stroke-width: 1.8px;
|
|
33
|
+
opacity: 0.4;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
&.marker-circle {
|
|
29
37
|
stroke: $marker-color;
|
|
30
38
|
stroke-width: 3px;
|
|
@@ -32,7 +40,20 @@ $marker-color-danger: #aa0000;
|
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
&.marker-circle-primary {
|
|
35
|
-
stroke: $marker-color-
|
|
43
|
+
stroke: $marker-color-info;
|
|
44
|
+
stroke-width: 3px;
|
|
45
|
+
opacity: 0.4;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&.marker-circle-info {
|
|
49
|
+
stroke: $marker-color-info;
|
|
50
|
+
stroke-width: 3px;
|
|
51
|
+
opacity: 0.4;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&.marker-circle-info-filled {
|
|
55
|
+
stroke: $marker-color-info;
|
|
56
|
+
fill: $marker-color-info;
|
|
36
57
|
stroke-width: 3px;
|
|
37
58
|
opacity: 0.4;
|
|
38
59
|
}
|
|
@@ -43,6 +64,39 @@ $marker-color-danger: #aa0000;
|
|
|
43
64
|
opacity: 0.4;
|
|
44
65
|
}
|
|
45
66
|
|
|
67
|
+
&.marker-circle-danger-filled {
|
|
68
|
+
stroke: $marker-color-danger;
|
|
69
|
+
fill: $marker-color-danger;
|
|
70
|
+
stroke-width: 3px;
|
|
71
|
+
opacity: 0.4;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&.marker-circle-warning {
|
|
75
|
+
stroke: $marker-color-warning;
|
|
76
|
+
stroke-width: 3px;
|
|
77
|
+
opacity: 0.4;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
&.marker-circle-warning-filled {
|
|
81
|
+
stroke: $marker-color-warning;
|
|
82
|
+
fill: $marker-color-warning;
|
|
83
|
+
stroke-width: 3px;
|
|
84
|
+
opacity: 0.4;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
&.marker-circle-success {
|
|
88
|
+
stroke: $marker-color-success;
|
|
89
|
+
stroke-width: 3px;
|
|
90
|
+
opacity: 0.4;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&.marker-circle-success-filled {
|
|
94
|
+
stroke: $marker-color-success;
|
|
95
|
+
fill: $marker-color-success;
|
|
96
|
+
stroke-width: 3px;
|
|
97
|
+
opacity: 0.4;
|
|
98
|
+
}
|
|
99
|
+
|
|
46
100
|
&.marker-square {
|
|
47
101
|
fill: black;
|
|
48
102
|
opacity: 0.11;
|
|
@@ -18,6 +18,9 @@ Author: shaack (https://shaack.com)
|
|
|
18
18
|
<g id="markerCircle" fill="#000000" fill-opacity="0">
|
|
19
19
|
<circle cx="20" cy="20" r="18"/>
|
|
20
20
|
</g>
|
|
21
|
+
<g id="markerCircleFilled">
|
|
22
|
+
<circle cx="20" cy="20" r="18"/>
|
|
23
|
+
</g>
|
|
21
24
|
<g id="markerDot">
|
|
22
25
|
<circle cx="20" cy="20" r="7"/>
|
|
23
26
|
</g>
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
return true
|
|
60
60
|
})
|
|
61
61
|
// define your own marker
|
|
62
|
-
const myOwnMarker = {class: "marker-circle-danger", slice: "
|
|
62
|
+
const myOwnMarker = {class: "marker-circle-danger-filled", slice: "markerCircleFilled"}
|
|
63
63
|
board2.context.addEventListener("contextmenu", (event) => {
|
|
64
64
|
event.preventDefault()
|
|
65
65
|
})
|
|
@@ -12,8 +12,13 @@
|
|
|
12
12
|
<body>
|
|
13
13
|
<h1><a href="../..">cm-chessboard</a></h1>
|
|
14
14
|
<h2>Example: RightClickAnnotator extension</h2>
|
|
15
|
-
<
|
|
15
|
+
<ul>
|
|
16
|
+
<li>Right-click to toggle green markers</li>
|
|
17
|
+
<li>Right-click + drag to draw green arrows</li>
|
|
18
|
+
<li>Use Alt for blue, Shift for red, Shift+Alt for orange</li>
|
|
19
|
+
</ul>
|
|
16
20
|
<div class="board" id="board"></div>
|
|
21
|
+
<button id="removeAllButton">Remove all annotations</button>
|
|
17
22
|
<script type="module">
|
|
18
23
|
import {Chessboard} from "../../src/Chessboard.js"
|
|
19
24
|
import {FEN} from "../../src/model/Position.js"
|
|
@@ -24,6 +29,11 @@
|
|
|
24
29
|
assetsUrl: "../../assets/",
|
|
25
30
|
extensions: [{class: RightClickAnnotator}]
|
|
26
31
|
})
|
|
32
|
+
|
|
33
|
+
document.getElementById("removeAllButton").addEventListener("click", (event) => {
|
|
34
|
+
board.removeArrows()
|
|
35
|
+
board.removeMarkers()
|
|
36
|
+
})
|
|
27
37
|
</script>
|
|
28
38
|
</body>
|
|
29
39
|
</html>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<link rel="stylesheet" href="styles/examples.css"/>
|
|
8
8
|
<link rel="stylesheet" href="../assets/chessboard.css"/>
|
|
9
9
|
<link rel="stylesheet" href="../assets/extensions/markers/markers.css"/>
|
|
10
|
+
<link rel="stylesheet" href="../assets/extensions/arrows/arrows.css"/>
|
|
10
11
|
<link rel="stylesheet" href="../assets/extensions/promotion-dialog/promotion-dialog.css"/>
|
|
11
12
|
</head>
|
|
12
13
|
<body>
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
import {PROMOTION_DIALOG_RESULT_TYPE, PromotionDialog} from "../src/extensions/promotion-dialog/PromotionDialog.js"
|
|
23
24
|
import {Accessibility} from "../src/extensions/accessibility/Accessibility.js"
|
|
24
25
|
import {Chess} from "https://cdn.jsdelivr.net/npm/chess.mjs@1/src/chess.mjs/Chess.js"
|
|
26
|
+
import {RightClickAnnotator} from "../src/extensions/right-click-annotator/RightClickAnnotator.js";
|
|
25
27
|
|
|
26
28
|
const chess = new Chess()
|
|
27
29
|
|
|
@@ -101,6 +103,7 @@
|
|
|
101
103
|
orientation: COLOR.white,
|
|
102
104
|
extensions: [
|
|
103
105
|
{class: Markers, props: {autoMarkers: MARKER_TYPE.square}},
|
|
106
|
+
{class: RightClickAnnotator},
|
|
104
107
|
{class: PromotionDialog},
|
|
105
108
|
{class: Accessibility, props: {visuallyHidden: true}}
|
|
106
109
|
]
|
package/index.html
CHANGED
|
@@ -9,31 +9,42 @@
|
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<h1>cm-chessboard</h1>
|
|
12
|
-
<p
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
<
|
|
12
|
+
<p>A JavaScript chessboard which is</p>
|
|
13
|
+
<ul>
|
|
14
|
+
<li>lightweight and ES6 module based</li>
|
|
15
|
+
<li>responsive and SVG rendered</li>
|
|
16
|
+
<li><b>without dependencies</b> 🥳</li>
|
|
17
|
+
<li>tested and it works</li>
|
|
18
|
+
</ul>
|
|
19
|
+
|
|
20
|
+
<p>cm-chessboard is the chessboard of <b><a href="https://www.chessmail.de">chessmail.de</a></b> and is used every day by <b>thousands of players</b>.</p>
|
|
21
|
+
|
|
22
|
+
<p class="text-info">cm-chessboard is easy to use: <a href="https://github.com/shaack/cm-chessboard">Repository and documentation on GitHub</a></p>
|
|
16
23
|
<div>
|
|
17
24
|
<h2>Examples</h2>
|
|
18
25
|
<ul>
|
|
26
|
+
<li><a href="examples/extensions/right-click-annotator.html">Draw Arrows and Markers with right-click</a> 🆕🔥</li>
|
|
19
27
|
<li><a href="examples/simple-boards.html">Simple chessboards, view only</a></li>
|
|
20
28
|
<li><a href="examples/responsive-board.html">Responsive chessboard</a></li>
|
|
21
29
|
<li><a href="examples/enable-input.html">Input enabled without validation</a></li>
|
|
22
30
|
<li><a href="examples/validate-moves.html">Input enabled, with move validation and promotion dialog</a> 🔥</li>
|
|
23
31
|
<li><a href="examples/pieces-animation.html">Set different positions, with animation</a></li>
|
|
24
|
-
<li><a href="examples/extensions/markers-extension.html">Context input, mark squares and detect clicks on fields</a></li>
|
|
25
32
|
<li><a href="examples/different-styles.html">Different styles and piece sets</a> 🎨</li>
|
|
26
|
-
<li><a href="examples/pointer-events.html">Pointer events on squares</a> 🆕</li>
|
|
27
33
|
<li><a href="examples/destroy-many-boards.html">Stress test, 5000 boards created and destroyed</a> 🤓 👍</li>
|
|
28
34
|
</ul>
|
|
29
|
-
<h3>Examples
|
|
35
|
+
<h3>Examples for the shipped cm-chessboard extensions</h3>
|
|
30
36
|
<ul>
|
|
31
|
-
<li
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
<li>
|
|
38
|
+
Draw arrows and markers on the board with
|
|
39
|
+
<a href="examples/extensions/right-click-annotator.html">RightClickAnnotator extension</a> 🆕🔥
|
|
40
|
+
<ul>
|
|
41
|
+
<li><a href="examples/extensions/markers-extension.html">Markers extension</a></li>
|
|
42
|
+
<li><a href="examples/extensions/arrows-extension.html">Arrows extension</a></li>
|
|
43
|
+
</ul>
|
|
44
|
+
</li>
|
|
45
|
+
<li>Draw HTML over the board with <a href="examples/extensions/html-layer-extension.html">HTML Layer extension</a></li>
|
|
46
|
+
<li>Allow displaying a promotion dialog with <a href="examples/extensions/promotion-dialog-extension.html">PromotionDialog extension</a></li>
|
|
47
|
+
<li>Make the board accessible with screen-reader support with <a href="examples/extensions/accessibility-extension.html">Accessibility extension</a></li>
|
|
37
48
|
</ul>
|
|
38
49
|
</div>
|
|
39
50
|
<h2>Chessboard</h2>
|
package/package.json
CHANGED
|
@@ -15,6 +15,7 @@ export const MARKER_TYPE = {
|
|
|
15
15
|
circle: {class: "marker-circle", slice: "markerCircle"},
|
|
16
16
|
circlePrimary: {class: "marker-circle-primary", slice: "markerCircle"},
|
|
17
17
|
circleDanger: {class: "marker-circle-danger", slice: "markerCircle"},
|
|
18
|
+
circleDangerFilled: {class: "marker-circle-danger-filled", slice: "markerCircleFilled"},
|
|
18
19
|
square: {class: "marker-square", slice: "markerSquare"},
|
|
19
20
|
dot: {class: "marker-dot", slice: "markerDot", position: 'above'},
|
|
20
21
|
bevel: {class: "marker-bevel", slice: "markerBevel"}
|
|
@@ -10,17 +10,26 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import {Extension, EXTENSION_POINT} from "../../model/Extension.js"
|
|
12
12
|
import {Arrows} from "../arrows/Arrows.js"
|
|
13
|
-
import {Markers
|
|
13
|
+
import {Markers} from "../markers/Markers.js"
|
|
14
14
|
import {Svg} from "../../lib/Svg.js"
|
|
15
15
|
|
|
16
16
|
export const ARROW_TYPE = {
|
|
17
|
-
|
|
17
|
+
success: { class: "arrow-success"},
|
|
18
|
+
warning: { class: "arrow-warning"},
|
|
19
|
+
info: { class: "arrow-info"},
|
|
20
|
+
danger: { class: "arrow-danger"}
|
|
18
21
|
}
|
|
19
|
-
export const MARKER_TYPE = {
|
|
20
22
|
|
|
23
|
+
export const MARKER_TYPE = {
|
|
24
|
+
success: {class: "marker-circle-success", slice: "markerCircle"},
|
|
25
|
+
warning: {class: "marker-circle-warning", slice: "markerCircle"},
|
|
26
|
+
info: {class: "marker-circle-info", slice: "markerCircle"},
|
|
27
|
+
danger: {class: "marker-circle-danger", slice: "markerCircle"},
|
|
21
28
|
}
|
|
22
29
|
|
|
23
30
|
export class RightClickAnnotator extends Extension {
|
|
31
|
+
|
|
32
|
+
/** @constructor */
|
|
24
33
|
constructor(chessboard, props = {}) {
|
|
25
34
|
super(chessboard)
|
|
26
35
|
this.props = props || {}
|
|
@@ -39,7 +48,6 @@ export class RightClickAnnotator extends Extension {
|
|
|
39
48
|
this.onMouseUp = this.onMouseUp.bind(this)
|
|
40
49
|
|
|
41
50
|
this.dragStart = undefined // {square, modifiers}
|
|
42
|
-
this.previewGroup = undefined
|
|
43
51
|
this.previewActiveTo = undefined // cache last to-square for preview
|
|
44
52
|
|
|
45
53
|
this.chessboard.context.addEventListener("contextmenu", this.onContextMenu)
|
|
@@ -48,11 +56,6 @@ export class RightClickAnnotator extends Extension {
|
|
|
48
56
|
this.chessboard.context.addEventListener("mouseup", this.onMouseUp)
|
|
49
57
|
this.chessboard.context.addEventListener("mouseleave", this.onMouseUp)
|
|
50
58
|
|
|
51
|
-
// ensure preview group exists after redraws
|
|
52
|
-
this.registerExtensionPoint(EXTENSION_POINT.afterRedrawBoard, () => {
|
|
53
|
-
this.ensurePreviewGroup()
|
|
54
|
-
})
|
|
55
|
-
|
|
56
59
|
this.registerExtensionPoint(EXTENSION_POINT.destroy, () => {
|
|
57
60
|
this.chessboard.context.removeEventListener("contextmenu", this.onContextMenu)
|
|
58
61
|
this.chessboard.context.removeEventListener("mousedown", this.onMouseDown)
|
|
@@ -60,12 +63,35 @@ export class RightClickAnnotator extends Extension {
|
|
|
60
63
|
this.chessboard.context.removeEventListener("mouseup", this.onMouseUp)
|
|
61
64
|
this.chessboard.context.removeEventListener("mouseleave", this.onMouseUp)
|
|
62
65
|
})
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
|
|
67
|
+
// register public API
|
|
68
|
+
this.chessboard.getAnnotations = this.getAnnotations.bind(this.chessboard)
|
|
69
|
+
this.chessboard.setAnnotations = this.setAnnotations.bind(this.chessboard)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
getAnnotations() {
|
|
73
|
+
return {
|
|
74
|
+
arrows: this.chessboard.getArrows(),
|
|
75
|
+
markers: this.chessboard.getMarkers()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
setAnnotations(annotations) {
|
|
80
|
+
this.chessboard.removeArrows()
|
|
81
|
+
this.chessboard.removeMarkers()
|
|
82
|
+
if (annotations.arrows) {
|
|
83
|
+
for (const arrow of annotations.arrows) {
|
|
84
|
+
this.chessboard.addArrow(arrow.type, arrow.from, arrow.to)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (annotations.markers) {
|
|
88
|
+
for (const marker of annotations.markers) {
|
|
89
|
+
this.chessboard.addMarker(marker.type, marker.square)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
65
92
|
}
|
|
66
93
|
|
|
67
94
|
onContextMenu(event) {
|
|
68
|
-
// prevent default context menu on chessboard
|
|
69
95
|
event.preventDefault()
|
|
70
96
|
}
|
|
71
97
|
|
|
@@ -89,9 +115,9 @@ export class RightClickAnnotator extends Extension {
|
|
|
89
115
|
|
|
90
116
|
onMouseUp(event) {
|
|
91
117
|
// clear preview regardless of button, but only act on right-button release
|
|
118
|
+
this.removePreviewArrow()
|
|
92
119
|
const start = this.dragStart
|
|
93
120
|
this.dragStart = undefined
|
|
94
|
-
this.clearPreview()
|
|
95
121
|
if (!start || event.button !== 2) {
|
|
96
122
|
return
|
|
97
123
|
}
|
|
@@ -130,27 +156,6 @@ export class RightClickAnnotator extends Extension {
|
|
|
130
156
|
return el ? el.getAttribute("data-square") : undefined
|
|
131
157
|
}
|
|
132
158
|
|
|
133
|
-
ensurePreviewGroup() {
|
|
134
|
-
// create or reset preview group used for transient arrow drawing
|
|
135
|
-
if (!this.chessboard?.view?.markersTopLayer) {
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
if (this.previewGroup && this.previewGroup.parentNode) {
|
|
139
|
-
// keep and clear existing
|
|
140
|
-
this.clearPreview()
|
|
141
|
-
return
|
|
142
|
-
}
|
|
143
|
-
this.previewGroup = Svg.addElement(this.chessboard.view.markersTopLayer, "g", {class: "right-click-annotator-preview"})
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
clearPreview() {
|
|
147
|
-
if (!this.previewGroup) return
|
|
148
|
-
while (this.previewGroup.firstChild) {
|
|
149
|
-
this.previewGroup.removeChild(this.previewGroup.firstChild)
|
|
150
|
-
}
|
|
151
|
-
this.previewActiveTo = undefined
|
|
152
|
-
}
|
|
153
|
-
|
|
154
159
|
onMouseMove(event) {
|
|
155
160
|
if (!this.dragStart) {
|
|
156
161
|
return
|
|
@@ -159,7 +164,6 @@ export class RightClickAnnotator extends Extension {
|
|
|
159
164
|
// We rely mainly on our dragStart flag and clear on mouseup/mouseleave
|
|
160
165
|
const toSquare = this.findSquareFromEvent(event)
|
|
161
166
|
if (!toSquare || toSquare === this.dragStart.square) {
|
|
162
|
-
this.clearPreview()
|
|
163
167
|
return
|
|
164
168
|
}
|
|
165
169
|
if (this.previewActiveTo === toSquare) {
|
|
@@ -172,80 +176,38 @@ export class RightClickAnnotator extends Extension {
|
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
drawPreviewArrow(from, to, type) {
|
|
175
|
-
this.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
refX: 20,
|
|
188
|
-
refY: 20,
|
|
189
|
-
viewBox: "0 0 40 40",
|
|
190
|
-
orient: "auto",
|
|
191
|
-
class: "arrow-head",
|
|
192
|
-
})
|
|
193
|
-
const spriteUrl = this.chessboard.props.assetsCache ? "" : this.chessboard.getExtension(Arrows)?.getSpriteUrl?.() || this.chessboard.props.assetsUrl + "extensions/arrows/arrows.svg"
|
|
194
|
-
Svg.addElement(marker, "use", {href: `${spriteUrl}#${type.slice}`})
|
|
195
|
-
// Compute centers of start and end squares
|
|
196
|
-
const cx1 = ptFrom.x + view.squareWidth / 2
|
|
197
|
-
const cy1 = ptFrom.y + view.squareHeight / 2
|
|
198
|
-
const cx2 = ptTo.x + view.squareWidth / 2
|
|
199
|
-
const cy2 = ptTo.y + view.squareHeight / 2
|
|
200
|
-
|
|
201
|
-
// Offset the line so it starts/ends at the edge of an invisible circle inside each square
|
|
202
|
-
const dx = cx2 - cx1
|
|
203
|
-
const dy = cy2 - cy1
|
|
204
|
-
const len = Math.hypot(dx, dy) || 1
|
|
205
|
-
const ux = dx / len
|
|
206
|
-
const uy = dy / len
|
|
207
|
-
// get offsets from Arrows extension props to match final arrow rendering
|
|
208
|
-
const arrowsExt = this.chessboard.getExtension(Arrows)
|
|
209
|
-
const offsetFrom = arrowsExt?.props?.offsetFrom ?? 0.72
|
|
210
|
-
const offsetTo = arrowsExt?.props?.offsetTo ?? 0.72
|
|
211
|
-
const halfMin = Math.min(view.squareWidth, view.squareHeight) / 2
|
|
212
|
-
const clamp01 = (v) => Math.max(0, Math.min(1, v))
|
|
213
|
-
const rFrom = halfMin * clamp01(offsetFrom)
|
|
214
|
-
const rTo = halfMin * clamp01(offsetTo)
|
|
215
|
-
const x1 = cx1 + ux * rFrom
|
|
216
|
-
const y1 = cy1 + uy * rFrom
|
|
217
|
-
const x2 = cx2 - ux * rTo
|
|
218
|
-
const y2 = cy2 - uy * rTo
|
|
219
|
-
|
|
220
|
-
const width = ((view.scalingX + view.scalingY) / 2) * 8
|
|
221
|
-
let lineFill = Svg.addElement(arrowsGroup, "line")
|
|
222
|
-
lineFill.setAttribute('x1', x1.toString())
|
|
223
|
-
lineFill.setAttribute('x2', x2.toString())
|
|
224
|
-
lineFill.setAttribute('y1', y1.toString())
|
|
225
|
-
lineFill.setAttribute('y2', y2.toString())
|
|
226
|
-
lineFill.setAttribute('class', 'arrow-line')
|
|
227
|
-
lineFill.setAttribute("marker-end", "url(#" + id + ")")
|
|
228
|
-
lineFill.setAttribute('stroke-width', width + "px")
|
|
179
|
+
if(!this.previewArrowType) {
|
|
180
|
+
this.previewArrowType = {...type}
|
|
181
|
+
}
|
|
182
|
+
this.chessboard.removeArrows(this.previewArrowType)
|
|
183
|
+
this.chessboard.addArrow(this.previewArrowType, from, to)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
removePreviewArrow() {
|
|
187
|
+
if(this.previewArrowType) {
|
|
188
|
+
this.chessboard.removeArrows(this.previewArrowType)
|
|
189
|
+
this.previewArrowType = undefined
|
|
190
|
+
}
|
|
229
191
|
}
|
|
230
192
|
|
|
231
193
|
modifiersToColorKey(modifiers) {
|
|
232
|
-
if (modifiers.shift && modifiers.alt) return "
|
|
233
|
-
if (modifiers.shift) return "
|
|
234
|
-
if (modifiers.alt) return "
|
|
235
|
-
return "
|
|
194
|
+
if (modifiers.shift && modifiers.alt) return "warning"
|
|
195
|
+
if (modifiers.shift) return "danger"
|
|
196
|
+
if (modifiers.alt) return "info"
|
|
197
|
+
return "success"
|
|
236
198
|
}
|
|
237
199
|
|
|
238
200
|
typesForColorKey(colorKey) {
|
|
239
201
|
switch (colorKey) {
|
|
240
|
-
case "
|
|
241
|
-
return {arrowType: ARROW_TYPE.
|
|
242
|
-
case "
|
|
243
|
-
return {arrowType: ARROW_TYPE.danger, circleType: MARKER_TYPE.
|
|
244
|
-
case "
|
|
245
|
-
return {arrowType:
|
|
246
|
-
case "
|
|
202
|
+
case "info":
|
|
203
|
+
return {arrowType: ARROW_TYPE.info, circleType: MARKER_TYPE.info}
|
|
204
|
+
case "danger":
|
|
205
|
+
return {arrowType: ARROW_TYPE.danger, circleType: MARKER_TYPE.danger}
|
|
206
|
+
case "warning":
|
|
207
|
+
return {arrowType: ARROW_TYPE.warning, circleType: MARKER_TYPE.warning}
|
|
208
|
+
case "success":
|
|
247
209
|
default:
|
|
248
|
-
return {arrowType:
|
|
210
|
+
return {arrowType: ARROW_TYPE.success, circleType: MARKER_TYPE.success}
|
|
249
211
|
}
|
|
250
212
|
}
|
|
251
213
|
}
|