Compare commits

9 Commits

10 changed files with 389 additions and 68 deletions

BIN
calenderwatch_client.wgt Normal file

Binary file not shown.

BIN
css/CourierPrimeBold.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
css/JetBrainsMono-Bold.ttf Normal file

Binary file not shown.

BIN
css/alba.regular.ttf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,15 +1,33 @@
@font-face{
font-family: courier;
src: url('CourierPrimeSansRegular.ttf');
}
@font-face{
font-family: fabiolo;
src: url('fabiolo-smallcap-regular.ttf')
}
.Roboto{
font-family: fabiolo;
}
html, body { html, body {
width: 100%; width: 100%;
height: 100%; height: 100%;
margin: 0; margin: 0;
overflow-y: hidden; overflow-y: hidden;
font-family: "courier";
} }
#container { #container {
display: -webkit-flex; display: -webkit-flex;
-webkit-align-items: center; -webkit-align-items: center;
width: 100%; width: 100%;
height: 100% height: 100%;
} }
#canvas-layout { #canvas-layout {
@ -19,9 +37,103 @@ html, body {
z-index: 1; z-index: 1;
} }
#canvas-content { #canvas-content {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
z-index: 2; z-index: 2;
} }
/*
hour&minutes
*/
#digital-body {
position: absolute;
width: 360px;
height: 360px;
top: 0px;
left: 0px;
background-size: 100%;
background-repeat: no-repeat;
overflow: hidden;
}
#str-just-hours {
text-transform: full-width;
font-size: 600%;
font-style: bold;
letter-spacing: -2px;
float: left;
color: white;
width: 90px;
text-align: right;
}
#rec-time {
position: relative;
display: inline-block;
top: 40%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
z-index: 1;
}
#str-hours {
font-size: 450%;
font-style: bold;
letter-spacing: -10px;
float: left;
color: white;
width: 80px;
text-align: right;
transform: translate(-5px, 0);
}
#str-console {
font-size: 250%;
float: left;
color: white;
visibility: hidden;
transform: translate(-6px, 8px);
}
#str-minutes {
font-size: 450%;
letter-spacing: -10px;
float: left;
color: white;
width: 70px;
text-align: left;
transform: translate(-15px, 0);
}
#str-ampm {
font-size: 280%;
color: white;
padding-top: 20%;
}
#str-event {
position: absolute;
display: inline-block;
top:60%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
font-size: 175%;
color: white;
text-align: center;
z-index: 2;
line-height: 100%;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
-webkit-box-orient: vertical;
}
}

View File

@ -6,14 +6,29 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<meta name="description" content="Canvas Watch - Canvas API & Time API" /> <meta name="description" content="Canvas Watch - Canvas API & Time API" />
<title>Canvas Watch</title> <title>Canvas Watch</title>
<link rel="stylesheet" type="text/css" href="css/style.css" /> <link rel="stylesheet" type="text/css" href="css/style.css" />
</head> </head>
<body> <body>
<div id="digital-body">
<div id="str-just-hours"></div>
<div id="rec-time">
<div id="str-hours"></div>
<div id="str-console">:</div>
<div id="str-minutes"></div>
</div>
<div id="str-event"></div>
</div>
<div id="container"> <div id="container">
<canvas id="canvas-layout"></canvas> <canvas id="canvas-layout"></canvas>
<canvas id="canvas-content"></canvas> <canvas id="canvas-content"></canvas>
</div> </div>
<script src="js/app.js"></script> <script src="js/app.js"></script>
</body> </body>

318
js/app.js
View File

@ -17,13 +17,15 @@
/* 'downloads' for debugging, /* 'downloads' for debugging,
* 'wgt-private' for any release */ * 'wgt-private' for any release */
var STORAGE_SPACE = "wgt-private"; var STORAGE_SPACE = "downloads";
var SHORT_WAIT = 10000; var SHORT_WAIT = 10000;
var LONG_WAIT = 600000; var LONG_WAIT = 30000; // 600000
var DESIGN = 2; // 0 - longitude, 1 - mission control, 2 - longitude
var wait_time = LONG_WAIT; var wait_time = LONG_WAIT;
var events = null; var events = null;
var deviceFingerprint = null; var deviceFingerprint = null;
var eventsTimeStamp = 0; var eventsTimeStamp = 0;
var flagDigital = true;
(function() { (function() {
var canvasLayout, var canvasLayout,
@ -33,6 +35,8 @@ var eventsTimeStamp = 0;
center, center,
watchRadius; watchRadius;
var flagConsole = true;
function deleteFile(name, callback) { function deleteFile(name, callback) {
@ -148,34 +152,35 @@ var eventsTimeStamp = 0;
} }
function getNewFingerprintFromServer() { function getNewFingerprintFromServer() {
getFileFromServer("/devicefingerprint.json", function() { getFileFromServer("devicefingerprint.json", function() {
console.log("getting device fingerprint from server") console.log("getting device fingerprint from server");
getJsonFile("devicefingerprint", function(df) {devicefingerprint = df; console.log(devicefingerprint)}); getJsonFile("devicefingerprint", function(df) {deviceFingerprint = df; console.log(deviceFingerprint);});
}); });
} }
function getDeviceFingerprint() { function getDeviceFingerprint() {
// check if device id set already as global, if it is return // check if device id set already as global, if it is return
if(deviceFingerprint != null) if(deviceFingerprint !== null) {
return; return;
}
// otherwise, check if there is a devicefingerprint file in wgt-private // otherwise, check if there is a devicefingerprint file in wgt-private
// if there is, open it up and get your device ID from it // if there is, open it up and get your device ID from it
getJsonFile("devicefingerprint", function(df) { getJsonFile("devicefingerprint", function(df) {
if(df != null) { if(df !== null) {
deviceFingerprint = df; deviceFingerprint = df;
} else { } else {
// otherwise, ask the longitude server for a device fingerprint file // otherwise, ask the longitude server for a device fingerprint file
getNewFingerprintFromServer(); getNewFingerprintFromServer();
} }
}) });
} }
function getFileFromServer(route, callback) { function getFileFromServer(route, callback) {
console.log("getting file"); console.log("getting file");
var server = "https://longitudecalendar.com/" var server = "https://longitudecalendar.com/";
var downloadRequest = new tizen.DownloadRequest(server + route, STORAGE_SPACE); var downloadRequest = new tizen.DownloadRequest(server + route, STORAGE_SPACE);
tizen.systeminfo.getPropertyValue('NETWORK', function(networkInfo) { tizen.systeminfo.getPropertyValue('NETWORK', function(networkInfo) {
if (networkInfo.networkType === 'NONE') { if (networkInfo.networkType === 'NONE') {
@ -216,7 +221,7 @@ var eventsTimeStamp = 0;
function updateCalendar() { function updateCalendar() {
if(deviceFingerprint == null) { if(deviceFingerprint === null) {
console.log("no fingerprint, loading from file or server"); console.log("no fingerprint, loading from file or server");
getDeviceFingerprint(); getDeviceFingerprint();
wait_time = SHORT_WAIT; wait_time = SHORT_WAIT;
@ -235,6 +240,18 @@ var eventsTimeStamp = 0;
return true; return true;
} }
function renderLine(context, p1, p2, thickness, color) {
context.save();
context.beginPath();
context.lineCap = "round";
context.lineWidth = thickness;
context.moveTo(p1.x, p1.y);
context.lineTo(p2.x, p2.y);
context.strokeStyle = color;
context.stroke();
context.restore();
}
/** /**
* Renders a circle with specific center, radius, and color * Renders a circle with specific center, radius, and color
* @private * @private
@ -252,7 +269,36 @@ var eventsTimeStamp = 0;
context.restore(); context.restore();
} }
/**
* Renders a circle with specific center, radius, and color
* @private
* @param {object} context - the context for the circle to be placed in
* @param {number} radius - the radius of the circle
* @param {string} color - the color of the circle
*/
function renderRing(context, center, radius, width, color) {
context.save();
context.beginPath();
context.arc(center.x, center.y, radius, 0, 2 * Math.PI);
context.strokeStyle = color;
context.lineWidth = width;
context.stroke();
context.closePath();
context.restore();
}
function renderSimpleArc(context, center, radius, thickness, color, startAngle, endAngle) {
context.save();
context.beginPath();
context.arc(center.x, center.y, radius, startAngle * Math.PI / 180., endAngle * Math.PI / 180.);
context.fillStyle = color;
context.strokeStyle = color;
context.lineWidth = thickness;
context.stroke();
context.restore();
}
/** /**
* Renders a partial with specific center, radius, and color * Renders a partial with specific center, radius, and color
* @private * @private
@ -260,14 +306,16 @@ var eventsTimeStamp = 0;
* @param {number} radius - the radius of the circle * @param {number} radius - the radius of the circle
* @param {string} color - the color of the circle * @param {string} color - the color of the circle
*/ */
function renderArc(context, center, radius, color, startAngle, endAngle, hardStart, hardStop) { function renderArc(context, center, radius, thickness, color, startAngle, endAngle, hardStart, hardStop) {
if(hardStart == undefined) if(hardStart == undefined) {
hardStart = false; hardStart = false;
if(hardStop == undefined) }
if(hardStop == undefined) {
hardStop= false; hardStop= false;
}
seperation = 5; var seperation = 3;
// if arc size smaller than separation for circles or circle, // if arc size smaller than separation for circles or circle,
// draw a circle // draw a circle
@ -283,27 +331,30 @@ var eventsTimeStamp = 0;
return; return;
} }
if(!hardStart) if(!hardStart) {
startAngle += seperation; startAngle += seperation;
}
if(startAngle >= 360) if(startAngle >= 360) {
startAngle -= 360; startAngle -= 360;
}
if(!hardStop) if(!hardStop) {
endAngle -= seperation; endAngle -= seperation;
}
if(endAngle<0) if(endAngle<0) {
endAngle += 360; endAngle += 360;
}
// otherwise draw an arc and two circles
// else draw an arc and two circles
context.save(); context.save();
context.beginPath(); context.beginPath();
context.arc(center.x, center.y, radius, startAngle * Math.PI / 180., endAngle * Math.PI / 180.); context.arc(center.x, center.y, radius, startAngle * Math.PI / 180., endAngle * Math.PI / 180.);
context.fillStyle = color; context.fillStyle = color;
context.strokeStyle = color; context.strokeStyle = color;
context.lineWidth = 18; context.lineWidth = thickness;
context.stroke(); context.stroke();
context.restore(); context.restore();
@ -326,7 +377,7 @@ var eventsTimeStamp = 0;
hour -= 18; hour -= 18;
else else
hour += 6; hour += 6;
angle = (hour) * 15; var angle = (hour) * 15;
return angle; return angle;
} }
@ -386,6 +437,14 @@ var eventsTimeStamp = 0;
renderCircle(ctxContent, polToCart(sunDistance, hourToAngle(hour + minute / 60)), 16, sunColor); renderCircle(ctxContent, polToCart(sunDistance, hourToAngle(hour + minute / 60)), 16, sunColor);
} }
function renderSmallSun(date, hour, minute, second) {
sunColor = "#FFD700";
sunDistance = document.body.clientWidth / 2 - 40;
renderCircle(ctxContent, polToCart(sunDistance, hourToAngle(hour + minute / 60)), 10, sunColor);
}
function renderEarth(date, minute, second) { function renderEarth(date, minute, second) {
var earthColor = "#0077BE"; var earthColor = "#0077BE";
@ -393,6 +452,17 @@ var eventsTimeStamp = 0;
renderCircle(ctxContent, polToCart(earthDistance, minuteToAngle(minute + second / 60)), 10, earthColor); renderCircle(ctxContent, polToCart(earthDistance, minuteToAngle(minute + second / 60)), 10, earthColor);
} }
function renderAnalog(hour, minute, second) {
// hour
var hourAngle = hourToAngle(hour + minute / 60)*2+180;
renderLine(ctxContent, polToCart(document.body.clientWidth / 2 - 120, hourAngle), polToCart(document.body.clientWidth / 2 - 60, hourAngle), 18, '#ffffff');
renderLine(ctxContent, polToCart(document.body.clientWidth / 2 - 120, hourAngle), polToCart(document.body.clientWidth / 2 - 60, hourAngle), 12, '#000000');
// minute
var minuteAngle = minuteToAngle(minute + second / 60);
renderLine(ctxContent, polToCart(document.body.clientWidth / 2 - 120, minuteAngle), polToCart(document.body.clientWidth / 2 - 40, minuteAngle), 18, '#ffffff');
}
/** /**
* Renders text at a specific center, radius, and color * Renders text at a specific center, radius, and color
@ -421,8 +491,6 @@ var eventsTimeStamp = 0;
* @private * @private
*/ */
function drawWatchLayout() { function drawWatchLayout() {
var i,
j;
// Clear canvas // Clear canvas
ctxLayout.clearRect(0, 0, ctxLayout.canvas.width, ctxLayout.canvas.height); ctxLayout.clearRect(0, 0, ctxLayout.canvas.width, ctxLayout.canvas.height);
@ -461,27 +529,35 @@ var eventsTimeStamp = 0;
* @private * @private
*/ */
function drawWatchContent() { function drawWatchContent() {
var datetime = tizen.time.getCurrentDateTime(), var datetime = tizen.time.getCurrentDateTime();
hour = datetime.getHours(),
minute = datetime.getMinutes(),
second = datetime.getSeconds(),
date = datetime.getDate();
// Clear canvas // Clear canvas
ctxContent.clearRect(0, 0, ctxContent.canvas.width, ctxContent.canvas.height); ctxContent.clearRect(0, 0, ctxContent.canvas.width, ctxContent.canvas.height);
// Draw the hour needle
renderSun(date, hour, minute, second);
// Draw the minute needle
var hour = datetime.getHours(),
minute = datetime.getMinutes(),
second = datetime.getSeconds(),
date = datetime.getDate();
if(DESIGN === 0) {
renderSun(date, hour, minute, second);
renderEarth(ctxContent, minute, second); renderEarth(ctxContent, minute, second);
} else if(DESIGN === 1) {
drawDigitalWatch();
} else if(DESIGN === 2) {
renderSmallSun(date, hour, minute, second);
drawDigitalWatch();
}
/* if no return from server yet */ /* if no return from server yet */
if(events == null) if(events === null) {
return; return;
}
/* if device not on server anymore */ /* if device not on server anymore */
if(events.kind == "not found") { if(events.kind === "not found") {
deviceFingerprint = null; deviceFingerprint = null;
events = null; events = null;
deleteFile("devicefingerprint", function() {}); deleteFile("devicefingerprint", function() {});
@ -489,7 +565,7 @@ var eventsTimeStamp = 0;
return; return;
} }
/* if device not registered */ /* if device not registered */
if(events.kind == "unregistered") { if(events.kind === "unregistered") {
wait_time = SHORT_WAIT; wait_time = SHORT_WAIT;
if(deviceFingerprint === null) { if(deviceFingerprint === null) {
} else { } else {
@ -498,63 +574,179 @@ var eventsTimeStamp = 0;
return; return;
} }
console.log("switched to long wait"); if(DESIGN === 0) {
var thickness = 18;
} else if(DESIGN === 1) {
var thickness = 50;
} else if(DESIGN === 2) {
var thickness = 18;
}
wait_time = LONG_WAIT; wait_time = LONG_WAIT;
/* else: device registered and all events saved */ var wroteEvent = false;
var thickness = 18;
var edge = document.body.clientWidth / 2 - thickness / 2 - 2;
for(var event in events.events){ for(var event in events.events){
var startedBeforeToday = false; var startedBeforeToday = false;
var endsAfterToday = false; var endsAfterToday = false;
var e = events.events[event]; var e = events.events[event];
// check if not today // check if not today
if(e.startDateTime.date.year != tizen.time.getCurrentDateTime().getFullYear() || if(e.startDateTime.date.year !== tizen.time.getCurrentDateTime().getFullYear() ||
e.startDateTime.date.month != tizen.time.getCurrentDateTime().getMonth() + 1 || e.startDateTime.date.month !== tizen.time.getCurrentDateTime().getMonth() + 1 ||
e.startDateTime.date.day != tizen.time.getCurrentDateTime().getDate()){ e.startDateTime.date.day !== tizen.time.getCurrentDateTime().getDate()){
// if not today, check if it is an earlier event // if not today, check if it is an earlier event
if(e.startDateTime.date.year < tizen.time.getCurrentDateTime().getFullYear()) if(e.startDateTime.date.year < tizen.time.getCurrentDateTime().getFullYear()) {
startedBeforeToday = true; startedBeforeToday = true;
else if(e.startDateTime.date.month < tizen.time.getCurrentDateTime().getMonth() + 1) } else if(e.startDateTime.date.month < tizen.time.getCurrentDateTime().getMonth() + 1) {
startedBeforeToday = true; startedBeforeToday = true;
else if(e.startDateTime.date.day < tizen.time.getCurrentDateTime().getDate()) } else if(e.startDateTime.date.day < tizen.time.getCurrentDateTime().getDate()) {
startedBeforeToday = true; startedBeforeToday = true;
else } else {
continue; continue;
} }
}
// check if not today // check if not today
if(e.stopDateTime.date.year != tizen.time.getCurrentDateTime().getFullYear() || if(e.stopDateTime.date.year !== tizen.time.getCurrentDateTime().getFullYear() ||
e.stopDateTime.date.month != tizen.time.getCurrentDateTime().getMonth() + 1 || e.stopDateTime.date.month !== tizen.time.getCurrentDateTime().getMonth() + 1 ||
e.stopDateTime.date.day != tizen.time.getCurrentDateTime().getDate()){ e.stopDateTime.date.day !== tizen.time.getCurrentDateTime().getDate()){
// if not check if later date // if not check if later date
if(e.startDateTime.date.year > tizen.time.getCurrentDateTime().getFullYear()) if(e.stopDateTime.date.year > tizen.time.getCurrentDateTime().getFullYear()) {
endsAfterToday = true; endsAfterToday = true;
else if(e.startDateTime.date.month > tizen.time.getCurrentDateTime().getMonth() + 1) } else if(e.stopDateTime.date.month > tizen.time.getCurrentDateTime().getMonth() + 1) {
endsAfterToday = true; endsAfterToday = true;
else if(e.startDateTime.date.day > tizen.time.getCurrentDateTime().getDate()) } else if(e.stopDateTime.date.day > tizen.time.getCurrentDateTime().getDate()) {
endsAfterToday = true; endsAfterToday = true;
else } else {
continue; continue;
} }
}
if(startedBeforeToday && endsAfterToday) if(startedBeforeToday && endsAfterToday) {
continue; continue;
}
var startTime = 0; var startTime = 0;
if(!startedBeforeToday) if(!startedBeforeToday) {
startTime = e.startDateTime.time.hour + e.startDateTime.time.minute / 60; startTime = e.startDateTime.time.hour + e.startDateTime.time.minute / 60;
}
var stopTime = 0; var stopTime = 24;
if(!endsAfterToday) if(!endsAfterToday) {
stopTime = e.stopDateTime.time.hour + e.stopDateTime.time.minute / 60; stopTime = e.stopDateTime.time.hour + e.stopDateTime.time.minute / 60;
renderArc(ctxContent, center, edge, e.color, hourToAngle(startTime), hourToAngle(stopTime), startedBeforeToday, endsAfterToday);
} }
if(DESIGN === 0) {
var edge = document.body.clientWidth / 2 - thickness / 2 - 2;
renderArc(ctxContent, center, edge, thickness, e.color, hourToAngle(startTime), hourToAngle(stopTime), startedBeforeToday, endsAfterToday);
} else if(DESIGN === 1) {
var edge = document.body.clientWidth / 2 - thickness / 2 - 2;
renderArc(ctxContent, center, edge, thickness, e.color, hourToAngle(startTime), hourToAngle(stopTime), true, true);
} else if(DESIGN === 2) {
var edge = document.body.clientWidth / 2 - thickness / 2 - 2;
renderArc(ctxContent, center, edge, thickness, e.color, hourToAngle(startTime), hourToAngle(stopTime), startedBeforeToday, endsAfterToday);
}
if(eventNow(e, hour, minute)) {
console.log("!!!writing name");
wroteEvent = true;
drawEventName(e.name);
}
}
if(!wroteEvent) {
drawEventName("");
}
if(DESIGN === 0) {
} else if(DESIGN === 1) {
var inner = document.body.clientWidth / 2 - thickness;
renderSimpleArc(ctxContent, center, 115, 8, "#FFFFFF", hourToAngle(20), hourToAngle(20+0.999))
for(var i = 0; i < 24; i++) {
renderSimpleArc(ctxContent, center, edge, thickness, "#000000", i*15-0.8, i*15+0.8);
}
} else if(DESIGN === 2) {
}
}
function eventNow(event, hour, minute) {
if( ((event.startDateTime.time.hour < hour) ||
(event.startDateTime.time.hour <= hour &&
event.startDateTime.time.minute <= minute)) ) {
console.log("start before");
}
if( ((event.stopDateTime.time.hour > hour) ||
(event.stopDateTime.time.hour >= hour &&
event.stopDateTime.time.minute >= minute)) ) {
console.log("stop after");
}
if( ((event.startDateTime.time.hour < hour) ||
(event.startDateTime.time.hour <= hour &&
event.startDateTime.time.minute <= minute)) &&
((event.stopDateTime.time.hour > hour) ||
(event.stopDateTime.time.hour >= hour &&
event.stopDateTime.time.minute >= minute)) ){
return true;
}
return false;
}
function drawEventName(name) {
var strEvent = document.getElementById("str-event");
strEvent.innerHTML = name;
}
function drawDigitalWatch(datetime) {
var strHours = document.getElementById("str-hours"),
strConsole = document.getElementById("str-console"),
strMinutes = document.getElementById("str-minutes"),
datetime = tizen.time.getCurrentDateTime(),
hour = datetime.getHours(),
minute = datetime.getMinutes();
strHours.innerHTML = hour;
strMinutes.innerHTML = minute;
if (hour < 10) {
strHours.innerHTML = "0" + hour;
}
if (minute < 10) {
strMinutes.innerHTML = "0" + minute;
}
// Each 0.5 second the visibility of flagConsole is changed.
if(flagDigital) {
if (flagConsole) {
strConsole.style.visibility = "visible";
flagConsole = false;
} else {
strConsole.style.visibility = "hidden";
flagConsole = true;
}
}
else {
strConsole.style.visibility = "visible";
flagConsole = false;
}
}
/**
* Sets to background image as BACKGROUND_URL,
* and starts timer for normal digital watch mode.
* @private
*/
function initDigitalWatch() {
flagDigital = true;
document.getElementById("digital-body").style.backgroundImage = BACKGROUND_URL;
interval = setInterval(updateTime, 500);
} }
function loopCalendar(offset_ms) { function loopCalendar(offset_ms) {
@ -635,13 +827,13 @@ document.addEventListener('ambientmodechanged', function(ev) {
/* Change the UI for ambient mode */ /* Change the UI for ambient mode */
//updateAmbientWatchFaceDOM(); // function to rearange DOM for AOD mode //updateAmbientWatchFaceDOM(); // function to rearange DOM for AOD mode
flagDigital = false;
updateTime(); updateTime();
} else { } else {
/* Change the UI for normal mode */ /* Change the UI for normal mode */
// updateNormalWatchFaceDOM(); // function to rearange DOM for AOD mode // updateNormalWatchFaceDOM(); // function to rearange DOM for AOD mode
flagDigital = true;
updateTime(); updateTime();
} }
}); });

2
js/jquery-3.5.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long