Add files via upload

This commit is contained in:
ballantynedewolf 2019-04-01 21:24:46 +11:00 committed by GitHub
parent 4b0e926bec
commit 9bec6a54d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 305 additions and 126 deletions

View File

@ -1,28 +1,26 @@
# WolfChart v1.4
by Ballantyne de Wolf and Offspring Digital
Supported by
<img src="https://github.com/ballantynedewolf/WolfChart/blob/master/Browserstack-logo%402x.png" height="50px" align="baseline">
This is a professional optometrist/optician/ophthalmologist tool for measuring visual acuity. It cannot be used safely by the general public.
This is professional optometrist/optician/ophthalmologist tool for measuring visual acuity. I cannot be used safely by the general public.
If you have any concerns about your vision or eyes, consult a qualified professional.
Now that's out of the way, the objectives are:
1. Clinically relevant, scientifically supported visual acuity measurement in the widest possible range of clinical settings
2. Open source with GNU licence
3. Can be used on a wide variety of screen hardware
3. Customisable optotypes and alphabets to come in version 2
3. Customisable optotypes and alphabets to come eg Hebrew, Chinese, Thai, Cyrillic etc
Ver1.6
- subtense array now to 3 decimal places, enabling
- improved scoring for Actual numerators - rounding previously made the numerator too complex and denominator different if using Actual vs Standard numerator
- cleaned up some superfluous code lines in this area.
- changed the Snellen R to try and make it more readable - in the field it was proving less readable than the other Snellens. Made the oblique stem more vertical.
# How to use WolfChart without an internet connection
As WolfChart is 100% Javascript, once it is open in your browser, no internet connection is needed. You will need to turn off any script blocking for WolfChart and do not prevent it from using Local Storage.
- Extract this archive to a location on your computer or network where it is unlikely to get moved in a hurry.
- Drag the **index.htm** file from this archive into your browser or paste its path into the browser address bar or use the browser's File>Open File menu option to search for it.
- Use the menu button top right to configure and calibrate your chart as normal
- Might be a good idea to bookmark it so that you can return quickly to WolfChart. Your configuration and calibration settings are kept even when you close the browser.
- Check periodically for updates when you have an internet connection. The version you are using is in the page title.
Ver1.5
- PWA version
- new alphabet for Snellen BS4274.3 - less random
# Version notes
Ver1.4
- various bug fixes
- improved consistency of svg elements to use only filled paths and polygons, no strokes.

155
index.htm
View File

