Chessboard.js: универсальная шахматная доска

Для своего проекта мне приходилось использовать сторонний виджет шахматной доски. Это ускоряет разработку на старте, но вызывает сложности при поддержке проекта. Так я решил создать универсальный модуль шахматной доски на чистом JavaScript + Canvas, лёгкий, без зависимостей и с открытым кодом.

14
","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"

2. В любой HTML элемент добавьте data-chessboard атрибут:

"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"
","lang":""}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"

Шахматная доска отобразиться при загрузке страницы:

"}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"Шахматная доска с установленной позицией FEN: rnbqkb1r/1p2pppp/p2p1n2/8/3NP3/2N5/PPP2PPP/R1BQKB1R w KQkq - 0 6","image":{"type":"image","data":{"uuid":"0368845d-86da-5593-891c-529deac16fa7","width":400,"height":400,"size":10312,"type":"png","color":"748baa","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAKAAoDAREAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAABAUGB//EACQQAAICAQIGAwEAAAAAAAAAAAECAwQRBSEABhITMWEHIkGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEF/8QAHBEBAAICAwEAAAAAAAAAAAAAAQACAxESQfAx/9oADAMBAAIRAxEAPwDVV5L0xKkPZWFJVcP3Y4/t1bEkZ3C7eDuT0k4ZQp3mtfhMQs62wex8Z8t3Z5Lk9R5JJ3Mrua9VyzMcklmkDHOfJAJ/QOLwr7cnO/gjyZiGyCcmnAx9koxJ/pAJ9gcCrsIwCLKHS9PoTaZUllo13d4I2ZmiUliVGSTjc8Bksl0HuPjqNBTqf//Z"}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Примеры использования"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"

1. С помощью установки FEN можно анимировать ходы:

"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"const board = new Chessboard({skin: \"brown-theme\"});\nconst fenPositions = [/* FEN-строки */];\nfenPositions.forEach((fen, index) => {\n setTimeout(() => board.setFEN(fen), (index + 1) * 1000);\n});","lang":""}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"Динамическое изменение позиции на шахматной доске","image":{"type":"image","data":{"uuid":"7f905296-52f6-5a42-a747-b2ab43c719e4","width":400,"height":400,"size":30076,"type":"gif","color":"efd8b6","hash":"","external_service":[],"duration":13.8,"isVideo":false,"has_audio":false}}}]}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"

2. Создаем доску размером 6x6, переворачиваем и изменяем тему:

"}},{"type":"code","cover":false,"hidden":false,"anchor":"","data":{"text":"// Устанавливаем нестандартный размер доски:\nconst board = new Chessboard({\n rows: 6, \n cols: 6, \n fen: \"nqkbnr/pppppp/6/6/PPPPPP/NQKBNR\"\n});\nboard.setOrientation(\"black\"); // Переворачиваем доску\n// Поддерживаемые темы:\nconst skinList = [\"green-theme\", \"brown-theme\", \"blue-theme\"];\n// Меняем тему каждые 2 секунды:\nskinList.forEach((skin, index) => {\n setTimeout(() => {\n board.setSkin(skin);\n }, (index + 1) * 2000);\n});","lang":""}},{"type":"media","cover":false,"hidden":false,"anchor":"","data":{"items":[{"title":"Нестандартный размер, переключение темы и переворот доски","image":{"type":"image","data":{"uuid":"5a169bb6-f2c6-5a41-a083-094762300ecb","width":400,"height":400,"size":88686,"type":"gif","color":"718ba3","hash":"","external_service":[],"duration":7.5,"isVideo":false,"has_audio":false}}}]}},{"type":"header","cover":false,"hidden":false,"anchor":"","data":{"style":"h2","text":"Репозиторий"}},{"type":"link","cover":false,"hidden":false,"anchor":"","data":{"link":{"type":"link","data":{"url":"https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fgitlab.com%2Fapicase%2FChessboard&postId=1905646","title":"Sergey Efimenko / Chessboard · GitLab","description":"Chessboard.js: Interactive Lightweight Chessboard","image":{"type":"image","data":{"uuid":"8d2a4b76-f7fb-50fe-922a-c0add3864014","width":180,"height":180,"size":3632,"type":"png","color":"ed5428","hash":"","external_service":[]}},"v":1,"hostname":"gitlab.com"}}}},{"type":"delimiter","cover":false,"hidden":false,"anchor":"","data":{"type":"default"}},{"type":"text","cover":false,"hidden":false,"anchor":"","data":{"text":"

#Универсальня_шахматаная_доска #Шахматная_доска #Шахматы #Chess #Chessboard #ChessboardJS #UniversalChessBoard #JavaScript #Canvas #GitLab

