cm-chessboard 4.4.2 → 4.5.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.
@@ -102,35 +102,35 @@ body * {
102
102
  @include cm-chessboard-theme(
103
103
  "default", // name
104
104
  #ecdab9, #c5a076 // squares
105
- )
105
+ );
106
106
  @include cm-chessboard-theme(
107
107
  "default-contrast", // name
108
108
  #ecdab9, #c5a076, // squares
109
109
  #333, #333, // coordinates in squares (white, black)
110
- )
110
+ );
111
111
  @include cm-chessboard-theme(
112
112
  "green", // name
113
113
  #E0DDCC, #4c946a // squares
114
- )
114
+ );
115
115
  @include cm-chessboard-theme(
116
116
  "blue", // name
117
117
  #d8ecfb, #86afcf // squares
118
- )
118
+ );
119
119
  @include cm-chessboard-theme(
120
120
  "chess-club", // name
121
121
  #E6D3B1, #AF6B3F, // squares
122
122
  #AF6B3F, #E6D3B1, // coordinates in squares (white, black)
123
123
  #E6D3B1, // coordinates in frame-mode
124
124
  #692e2b, #692e2b // border and frame background
125
- )
125
+ );
126
126
  @include cm-chessboard-theme(
127
127
  "chessboard-js", // name
128
128
  #f0d9b5, #b58863, // squares
129
129
  #b58863, #f0d9b5, // coordinates in squares (white, black)
130
130
  #404040, // coordinates in frame-mode
131
131
  #404040, #f0d9b5 // border and frame background
132
- )
132
+ );
133
133
  @include cm-chessboard-theme(
134
134
  "black-and-white", // name
135
135
  #ffffff, #9c9c9c // squares
136
- )
136
+ );
@@ -4,11 +4,11 @@
4
4
  <meta charset="UTF-8">
5
5
  <title>cm-chessboard</title>
6
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/styles/cm-chessboard.css"/>
7
+ <link rel="stylesheet" href="../styles/examples.css"/>
8
+ <link rel="stylesheet" href="../../assets/styles/cm-chessboard.css"/>
9
9
  </head>
10
10
  <body>
11
- <h1><a href="../">cm-chessboard</a></h1>
11
+ <h1><a href="../..">cm-chessboard</a></h1>
12
12
  <h2>Example: Accessibility extension</h2>
13
13
  <p>
14
14
  This example shows, how the accessibility extension from cm-chessboard works.
@@ -24,17 +24,17 @@
24
24
  <li>Display these features visually hidden or not</li>
25
25
  </ul>
26
26
  <h3>The chessboard</h3>
27
- <div class="board green" id="board"></div>
27
+ <div class="board" id="board"></div>
28
28
  <button style="margin-bottom: 10px"
29
29
  onclick="window.setOrientation()">Switch Orientation
30
30
  </button>
31
31
  <script type="module">
32
- import {Chessboard} from "../src/cm-chessboard/Chessboard.js"
33
- import {Accessibility} from "../src/cm-chessboard/extensions/Accessibility.js"
32
+ import {Chessboard} from "../../src/cm-chessboard/Chessboard.js"
33
+ import {Accessibility} from "../../src/cm-chessboard/extensions/accessibility/Accessibility.js"
34
34
 
