-
-
Save PrintStructor/9e25d57992240fcac02ee42b8070853a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: deep-green; icon-glyph: eye; | |
let location = "1"; | |
let param = args.widgetParameter; | |
if (param != null && param.length > 0) { | |
location = param; | |
} | |
// TODO embed https://www.mysports.com/nox/public/v1/studios/1225816400/utilization/v2/indicator/limits with different color scheme | |
// utilizationIndicatorLowLimitPercentage:37 | |
// utilizationIndicatorNormalLimitPercentage:62 | |
const studios = { | |
"1": { | |
studioName:"Brunnthal", | |
studioId:"1225817660", | |
referer:"c3BlZWRmaXRuZXNzOjEyMjU4MTc2NjA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-brunnthal", | |
logo:"Logo_Brunnthal.png" | |
}, | |
"2": { | |
studioName:"Sendling", | |
studioId:"1217120190", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTcxMjAxOTA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-sendling", | |
logo:"Logo_Sendling.png" | |
}, | |
"3": { | |
studioName:"Bad_Aibling", | |
studioId:"1210005780", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTAwMDU3ODA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-badaibling", | |
logo:"Logo_Bad_Aibling.png" | |
}, | |
"4": { | |
studioName:"Bruckmuehl", | |
studioId:"1212577740", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTI1Nzc3NDA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-bruckmuehl", | |
logo:"Logo_Bruckmuehl.png" | |
}, | |
"5": { | |
studioName:"Grafing", | |
studioId:"1225816400", | |
referer:"c3BlZWRmaXRuZXNzOjEyMjU4MTY0MDA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-grafing", | |
logo:"Logo_Grafing.png" | |
}, | |
"6": { | |
studioName:"Gunzenhausen", | |
studioId:"1210005450", | |
referer:"d2VoZWJhOjEyMTAwMDU0NTA%3D", | |
tenant:"speedfitness", | |
tenant:"weheba", | |
URL:"speedfitness-gunzenhausen", | |
logo:"Logo_Gunzenhausen.png" | |
}, | |
"7": { | |
studioName:"Mainburg", | |
studioId:"speedfitness-mainburg", | |
referer:"Not yet available", | |
tenant:"speedfitness", | |
URL:"speedfitness-mainburg", | |
logo:"Logo_Mainburg.png" | |
}, | |
"8": { | |
studioName:"Wasserburg", | |
studioId:"1217120110", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTcxMjAxMTA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-wasserburg", | |
logo:"Logo_Wasserburg.png" | |
} | |
} | |
console.log(studios[location].studioId) | |
const studioId = studios[location].studioId; | |
const studioURL = studios[location].URL; | |
const studioTenant = studios[location].tenant; | |
const contextSize = 282; | |
const fitXOrange = new Color("#ff8c00"); | |
const lightGrey = new Color("#bfbbbb"); | |
const widgetBackgroundColor = Color.black() | |
// Adjustments for the API CALL | |
const apiURL = "https://www.mysports.com/nox/public/v1/studios/" + studioId + "/utilization/v2/today"; | |
const reqBodyData = {}; | |
const logoURL = "https://" + studioURL + ".de/files/cto_layout/themedesigner/uploads/" + studios[location].logo; | |
const tapURL = "https://www.mysports.com/studio/" + studios[location].referer + "?ref=portal"; | |
console.log(tapURL) | |
console.log(logoURL) | |
var colorConfig = { | |
fitXOrange: new Color("#ff8c00"), | |
lightGrey: new Color("#bfbbbb"), | |
widgetBackgroundColor: Color.black(), | |
canvFillColor: new Color("#ed721b"), | |
canvStrokeColor: new Color("#B0B0B0"), | |
canvTextColor: new Color("#f7f7f7") | |
} | |
var sizeConfig = { | |
context: 282, | |
canvas: 200, | |
canvText: 45, | |
canvWidth: 10, | |
canvRadius: 90 | |
} | |
// Get the Info from Studio | |
const studioInfo = await fetchStoreInformation(); | |
// DrawContext for circle | |
// Circle Diagram vars | |
let fillColor = 'ed721b'; | |
let strokeColor = 'B0B0B0'; | |
let textColor = 'f7f7f7'; | |
const canvas = new DrawContext(); | |
const canvSize = 200; | |
const canvTextSize = 45 | |
const canvWidth = 10 | |
const canvRadius = 90; | |
canvas.opaque = false | |
canvas.size = new Size(canvSize, canvSize); | |
canvas.respectScreenScale = true; | |
// Build Widget | |
const mainWidget = await createWidget(); | |
// used for debugging if script runs inside the app | |
if (!config.runsInWidget) { | |
await mainWidget.presentSmall(); | |
} | |
Script.setWidget(mainWidget); | |
Script.complete(); | |
// ### Modules or Functions #### | |
// Build the content of the widget | |
async function createWidget() { | |
const widget = new ListWidget(); | |
widget.backgroundColor = widgetBackgroundColor; | |
//get the current date | |
var d = new Date(); | |
const currentWeekDay = d.getDay(); | |
// not sure when their time start | |
const currentHour = d.getHours(); | |
// top row this studio name and logo | |
widget.addSpacer(4); | |
const logoImg = await getImage(studios[location].logo); | |
widget.setPadding(5, 5, 5, 5); | |
const titleFontSize = 14; | |
const detailFontSize = 14; | |
// url whem tap widget | |
console.log(tapURL) | |
widget.url = tapURL; | |
// present the studio logo | |
const logoImageStack = widget.addStack(); | |
logoImageStack.backgroundColor = widgetBackgroundColor | |
logoImageStack.cornerRadius = 8; | |
const wimg = logoImageStack.addImage(logoImg); | |
wimg.centerAlignImage(); | |
if (studioInfo == "No data") { | |
wTxt = widget.addText(studioInfo) | |
wTxt.centerAlignText() | |
wTxt.textColor = new Color(textColor) | |
return widget | |
} | |
// Row1 Title Stack | |
const percentTitle = widget.addText("Live-Auslastung") | |
percentTitle.centerAlignText() | |
percentTitle.font = Font.regularSystemFont(detailFontSize); | |
percentTitle.textColor = new Color(textColor) | |
// Row2 Draw circle with percentage in the middle | |
// get the reamaining percentage | |
let remainingPercentage = (studioInfo.percentage).toFixed(0); | |
// draw canvas | |
drawArc( | |
new Point(canvSize / 2, canvSize / 2), | |
canvRadius, | |
canvWidth, | |
Math.floor(remainingPercentage * 3.6) | |
); | |
// draw text rectangle | |
const canvTextRect = new Rect( | |
0, | |
100 - canvTextSize / 2, | |
canvSize, | |
canvTextSize | |
); | |
// format the text | |
canvas.setTextAlignedCenter(); | |
canvas.setTextColor(new Color(textColor)); | |
canvas.setFont(Font.regularSystemFont(canvTextSize)); | |
canvas.drawTextInRect(`${studioInfo.percentage}%`, canvTextRect); | |
// present the image | |
const canvImage = canvas.getImage(); | |
let image = widget.addImage(canvImage); | |
image.centerAlignImage() | |
//adjust position | |
widget.addSpacer() | |
// Row3 display the time of last updastee | |
const dateLabel = widget.addDate(d); | |
dateLabel.font = Font.regularSystemFont(10); | |
dateLabel.textColor = Color.lightGray(); | |
dateLabel.applyTimeStyle(); | |
dateLabel.centerAlignText(); | |
// finished return widget | |
return widget | |
} | |
// fetches information of the configured studio | |
async function fetchStoreInformation() { | |
let url = apiURL; | |
let tenant = studioTenant; | |
if (!tenant) { | |
tenant = "speedfitness"; | |
} | |
// let data = JSON.stringify(reqBodyData); | |
let req = new Request(url); | |
req.method = "GET" | |
req.headers = { 'Connection':'keep-alive', 'Accept': 'application/json, text/plain, */*', 'referer': tapURL, 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', 'Content-Type': 'application/json', 'x-tenant': tenant } | |
// req.body = data | |
console.log("Request:") | |
console.log(req) | |
let apiResults = await req.loadString(); | |
console.log("Response:") | |
console.log(apiResults) | |
console.log("Return Code:" + req.response.statusCode) | |
if (req.response.statusCode != 200) { | |
console.error(req.response.statusCode + "https - Bad Request") | |
return "No data" | |
} else if (req.response.statusCode == 404) { | |
// TODO: implement error handling | |
console.log("error code:" + req.response.statusCode) | |
return "No data" | |
} else if (req.response.statusCode == 200) { | |
apiResults = JSON.parse(apiResults); | |
} | |
for (let data_set of apiResults) { | |
if (data_set.current == true) { | |
apiResult = data_set | |
} | |
} | |
if (!apiResult) { | |
return "No data" | |
} | |
return apiResult; | |
} | |
// get images from local filestore or download them once | |
async function getImage(localImage) { | |
let fm = FileManager.local(); | |
let dir = fm.documentsDirectory(); | |
let path = fm.joinPath(dir, localImage); | |
if (fm.fileExists(path)) { | |
return fm.readImage(path); | |
} else { | |
// download once | |
let imageUrl = logoURL; | |
let iconImage = await loadImage(imageUrl); | |
fm.writeImage(path, iconImage); | |
return iconImage; | |
} | |
} | |
// helper function to download an image from a given url | |
async function loadImage(imgUrl) { | |
const req = new Request(imgUrl); | |
return await req.loadImage(); | |
} | |
// Helper for drawing Canvas | |
// Math Sig | |
function sinDeg(deg) { | |
return Math.sin((deg * Math.PI) / 180); | |
} | |
// Math Cos | |
function cosDeg(deg) { | |
return Math.cos((deg * Math.PI) / 180); | |
} | |
// Draw an Arc | |
function drawArc(ctr, rad, w, deg) { | |
bgx = ctr.x - rad; | |
bgy = ctr.y - rad; | |
bgd = 2 * rad; | |
bgr = new Rect(bgx, bgy, bgd, bgd); | |
canvas.setFillColor(new Color(fillColor)); | |
canvas.setStrokeColor(new Color(strokeColor)); | |
canvas.setLineWidth(w); | |
canvas.strokeEllipse(bgr); | |
for (t = 0; t < deg; t++) { | |
rect_x = ctr.x + rad * sinDeg(t) - w / 2; | |
rect_y = ctr.y - rad * cosDeg(t) - w / 2; | |
rect_r = new Rect(rect_x, rect_y, w, w); | |
canvas.fillEllipse(rect_r); | |
} | |
} | |
// Draw a line | |
function drawLine(x1, y1, x2, y2, ctx, width, color) { | |
const path = new Path(); | |
path.move(new Point(x1, y1)); | |
path.addLine(new Point(x2, y2)); | |
ctx.addPath(path); | |
ctx.setStrokeColor(color); | |
ctx.setLineWidth(width); | |
ctx.strokePath(); | |
} | |
// Draw a Point | |
function drawPoint(x, y, ctx, color, width = 2) { | |
const rec = new Rect(x - width / 2, y - width / 2, width, width); | |
ctx.setStrokeColor(color); | |
ctx.setFillColor(color); | |
ctx.setLineWidth(2); | |
ctx.strokeEllipse(rec); | |
ctx.fillEllipse(rec); | |
} | |
// Draw text | |
function drawText(text, fontSize, x, y, ctx, color = Color.black()) { | |
ctx.setFont(Font.boldSystemFont(fontSize)); | |
ctx.setTextColor(color); | |
ctx.drawText(new String(text).toString(), new Point(x, y)); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Variables used by Scriptable. | |
// These must be at the very top of the file. Do not edit. | |
// icon-color: deep-green; icon-glyph: eye; | |
let logs = []; | |
function log(message) { | |
logs.push(new Date().toISOString() + ": " + message); | |
console.log(message); | |
} | |
log("Script started."); | |
let location = "7"; | |
let param = args.widgetParameter; | |
if (param != null && param.length > 0) { | |
location = param; | |
} | |
log("Location: " + location); | |
const studios = { | |
"1": { | |
studioName:"Brunnthal", | |
studioId:"1225817660", | |
referer:"c3BlZWRmaXRuZXNzOjEyMjU4MTc2NjA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-brunnthal", | |
}, | |
"2": { | |
studioName:"Sendling", | |
studioId:"1217120190", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTcxMjAxOTA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-sendling", | |
}, | |
"3": { | |
studioName:"Bad_Aibling", | |
studioId:"1210005780", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTAwMDU3ODA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-badaibling", | |
}, | |
"4": { | |
studioName:"Bruckmuehl", | |
studioId:"1212577740", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTI1Nzc3NDA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-bruckmuehl", | |
}, | |
"5": { | |
studioName:"Grafing", | |
studioId:"1225816400", | |
referer:"c3BlZWRmaXRuZXNzOjEyMjU4MTY0MDA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-grafing", | |
}, | |
"6": { | |
studioName:"Gunzenhausen", | |
studioId:"1210005450", | |
referer:"d2VoZWJhOjEyMTAwMDU0NTA%3D", | |
tenant:"weheba", | |
URL:"speedfitness-gunzenhausen", | |
}, | |
"7": { | |
studioName:"Mainburg", | |
studioId:"1210005670", | |
referer:"d2VoZWJhOjEyMTIxNDk4MjA%3D", | |
tenant:"speedfitness", | |
// tenant: "weheba", | |
URL:"speedfitness-mainburg", | |
}, | |
"8": { | |
studioName:"Wasserburg", | |
studioId:"1217120110", | |
referer:"c3BlZWRmaXRuZXNzOjEyMTcxMjAxMTA%3D", | |
tenant:"speedfitness", | |
URL:"speedfitness-wasserburg", | |
} | |
} | |
const studioId = studios[location].studioId; | |
const studioURL = studios[location].URL; | |
const studioTenant = studios[location].tenant; | |
const contextSize = 282; | |
const fitXOrange = new Color("#ff8c00"); | |
const lightGrey = new Color("#bfbbbb"); | |
const widgetBackgroundColor = Color.black() | |
const apiURL = `https://www.mysports.com/nox/public/v1/studios/${studioId}/utilization/v2/today`; | |
const logoURL = "https://www.speedfitness.de/wp-content/uploads/thegem-logos/logo_a5e5de086934358122444a1c6ecc0453_1x.png"; | |
const tapURL = `https://www.mysports.com/studio/${studios[location].referer}?ref=portal`; | |
deleteOldLogo(); | |
log("Full Logo URL: " + logoURL); | |
var colorConfig = { | |
fitXOrange: new Color("#ff8c00"), | |
lightGrey: new Color("#bfbbbb"), | |
widgetBackgroundColor: Color.black(), | |
canvFillColor: new Color("#ed721b"), | |
canvStrokeColor: new Color("#B0B0B0"), | |
canvTextColor: new Color("#f7f7f7") | |
} | |
var sizeConfig = { | |
context: 282, | |
canvas: 200, | |
canvText: 45, | |
canvWidth: 10, | |
canvRadius: 90 | |
} | |
// Get the Info from Studio | |
let studioInfo; | |
try { | |
studioInfo = await fetchStoreInformation(); | |
log("Studio Info: " + JSON.stringify(studioInfo)); | |
} catch (error) { | |
log("Error fetching studio information: " + error); | |
studioInfo = "No data"; | |
} | |
// DrawContext for circle | |
let strokeColor = 'B0B0B0'; | |
let textColor = 'f7f7f7'; | |
const canvas = new DrawContext(); | |
const canvSize = 200; | |
const canvTextSize = 45 | |
const canvWidth = 10 | |
const canvRadius = 90; | |
canvas.opaque = false | |
canvas.size = new Size(canvSize, canvSize); | |
canvas.respectScreenScale = true; | |
// Build Widget | |
const mainWidget = await createWidget(); | |
// used for debugging if script runs inside the app | |
if (!config.runsInWidget) { | |
await mainWidget.presentSmall(); | |
} | |
Script.setWidget(mainWidget); | |
log("Script completed."); | |
if (!config.runsInWidget) { | |
let logsText = logs.join("\n"); | |
let alert = new Alert(); | |
alert.title = "Script Logs"; | |
alert.message = logsText; | |
alert.addAction("OK"); | |
alert.present(); | |
} | |
Script.complete(); | |
async function createWidget() { | |
log("Creating widget"); | |
const widget = new ListWidget(); | |
widget.backgroundColor = widgetBackgroundColor; | |
var d = new Date(); | |
widget.addSpacer(4); | |
try { | |
log("Attempting to load logo image"); | |
const logoImg = await getImage("logo.png"); | |
log("Logo image loaded successfully"); | |
const logoImageStack = widget.addStack(); | |
logoImageStack.backgroundColor = widgetBackgroundColor | |
logoImageStack.cornerRadius = 8; | |
const wimg = logoImageStack.addImage(logoImg); | |
wimg.centerAlignImage(); | |
log("Logo image added to widget"); | |
// Füge den Studionamen hinzu | |
widget.addSpacer(4); | |
const studioNameText = widget.addText(studios[location].studioName); | |
studioNameText.font = Font.mediumSystemFont(12); | |
studioNameText.textColor = Color.white(); | |
studioNameText.centerAlignText(); | |
log("Studio name added to widget"); | |
} catch (error) { | |
log("Error loading logo image: " + error); | |
const fallbackText = widget.addText(studios[location].studioName); | |
fallbackText.font = Font.boldSystemFont(16); | |
fallbackText.textColor = new Color(textColor); | |
fallbackText.centerAlignText(); | |
log("Fallback text added to widget"); | |
} | |
widget.setPadding(5, 5, 5, 5); | |
const titleFontSize = 12; | |
const detailFontSize = 12; | |
widget.url = tapURL; | |
if (studioInfo == "No data") { | |
wTxt = widget.addText(studioInfo) | |
wTxt.centerAlignText() | |
wTxt.textColor = new Color(textColor) | |
return widget | |
} | |
const percentTitle = widget.addText("Live-Auslastung") | |
percentTitle.centerAlignText() | |
percentTitle.font = Font.mediumSystemFont(detailFontSize); | |
percentTitle.textColor = new Color(textColor) | |
try { | |
let remainingPercentage = (studioInfo.percentage).toFixed(0); | |
let utilizationColor = getUtilizationColor(remainingPercentage); | |
drawArc( | |
new Point(canvSize / 2, canvSize / 2), | |
canvRadius, | |
canvWidth, | |
Math.floor(remainingPercentage * 3.6), | |
utilizationColor | |
); | |
const canvTextRect = new Rect( | |
0, | |
100 - canvTextSize / 2, | |
canvSize, | |
canvTextSize | |
); | |
canvas.setTextAlignedCenter(); | |
canvas.setTextColor(new Color(textColor)); | |
canvas.setFont(Font.mediumSystemFont(canvTextSize)); | |
canvas.drawTextInRect(`${studioInfo.percentage}%`, canvTextRect); | |
const canvImage = canvas.getImage(); | |
let image = widget.addImage(canvImage); | |
image.centerAlignImage() | |
} catch (error) { | |
log("Error drawing arc or adding image: " + error); | |
widget.addText("Error displaying utilization"); | |
} | |
widget.addSpacer() | |
const dateLabel = widget.addDate(d); | |
dateLabel.font = Font.regularSystemFont(10); | |
dateLabel.textColor = Color.lightGray(); | |
dateLabel.applyTimeStyle(); | |
dateLabel.centerAlignText(); | |
return widget | |
} | |
async function fetchStoreInformation() { | |
try { | |
let url = apiURL; | |
let tenant = studioTenant || "speedfitness"; | |
let req = new Request(url); | |
req.method = "GET" | |
req.headers = { | |
'Connection': 'keep-alive', | |
'Accept': 'application/json, text/plain, */*', | |
'referer': tapURL, | |
'Accept-Encoding': 'gzip, deflate, br', | |
'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7', | |
'Content-Type': 'application/json', | |
'x-tenant': tenant | |
} | |
let apiResponse = await req.loadString(); | |
log("Full API Response: " + apiResponse); | |
if (req.response.statusCode !== 200) { | |
log("HTTP-Fehler: " + req.response.statusCode); | |
return "No data"; | |
} | |
let apiResults; | |
try { | |
apiResults = JSON.parse(apiResponse); | |
} catch (parseError) { | |
log("Error parsing API response: " + parseError); | |
return "No data"; | |
} | |
let apiResult; | |
for (let data_set of apiResults) { | |
if (data_set.current == true) { | |
apiResult = data_set; | |
break; | |
} | |
} | |
if (!apiResult || typeof apiResult.percentage !== 'number') { | |
log("Invalid or missing data in API response"); | |
return "No data"; | |
} | |
log("Parsed Studio Info: " + JSON.stringify(apiResult)); | |
return apiResult; | |
} catch (error) { | |
log("Fehler beim Abrufen der Daten: " + error); | |
return "No data"; | |
} | |
} | |
async function getImage(localImage) { | |
try { | |
let fm = FileManager.local(); | |
let dir = fm.documentsDirectory(); | |
let path = fm.joinPath(dir, localImage); | |
log("Full image path: " + path); | |
if (fm.fileExists(path)) { | |
log("Loading cached image"); | |
return fm.readImage(path); | |
} else { | |
log("Downloading new image"); | |
let imageUrl = logoURL; | |
log("Downloading image from: " + imageUrl); | |
let iconImage = await loadImage(imageUrl); | |
if (iconImage) { | |
fm.writeImage(path, iconImage); | |
log("New image saved to cache"); | |
return iconImage; | |
} else { | |
throw new Error("Failed to load image"); | |
} | |
} | |
} catch (error) { | |
log("Error in getImage: " + error); | |
throw error; | |
} | |
} | |
async function loadImage(imgUrl) { | |
try { | |
log("Attempting to load image from: " + imgUrl); | |
const req = new Request(imgUrl); | |
const image = await req.loadImage(); | |
if (image) { | |
log("Image loaded successfully"); | |
return image; | |
} else { | |
throw new Error("Image loading failed"); | |
} | |
} catch (error) { | |
log("Detailed error loading image: " + error.message + " " + JSON.stringify(error, Object.getOwnPropertyNames(error))); | |
return null; | |
} | |
} | |
function deleteOldLogo() { | |
let fm = FileManager.local(); | |
let dir = fm.documentsDirectory(); | |
let path = fm.joinPath(dir, "logo.png"); | |
if (fm.fileExists(path)) { | |
fm.remove(path); | |
log("Old logo deleted"); | |
} else { | |
log("No old logo found to delete"); | |
} | |
} | |
function getUtilizationColor(percentage) { | |
if (percentage <= 33) { | |
return new Color("00ff00"); // Grün | |
} else if (percentage <= 66) { | |
return new Color("ffa500"); // Orange | |
} else { | |
return new Color("ff0000"); // Rot | |
} | |
} | |
function sinDeg(deg) { | |
return Math.sin((deg * Math.PI) / 180); | |
} | |
function cosDeg(deg) { | |
return Math.cos((deg * Math.PI) / 180); | |
} | |
function drawArc(ctr, rad, w, deg, color) { | |
bgx = ctr.x - rad; | |
bgy = ctr.y - rad; | |
bgd = 2 * rad; | |
bgr = new Rect(bgx, bgy, bgd, bgd); | |
canvas.setFillColor(color); | |
canvas.setStrokeColor(new Color(strokeColor)); | |
canvas.setLineWidth(w); | |
canvas.strokeEllipse(bgr); | |
for (t = 0; t < deg; t++) { | |
rect_x = ctr.x + rad * sinDeg(t) - w / 2; | |
rect_y = ctr.y - rad * cosDeg(t) - w / 2; | |
rect_r = new Rect(rect_x, rect_y, w, w); | |
canvas.fillEllipse(rect_r); | |
} | |
} | |
function drawLine(x1, y1, x2, y2, ctx, width, color) { | |
const path = new Path(); | |
path.move(new Point(x1, y1)); | |
path.addLine(new Point(x2, y2)); | |
ctx.addPath(path); | |
ctx.setStrokeColor(color); | |
ctx.setLineWidth(width); | |
ctx.strokePath(); | |
} | |
function drawPoint(x, y, ctx, color, width = 2) { | |
const rec = new Rect(x - width / 2, y - width / 2, width, width); | |
ctx.setStrokeColor(color); | |
ctx.setFillColor(color); | |
ctx.setLineWidth(2); | |
ctx.strokeEllipse(rec); | |
ctx.fillEllipse(rec); | |
} | |
function drawText(text, fontSize, x, y, ctx, color = Color.black()) { | |
ctx.setFont(Font.boldSystemFont(fontSize)); | |
ctx.setTextColor(color); | |
ctx.drawText(new String(text).toString(), new Point(x, y)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment