Photographing Chess Clock

Discussion of anything and everything relating to chess playing software and machines.

Moderators: hgm, Harvey Williamson, bob

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
User avatar
hgm
Posts: 22909
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Photographing Chess Clock

Post by hgm » Mon Oct 10, 2016 1:42 pm

I wrote a cool app for my laptop, to use it as a game-recording chess clock. The app runs in the web browser (i.e. it is a HTML file that I open in the browser to start the chess clock). It (of course) displays the time of both players, and the running clock can be switched by pressing keys on the left or right half of the keyboard. (The space bar stops both clocks.) This allows you to put the laptop beside the board, and use it as chess clock:

Image

There is more, though: the clock app starts up the web-cam, and saves an image every time the clock is switched (presumably after every move). This records the entire game, and allows you to write it down later (e.g. if it was a blitz game, and you had no time for notation).

Unfortunately the webcam of my laptop was looking rather upward, so I taped as mall mirror to the lid of my laptop to aim its gaze at the chess board.

Screenshot:

Image

The app is based on snapshot web app I found here. You just have to download and unzip that, and put the following text in a file chessclock.html in the 'Demos' folder of that download:

Code: Select all

<!doctype html>

<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>WebcamJS Test Page</title>
	<style type="text/css">
		body &#123; font-family&#58; Helvetica, sans-serif; &#125;
		h2, h3 &#123; margin-top&#58;0; &#125;
		form &#123; margin-top&#58; 15px; &#125;
		form > input &#123; margin-right&#58; 15px; &#125;
	</style>
</head>
<body>
<div align="center">
<table><tr><td>
	<h2>Life image&#58;</h2>
	<div id="my_camera"></div>
</td><td cellpadding="20">
	<h1>Webcam Chess Clock</h1>
</td><td>
	<div id="results"><div style="border&#58;1px;background&#58;#cccccc;padding&#58;20px;">Your captured image will appear here...</div></div>
</td></tr></table>
	
	<!-- First, include the Webcam.js JavaScript Library -->
	<script type="text/javascript" src="../webcam.js"></script>
	
	<!-- Configure a few settings and attach camera -->
	<script language="JavaScript">
		Webcam.set&#40;&#123;
			width&#58; 320,
			height&#58; 240,
			image_format&#58; 'jpeg',
			jpeg_quality&#58; 90
		&#125;);
		Webcam.attach&#40; '#my_camera' );
	</script>
	
	<!-- A button for taking snaps -->
	<form>
		<input type=button value="Take Snapshot" onClick="take_snapshot&#40;)">
		Start time&#58; <input type=text value="3600" id="starttime">
		<input type=button value="Reset Clocks" onClick="Reset&#40;)">
		<input type=button value="Swap Players" onClick="Swap&#40;)">
		<input type=button value="<<" onClick="GoTo&#40;0&#41;">
		<input type=button value="<" onClick="GoTo&#40;-1&#41;">
		<input type=button value=">" onClick="GoTo&#40;1&#41;">
		<input type=button value=">>" onClick="GoTo&#40;9999&#41;">
	</form>

	<p id="key" style="background&#58;#8080FF;"></p>

	<table cellpadding="10" border="1"><tr>
		<td id="player1" style="font-size&#58;75px;" width="50%">Sente&#58;</td>
		<td id="player2" style="font-size&#58;74px;" width="50%">Gote&#58;</td>
	</tr><tr>
		<td id="clock1" style="font-size&#58;150px;background&#58;black;color&#58;white;"></td>
		<td id="clock2" style="font-size&#58;150px;"></td>
	</tr></table>
