cm-chessboard 8.7.8 → 8.7.9
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.
|
@@ -28,4 +28,22 @@
|
|
|
28
28
|
stroke-linecap: round;
|
|
29
29
|
opacity: 0.5; }
|
|
30
30
|
|
|
31
|
+
/* custom colors for RightClickAnnotator */
|
|
32
|
+
.cm-chessboard .arrow-green .arrow-head {
|
|
33
|
+
fill: #2e7d32; /* green */
|
|
34
|
+
fill-rule: nonzero;
|
|
35
|
+
fill-opacity: 1; }
|
|
36
|
+
.cm-chessboard .arrow-green .arrow-line {
|
|
37
|
+
stroke: #2e7d32;
|
|
38
|
+
stroke-linecap: round;
|
|
39
|
+
opacity: 0.5; }
|
|
40
|
+
.cm-chessboard .arrow-orange .arrow-head {
|
|
41
|
+
fill: #ff9800; /* orange */
|
|
42
|
+
fill-rule: nonzero;
|
|
43
|
+
fill-opacity: 1; }
|
|
44
|
+
.cm-chessboard .arrow-orange .arrow-line {
|
|
45
|
+
stroke: #ff9800;
|
|
46
|
+
stroke-linecap: round;
|
|
47
|
+
opacity: 0.5; }
|
|
48
|
+
|
|
31
49
|
/*# sourceMappingURL=arrows.css.map */
|
|
@@ -34,4 +34,14 @@
|
|
|
34
34
|
fill: black;
|
|
35
35
|
opacity: 0.2; }
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
/* custom colors for RightClickAnnotator */
|
|
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 */
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>cm-chessboard</title>
|
|
6
|
+
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1.0"/>
|
|
7
|
+
<link rel="stylesheet" href="../styles/examples.css"/>
|
|
8
|
+
<link rel="stylesheet" href="../../assets/chessboard.css"/>
|
|
9
|
+
<link rel="stylesheet" href="../../assets/extensions/markers/markers.css"/>
|
|
10
|
+
<link rel="stylesheet" href="../../assets/extensions/arrows/arrows.css"/>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<h1><a href="../..">cm-chessboard</a></h1>
|
|
14
|
+
<h2>Example: RightClickAnnotator extension</h2>
|
|
15
|
+
<p>Right-click to toggle green markers. Right-click + drag to draw green arrows. Use Alt for blue, Shift for red, Shift+Alt for orange.</p>
|
|
16
|
+
<div class="board" id="board"></div>
|
|
17
|
+
<script type="module">
|
|
18
|
+
import {Chessboard} from "../../src/Chessboard.js"
|
|
19
|
+
import {FEN} from "../../src/model/Position.js"
|
|
20
|
+
import {RightClickAnnotator} from "../../src/extensions/right-click-annotator/RightClickAnnotator.js"
|
|
21
|
+
|
|
22
|
+
const board = new Chessboard(document.getElementById("board"), {
|
|
23
|
+
position: FEN.start,
|
|
24
|
+
assetsUrl: "../../assets/",
|
|
25
|
+
extensions: [{class: RightClickAnnotator}]
|
|
26
|
+
})
|
|
27
|
+
</script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
package/index.html
CHANGED
|
@@ -33,6 +33,7 @@ It works, it is cool and it is easy to use. 👍</p>
|
|
|
33
33
|
<li><a href="examples/extensions/html-layer-extension.html">HTML Layer extension</a></li>
|
|
34
34
|
<li><a href="examples/extensions/promotion-dialog-extension.html">PromotionDialog extension</a></li>
|
|
35
35
|
<li><a href="examples/extensions/accessibility-extension.html">Accessibility extension</a></li>
|
|
36
|
+
<li><a href="examples/extensions/right-click-annotator.html">RightClickAnnotator extension</a></li>
|
|
36
37
|
</ul>
|
|
37
38
|
</div>
|
|
38
39
|
<h2>Chessboard</h2>
|
package/package.json
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension: RightClickAnnotator
|
|
3
|
+
* Combines Arrows and Markers to draw/toggle arrows and circle markers with right-click + modifiers.
|
|
4
|
+
* Colors:
|
|
5
|
+
* - Green: Right-click
|
|
6
|
+
* - Blue: Alt + Right-click
|
|
7
|
+
* - Red: Shift + Right-click
|
|
8
|
+
* - Orange: Shift + Alt + Right-click
|
|
9
|
+
* Redrawing the same arrow or marker removes it.
|
|
10
|
+
*/
|
|
11
|
+
import {Extension, EXTENSION_POINT} from "../../model/Extension.js"
|
|
12
|
+
import {Arrows, ARROW_TYPE} from "../arrows/Arrows.js"
|
|
13
|
+
import {Markers, MARKER_TYPE} from "../markers/Markers.js"
|
|
14
|
+
|
|
15
|
+
// Define persistent type objects for matching (strict equality used in core extensions)
|
|
16
|
+
const ARROW_GREEN = {class: "arrow-green", slice: "arrowDefault", headSize: 7}
|
|
17
|
+
const ARROW_ORANGE = {class: "arrow-orange", slice: "arrowDefault", headSize: 7}
|
|
18
|
+
|
|
19
|
+
const CIRCLE_GREEN = {class: "marker-circle-green", slice: "markerCircle"}
|
|
20
|
+
const CIRCLE_ORANGE = {class: "marker-circle-orange", slice: "markerCircle"}
|
|
21
|
+
|
|
22
|
+
export class RightClickAnnotator extends Extension {
|
|
23
|
+
constructor(chessboard, props = {}) {
|
|
24
|
+
super(chessboard)
|
|
25
|
+
this.props = props || {}
|
|
26
|
+
|
|
27
|
+
// Ensure Arrows and Markers extensions are available
|
|
28
|
+
if (!this.chessboard.getExtension(Arrows)) {
|
|
29
|
+
this.chessboard.addExtension(Arrows)
|
|
30
|
+
}
|
|
31
|
+
if (!this.chessboard.getExtension(Markers)) {
|
|
32
|
+
this.chessboard.addExtension(Markers)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.onContextMenu = this.onContextMenu.bind(this)
|
|
36
|
+
this.onMouseDown = this.onMouseDown.bind(this)
|
|
37
|
+
this.onMouseUp = this.onMouseUp.bind(this)
|
|
38
|
+
|
|
39
|
+
this.dragStart = undefined // {square, modifiers}
|
|
40
|
+
|
|
41
|
+
this.chessboard.context.addEventListener("contextmenu", this.onContextMenu)
|
|
42
|
+
this.chessboard.context.addEventListener("mousedown", this.onMouseDown)
|
|
43
|
+
this.chessboard.context.addEventListener("mouseup", this.onMouseUp)
|
|
44
|
+
|
|
45
|
+
this.registerExtensionPoint(EXTENSION_POINT.destroy, () => {
|
|
46
|
+
this.chessboard.context.removeEventListener("contextmenu", this.onContextMenu)
|
|
47
|
+
this.chessboard.context.removeEventListener("mousedown", this.onMouseDown)
|
|
48
|
+
this.chessboard.context.removeEventListener("mouseup", this.onMouseUp)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
onContextMenu(event) {
|
|
53
|
+
// prevent default context menu on chessboard
|
|
54
|
+
event.preventDefault()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onMouseDown(event) {
|
|
58
|
+
// right button only
|
|
59
|
+
if (event.button !== 2) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
const square = this.findSquareFromEvent(event)
|
|
63
|
+
if (!square) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
this.dragStart = {
|
|
67
|
+
square,
|
|
68
|
+
modifiers: {
|
|
69
|
+
alt: event.altKey,
|
|
70
|
+
shift: event.shiftKey
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
onMouseUp(event) {
|
|
76
|
+
if (event.button !== 2) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
const start = this.dragStart
|
|
80
|
+
this.dragStart = undefined
|
|
81
|
+
if (!start) {
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
const endSquare = this.findSquareFromEvent(event) || start.square
|
|
85
|
+
const colorKey = this.modifiersToColorKey(start.modifiers)
|
|
86
|
+
const {arrowType, circleType} = this.typesForColorKey(colorKey)
|
|
87
|
+
|
|
88
|
+
if (start.square && endSquare && start.square !== endSquare) {
|
|
89
|
+
// toggle arrow
|
|
90
|
+
const existing = this.chessboard.getArrows(arrowType, start.square, endSquare)
|
|
91
|
+
if (existing && existing.length > 0) {
|
|
92
|
+
this.chessboard.removeArrows(arrowType, start.square, endSquare)
|
|
93
|
+
} else {
|
|
94
|
+
this.chessboard.addArrow(arrowType, start.square, endSquare)
|
|
95
|
+
}
|
|
96
|
+
} else if (start.square) {
|
|
97
|
+
// toggle marker on start square
|
|
98
|
+
const existingMarkers = this.chessboard.getMarkers(circleType, start.square)
|
|
99
|
+
if (existingMarkers && existingMarkers.length > 0) {
|
|
100
|
+
this.chessboard.removeMarkers(circleType, start.square)
|
|
101
|
+
} else {
|
|
102
|
+
this.chessboard.addMarker(circleType, start.square)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
findSquareFromEvent(event) {
|
|
108
|
+
const target = /** @type {HTMLElement} */(event.target)
|
|
109
|
+
if (!target) return undefined
|
|
110
|
+
if (target.getAttribute && target.getAttribute("data-square")) {
|
|
111
|
+
return target.getAttribute("data-square")
|
|
112
|
+
}
|
|
113
|
+
const el = target.closest && target.closest("[data-square]")
|
|
114
|
+
return el ? el.getAttribute("data-square") : undefined
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
modifiersToColorKey(modifiers) {
|
|
118
|
+
if (modifiers.shift && modifiers.alt) return "orange"
|
|
119
|
+
if (modifiers.shift) return "red"
|
|
120
|
+
if (modifiers.alt) return "blue"
|
|
121
|
+
return "green"
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
typesForColorKey(colorKey) {
|
|
125
|
+
switch (colorKey) {
|
|
126
|
+
case "blue":
|
|
127
|
+
return {arrowType: ARROW_TYPE.default, circleType: MARKER_TYPE.circlePrimary}
|
|
128
|
+
case "red":
|
|
129
|
+
return {arrowType: ARROW_TYPE.danger, circleType: MARKER_TYPE.circleDanger}
|
|
130
|
+
case "orange":
|
|
131
|
+
return {arrowType: ARROW_ORANGE, circleType: CIRCLE_ORANGE}
|
|
132
|
+
case "green":
|
|
133
|
+
default:
|
|
134
|
+
return {arrowType: ARROW_GREEN, circleType: CIRCLE_GREEN}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|