35
35
  const chessboard = new Chessboard(document.getElementById("board"), {
36
36
  position: "rn2k1r1/ppp1pp1p/3p2p1/5bn1/P7/2N2B2/1PPPPP2/2BNK1RR w Gkq - 4 11",
37
- sprite: {url: "../assets/images/chessboard-sprite.svg"},
37
+ sprite: {url: "../../assets/images/chessboard-sprite.svg"},
38
38
  // animationDuration: 0, // optional, set to 0 to disable animations
39
39
  style: {
40
40
  cssClass: "default-contrast" // make the coordinates better visible with the "default-contrast" theme
@@ -0,0 +1,44 @@
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/styles/cm-chessboard.css"/>
9
+ <link rel="stylesheet" href="../../src/cm-chessboard/extensions/arrows/assets/arrows.css"/>
10
+ </head>
11
+ <body>
12
+ <h1><a href="../..">cm-chessboard</a></h1>
13
+ <h2>Example: Arrows extension</h2>
14
+ <div class="board" id="board"></div>
15
+ <script type="module">
16
+ import {ARROW_TYPE, Arrows} from "../../src/cm-chessboard/extensions/arrows/Arrows.js"
17
+ import {Chessboard} from "../../src/cm-chessboard/Chessboard.js"
18
+
19
+ const chessboard = new Chessboard(document.getElementById("board"), {
20
+ position: "rn2k1r1/ppp1pp1p/3p2p1/5bn1/P7/2N2B2/1PPPPP2/2BNK1RR w Gkq - 4 11",
21
+ sprite: {url: "../../assets/images/chessboard-sprite.svg"},
22
+ // animationDuration: 0, // optional, set to 0 to disable animations
23
+ style: {
24
+ cssClass: "default-contrast" // make the coordinates better visible with the "default-contrast" theme
25
+ },
26
+ extensions:
27
+ [{
28
+ class: Arrows,
29
+ props: {
30
+ sprite: {
31
+ url: "../../src/cm-chessboard/extensions/arrows/assets/arrows.svg",
32
+ size: 40,
33
+ cache: true
34
+ }
35
+ }
36
+
37
+ }]
38
+ })
39
+ chessboard.addArrow("f3", "d5", ARROW_TYPE.default);
40
+ chessboard.addArrow("b8", "c6", ARROW_TYPE.default);
41
+ chessboard.addArrow("d2", "d3", ARROW_TYPE.default);
42
+ </script>
43
+ </body>
44
+ </html>
package/index.html CHANGED
@@ -29,7 +29,8 @@ It works, it is cool and it is easy to use. 👍</p>
29
29
  </ul>
30
30
  <h3>Examples of extensions</h3>
31
31
  <ul>
32
- <li><a href="examples/accessible-chessboard.html">Accessibility extension</a> 🆕</li>
32
+ <li><a href="examples/extensions/chessboard-accessibility-extension.html">Accessibility extension</a> 🆕</li>
33
+ <li><a href="examples/extensions/chessboard-arrows-extension.html">Arrows extension</a> 🆕</li>
33
34
  </ul>
34
35
  </div>
35
36
  <h2>Chessboard</h2>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cm-chessboard",
3
- "version": "4.4.2",
3
+ "version": "4.5.0",
4
4
  "description": "A JavaScript chessboard which is lightweight, ES6 module based, responsive, SVG rendered and without dependencies.",
5
5
  "keywords": [
6
6
  "chess",
@@ -87,18 +87,18 @@ export class Chessboard {
87
87
  this.props.language = "en"
88
88
  }
89
89
 
90
- this.moveTask = Promise.resolve()
91
90
  this.state = new ChessboardState()
92
91
  this.view = new ChessboardView(this)
93
92
  this.positionAnimationsQueue = new PositionAnimationsQueue(this)
94
93
  this.state.orientation = this.props.orientation
95
- this.view.redrawBoard()
96
- this.state.position = new Position(this.props.position)
97
- this.view.redrawPieces()
98
94
  // instantiate extensions
99
95
  for (const extensionData of this.props.extensions) {
100
96
  this.extensions.push(new extensionData.class(this, extensionData.props))
101
97
  }
98
+ this.view.redrawBoard()
99
+ this.state.position = new Position(this.props.position)
100
+ this.view.redrawPieces()
101
+ this.state.invokeExtensionPoints(EXTENSION_POINT.positionChanged)
102
102
  }
103
103
 
104
104
  // API //
@@ -3,9 +3,9 @@
3
3
  * Repository: https://github.com/shaack/cm-chessboard
4
4
  * License: MIT, see file 'LICENSE'
5
5
  */
6
- import {Extension, EXTENSION_POINT} from "../model/Extension.js"
7
- import {piecesTranslations, renderPieceTitle} from "../view/ChessboardView.js"
8
- import {COLOR, INPUT_EVENT_TYPE} from "../Chessboard.js"
6
+ import {Extension, EXTENSION_POINT} from "../../model/Extension.js"
7
+ import {piecesTranslations, renderPieceTitle} from "../../view/ChessboardView.js"
8
+ import {COLOR, INPUT_EVENT_TYPE} from "../../Chessboard.js"
9
9
 
10
10
  const hlTranslations = {
11
11
  de: {
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Author and copyright: Barak Michener (@barakmich)
3
+ * Repository: https://github.com/shaack/cm-chessboard
4
+ * License: MIT, see file 'LICENSE'
5
+ */
6
+
7
+ import {Extension, EXTENSION_POINT} from "../../model/Extension.js"
8
+ import {Svg} from "../../view/ChessboardView.js"
9
+
10
+ export const ARROW_TYPE = {
11
+ default: {class: "arrow-default", slice: "arrowDefault", headSize: 7},
12
+ pointy: {class: "arrow-pointy", slice: "arrowPointy", headSize: 7},
13
+ }
14
+
15
+ export class Arrows extends Extension {
16
+ constructor(chessboard, props) {
17
+ super(chessboard, props)
18
+ this.registerExtensionPoint(EXTENSION_POINT.redrawBoard, () => {
19
+ this.onRedrawBoard()
20
+ })
21
+ let defaultProps = {
22
+ sprite: {
23
+ url: "./assets/images/chessboard-arrows.svg",
24
+ size: 40,
25
+ cache: true
26
+ },
27
+ }
28
+ this.props = {}
29
+ Object.assign(this.props, defaultProps)
30
+ Object.assign(this.props, props)
31
+ if (this.props.sprite.cache) {
32
+ this.chessboard.view.cacheSpriteToDiv("chessboardArrowSpriteCache", this.props.sprite.url)
33
+ }
34
+ this.registerMethod("addArrow", this.addArrow)
35
+ this.registerMethod("getArrows", this.getArrows)
36
+ this.registerMethod("removeArrows", this.removeArrows)
37
+ this.arrowGroup = Svg.addElement(chessboard.view.piecesLayer, "g", {class: "arrows"})
38
+ this.arrows = []
39
+ }
40
+
41
+ onRedrawBoard() {
42
+ while (this.arrowGroup.firstChild) {
43
+ this.arrowGroup.removeChild(this.arrowGroup.firstChild)
44
+ }
45
+ this.arrows.forEach((arrow) => {
46
+ this.drawArrow(arrow)
47
+ })
48
+ }
49
+
50
+ drawArrow(arrow) {
51
+ const arrowsGroup = Svg.addElement(this.arrowGroup, "g")
52
+ arrowsGroup.setAttribute("data-arrow", arrow.from + arrow.to)
53
+ arrowsGroup.setAttribute("class", "arrow " + arrow.type.class)
54
+
55
+ const view = this.chessboard.view
56
+ const sqfrom = document.querySelectorAll('[data-square="' + arrow.from + '"]')[0]
57
+ const sqto = document.querySelectorAll('[data-square="' + arrow.to + '"]')[0]
58
+ const spriteUrl = this.chessboard.props.sprite.cache ? "" : this.chessboard.props.sprite.url
59
+ const defs = Svg.addElement(arrowsGroup, "defs")
60
+ const id = "arrow-" + arrow.from + arrow.to
61
+ const marker = Svg.addElement(defs, "marker", {
62
+ id: id,
63
+ markerWidth: arrow.type.headSize,
64
+ markerHeight: arrow.type.headSize,
65
+ //markerUnits: "userSpaceOnUse",
66
+ refX: 20,
67
+ refY: 20,
68
+ viewBox: "0 0 40 40",
69
+ orient: "auto",
70
+ class: "arrow-head",
71
+ })
72
+
73
+ const ignored = Svg.addElement(marker, "use", {
74
+ href: `${spriteUrl}#${arrow.type.slice}`,
75
+ })
76
+
77
+
78
+ const x1 = sqfrom.x.baseVal.value + (sqfrom.width.baseVal.value / 2)
79
+ const x2 = sqto.x.baseVal.value + (sqto.width.baseVal.value / 2)
80
+ const y1 = sqfrom.y.baseVal.value + (sqfrom.height.baseVal.value / 2)
81
+ const y2 = sqto.y.baseVal.value + (sqto.height.baseVal.value / 2)
82
+
83
+ const width = ((view.scalingX + view.scalingY) / 2) * 4
84
+ let lineFill = Svg.addElement(arrowsGroup, "line")
85
+ lineFill.setAttribute('x1', x1)
86
+ lineFill.setAttribute('x2', x2)
87
+ lineFill.setAttribute('y1', y1)
88
+ lineFill.setAttribute('y2', y2)
89
+ lineFill.setAttribute('class', 'arrow-line')
90
+ lineFill.setAttribute("marker-end", "url(#" + id + ")")
91
+ lineFill.setAttribute('stroke-width', width + "px")
92
+
93
+ }
94
+
95
+ addArrow(from, to, type) {
96
+ this.arrows.push(new Arrow(from, to, type))
97
+ this.chessboard.view.redrawBoard()
98
+ }
99
+
100
+ getArrows(from = undefined, to = undefined, type = undefined) {
101
+ let arrows = []
102
+ this.arrows.forEach((arrow) => {
103
+ if (arrow.matches(from, to, type)) {
104
+ arrows.push(arrow)
105
+ }
106
+ })
107
+ return arrows
108
+ }
109
+
110
+ removeArrows(from = undefined, to = undefined, type = undefined) {
111
+ this.arrows = this.arrows.filter((arrow) => !arrow.matches(from, to, type))
112
+ this.chessboard.view.redrawBoard()
113
+ }
114
+ }
115
+
116
+ class Arrow {
117
+ constructor(from, to, type) {
118
+ this.from = from
119
+ this.to = to
120
+ this.type = type
121
+ }
122
+
123
+ matches(from = undefined, to = undefined, type = undefined) {
124
+ if (from && from !== this.from) {
125
+ return false
126
+ }
127
+ if (to && to !== this.to) {
128
+ return false
129
+ }
130
+ return !(type && type !== this.type);
131
+ }
132
+ }
@@ -0,0 +1,11 @@
1
+ .cm-chessboard .arrows .arrow-head {
2
+ fill: blue;
3
+ fill-rule: nonzero;
4
+ fill-opacity: 1; }
5
+
6
+ .cm-chessboard .arrows .arrow-line {
7
+ stroke: blue;
8
+ stroke-linecap: round;
9
+ opacity: 0.5; }
10
+
11
+ /*# sourceMappingURL=arrows.css.map */
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "file": "arrows.css",
4
+ "sources": [
5
+ "arrows.scss"
6
+ ],
7
+ "names": [],
8
+ "mappings": "AAAA,AAEI,cAFU,CACZ,OAAO,CACL,WAAW,CAAC;EACV,IAAI,EAAE,IAAI;EACV,SAAS,EAAE,OAAO;EAClB,YAAY,EAAE,CAAC,GAChB;;AANL,AAQI,cARU,CACZ,OAAO,CAOL,WAAW,CAAC;EACV,MAAM,EAAE,IAAI;EACZ,cAAc,EAAE,KAAK;EACrB,OAAO,EAAE,GAAG,GACb"
9
+ }
@@ -0,0 +1,15 @@
1
+ .cm-chessboard {
2
+ .arrows {
3
+ .arrow-head {
4
+ fill: blue;
5
+ fill-rule: nonzero;
6
+ fill-opacity: 1;
7
+ }
8
+
9
+ .arrow-line {
10
+ stroke: blue;
11
+ stroke-linecap: round;
12
+ opacity: 0.5;
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!--
3
+
4
+ LICENSE
5
+ =======
6
+
7
+ License: Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
8
+ https://creativecommons.org/licenses/by-sa/3.0/
9
+
10
+
11
+ -->
12
+
13
+ <svg
14
+ width="40px"
15
+ height="40px"
16
+ viewBox="0 0 40 40"
17
+ version="1.1"
18
+ xmlns="http://www.w3.org/2000/svg">
19
+ <title
20
+ id="title47">cm-chessbord arrowheads</title>
21
+ <desc
22
+ id="desc49">Arrowheads for cm-chessboard (https://shaack.com/projekte/cm-chessboard/).</desc>
23
+ <g id="arrowDefault" transform="matrix(5.1931792,0,0,5.1931792,3.5980168,-0.83225447)">
24
+ <path
25
+ d="M 0.535156,0.398438 C 0.398438,0.507812 0.316406,0.671875 0.3125,0.847656 0.316406,1.02344 0.398438,1.1875 0.535156,1.29688 L 3.01172,3.35938 3.72266,4.01563 3.01172,4.64453 0.535156,6.67969 C 0.394531,6.79297 0.3125,6.96094 0.3125,7.13672 c 0,0.17578 0.082031,0.34375 0.222656,0.45703 0.328125,0.25781 0.792974,0.25781 1.117184,0 L 5.45703,4.46094 C 5.59766,4.34766 5.68359,4.17969 5.69141,4 5.69141,3.82031 5.60547,3.65234 5.45703,3.54297 L 1.64453,0.394531 C 1.31641,0.148438 0.859375,0.148438 0.535156,0.398438 Z m 0,0"
26
+ class="head-fill" />
27
+ </g>
28
+ <g id="arrowPointy">
29
+ <path d="M 20,20 5,5 35,20 5,35 Z" class="head-fill"/>
30
+ </g>
31
+ </svg>
@@ -10,7 +10,8 @@ export const EXTENSION_POINT = {
10
10
  moveInputToggled: "moveInputToggled", // move input was enabled or disabled
11
11
  moveInput: "moveInput", // move started, cancelled or done
12
12
  moveInputStateChanged: "moveInput", // TODO deprecated, use `moveInput`
13
- destroy: "destroy" // called, before the board is destroyed
13
+ destroy: "destroy", // called, before the board is destroyed
14
+ redrawBoard: "redrawBoard" // called while redrawing the board
14
15
  }
15
16
 
16
17
  export class Extension {
@@ -27,4 +28,10 @@ export class Extension {
27
28
  this.chessboard.state.extensionPoints[name].push(callback)
28
29
  }
29
30
 
31
+ registerMethod(name, callback) {
32
+ if (!this.chessboard[name]) {
33
+ this.chessboard[name] = (...args) => {callback.apply(this, args)}
34
+ }
35
+ }
36
+
30
37
  }
@@ -58,7 +58,7 @@ export class ChessboardView {
58
58
  this.moveCanceledCallback.bind(this)
59
59
  )
60
60
  if (chessboard.props.sprite.cache) {
61
- this.cacheSprite()
61
+ this.cacheSpriteToDiv("chessboardSpriteCache", this.chessboard.props.sprite.url)
62
62
  }
63
63
  this.context = document.createElement("div")
64
64
  this.chessboard.context.appendChild(this.context)
@@ -108,15 +108,14 @@ export class ChessboardView {
108
108
 
109
109
  // Sprite //
110
110
 
111
- cacheSprite() {
112
- const wrapperId = "chessboardSpriteCache"
111
+ cacheSpriteToDiv(wrapperId, url) {
113
112
  if (!document.getElementById(wrapperId)) {
114
113
  const wrapper = document.createElement("div")
115
114
  wrapper.style.display = "none"
116
115
  wrapper.id = wrapperId
117
116
  document.body.appendChild(wrapper)
118
117
  const xhr = new XMLHttpRequest()
119
- xhr.open("GET", this.chessboard.props.sprite.url, true)
118
+ xhr.open("GET", url, true)
120
119
  xhr.onload = function () {
121
120
  wrapper.insertAdjacentHTML('afterbegin', xhr.response)
122
121
  }
@@ -137,8 +136,10 @@ export class ChessboardView {
137
136
  this.updateMetrics()
138
137
  this.boardGroup = Svg.addElement(this.svg, "g", {class: "board"})
139
138
  this.coordinatesGroup = Svg.addElement(this.svg, "g", {class: "coordinates"})
140
- this.markersGroup = Svg.addElement(this.svg, "g", {class: "markers"})
141
- this.piecesGroup = Svg.addElement(this.svg, "g", {class: "pieces"})
139
+ this.markersLayer = Svg.addElement(this.svg, "g", {class: "markers-layer"})
140
+ this.markersGroup = Svg.addElement(this.markersLayer, "g", {class: "markers"})
141
+ this.piecesLayer = Svg.addElement(this.svg, "g", {class: "pieces-layer"})
142
+ this.piecesGroup = Svg.addElement(this.piecesLayer, "g", {class: "pieces"})
142
143
  }
143
144
 
144
145
  updateMetrics() {
@@ -177,6 +178,7 @@ export class ChessboardView {
177
178
  this.redrawSquares()
178
179
  this.drawCoordinates()
179
180
  this.drawMarkers()
181
+ this.chessboard.state.invokeExtensionPoints(EXTENSION_POINT.redrawBoard)
180
182
  this.visualizeInputState()
181
183
  }
182
184
 
@@ -489,7 +491,7 @@ export class Svg {
489
491
  * @param attributes
490
492
  * @returns {Element}
491
493
  */
492
- static addElement(parent, name, attributes) {
494
+ static addElement(parent, name, attributes, sibling = undefined) {
493
495
  let element = document.createElementNS(SVG_NAMESPACE, name)
494
496
  if (name === "use") {
495
497
  attributes["xlink:href"] = attributes["href"] // fix for safari
@@ -504,7 +506,11 @@ export class Svg {
504
506
  }
505
507
  }
506
508
  }
507
- parent.appendChild(element)
509
+ if (sibling !== undefined) {
510
+ parent.appendChild(element)
511
+ } else {
512
+ parent.insertBefore(element, sibling)
513
+ }
508
514
  return element
509
515
  }
510
516