xiv-character-cards
Advanced tools
Comparing version
const fetch = require("node-fetch"); | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
const { createCanvas, loadImage, registerFont } = require("canvas"); | ||
registerFont('SourceSansPro-Regular.ttf', { family: 'Source Sans Pro', style: 'Regular' }); | ||
registerFont('SourceSansPro-SemiBold.ttf', { family: 'Source Sans Pro', style: 'SemiBold' }); | ||
function absolute(relativePath) { | ||
return path.join(__dirname, relativePath); | ||
} | ||
registerFont(absolute('SourceSansPro-Regular.ttf'), { family: 'Source Sans Pro', style: 'Regular' }); | ||
registerFont(absolute('SourceSansPro-SemiBold.ttf'), { family: 'Source Sans Pro', style: 'SemiBold' }); | ||
const primary = "rgba(178, 214, 249, 1)"; | ||
@@ -17,16 +22,60 @@ const white = "rgba(255, 255, 255,1)"; | ||
const jobsRowStart = 495; | ||
const jobsRowTextStartX = 495; | ||
const jobsRowTextSize = 30; | ||
const jobsRowTextSpacer = jobsRowTextSize * 2; | ||
const deityIconCol = 252; | ||
const deityIconRow = 805; | ||
const rectHeightRow1 = 120; // Title, Name, World | ||
const rectHeightRow2 = 40; // Mounts, Minions | ||
const rectHeightRow3 = 210; // Info | ||
const rectHeightRow4 = 175; // Jobs | ||
const gcRankIconCol = 293; | ||
const gcRankIconRow = 799; | ||
const rectSpacing = 8; | ||
const rectHalfWidthSpacing = 10; | ||
const rectFullWidth = 400; | ||
const rectHalfWidth = (rectFullWidth / 2) - (rectHalfWidthSpacing / 2); | ||
const rectStartX = 464; | ||
const rectStartXHalf = rectStartX + rectHalfWidth + rectHalfWidthSpacing; | ||
const rectStartRow1Y = 15; | ||
const rectStartRow2Y = rectStartRow1Y + rectHeightRow1 + rectSpacing; | ||
const rectStartRow3Y = rectStartRow2Y + rectHeightRow2 + rectSpacing; | ||
const rectStartRow4Y = rectStartRow3Y + rectHeightRow3 + rectSpacing; | ||
const jobsStartSpacing = 10; | ||
const jobsRowSpacing = 8; | ||
const jobsRowIcon1Y = rectStartRow4Y + jobsStartSpacing; | ||
const jobsRowText1Y = jobsRowIcon1Y + 45; | ||
const jobsRowIcon2Y = jobsRowText1Y + jobsRowSpacing; | ||
const jobsRowText2Y = jobsRowIcon2Y + 45; | ||
const jobsRowIcon3Y = jobsRowText2Y + jobsRowSpacing; | ||
const jobsRowText3Y = jobsRowIcon3Y + 45; | ||
const textTitleY = rectStartRow1Y + 34; | ||
const textServerY = rectStartRow1Y + 104; | ||
const textNameNoTitleY = rectStartRow1Y + 59; | ||
const textNameTitleY = rectStartRow1Y + 79; | ||
const textMountMinionY = rectStartRow2Y + 28; | ||
const iconMountMinionY = rectStartRow2Y + 5; | ||
const deityIconY = rectStartRow3Y + 69; | ||
const deityIconX = 805; | ||
const gcRankIconY = rectStartRow3Y + 110; | ||
const gcRankIconX = 799; | ||
const fcCrestScale = 38; | ||
const fcCrestCol = 345; | ||
const fcCrestRow = 800; | ||
const fcCrestY = rectStartRow3Y + 162; | ||
const fcCrestX = 800; | ||
const infoTextStartSpacing = 22; | ||
const infoTextSmallStartY = rectStartRow3Y + infoTextStartSpacing; | ||
const infoTextBigStartY = infoTextSmallStartY + 25; | ||
const infoTextSpacing = 50; | ||
class CardCreator { | ||
@@ -47,43 +96,45 @@ constructor() { | ||
async init() { | ||
this.bgImage = await loadImage("./chara_n.png"); | ||
this.bgImage = await loadImage(absolute("./chara.png")); | ||
this.imgMinion = await loadImage("./minion.png"); | ||
this.imgMount = await loadImage("./mount.png"); | ||
this.imgMinion = await loadImage(absolute("./minion.png")); | ||
this.imgMount = await loadImage(absolute("./mount.png")); | ||
this.imgIlvl = await loadImage(absolute("./ilvl_n.png")); | ||
this.imgShadow = await loadImage(absolute("./shadow.png")); | ||
this.imgAlchemist = await loadImage("./cj/1/alchemist.png"); | ||
this.imgArmorer = await loadImage("./cj/1/armorer.png"); | ||
this.imgBlacksmith = await loadImage("./cj/1/blacksmith.png"); | ||
this.imgCarpenter = await loadImage("./cj/1/carpenter.png"); | ||
this.imgCulinarian = await loadImage("./cj/1/culinarian.png"); | ||
this.imgGoldsmith = await loadImage("./cj/1/goldsmith.png"); | ||
this.imgLeatherworker = await loadImage("./cj/1/leatherworker.png"); | ||
this.imgWeaver = await loadImage("./cj/1/weaver.png"); | ||
this.imgAlchemist = await loadImage(absolute("./cj/1/alchemist.png")); | ||
this.imgArmorer = await loadImage(absolute("./cj/1/armorer.png")); | ||
this.imgBlacksmith = await loadImage(absolute("./cj/1/blacksmith.png")); | ||
this.imgCarpenter = await loadImage(absolute("./cj/1/carpenter.png")); | ||
this.imgCulinarian = await loadImage(absolute("./cj/1/culinarian.png")); | ||
this.imgGoldsmith = await loadImage(absolute("./cj/1/goldsmith.png")); | ||
this.imgLeatherworker = await loadImage(absolute("./cj/1/leatherworker.png")); | ||
this.imgWeaver = await loadImage(absolute("./cj/1/weaver.png")); | ||
this.imgBotanist = await loadImage("./cj/1/botanist.png"); | ||
this.imgFisher = await loadImage("./cj/1/fisher.png"); | ||
this.imgMiner = await loadImage("./cj/1/miner.png"); | ||
this.imgBotanist = await loadImage(absolute("./cj/1/botanist.png")); | ||
this.imgFisher = await loadImage(absolute("./cj/1/fisher.png")); | ||
this.imgMiner = await loadImage(absolute("./cj/1/miner.png")); | ||
this.imgPaladin = await loadImage("./cj/1/paladin.png"); | ||
this.imgWarrior = await loadImage("./cj/1/warrior.png"); | ||
this.imgDarkKnight = await loadImage("./cj/1/darkknight.png"); | ||
this.imgGunbreaker = await loadImage("./cj/1/gunbreaker.png"); | ||
this.imgPaladin = await loadImage(absolute("./cj/1/paladin.png")); | ||
this.imgWarrior = await loadImage(absolute("./cj/1/warrior.png")); | ||
this.imgDarkKnight = await loadImage(absolute("./cj/1/darkknight.png")); | ||
this.imgGunbreaker = await loadImage(absolute("./cj/1/gunbreaker.png")); | ||
this.imgWhitemage = await loadImage("./cj/1/whitemage.png"); | ||
this.imgScholar = await loadImage("./cj/1/scholar.png"); | ||
this.imgAstrologian = await loadImage("./cj/1/astrologian.png"); | ||
this.imgWhitemage = await loadImage(absolute("./cj/1/whitemage.png")); | ||
this.imgScholar = await loadImage(absolute("./cj/1/scholar.png")); | ||
this.imgAstrologian = await loadImage(absolute("./cj/1/astrologian.png")); | ||
this.imgBard = await loadImage("./cj/1/bard.png"); | ||
this.imgMachinist = await loadImage("./cj/1/machinist.png"); | ||
this.imgDancer = await loadImage("./cj/1/dancer.png"); | ||
this.imgBard = await loadImage(absolute("./cj/1/bard.png")); | ||
this.imgMachinist = await loadImage(absolute("./cj/1/machinist.png")); | ||
this.imgDancer = await loadImage(absolute("./cj/1/dancer.png")); | ||
this.imgDragoon = await loadImage("./cj/1/dragoon.png"); | ||
this.imgMonk = await loadImage("./cj/1/monk.png"); | ||
this.imgNinja = await loadImage("./cj/1/ninja.png"); | ||
this.imgSamurai = await loadImage("./cj/1/samurai.png"); | ||
this.imgDragoon = await loadImage(absolute("./cj/1/dragoon.png")); | ||
this.imgMonk = await loadImage(absolute("./cj/1/monk.png")); | ||
this.imgNinja = await loadImage(absolute("./cj/1/ninja.png")); | ||
this.imgSamurai = await loadImage(absolute("./cj/1/samurai.png")); | ||
this.imgBlackmage = await loadImage("./cj/1/blackmage.png"); | ||
this.imgSummoner = await loadImage("./cj/1/summoner.png"); | ||
this.imgRedmage = await loadImage("./cj/1/redmage.png"); | ||
this.imgBlackmage = await loadImage(absolute("./cj/1/blackmage.png")); | ||
this.imgSummoner = await loadImage(absolute("./cj/1/summoner.png")); | ||
this.imgRedmage = await loadImage(absolute("./cj/1/redmage.png")); | ||
this.imgBluemage = await loadImage('./cj/1/bluemage.png'); | ||
this.imgBluemage = await loadImage(absolute('./cj/1/bluemage.png')); | ||
@@ -108,15 +159,14 @@ await this.countMountsMinions(); | ||
async createCrest(crestAry) { | ||
const canvas = createCanvas(fcCrestScale, fcCrestScale); | ||
const canvas = createCanvas(128, 128); | ||
const ctx = canvas.getContext("2d"); | ||
var crestLayer2 = await loadImage(crestAry[0]); | ||
ctx.drawImage(crestLayer2, 0, 0, fcCrestScale, fcCrestScale); | ||
if (crestAry.length == 0) | ||
return null; | ||
var crestLayer1 = await loadImage(crestAry[1]); | ||
ctx.drawImage(crestLayer1, 0, 0, fcCrestScale, fcCrestScale); | ||
for (var i = 0; i < crestAry.length; i++) { | ||
var crestLayer = await loadImage(crestAry[i]); | ||
ctx.drawImage(crestLayer, 0, 0, 128, 128); | ||
} | ||
var crestLayer0 = await loadImage(crestAry[2]); | ||
ctx.drawImage(crestLayer0, 0, 0, fcCrestScale, fcCrestScale); | ||
var imgd = ctx.getImageData(0, 0, 135, 135), | ||
var imgd = ctx.getImageData(0, 0, 128, 128), | ||
pix = imgd.data, | ||
@@ -145,2 +195,41 @@ newColor = { r: 0, g: 0, b: 0, a: 0 }; | ||
getItemLevel(gearset) { | ||
var ilvl = 0; | ||
var cnt = 0; | ||
var mainHandLvl = 0; | ||
var hasOffHand = false; | ||
for (var key in gearset) { | ||
var piece = gearset[key]; | ||
if (key == 'SoulCrystal') | ||
continue; | ||
if (key == 'MainHand') | ||
mainHandLvl = piece.Item.LevelItem; | ||
if (key == 'OffHand') | ||
hasOffHand = true; | ||
ilvl += piece.Item.LevelItem; | ||
cnt++; | ||
} | ||
if (!hasOffHand) { | ||
ilvl += mainHandLvl; | ||
cnt++; | ||
} | ||
if (cnt == 0) | ||
return 0; | ||
return this.pad(Math.floor(ilvl / cnt), 4); | ||
} | ||
pad(num, size) { | ||
num = num.toString(); | ||
while (num.length < size) num = "0" + num; | ||
return num; | ||
} | ||
async createCard(charaId) { | ||
@@ -155,3 +244,3 @@ var response = await fetch(`https://xivapi.com/character/${charaId}?extended=1&data=FC,mimo`); | ||
ctx.drawImage(this.bgImage, 441, 0, 900, 600); | ||
ctx.drawImage(this.bgImage, -10, 0, 900, 600); | ||
@@ -163,16 +252,17 @@ ctx.drawImage(portrait, 0, 0, 441, 600); | ||
ctx.beginPath(); | ||
ctx.fillRect(464, 7, 400, 120); | ||
ctx.fillRect(rectStartX, rectStartRow1Y, rectFullWidth, rectHeightRow1); | ||
ctx.fillRect(464, 135, 195, 40); | ||
ctx.fillRect(669, 135, 195, 40); | ||
ctx.fillRect(rectStartX, rectStartRow2Y, rectHalfWidth, rectHeightRow2); | ||
ctx.fillRect(rectStartXHalf, rectStartRow2Y, rectHalfWidth, rectHeightRow2); | ||
ctx.fillRect(464, 183, 400, 210); | ||
ctx.fillRect(464, 405, 400, 175); | ||
ctx.fillRect(rectStartX, rectStartRow3Y, rectFullWidth, rectHeightRow3); | ||
ctx.fillRect(rectStartX, rectStartRow4Y, rectFullWidth, rectHeightRow4); | ||
ctx.stroke(); | ||
ctx.textAlign = "center"; | ||
ctx.font = med; | ||
ctx.fillStyle = primary; | ||
ctx.fillText(data.Character.Title.Name, 665, 45); | ||
ctx.fillText(data.Character.Title.Name, 665, textTitleY); | ||
ctx.font = small; | ||
ctx.fillText(`${data.Character.Server} (${data.Character.DC})`, 665, 115); | ||
ctx.fillText(`${data.Character.Server} (${data.Character.DC})`, 665, textServerY); | ||
@@ -183,18 +273,28 @@ | ||
ctx.textAlign = "left"; | ||
ctx.fillText("Race & Clan", 480, 205); | ||
ctx.fillText("Guardian", 480, 255); | ||
ctx.fillText("Race & Clan", 480, infoTextSmallStartY); | ||
ctx.fillText("Guardian", 480, infoTextSmallStartY + infoTextSpacing); | ||
if (data.Character.GrandCompany.Company != null) { | ||
ctx.fillText("Grand Company", 480, 305); | ||
ctx.fillText("Grand Company", 480, infoTextSmallStartY + infoTextSpacing * 2); | ||
} | ||
if (data.Character.FreeCompanyName != null) { | ||
ctx.fillText("Free Company", 480, 355); | ||
ctx.fillText("Free Company", 480, infoTextSmallStartY + infoTextSpacing * 3); | ||
} | ||
ctx.fillStyle = grey; | ||
ctx.font = smed; | ||
var ilvl = this.getItemLevel(data.Character.GearSet.Gear); | ||
ctx.drawImage(this.imgShadow, 441 - 143, -15, 170, 90); | ||
ctx.drawImage(this.imgIlvl, 441 - 92, 12, 24, 27); | ||
ctx.fillText(ilvl, 441 - 65, 35); | ||
ctx.fillStyle = white; | ||
ctx.font = large; | ||
ctx.textAlign = "center"; | ||
// Chara Name | ||
if (data.Character.Title.Name == null || data.Character.Title.Name == "") { | ||
ctx.fillText(data.Character.Name, 665, 70); | ||
ctx.fillText(data.Character.Name, 665, textNameNoTitleY); | ||
} else { | ||
ctx.fillText(data.Character.Name, 665, 90); | ||
ctx.fillText(data.Character.Name, 665, textNameTitleY); | ||
} | ||
@@ -204,24 +304,43 @@ // Race, Clan, Guardian, GC, FC Info | ||
ctx.textAlign = "left"; | ||
ctx.fillText(`${data.Character.Race.Name}, ${data.Character.Tribe.Name}`, 480, 230); | ||
ctx.fillText(`${data.Character.Race.Name}, ${data.Character.Tribe.Name}`, 480, infoTextBigStartY); | ||
ctx.fillText(data.Character.GuardianDeity.Name, 480, 280); | ||
ctx.fillText(data.Character.GuardianDeity.Name, 480, infoTextBigStartY + infoTextSpacing); | ||
var deityIcon = await loadImage('https://xivapi.com/' + data.Character.GuardianDeity.Icon); | ||
ctx.drawImage(deityIcon, deityIconRow, deityIconCol, 28, 28); | ||
ctx.drawImage(deityIcon, deityIconX, deityIconY, 28, 28); | ||
if (data.Character.GrandCompany.Company != null) { | ||
ctx.fillText(data.Character.GrandCompany.Company.Name, 480, 330); | ||
ctx.fillText(data.Character.GrandCompany.Company.Name, 480, infoTextBigStartY + infoTextSpacing * 2); | ||
var gcRankIcon = await loadImage('https://xivapi.com/' + data.Character.GrandCompany.Rank.Icon); | ||
ctx.drawImage(gcRankIcon, gcRankIconRow, gcRankIconCol, 40, 40); | ||
ctx.drawImage(gcRankIcon, gcRankIconX, gcRankIconY, 40, 40); | ||
} | ||
if (data.Character.FreeCompanyName != null) { | ||
var crestImage = await this.createCrest(data.FreeCompany.Crest); | ||
ctx.drawImage(crestImage, fcCrestRow, fcCrestCol, fcCrestScale, fcCrestScale); | ||
ctx.fillText(data.Character.FreeCompanyName, 480, 380); | ||
if (crestImage !== null) | ||
ctx.drawImage(crestImage, fcCrestX, fcCrestY, fcCrestScale, fcCrestScale); | ||
const fcMeasure = ctx.measureText(data.Character.FreeCompanyName); | ||
ctx.fillText(data.Character.FreeCompanyName, 480, infoTextBigStartY + infoTextSpacing * 3); | ||
ctx.fillStyle = grey; | ||
ctx.font = small; | ||
ctx.fillText(`«${data.FreeCompany.Tag}»`, 480 + fcMeasure.width + 10, infoTextBigStartY + infoTextSpacing * 3); | ||
} | ||
ctx.font = smed; | ||
ctx.fillStyle = white; | ||
// Minion & Mount percentages | ||
const mountsPct = Math.ceil((data.Mounts.length / this.countMount) * 100); | ||
const minionsPct = Math.ceil((data.Minions.length / this.countMinion) * 100); | ||
var mountsPct = '??'; | ||
if (data.Mounts !== null) { | ||
mountsPct = Math.ceil((data.Mounts.length / this.countMount) * 100); | ||
} | ||
var minionsPct = '??'; | ||
if (data.Minions !== null) { | ||
minionsPct = Math.ceil((data.Minions.length / this.countMinion) * 100); | ||
} | ||
@@ -231,4 +350,4 @@ const mountsMeasure = ctx.measureText(`${mountsPct}%`); | ||
ctx.fillText(`${mountsPct}%`, 480, 163); | ||
ctx.fillText(`${minionsPct}%`, 685, 163); | ||
ctx.fillText(`${mountsPct}%`, 480, textMountMinionY); | ||
ctx.fillText(`${minionsPct}%`, 685, textMountMinionY); | ||
@@ -238,7 +357,7 @@ ctx.fillStyle = grey; | ||
ctx.fillText("Mounts", 480 + mountsMeasure.width + 5, 163); | ||
ctx.fillText("Minions", 685 + minionsMeasure.width + 5, 163); | ||
ctx.fillText("Mounts", 480 + mountsMeasure.width + 5, textMountMinionY); | ||
ctx.fillText("Minions", 685 + minionsMeasure.width + 5, textMountMinionY); | ||
ctx.drawImage(this.imgMount, 620, 140, 32, 32); | ||
ctx.drawImage(this.imgMinion, 834, 140, 19, 32); | ||
ctx.drawImage(this.imgMount, 620, iconMountMinionY, 32, 32); | ||
ctx.drawImage(this.imgMinion, 834, iconMountMinionY, 19, 32); | ||
@@ -252,129 +371,129 @@ ctx.fillStyle = white; | ||
var cJobsRowX = jobsRowStart; | ||
ctx.drawImage(this.imgAlchemist, 480, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[24].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
var cJobsRowTextX = jobsRowTextStartX; | ||
ctx.drawImage(this.imgAlchemist, 480, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[24].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgArmorer, 510, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[20].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgArmorer, 510, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[20].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgBlacksmith, 540, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[19].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgBlacksmith, 540, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[19].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgCarpenter, 570, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[18].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgCarpenter, 570, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[18].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgCulinarian, 600, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[25].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgCulinarian, 600, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[25].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgGoldsmith, 630, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[21].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgGoldsmith, 630, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[21].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgLeatherworker, 660, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[22].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgLeatherworker, 660, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[22].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgWeaver, 690, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[23].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSpacer; | ||
ctx.drawImage(this.imgWeaver, 690, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[23].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSpacer; | ||
// Gathering | ||
ctx.drawImage(this.imgBotanist, 750, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[27].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgBotanist, 750, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[27].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgFisher, 780, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[28].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgFisher, 780, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[28].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgMiner, 810, 520, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[26].Level, cJobsRowX, 565); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgMiner, 810, jobsRowIcon3Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[26].Level, cJobsRowTextX, jobsRowText3Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
// Tanks | ||
cJobsRowX = jobsRowStart; | ||
cJobsRowTextX = jobsRowTextStartX; | ||
ctx.drawImage(this.imgPaladin, 480, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[0].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgPaladin, 480, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[0].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgWarrior, 510, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[1].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgWarrior, 510, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[1].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgDarkKnight, 540, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[2].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgDarkKnight, 540, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[2].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgGunbreaker, 570, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[3].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSpacer; | ||
ctx.drawImage(this.imgGunbreaker, 570, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[3].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSpacer; | ||
// Healers | ||
ctx.drawImage(this.imgWhitemage, 630, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[8].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgWhitemage, 630, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[8].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgScholar, 660, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[9].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgScholar, 660, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[9].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgAstrologian, 690, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[10].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSpacer; | ||
ctx.drawImage(this.imgAstrologian, 690, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[10].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSpacer; | ||
// DPS | ||
// Ranged | ||
ctx.drawImage(this.imgBard, 750, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[11].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgBard, 750, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[11].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgMachinist, 780, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[12].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgMachinist, 780, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[12].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgDancer, 810, 415, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[13].Level, cJobsRowX, 460); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgDancer, 810, jobsRowIcon1Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[13].Level, cJobsRowTextX, jobsRowText1Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
// Melee | ||
cJobsRowX = jobsRowStart; | ||
cJobsRowTextX = jobsRowTextStartX; | ||
ctx.drawImage(this.imgDragoon, 480, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[5].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgDragoon, 480, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[5].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgMonk, 510, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[4].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgMonk, 510, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[4].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgNinja, 540, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[6].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgNinja, 540, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[6].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgSamurai, 570, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[7].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSpacer; | ||
ctx.drawImage(this.imgSamurai, 570, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[7].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSpacer; | ||
// Caster | ||
ctx.drawImage(this.imgBlackmage, 630, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[14].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgBlackmage, 630, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[14].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgSummoner, 660, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[15].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgSummoner, 660, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[15].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
ctx.drawImage(this.imgRedmage, 690, 465, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[16].Level, cJobsRowX, 515); | ||
cJobsRowX += jobsRowTextSize; | ||
ctx.drawImage(this.imgRedmage, 690, jobsRowIcon2Y, 30, 30); | ||
ctx.fillText(data.Character.ClassJobs[16].Level, cJobsRowTextX, jobsRowText2Y); | ||
cJobsRowTextX += jobsRowTextSize; | ||
// Limited | ||
ctx.drawImage(this.imgBluemage, 780, 465, 33, 33); | ||
ctx.fillText(data.Character.ClassJobs[17].Level, 796, 515); | ||
ctx.drawImage(this.imgBluemage, 780, jobsRowIcon2Y, 33, 33); | ||
ctx.fillText(data.Character.ClassJobs[17].Level, 796, jobsRowText2Y); | ||
@@ -385,2 +504,2 @@ return canvas.toBuffer(); | ||
exports.CardCreator = CardCreator; | ||
exports.CardCreator = CardCreator; |
{ | ||
"name": "xiv-character-cards", | ||
"version": "1.0.0", | ||
"version": "1.1.0", | ||
"main": "create-card.js", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
4856752
124.38%57
21.28%370
30.74%4
33.33%