@ -7,9 +7,12 @@
<html lang=en>
<head>
<title>WolfChart v1.4</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMTgwMTE3NDA3MjA2ODExOEY2MkIwMEUyRkE1Q0M4MyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCOEJEQTI1Q0UxRDgxMUU2ODM2MEU4MjNCQjMzQzc0NCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCOEJEQTI1QkUxRDgxMUU2ODM2MEU4MjNCQjMzQzc0NCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjAxODAxMTc0MDcyMDY4MTE5OTRDOTZBNzFFRERBQUJGIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAxODAxMTc0MDcyMDY4MTE4RjYyQjAwRTJGQTVDQzgzIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+xrWOYgAAAt1JREFUeNp8k0lMU1EUhs+9b2pLW6a28ArYWqEgahhCSaoIJCASLC6MK2OiaFzgxoWBRBcsVWKMiboxxhDcGYPRiEAYNIoDRAwOYIIyTy1Qa5laXtv3nq9FtAXiSe5dnHv+755z7rlIFEUQeZ7pGGk9xVGYq9xZ0Qj/sdaJ9hPg9cSUp9kaEEF6yZCX88bpHjTdeUaPU9MF/aXHCqtrEsg4R7jQyS9qHr+5W2/vbjtjW00CuFTcAuqY8RAAMcxKtqh3Zo+Q7PjUp5OOr1esuOhoLU/L55F0Tvi5OEd3c33pl+EMky8VICF2AeQyd1C7ngFBrYgq2U9ECKyR0sPYi95dT+7faPLx67eTGKDEaAVTskWKXQVRySwjivb8AwCISKlygz8AvdOd0Of4Bgq9BuRKpdQgEQJeD2qbeA+5XhdY2XxAUSoXAPaFA8CroBc/+gZhMl0NmVUXQZlqgkRt1nUMxNqss79udWQMJt69hYBjEPKictyKPzq8AVg9tP8pWXMaEi35MNH4CJw9PRCfvLtLs2NPu6uvD8YbHoI2Kwuo2ipYLi9o3tD9zUCTkn1vRXSXzfn542xlKVDR0dIhPYWB9NDR8QJ7pASrMsygjc94nmCw3NoCCFpKkrV6ZdluoQqtBppUukjMzCCEfbqcvDnOv8xSSGbfkXzgXLBnsLmE0GMQjNNoKK7i1zgggJrBmFpCiFgjETMpNRKMhqKzJCm3h2vIzZOmVLIv9fq8mxy3mL7hY2TqKVaR+1mlSm7dMpqhUd60BCGg+OUcq2i9YGtpPl/W4Zr7UcnzfvV2sXgTD4U2RHjUKn07E6tzy+J0bpU6qQNjcmm7siOJgkAEutouC7PT2VuymnNkBjpb6qSPR4X7I3uAEI8AB8RrV1+Lqakf0PyCSYrCYoJ2GEZHc9Hh8tuAsT9CEqREmMDTwvD3gzAwYIOhoSIJgMBs7kZ79zVDmvmV9IW58PDfAgwAeylIM837S9EAAAAASUVORK5CYII=" />
<title>WolfChart v1.6</title>
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAdCAMAAAD8QJ61AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADBQTFRFqamphoaGxcXF1tbW9/f3U1NTLi4uurq64+PjnZ2ddHR07Ozsk5OTAAAA////////NZC25gAAABB0Uk5T////////////////////AOAjXRkAAAFRSURBVHjadFNZYsUgCATU4AJ6/9sWFVP72vJhCA4wLMK4hUoYHwKXHgp3xj4I+C9AQw6994ZIHZjpF6DGviTPL2YuF4ARGofoCJfSDyDX3CPUzuXc1XlAPAB0c3pcacozC0rcAHeMj4IH0LotAjcAVB8PoOqxpBtAyDOYPewAqu5U4oCSPYOZNU1tKk4nWYRDXXRdPM/66nZrGF5A0h9ySsOTIv68PzkMELEtOh+AzXcCRsS8M6QyD+OQxI6rFeK1W5+qNrSPvDkwOsBrsMhozutntpvZGhXhroHq0VZP0AB5QjOk3QA+0Af3zGE09lYuZ5q4BOS7gfe4eycj+uzYPovJYQSp4SyCyilwjS37yr0xzP2d5AxwdjLQPRDrbFi8iN6txskpeztsd4SsvRG/1z4ai1BFxEAFZT4vKNLudwE2lRHJctH/T8+klPJh+RJgAA5sKxGB5VuMAAAAAElFTkSuQmCC" />
<meta charset="utf-8" />
<link rel="manifest" href="/manifest.json">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#86c7ef">
<style type="text/css">
.old_ie .setting-bar,
@ -352,7 +355,7 @@
right: 0px;
top: 9px;
}*/
/*accodion*/
/*accordion*/
.panel-title a {
display: block;
padding: 10px;
@ -1076,7 +1079,7 @@
</svg>
</a>
<div class="panel-body">
Very quick guide: Calibrate and configure your chart using this help guide. Click or tap on white space to scroll the chart up and down, or use the up and down arrows on your keyboard. Click or tap on any letter to mask it. Click or tap on any line label to mask that line. Click again to unmask. <br /><br />
Very quick guide: Calibrate and configure your chart using this help guide. Click or tap on white space to scroll the chart up and down, or use the up and down arrows on your keyboard. Click or tap on any letter to mask it. Click or tap on any line label to mask that line. Click or tap again to unmask. <br /><br />
</div>
<div class="accordion">
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
@ -1117,7 +1120,7 @@
<strong>Notation</strong>: Sets the notation type on the VA label on each chart line. Each notation type has a fixed array of chart lines. "Metres" is standard Snellen notation eg. 6/6; "Feet" is the US equivalent eg. 20/20; DecimalV is a decimal equivalent of Snellen notation eg. 6/60 = 0.1, 6/12 = 0.5; logMAR is explained here <a href="https://en.wikipedia.org/wiki/LogMAR_chart" target="_blank">https://en.wikipedia.org/wiki/LogMAR_chart.</a>
</li>
<li>
<strong>Numerator</strong>: Sets the numerator of only the fraction notation types, in which the numerator nominally describes the test distance. "Actual" is the value entered in Distance rounded to the nearest 0.1, and VA labels will show the proportionally adjusted denominator. Eg if you set the Distance to 3160mm, the VA labels will be 3.2/3.2, 3.2/9.6 etc. "Standard" is either 6 or 20 depending on the value you set in Notation above. VA labels will display as either 6/ or 20/ regardless of the value in Distance (see below). Please note that it is not advisable to use Standard if the Distance varies a large amount from 6000mm, say outside 5000-7000mm.
<strong>Numerator</strong>: Sets the numerator of only the fraction notation types. If Notation is set to logMar or DecimalV, this setting makes no difference. "Actual" is the value entered in Distance (see below) rounded to the nearest 0.1m or 1ft, and VA labels will show this rounded numerator and a proportionally adjusted denominator. "Standard" is either 6 or 20 depending whether Notation is set to Metres or Feet above. VA labels will display as either 6/ or 20/ regardless of the value in Distance. Please note that it is not advisable to use Standard if the Distance varies a large amount from 6000mm(20ft), say outside 5000-7000mm(16-23ft). The numerator should be the tested distance or near to it.
</li>
</ul>
@ -1136,7 +1139,7 @@
<div class="panel-body">
<p> The two CALIBRATION values are the ONLY values that influence the display size of the chart lines. The RECORDING values above only change the VA labels on the chart lines, and have no bearing on the chart lines themselves.</p>
<ul>
<li><strong>Distance</strong>: Enter the distance from the patient's eye to the letter chart in mm. Eg 6m is 6000mm. If using a mirror to double the test distance, measure BOTH from the patient's eye to the mirror AND from the mirror to the chart and ADD the two distances (and don't forget to check the Mirrored/Direct setting - see below). If you are using Notation value of "Feet", Distance will be converted to feet to the nearest 0.1, or to 20 depending on the value in Numerator.</li>
<li><strong>Distance</strong>: Enter the distance from the patient's eye to the letter chart in mm. Eg 6m is 6000mm. You can work in feet (see Notation above) but you MUST enter the Distance in mm. If using a mirror to double the test distance, measure BOTH from the patient's eye to the mirror AND from the mirror to the chart and ADD the two distances (and don't forget to check the Mirrored/Direct setting - see below). If you are using Notation value of "Feet", Distance will be converted to the nearest foot, or to 20 depending on the value in Numerator.</li>
<li>
<strong>Length of the line below</strong>: Calibrates the chart for the pixel density of the display being used. Measure the ruler line as accurately as possible. Measure two more times, and if the values vary, enter an average. You will need to re-check this value if you change display hardware, graphics adapter settings, or if you turn your display from landscape to portrait or vice versa. Take particular care here if you are using extended display from a laptop as pixel density may be different between the laptop screen and the external display.
</li>
@ -1171,10 +1174,11 @@
<div id="collapseThree" class="panel-collapse collapse">
<div class="panel-body">
<ul>
<!-- <li><strong>Sort</strong>: Lines of the chart are always displayed with the smallest at the bottom. Unless the display is very large (about 1m wide by about 1.5m tall), the chart will display in pages - see SHORTCUTS below. Here you can select whether to display the page of the smallest or largest lines first on refresh or reconfigure. By default, the smallest subtense is 0.5arcmin, the largest 10 arcmin.</li> -->
<li><strong>Sort</strong>: Unless the display is very large (about 1m wide by about 1.5m tall), the chart will display in pages - see SHORTCUTS below. Here you can select whether to display the page of the smallest or largest lines first on refresh or reconfigure. </li>
<li><strong>Mirrored/Direct</strong>: Select "Direct" if the chart is to be viewed directly, otherwise select "Mirrored" and the letters and lines will be reversed, but the labels not. If changing this setting, don't forget to set the Distance (see above) accordingly.</li>
<li>
<strong>Text colour</strong>: This field accepts any rgba colour value. Eg. 0,0,0,1 is black; 0,0,0,0.1 is 10% black; 255,0,0,1 is pure red.
<strong>Text colour</strong>: Select from the colour picker or enter any valid rgba string Eg. rgba(0,0,0,1) is black; rgba(0,0,0,0.1) is 10% black; rgba(255,0,0,1) is pure red.
</li>
</ul>
</div>
@ -1210,7 +1214,7 @@
</div>
</div>
<!--end guide-section-->
<div id="displaySetting">
<div id="displaySetting" style="height:100%;">
<div data-line="1" class="character-line">
<div class="char-line" id="line-1"></div>
</div>
@ -1284,7 +1288,8 @@
<path d="M 0 0 H 2.5 A 1.5 1.5 0 0 1 2.5 3 H 1 V 5 H 0 V 1 H 1 V 2 H 2.5 A 0.5 0.5 0 0 0 2.5 1 H 0 V 0" fill="black"></path>
</svg>
<svg id="Snellen_R" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0,0,4,5" height="8.73mm" style="margin: 3.49mm;">
<path d="M 0 0 H 2.5 A 1.5 1.5 0 0 1 2.5 3 L 4 5 H 2.8 L 1.3 3 H 1 V 5 H 0 V 1 H 1 V 2 H 2.5 A 0.5 0.5 0 0 0 2.5 1 H 0 V 0" fill="black"></path>
<path d="M 0 0 H 2.5 A 1.5 1.5 0 0 1 2.5 3 L 2.9 2.8 L 4 5 H 2.8 L 1.8 3 H 1 V 5 H 0 V 1 H 1 V 2 H 2.5 A 0.5 0.5 0 0 0 2.5 1 H 0 V 0" fill="black">
</path>
</svg>
<svg id="Snellen_T" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0,0,4,5" height="8.73mm" style="margin: 3.49mm;">
<polygon points="0,0 4,0 4,1 2.5,1 2.5,5 1.5,5 1.5,1 0,1" fill="black" />
@ -1531,7 +1536,7 @@
var dist = $('#iDistance').val();
switch (notation) {
case "1"://metres
var ar = [0.5, 0.63, 0.79, 1, 1.26, 1.58, 2, 2.51, 3.16, 3.98, 5.01, 6.31, 7.94, 10];
var ar = [0.501, 0.631, 0.794, 1, 1.259, 1.585, 2, 2.512, 3.162, 3.981, 5.012, 6.31, 7.943, 10];
//always input mm
if (numeratorType == "2") {
var scoreDisplay = ['6/3', '6/3.8', '6/4.8', '6/6', '6/7.5', '6/9.5', '6/12', '6/15', '6/19', '6/24', '6/30', '6/38', '6/48', '6/60'];
@ -1542,15 +1547,18 @@
else {
var numerator = Math.round(dist / 100) / 10;
for (a = 0; a < ar.length; a++) {
if (a<6){
var score = Math.round(ar[a] * numerator * 10) / 10;
var str = numerator + "/" + score,
score = score / numerator;
} else {
var score = Math.round(ar[a] * numerator);
}
var str = numerator + "/" + score;
chartArray[a] = [ar[a], str];
}
}
break;
case "2"://feet
var ar = [0.5, 0.63, 0.79, 1, 1.26, 1.58, 2, 2.51, 3.16, 3.98, 5.01, 6.31, 7.94, 10];
var ar = [0.501, 0.631, 0.794, 1, 1.259, 1.585, 2, 2.512, 3.162, 3.981, 5.012, 6.31, 7.943, 10];
if (numeratorType == "2") {
var scoreDisplay = ['20/10', '20/12.5', '20/16', '20/20', '20/25', '20/32', '20/40', '20/50', '20/63', '20/80', '20/100', '20/125', '20/160', '20/200'];
for (a = 0; a < ar.length; a++) {
@ -1558,24 +1566,23 @@
}
}
else {
var numerator = Math.round(dist / 100) / 10;
var numerator = Math.round(dist * 3.28084 / 1000);
for (a = 0; a < ar.length; a++) {
var score = Math.round(ar[a] * numerator * 10) / 10;
var str = numerator + "/" + score,
score = score / numerator;
var score = Math.round(ar[a] * numerator);
var str = numerator + "/" + score;
chartArray[a] = [ar[a], str];
}
}
break;
case "3"://logMar
var ar = [0.5, 0.63, 0.79, 1, 1.26, 1.58, 2, 2.51, 3.16, 3.98, 5.01, 6.31, 7.94, 10];
var ar = [0.501, 0.631, 0.794, 1, 1.259, 1.585, 2, 2.512, 3.162, 3.981, 5.012, 6.31, 7.943, 10];
var scoreDisplay = ['-0.3', '-0.2', '-0.1', '0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1'];
for (a = 0; a < ar.length; a++) {
chartArray[a] = [ar[a], scoreDisplay[a]];
}
break;
case "4"://Decimal
var ar = [0.5, 0.63, 0.79, 1, 1.26, 1.58, 2, 2.51, 3.16, 3.98, 5.01, 6.31, 7.94, 10];
var ar = [0.501, 0.631, 0.794, 1, 1.259, 1.585, 2, 2.512, 3.162, 3.981, 5.012, 6.31, 7.943, 10];
var scoreDisplay = ['2', '1.6', '1.25', '1', '0.8', '0.63', '0.5', '0.4', '0.32', '0.25', '0.2', '0.16', '0.125', '0.1'];
for (a = 0; a < ar.length; a++) {
chartArray[a] = [ar[a], scoreDisplay[a]];
@ -1596,13 +1603,14 @@
arrayCharacter = ['Snellen_N,Snellen_L,Snellen_A,Snellen_Y,Snellen_Z', 'Snellen_E,Snellen_F,Snellen_R,Snellen_D,Snellen_U', 'Snellen_T,Snellen_P,Snellen_V,Snellen_H,Snellen_X', 'Snellen_Y,Snellen_E,Snellen_L,Snellen_R,Snellen_T', 'Snellen_F,Snellen_X,Snellen_U,Snellen_D,Snellen_H', 'Snellen_A,Snellen_N,Snellen_P,Snellen_V,Snellen_Z', 'Snellen_H,Snellen_Z,Snellen_T,Snellen_Y,Snellen_D', 'Snellen_V,Snellen_F,Snellen_X,Snellen_N,Snellen_R', 'Snellen_A,Snellen_L,Snellen_P,Snellen_U,Snellen_E', 'Snellen_P,Snellen_U,Snellen_V,Snellen_F,Snellen_Y', 'Snellen_T,Snellen_A,Snellen_H,Snellen_E,Snellen_D', 'Snellen_L,Snellen_R,Snellen_N,Snellen_Z,Snellen_X', 'Snellen_D,Snellen_Y,Snellen_P,Snellen_L,Snellen_N', 'Snellen_Z,Snellen_A,Snellen_T,Snellen_F,Snellen_R']
break;
case '2'://BS4274.3
arrayCharacter = ['Snellen_N,Snellen_R,Snellen_P,Snellen_D,Snellen_Z', 'Snellen_U,Snellen_V,Snellen_E,Snellen_H,Snellen_F', 'Snellen_V,Snellen_R,Snellen_H,Snellen_N,Snellen_D', 'Snellen_F,Snellen_P,Snellen_U,Snellen_Z,Snellen_E', 'Snellen_P,Snellen_E,Snellen_F,Snellen_H,Snellen_N', 'Snellen_U,Snellen_Z,Snellen_V,Snellen_R,Snellen_D', 'Snellen_H,Snellen_N,Snellen_R,Snellen_U,Snellen_Z', 'Snellen_E,Snellen_D,Snellen_F,Snellen_P,Snellen_V', 'Snellen_D,Snellen_Z,Snellen_E,Snellen_N,Snellen_R', 'Snellen_H,Snellen_F,Snellen_P,Snellen_V,Snellen_U', 'Snellen_P,Snellen_E,Snellen_H,Snellen_U,Snellen_D', 'Snellen_R,Snellen_Z,Snellen_F,Snellen_N,Snellen_V', 'Snellen_V,Snellen_F,Snellen_E,Snellen_N,Snellen_H', 'Snellen_U,Snellen_D,Snellen_P,Snellen_R,Snellen_Z']
arrayCharacter = ['Snellen_U,Snellen_R,Snellen_N,Snellen_D,Snellen_V', 'Snellen_N,Snellen_F,Snellen_R,Snellen_Z,Snellen_E', 'Snellen_P,Snellen_D,Snellen_F,Snellen_H,Snellen_U', 'Snellen_R,Snellen_P,Snellen_N,Snellen_E,Snellen_Z', 'Snellen_D,Snellen_V,Snellen_E,Snellen_P,Snellen_R', 'Snellen_U,Snellen_D,Snellen_H,Snellen_V,Snellen_N', 'Snellen_Z,Snellen_U,Snellen_V,Snellen_F,Snellen_P', 'Snellen_E,Snellen_R,Snellen_D,Snellen_H,Snellen_Z', 'Snellen_U,Snellen_D,Snellen_P,Snellen_N,Snellen_F', 'Snellen_V,Snellen_E,Snellen_H,Snellen_U,Snellen_P', 'Snellen_F,Snellen_Z,Snellen_V,Snellen_R,Snellen_N', 'Snellen_H,Snellen_R,Snellen_E,Snellen_Z,Snellen_D', 'Snellen_N,Snellen_F,Snellen_H,Snellen_P,Snellen_Z', 'Snellen_U,Snellen_V,Snellen_F,Snellen_E,Snellen_H']
break;
case '3':
arrayCharacter = ['Sloan_Z,Sloan_V,Sloan_K,Sloan_E,Sloan_S', 'Sloan_H,Sloan_N,Sloan_D,Sloan_C,Sloan_O', 'Sloan_V,Sloan_C,Sloan_Z,Sloan_R,Sloan_H', 'Sloan_E,Sloan_S,Sloan_K,Sloan_O,Sloan_N', 'Sloan_D,Sloan_V,Sloan_R,Sloan_O,Sloan_C', 'Sloan_S,Sloan_Z,Sloan_H,Sloan_K,Sloan_E', 'Sloan_K,Sloan_E,Sloan_H,Sloan_R,Sloan_V', 'Sloan_D,Sloan_C,Sloan_N,Sloan_Z,Sloan_O', 'Sloan_C,Sloan_N,Sloan_O,Sloan_S,Sloan_Z', 'Sloan_V,Sloan_R,Sloan_D,Sloan_H,Sloan_K', 'Sloan_R,Sloan_O,Sloan_D,Sloan_K,Sloan_H', 'Sloan_S,Sloan_V,Sloan_C,Sloan_E,Sloan_Z', 'Sloan_Z,Sloan_S,Sloan_N,Sloan_E,Sloan_D', 'Sloan_R,Sloan_H,Sloan_K,Sloan_O,Sloan_V']
//CHNRV,DKOSZ,VORDN,HZCKX,OKVHD,ZRNSC,KSDCH,RNOVZ,DHROK,CNZSV,HOSDN,VCKZR,DHRNO,SVCKZ
arrayCharacter = ['Sloan_C,Sloan_H,Sloan_N,Sloan_R,Sloan_V', 'Sloan_D,Sloan_K,Sloan_O,Sloan_S,Sloan_V', 'Sloan_V,Sloan_O,Sloan_R,Sloan_D,Sloan_N', 'Sloan_H,Sloan_Z,Sloan_C,Sloan_K,Sloan_X', 'Sloan_O,Sloan_K,Sloan_V,Sloan_H,Sloan_D', 'Sloan_Z,Sloan_R,Sloan_N,Sloan_S,Sloan_C', 'Sloan_K,Sloan_S,Sloan_D,Sloan_C,Sloan_H', 'Sloan_R,Sloan_N,Sloan_O,Sloan_V,Sloan_Z', 'Sloan_D,Sloan_H,Sloan_R,Sloan_O,Sloan_K', 'Sloan_C,Sloan_N,Sloan_Z,Sloan_S,Sloan_V', 'Sloan_H,Sloan_O,Sloan_S,Sloan_D,Sloan_N', 'Sloan_C,Sloan_V,Sloan_K,Sloan_Z,Sloan_R', 'Sloan_D,Sloan_H,Sloan_R,Sloan_N,Sloan_O', 'Sloan_S,Sloan_V,Sloan_C,Sloan_K,Sloan_Z']
break;
case '4':
arrayCharacter = ['Sloan_V,Sloan_N,Sloan_T,Sloan_C,Sloan_E', 'Sloan_P,Sloan_X,Sloan_R,Sloan_Z,Sloan_S', 'Sloan_D,Sloan_H,Sloan_O,Sloan_L,Sloan_K', 'Sloan_E,Sloan_T,Sloan_K,Sloan_O,Sloan_D', 'Sloan_C,Sloan_S,Sloan_N,Sloan_R,Sloan_H', 'Sloan_P,Sloan_L,Sloan_X,Sloan_Z,Sloan_V', 'Sloan_N,Sloan_K,Sloan_Z,Sloan_P,Sloan_O', 'Sloan_E,Sloan_V,Sloan_R,Sloan_X,Sloan_D', 'Sloan_T,Sloan_C,Sloan_S,Sloan_L,Sloan_H', 'Sloan_V,Sloan_H,Sloan_D,Sloan_X,Sloan_S', 'Sloan_R,Sloan_K,Sloan_O,Sloan_L,Sloan_E', 'Sloan_Z,Sloan_P,Sloan_C,Sloan_N,Sloan_T', 'Sloan_T,Sloan_E,Sloan_C,Sloan_V,Sloan_R', 'Sloan_H,Sloan_L,Sloan_D,Sloan_P,Sloan_N']
arrayCharacter = ['Sloan_V,Sloan_N,Sloan_T,Sloan_C,Sloan_E', 'Sloan_P,Sloan_X,Sloan_R,Sloan_Z,Sloan_S', 'Sloan_D,Sloan_H,Sloan_O,Sloan_L,Sloan_K', 'Sloan_E,Sloan_T,Sloan_K,Sloan_O,Sloan_D', 'Sloan_C,Sloan_S,Sloan_N,Sloan_R,Sloan_H', 'Sloan_P,Sloan_L,Sloan_X,Sloan_Z,Sloan_V', 'Sloan_N,Sloan_K,Sloan_Z,Sloan_P,Sloan_O', 'Sloan_E,Sloan_V,Sloan_R,Sloan_X,Sloan_D', 'Sloan_T,Sloan_C,Sloan_S,Sloan_L,Sloan_H', 'Sloan_V,Sloan_H,Sloan_X,Sloan_D,Sloan_S', 'Sloan_R,Sloan_O,Sloan_K,Sloan_L,Sloan_E', 'Sloan_Z,Sloan_P,Sloan_C,Sloan_N,Sloan_T', 'Sloan_T,Sloan_E,Sloan_V,Sloan_C,Sloan_R', 'Sloan_H,Sloan_L,Sloan_D,Sloan_P,Sloan_N']
break;
case '5':
arrayCharacter = ['LandoltC_N,LandoltC_S,LandoltC_E,LandoltC_N,LandoltC_W', 'LandoltC_E,LandoltC_E,LandoltC_N,LandoltC_W,LandoltC_S', 'LandoltC_E,LandoltC_S,LandoltC_S,LandoltC_W,LandoltC_N', 'LandoltC_N,LandoltC_W,LandoltC_N,LandoltC_S,LandoltC_E', 'LandoltC_S,LandoltC_W,LandoltC_N,LandoltC_W,LandoltC_E', 'LandoltC_W,LandoltC_E,LandoltC_S,LandoltC_N,LandoltC_S', 'LandoltC_W,LandoltC_N,LandoltC_E,LandoltC_S,LandoltC_W', 'LandoltC_S,LandoltC_N,LandoltC_N,LandoltC_W,LandoltC_E', 'LandoltC_N,LandoltC_E,LandoltC_S,LandoltC_W,LandoltC_W', 'LandoltC_N,LandoltC_S,LandoltC_E,LandoltC_N,LandoltC_W', 'LandoltC_E,LandoltC_E,LandoltC_N,LandoltC_W,LandoltC_S', 'LandoltC_E,LandoltC_S,LandoltC_S,LandoltC_W,LandoltC_N', 'LandoltC_N,LandoltC_W,LandoltC_N,LandoltC_S,LandoltC_E', 'LandoltC_S,LandoltC_W,LandoltC_N,LandoltC_W,LandoltC_E']
@ -1651,7 +1659,7 @@
fifthChartRemove = $('#line-' + (i + 1)).find('svg:nth-child(5)');
var convertViewWidth = convertFunction.ConvertMMToPixel(viewWidth);
if (convertViewWidth >= svgWidth * 5) {
console.log('show all');
//console.log('show all');
$('#line-' + (i + 1)).find('svg').show();
}
else if (convertViewWidth >= svgWidth * 4) {
@ -1687,23 +1695,7 @@
$('#line-' + (i + 1)).parent().addClass('display-none');
}
};
////caculator viewportHeight
//var totalHeight = 0;
////get total of SVG height
//$('.char-line').each(function () {
// var svgHeight = convertFunction.ConvertPixelToMM($(this).parent().height());
// totalHeight = totalHeight + svgHeight;
//});
////remove line if more than viewport height
//$('.char-line').reverse().each(function () {
// var svgHeight = convertFunction.ConvertPixelToMM($(this).parent().height());
// if ((totalHeight - svgHeight) > viewHight) {
// $(this).removeAttr('style');
// $(this).parent().find('>div').html('');
// $(this).parent().find('.scoreBox').remove();
// totalHeight = totalHeight - svgHeight;
// }
//});
};
this.YatesShuffle = function (array) {
@ -1976,7 +1968,7 @@
return this.value; // $(this).val()
}).get();
function countInArray(array, what) {
return array.filter(function(item) { return item == what;}).length;
return array.filter(item => item == what).length;
}
var result = false;
var currentVal = $(element).val();
@ -2023,16 +2015,6 @@
maxWidht = $(this).width();
}
});
/*if ($maxWidthEle != undefined) {
if (isSmall) {
var scorePosition = $maxWidthEle.width();
}
else {
var scorePosition = $maxWidthEle.offset().left + $maxWidthEle.width();
}
$('.scoreBox').css('left', scorePosition);
}*/
//set widht for scorebox
$('.scoreBox').each(function () {
if ($(this).outerWidth() > scoreWidth) {
scoreWidth = $(this).outerWidth();
@ -2182,37 +2164,6 @@
return (mm * dpi) / 25.4
};
this.ScrollTopDistance = function () {
//scrollPos = $(window).scrollTop();
//$('#displaySetting > div').each(function () {
// var elementPos = parseInt($(this).offset().top),
// isStop = false;
// preveElemt = $(this).prev();
// if (preveElemt.length > 0) {
// if (elementPos <= scrollPos + 1 && parseInt($(this).next().offset().top) > scrollPos) {
// if (elementPos == scrollPos + 1) {
// $("html, body").animate({ scrollTop: parseInt(scrollPos - (preveElemt.height())) }, "slow");
// }
// else if (elementPos < scrollPos + 1) {
// $("html, body").animate({ scrollTop: parseInt(preveElemt.offset().top) }, "slow");
// }
// }
// else if ($(window).scrollTop() + $(window).height() == $(document).height()) {//check if scroll end of bottom
// // The element is not visible, do something else
// var offsetArr = [],
// prevOfsset = null;
// $('#displaySetting > div').each(function () {
// offsetArr.push(parseInt($(this).offset().top));//get all offset top of element
// });
// $.each(offsetArr, function () {
// if (this <= scrollPos && (prevOfsset == null || (scrollPos - this) < (scrollPos - prevOfsset))) {
// prevOfsset = this;//get the min offset top near scrollTop
// }
// });
// $("html, body").animate({ scrollTop: parseInt(prevOfsset) }, "fast");
// return false;
// }
// }
//});
var scrollPos = $(window).scrollTop(),
screenHeight = $(window).height(),
checkViewPort = this;
@ -2234,28 +2185,12 @@
$('.scroll-div').remove();
};
this.DivideScrollPage = function () {
//
console.log(window.innerHeight + " " + $(window).height());
var maxHeight = $(window).height(),
quotalHeight = 0,
checkHeight = false;
/* $('#displaySetting').find('.character-line').each(function () {
if ($(this).height() > maxHeight) {
checkHeight = true;
}
});
if (checkHeight) {
//$('#displaySetting').html('<div data-line="1" class="character-line"><div class="char-line" id="line-1"></div></div><div data-line="2" class="character-line"><div class="char-line" id="line-2"></div></div>'
// + '<div data-line="3" class="character-line"><div class="char-line" id="line-3"></div></div><div data-line="4" class="character-line"><div class="char-line" id="line-4"></div></div>'
// + '<div data-line="5" class="character-line"><div class="char-line" id="line-5"></div></div><div data-line="6" class="character-line"><div class="char-line" id="line-6"></div></div>'
// + '<div data-line="7" class="character-line"><div class="char-line" id="line-7"></div></div><div data-line="8" class="character-line"><div class="char-line" id="line-8"></div></div>'
// + '<div data-line="9" class="character-line"><div class="char-line" id="line-9"></div></div><div data-line="10" class="character-line"><div class="char-line" id="line-10"></div></div>'
// + '<div data-line="11" class="character-line"><div class="char-line" id="line-11"></div></div><div data-line="12" class="character-line"><div class="char-line" id="line-12"></div></div>'
// + '<div data-line="13" class="character-line"><div class="char-line" id="line-13"></div></div><div data-line="14" class="character-line"><div class="char-line" id="line-14"></div></div>');
//alert('The distance is too large, please update again.');
}
*/
//else {
$('#displaySetting >div').each(function () {
$('#displaySetting >div').each(function () {
if ($(this).find('.char-line').height() > 0) {
if ($(this).height() + quotalHeight <= maxHeight) {
quotalHeight = quotalHeight + $(this).height();
@ -2285,7 +2220,6 @@
$(this).remove();
}
});
//}
};
this.CheckCharacterViewPort = function () {
@ -2399,15 +2333,6 @@
$('.setting-bar').removeClass('active');
$('.guide-section').removeClass('active');
$('.mask').removeClass('active');
//set widht height for body
//if (callBackFunction.ConvertPixelToMM($('#displaySetting').height()) < viewHight) {
// $('#displaySetting').css('height', callBackFunction.ConvertPixelToMM($('#displaySetting').height()) + 'mm')
//} else {
// $('#displaySetting').css({
// height: viewHight + 'mm',
// });
//}
//set widht
var $Element, maxEleWidht = 0
$('#displaySetting').find('>div').find('.char-line').each(function () {
if ($(this).width() > maxEleWidht) {
@ -2570,5 +2495,11 @@
configWolf.Init();
});
</script>
<script>if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(function() { console.log("INDEX:Service Worker Registered"); });
}
</script>
</body>
</html>

52
manifest.json Normal file
View File

@ -0,0 +1,52 @@
{
"name": "WolfChart v1.5",
"short_name": "WolfChart",
"theme_color": "#86c7ef",
"background_color": "#86c7ef",
"display": "fullscreen",
"scope": "/",
"start_url": "/test_index.htm",
"icons": [
{
"src": "images/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "images/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
},
{
"src": "images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "images/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src": "images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"splash_pages": null
}

198
sw.js Normal file
View File

@ -0,0 +1,198 @@
"use strict";
//console.log('WORKER: executing.');
/* A version number is useful when updating the worker logic,
allowing you to remove outdated cache entries during the update.
*/
var version = 'v1::';
/* These resources will be downloaded and cached by the service worker
during the installation process. If any resource fails to be downloaded,
then the service worker won't be installed either.
*/
var offlineFundamentals = [
'test_index.htm',
'manifest.json'
];
/* The install event fires when the service worker is first installed.
You can use this event to prepare the service worker to be able to serve
files while visitors are offline.
*/
self.addEventListener("install", function(event) {
//console.log('WORKER: install event in progress.');
/* Using event.waitUntil(p) blocks the installation process on the provided
promise. If the promise is rejected, the service worker won't be installed.
*/
event.waitUntil(
/* The caches built-in is a promise-based API that helps you cache responses,
as well as finding and deleting them.
*/
caches
/* You can open a cache by name, and this method returns a promise. We use
a versioned cache name here so that we can remove old cache entries in
one fell swoop later, when phasing out an older service worker.
*/
.open(version + 'fundamentals')
.then(function(cache) {
/* After the cache is opened, we can fill it with the offline fundamentals.
The method below will add all resources in `offlineFundamentals` to the
cache, after making requests for them.
*/
return cache.addAll(offlineFundamentals);
})
.then(function() {
//console.log('WORKER: install completed');
})
);
});
/* The fetch event fires whenever a page controlled by this service worker requests
a resource. This isn't limited to `fetch` or even XMLHttpRequest. Instead, it
comprehends even the request for the HTML page on first load, as well as JS and
CSS resources, fonts, any images, etc.
*/
self.addEventListener("fetch", function(event) {
//console.log('WORKER: fetch event in progress.');
/* We should only cache GET requests, and deal with the rest of method in the
client-side, by handling failed POST,PUT,PATCH,etc. requests.
*/
if (event.request.method !== 'GET') {
/* If we don't block the event as shown below, then the request will go to
the network as usual.
*/
//console.log('WORKER: fetch event ignored.', event.request.method, event.request.url);
return;
}
/* Similar to event.waitUntil in that it blocks the fetch event on a promise.
Fulfillment result will be used as the response, and rejection will end in a
HTTP response indicating failure.
*/
event.respondWith(
caches
/* This method returns a promise that resolves to a cache entry matching
the request. Once the promise is settled, we can then provide a response
to the fetch request.
*/
.match(event.request)
.then(function(cached) {
/* Even if the response is in our cache, we go to the network as well.
This pattern is known for producing "eventually fresh" responses,
where we return cached responses immediately, and meanwhile pull
a network response and store that in the cache.
Read more:
https://ponyfoo.com/articles/progressive-networking-serviceworker
*/
var networked = fetch(event.request)
// We handle the network request with success and failure scenarios.
.then(fetchedFromNetwork, unableToResolve)
// We should catch errors on the fetchedFromNetwork handler as well.
.catch(unableToResolve);
/* We return the cached response immediately if there is one, and fall
back to waiting on the network as usual.
*/
//console.log('WORKER: fetch event', cached ? '(cached)' : '(network)', event.request.url);
return cached || networked;
function fetchedFromNetwork(response) {
/* We copy the response before replying to the network request.
This is the response that will be stored on the ServiceWorker cache.
*/
var cacheCopy = response.clone();
//console.log('WORKER: fetch response from network.', event.request.url);
caches
// We open a cache to store the response for this request.
.open(version + 'pages')
.then(function add(cache) {
/* We store the response for this request. It'll later become
available to caches.match(event.request) calls, when looking
for cached responses.
*/
return cache.put(event.request, cacheCopy);
})
.then(function() {
//console.log('WORKER: fetch response stored in cache.', event.request.url);
});
// Return the response so that the promise is settled in fulfillment.
return response;
}
/* When this method is called, it means we were unable to produce a response
from either the cache or the network. This is our opportunity to produce
a meaningful response even when all else fails. It's the last chance, so
you probably want to display a "Service Unavailable" view or a generic
error response.
*/
function unableToResolve () {
/* There's a couple of things we can do here.
- Test the Accept header and then return one of the `offlineFundamentals`
e.g: `return caches.match('/some/cached/image.png')`
- You should also consider the origin. It's easier to decide what
"unavailable" means for requests against your origins than for requests
against a third party, such as an ad provider.
- Generate a Response programmaticaly, as shown below, and return that.
*/
//console.log('WORKER: fetch request failed in both cache and network.');
/* Here we're creating a response programmatically. The first parameter is the
response body, and the second one defines the options for the response.
*/
return new Response('<h1>Service Unavailable</h1>', {
status: 503,
statusText: 'Service Unavailable',
headers: new Headers({
'Content-Type': 'text/html'
})
});
}
})
);
});
/* The activate event fires after a service worker has been successfully installed.
It is most useful when phasing out an older version of a service worker, as at
this point you know that the new worker was installed correctly. In this example,
we delete old caches that don't match the version in the worker we just finished
installing.
*/
self.addEventListener("activate", function(event) {
/* Just like with the install event, event.waitUntil blocks activate on a promise.
Activation will fail unless the promise is fulfilled.
*/
//console.log('WORKER: activate event in progress.');
event.waitUntil(
caches
/* This method returns a promise which will resolve to an array of available
cache keys.
*/
.keys()
.then(function (keys) {
// We return a promise that settles when all outdated caches are deleted.
return Promise.all(
keys
.filter(function (key) {
// Filter by keys that don't start with the latest version prefix.
return !key.startsWith(version);
})
.map(function (key) {
/* Return a promise that's fulfilled
when each outdated cache is deleted.
*/
return caches.delete(key);
})
);
})
.then(function() {
//console.log('WORKER: activate completed.');
})
);
});