"}}],"summaryContent":null,"isExistSummaryContent":false,"warningFromEditor":null,"warningFromEditorTitle":null,"counters":{"comments":5,"favorites":2,"reposts":0,"views":1704,"hits":404,"reads":null,"online":0},"dateFavorite":0,"hitsCount":404,"isCommentsEnabled":true,"isLikesEnabled":true,"isRemovedByUserRequest":false,"isFavorited":false,"isPinned":false,"repostId":null,"repostData":null,"subscribedToTreads":false,"isEditorial":false,"isAudioAvailable":false,"audioUrl":null,"isAudioAvailableToGenerate":false,"commentEditor":{"enabled":true,"who":null,"text":"","until":null,"reason":null,"type":"everybody"},"isBlur":false,"isPublished":true,"isDisabledAd":false,"withheld":[],"ogTitle":null,"ogDescription":"Универсальная шахматная доска, модуль на JavaScript, рендеринг через Canvas, установка позиций с FEN-нотацией, кастомизация и нестандартные размеры.","url":"https://vc.ru/tribuna/1905646-chessboard-js-universalnaya-shahmatnaya-doska","author":{"id":72936,"name":"Сергей Ефименко","nickname":null,"description":null,"uri":"","avatar":{"type":"image","data":{"uuid":"6aeec8ce-95cf-5153-86f5-2ef3246f899f","width":640,"height":640,"size":111806,"type":"jpg","color":"bed8e5","hash":"","external_service":[],"base64preview":"/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAICAgICAQICAgIDAgIDAwYEAwMDAwcFBQQGCAcJCAgHCAgJCg0LCQoMCggICw8LDA0ODg8OCQsQERAOEQ0ODg7/2wBDAQIDAwMDAwcEBAcOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAAKAAoDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAABwj/xAAmEAACAQIFAgcAAAAAAAAAAAABAgMEBQAGBxEhEzEUIkJRYXFy/8QAFAEBAAAAAAAAAAAAAAAAAAAABv/EABoRAAIDAQEAAAAAAAAAAAAAAAECAAMRIRP/2gAMAwEAAhEDEQA/ALBzZm+jXVXL9FQvAtplzU/jJyzDdCIX5UeUrv2J5B+8Lkmpen0VQ8Ul8tyujFWBePgjv6sQBcUQZrZwihzbusWA56gYbP8Aoe/fALW3u9NeKtmu9azGZiSapySdz84Si29Ccc9hPxpcDVHJ/9k="}},"cover":null,"achievements":[{"title":"Год на vc.ru","code":"registration_1_year","description":"Первый год с vc.ru. Получена 24 июля 2025.","previewUuid":"0d11c244-49de-50e7-894e-b9b27945d42b","formats":{"glb":"https://static.vc.ru/achievements/fish.glb","usdz":"https://static.vc.ru/achievements/fish.usdz"},"viewData":{"contentColor":"#C67AA3","textMaxWidth":0.634765625,"textX":0.5888671875,"textY":0.54296875,"logoX":0.5859375,"logoY":0.6669921875,"logoXNoText":0.6044921875,"logoYNoText":0.5439453125},"id":5348510,"userId":72936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/5348510"},{"title":"3 года на vc.ru","code":"registration_3_years","description":"Провёл 3 года вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"d9d72ac5-bcb5-55e0-8c72-b99251e5cdd9","formats":{"glb":"https://static.vc.ru/achievements/shark.glb","usdz":"https://static.vc.ru/achievements/shark.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.5205078125,"textY":0.341796875,"logoX":0.5205078125,"logoY":0.4609375,"logoXNoText":0.5,"logoYNoText":0.3662109375},"id":1724423,"userId":72936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/1724423"},{"title":"5 лет на vc.ru","code":"registration_5_years","description":"Провёл 5 лет вместе с vc.ru. Получена 23 июля 2025.","previewUuid":"a9140d54-73b8-5f40-afa8-449fbaafd42b","formats":{"glb":"https://static.vc.ru/achievements/whale.glb","usdz":"https://static.vc.ru/achievements/whale.usdz"},"viewData":{"contentColor":"#8E6F09","textMaxWidth":0.66796875,"textX":0.533203125,"textY":0.658203125,"logoX":0.533203125,"logoY":0.77734375,"logoXNoText":0.4375,"logoYNoText":0.66015625},"id":497715,"userId":72936,"count":0,"shareImage":"https://api.vc.ru/achievements/share/497715"}],"lastModificationDate":1764919762,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":true,"badgeId":null,"isDonationsEnabled":true,"isPlusGiftEnabled":true,"isUnverifiedBlogForCompanyWithoutPro":false,"isRemovedByUserRequest":false,"isFrozen":false,"isDisabledAd":false,"isPlus":false,"isVerified":false,"isPro":false,"yandexMetricaId":null,"badge":null,"isOnline":false,"tgChannelShortname":null,"isUnsubscribable":true,"type":1,"subtype":"personal_blog"},"subsite":{"id":199116,"name":"Трибуна","description":"Место для продвижения себя или своего проекта. Берёте в руки микрофон и рассказываете всем, почему вы крутой. Как это делается: https://vc.ru/tribuna/58504","uri":"/tribuna","avatar":{"type":"image","data":{"uuid":"04607ca7-338b-561e-9403-3f06a70ef789","width":1200,"height":1200,"size":78591,"type":"png","color":"ebfbe3","hash":"302828e8f0303030","external_service":[]}},"cover":{"type":"image","data":{"uuid":"469caab9-c9db-5650-af7d-edf2c276c021","width":960,"height":280,"size":19176,"type":"png","color":"ebfbe3","hash":"","external_service":[]}},"lastModificationDate":1695887949,"isSubscribed":false,"isSubscribedToNewPosts":false,"isMuted":false,"isAvailableForMessenger":false,"isDisabledAd":false,"nickname":"tribuna","isUnsubscribable":true,"badge":null,"badgeId":null,"isDonationsEnabled":false,"isOnline":false,"isPlus":false,"isUnverifiedBlogForCompanyWithoutPro":false,"isVerified":false,"isRemovedByUserRequest":false,"isFrozen":false,"isPro":false,"type":2,"subtype":"community"},"reactions":{"counters":[{"id":1,"count":14}],"reactionId":0},"isNews":false,"source":null,"clusters":[],"donations":{"amount":0,"isDonated":false},"commentsSeenCount":null}}],"ogTitle":null,"ogDescription":null,"isAnonymized":true}};