</div>

	<!-- Code to handle taking the snapshot and displaying it locally -->
	<script language="JavaScript">
		var images = new Array&#40;);
		var nrOfImages = 0;
		var times = new Array&#40;);
		var active = 1;
		var current = 0;
		times&#91;1&#93; = times&#91;2&#93; = 3600;
		DisplayTime&#40;1, times&#91;1&#93;);
		DisplayTime&#40;2, times&#91;2&#93;);

		window.addEventListener&#40;"keydown", KeyHit, false&#41;;

		var timer = setTimeout&#40;"Clock&#40;);", 100&#41;;

		function Display&#40;n&#41; &#123;
			document.getElementById&#40;'results').innerHTML = 
				'<h2>Here is your image&#58;</h2>' + 
				'<img src="'+images&#91;n&#93;+'"/>';
		&#125;

		function take_snapshot&#40;) &#123;
			// take snapshot and get image data
			Webcam.snap&#40; function&#40;data_uri&#41; &#123;
				// display results in page
				document.getElementById&#40;'results').innerHTML = 
					'<h2>Captured image&#58;</h2>' + 
					'<img src="'+data_uri+'"/>';
				current = nrOfImages;
				images&#91;nrOfImages++&#93; = data_uri; // save the snapshot
			&#125; );
		&#125;

		function SecToTime&#40;t&#41; &#123;
			var s = 0; if&#40;t<0&#41; &#123; s = 1; t = -t; &#125;
			var sec = t % 60; t = &#40;t - sec&#41;/60; if&#40;sec < 10&#41; sec = '0' + sec;
			var min = t % 60; t = &#40;t - min&#41;/60; if&#40;min < 10&#41; min = '0' + min;
			return s ? '-' + min + '&#58;' + sec &#58; t + '&#58;' + min + '&#58;' + sec;
		&#125;

		function DisplayTime&#40;n, t&#41; &#123;
			document.getElementById&#40;"clock" + n&#41;.innerHTML = SecToTime&#40;t&#41;;
		&#125;

		function Clock&#40;) &#123;
			if&#40;active&#41; &#123;
				var t = times&#91;active&#93;;
				times&#91;active&#93;--;
				DisplayTime&#40;active, t&#41;;
			&#125;
			timer = setTimeout&#40;"Clock&#40;);", 1000&#41;;
		&#125;

		function Switch&#40;side&#41; &#123;
			if&#40;side == active&#41; return;
			if&#40;active&#41; &#123;
				document.getElementById&#40;"clock" + active&#41;.style.color = "black";
				document.getElementById&#40;"clock" + active&#41;.style.background = "white";
				take_snapshot&#40;);
			&#125;
			active = side;
			if&#40;active&#41; &#123;
				document.getElementById&#40;"clock" + active&#41;.style.color = "white";
				document.getElementById&#40;"clock" + active&#41;.style.background = "black";
			&#125;
		&#125;

		var left = '`123456qwertyasdfghzxcvb';
		var right = "7890-=uiop&#91;&#93;jkl;'nm,./";

		function KeyHit&#40;ev&#41; &#123;
			var c = ev.key;
//			document.getElementById&#40;"key").innerHTML = c.charCodeAt&#40;0&#41;;
			if&#40;c.charCodeAt&#40;0&#41; == 92 || c == 'Backspace' || c == 'Delete') c = 'p';
			if&#40;c == 'Tab' || c == 'Escape') c = 'q';
			if&#40;c == ' ') Switch&#40;0&#41;; else
			if&#40;left.search&#40;c&#41; >= 0&#41; Switch&#40;2&#41;; else
			if&#40;right.search&#40;c&#41; >= 0&#41; Switch&#40;1&#41;;
		&#125;

		function GoTo&#40;n&#41; &#123;
			if&#40;!n&#41; current = n; else if&#40;n == 9999&#41; current = nrOfImages - 1; else current += n;
			if&#40;current < 0&#41; current = 0; else if &#40;current >= nrOfImages&#41; current = nrOfImages - 1;
			Display&#40;current&#41;;
		&#125;

		function Reset&#40;)&#123;
			var newTime = parseInt&#40;document.getElementById&#40;"starttime").value&#41;;
			times&#91;1&#93; = times&#91;2&#93; = newTime;
			Switch&#40;0&#41;; active = nrOfImages = current = 0;
			DisplayTime&#40;1, times&#91;1&#93;); DisplayTime&#40;2, times&#91;2&#93;);
		&#125;

		function Swap&#40;) &#123;
			var h = times&#91;1&#93;; times&#91;1&#93; = times&#91;2&#93;; times&#91;2&#93; = h;
			var side = active; Switch&#40;0&#41;;
			h = document.getElementById&#40;"player1").innerHTML;
			document.getElementById&#40;"player1").innerHTML = document.getElementById&#40;"player2").innerHTML;
			document.getElementById&#40;"player2").innerHTML = h;
			DisplayTime&#40;1, times&#91;1&#93;); DisplayTime&#40;2, times&#91;2&#93;);
			if&#40;side&#41; Switch&#40;3 - side&#41;; else Switch&#40;side&#41;;
		&#125;
	</script>
	
</body>
</html>

Henk
Posts: 5481
Joined: Mon May 27, 2013 8:31 am

Re: Photographing Chess Clock

Post by Henk » Mon Oct 10, 2016 5:12 pm

What happens if you click on right mouse button in the browser. Does the clock still tick ?

User avatar
hgm
Posts: 22909
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: Photographing Chess Clock

Post by hgm » Mon Oct 10, 2016 5:31 pm

Yes, it does. A contect menu pops up, but the clock keeps decrementing. Doesn't that happen for you?

Most annoying thing is that when you try to enter a 'start time', the clocks already switch for every digit you type in the 'start time' entry. This because I attached the eventListener to the entire window.

I do have a version now that also does Fischer and Bronstein TC. (To be entered as basetime+inc or basetime-deadtime, respectively.)

It also flips the image to compensates for the mirror.

Jesse Gersenson
Posts: 565
Joined: Sat Aug 20, 2011 7:43 am
Contact:

Re: Photographing Chess Clock

Post by Jesse Gersenson » Mon Oct 10, 2016 5:39 pm

Nice tool HG.

I didn't realize a WEBbrowser could snap a picture of the user each time they interact with the machine, and then silently upload the images to a server?!

User avatar
hgm
Posts: 22909
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: Photographing Chess Clock

Post by hgm » Mon Oct 10, 2016 6:06 pm

This app doesn't upload them, although I suppose it could do that. The webcam snapshot app I started from just returns a URI that only seems to be valid from within the current web page. What I do is just store all these URI in an array, so that you can step through them after the game. They disappear after you leave the page. It could be that the browser stores them in the browser cache, but it could also keep them in memory. There is no server involved,and I am not sure the images appear anywhere in your file system.

Jesse Gersenson
Posts: 565
Joined: Sat Aug 20, 2011 7:43 am
Contact:

Re: Photographing Chess Clock

Post by Jesse Gersenson » Mon Oct 10, 2016 6:52 pm

https://github.com/jhuckaby/webcamjs
Submitting Images to a Server

The Webcam.snap() function delivers your image by way of a client-side JavaScript Data URI. The binary image data is encoded with Base64 and stuffed into the URI. You can use this image in JavaScript and display it on your page. However, the library also provides a way to decode and submit this image data to a server API endpoint, via binary AJAX. Example:

Webcam.snap( function(data_uri) {
// snap complete, image data is in 'data_uri'

Webcam.upload( data_uri, 'myscript.php', function(code, text) {
// Upload complete!
// 'code' will be the HTTP response code from the server, e.g. 200
// 'text' will be the raw response content
} );

} );
That's a choice the HTML5 creators made; your tool is pragmatic and I plan to use it.

User avatar
hgm
Posts: 22909
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: Photographing Chess Clock

Post by hgm » Tue Oct 11, 2016 11:08 am

I now uploaded a somewhat more polished version of the clock app, as a zip file which also contains the necessary webcam driver, (which I had to modify a bit compared to the original one) so that it becomes a self-sufficient package. Just unzip and open the clock.html file that is contained in the folder in your web browser.

The old version had some problems when keys that had a function in Windows were used to switch the clock. (E.g. <Tab> would switch focus to the next button as a side effect, until that focus arrived at the text entry for 'start time', after which any key you hit would be considered typed there, rather than switch the clock. And the space bar needed to stop the clocks would also activate the button that had focus, which typically would be the Reset Clocks button...)

The new version fixes all that, and allows resetting of the clocks only when they are stopped. It also displays the number of moves played so far by the thinking player, and implements classical TC as well as Fischer, Bronstein and sudden-death TCs. It also flips the image from the camera vertically, to cancel the effect of the mirror. (This is why I had to modify the webcam.js script; the origial one did support only horizontal flipping, and I changed that to vertical.)

Download from http://hgm.nubati.net/clock.zip (only 19KB)

User avatar
GONeill
Posts: 51
Joined: Sun Jun 15, 2014 4:40 am
Contact:

Re: Photographing Chess Clock

Post by GONeill » Tue Oct 11, 2016 9:10 pm

That's great, but there is one small issue.

If, when you start the file, you reply 'Not now' to the browser's (Firefox) request to share the webcam (perhaps because you only want to use the clock function) you then get errors after each move:

Code: Select all

Webcam.js Error&#58; Webcam is not loaded yet
Would it be possible to check if the webcam was initiated successfully and, if not, then not call the webcam.js functions at all? Or maybe have a checkbox on the screen to enable/disable the webcam?

User avatar
hgm
Posts: 22909
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: Photographing Chess Clock

Post by hgm » Tue Oct 11, 2016 9:26 pm

Well, the whole point of the thing was the webcam. I imagined people that did want to use a plain chess clock would have one.

But what you request should be easy to do. For the time being you could just remove the line "take_snapshot()" from the function Switch in clock.html to make a version that does not try to use the camera. (It would still ask for the camera use at startup and probably complain once when it does not get it; if you want to get rid of that too you should delete the entire <script>...</script> section that contains the "Webcam.attach(...)".

User avatar
hgm
Posts: 22909
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: Photographing Chess Clock

Post by hgm » Wed Oct 12, 2016 11:35 am

OK, I uploaded a new version to the same link. It now doesn't display an error popup when the camera access is denied, but just displays a message in the area where otherwise the snapshot would appear.

I also increased the resolution to 100 ms (was 1 sec), and display the new time immediately after switching, rather than on the next tick. (This is less confusing in case you get an increment.)

I also made it possible to decrease the move count, in case there was a takeback or spurious clock pressing, by clicking on the move number. It does not undo the effects of starting a new session in classical TC, though; the erased moves will just be added to the session in progress. It would also not deduct already awarded increments in Fischer TC.

Image

Post Reply