2018-10-01 15:33:43 +08:00
|
|
|
|
class CanvasDraw{
|
|
|
|
|
constructor(){
|
2019-01-30 00:10:56 +08:00
|
|
|
|
this.diffStarPath = new Path2D(vectors.diffStar)
|
|
|
|
|
this.longVowelMark = new Path2D(vectors.longVowelMark)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
this.diffIconPath = [[{w: 40, h: 33}, {
|
|
|
|
|
fill: "#ff2803",
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffEasy1)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}, {
|
|
|
|
|
fill: "#ffb910",
|
|
|
|
|
noStroke: true,
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffEasy2)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}], [{w: 48, h: 31}, {
|
|
|
|
|
fill: "#8daf51",
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffNormal)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}], [{w: 56, h: 37}, {
|
|
|
|
|
fill: "#784439",
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffHard1)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}, {
|
|
|
|
|
fill: "#000",
|
|
|
|
|
noStroke: true,
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffHard2)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}, {
|
|
|
|
|
fill: "#414b2b",
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffHard3)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}], [{w: 29, h: 27}, {
|
|
|
|
|
fill: "#db1885",
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffOni1)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}, {
|
|
|
|
|
fill: "#fff",
|
2019-01-30 00:10:56 +08:00
|
|
|
|
d: new Path2D(vectors.diffOni2)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}]]
|
|
|
|
|
|
|
|
|
|
this.diffPath = {
|
2019-01-30 00:10:56 +08:00
|
|
|
|
good: new Path2D(vectors.good),
|
|
|
|
|
ok: new Path2D(vectors.ok),
|
|
|
|
|
bad: new Path2D(vectors.bad)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-30 00:10:56 +08:00
|
|
|
|
this.crownPath = new Path2D(vectors.crown)
|
|
|
|
|
this.soulPath = new Path2D(vectors.soul)
|
2018-10-25 22:18:41 +08:00
|
|
|
|
|
|
|
|
|
this.optionsPath = {
|
2019-01-30 00:10:56 +08:00
|
|
|
|
main: new Path2D(vectors.options),
|
|
|
|
|
shadow: new Path2D(vectors.optionsShadow)
|
2018-10-25 22:18:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-01 15:33:43 +08:00
|
|
|
|
this.regex = {
|
|
|
|
|
comma: /[,.]/,
|
|
|
|
|
ideographicComma: /[、。]/,
|
2019-03-06 05:48:30 +08:00
|
|
|
|
apostrophe: /[''’]/,
|
2018-11-11 03:12:29 +08:00
|
|
|
|
degree: /[゚°]/,
|
2019-03-06 05:48:30 +08:00
|
|
|
|
brackets: /[\((\))\[\]「」『』【】::;;]/,
|
2018-12-06 04:33:34 +08:00
|
|
|
|
tilde: /[\--~~〜_]/,
|
2018-11-18 20:30:06 +08:00
|
|
|
|
tall: /[bbddffgghhj-lj-ltt♪]/,
|
|
|
|
|
i: /[ii]/,
|
2018-10-28 02:35:04 +08:00
|
|
|
|
uppercase: /[A-ZA-Z]/,
|
2018-10-01 15:33:43 +08:00
|
|
|
|
lowercase: /[a-za-z・]/,
|
2018-10-28 02:35:04 +08:00
|
|
|
|
latin: /[A-ZA-Za-za-z・]/,
|
2018-11-18 20:30:06 +08:00
|
|
|
|
numbers: /[0-90-9]/,
|
2018-10-28 02:35:04 +08:00
|
|
|
|
exclamation: /[!!\?? ]/,
|
|
|
|
|
question: /[\??]/,
|
2018-10-01 15:33:43 +08:00
|
|
|
|
smallHiragana: /[ぁぃぅぇぉっゃゅょァィゥェォッャュョ]/,
|
|
|
|
|
hiragana: /[\u3040-\u30ff]/,
|
|
|
|
|
todo: /[トド]/,
|
|
|
|
|
en: /[ceghknsuxyzceghknsuxyz]/,
|
|
|
|
|
em: /[mwmw]/,
|
|
|
|
|
emCap: /[MWMW]/,
|
|
|
|
|
rWidth: /[abdfIjo-rtvabdfIjo-rtv]/,
|
2018-12-06 04:33:34 +08:00
|
|
|
|
lWidth: /[ilil]/,
|
|
|
|
|
ura: /\s*[\((]裏[\))]$/
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-18 20:30:06 +08:00
|
|
|
|
var numbersFull = "0123456789"
|
|
|
|
|
var numbersHalf = "0123456789"
|
|
|
|
|
this.numbersFullToHalf = {}
|
|
|
|
|
for(var i = 0; i < 10; i++){
|
|
|
|
|
this.numbersFullToHalf[numbersFull[i]] = numbersHalf[i]
|
|
|
|
|
this.numbersFullToHalf[numbersHalf[i]] = numbersHalf[i]
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 21:07:53 +08:00
|
|
|
|
this.songFrameCache = new CanvasCache()
|
|
|
|
|
this.diffStarCache = new CanvasCache()
|
|
|
|
|
this.crownCache = new CanvasCache()
|
|
|
|
|
|
2018-10-01 15:33:43 +08:00
|
|
|
|
this.tmpCanvas = document.createElement("canvas")
|
|
|
|
|
this.tmpCtx = this.tmpCanvas.getContext("2d")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roundedRect(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
var x = config.x
|
|
|
|
|
var y = config.y
|
|
|
|
|
var w = config.w
|
|
|
|
|
var h = config.h
|
|
|
|
|
var r = config.radius
|
|
|
|
|
ctx.beginPath()
|
2018-10-25 22:18:41 +08:00
|
|
|
|
this.roundedCorner(ctx, x, y, r, 0)
|
|
|
|
|
this.roundedCorner(ctx, x + w, y, r, 1)
|
|
|
|
|
this.roundedCorner(ctx, x + w, y + h, r, 2)
|
|
|
|
|
this.roundedCorner(ctx, x, y + h, r, 3)
|
|
|
|
|
ctx.closePath()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roundedCorner(ctx, x, y, r, rotation){
|
|
|
|
|
var pi = Math.PI
|
|
|
|
|
switch(rotation){
|
|
|
|
|
case 0:
|
|
|
|
|
return ctx.arc(x + r, y + r, r, pi, pi / -2)
|
|
|
|
|
case 1:
|
|
|
|
|
return ctx.arc(x - r, y + r, r, pi / -2, 0)
|
|
|
|
|
case 2:
|
|
|
|
|
return ctx.arc(x - r, y - r, r, 0, pi / 2)
|
|
|
|
|
case 3:
|
|
|
|
|
return ctx.arc(x + r, y - r, r, pi / 2, pi)
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
songFrame(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
var x = config.x
|
|
|
|
|
var y = config.y
|
|
|
|
|
var w = config.width
|
|
|
|
|
var h = config.height
|
|
|
|
|
var border = config.border
|
|
|
|
|
var innerBorder = config.innerBorder
|
|
|
|
|
var allBorders = border + innerBorder
|
|
|
|
|
var innerX = x + allBorders
|
|
|
|
|
var innerY = y + allBorders
|
|
|
|
|
var innerW = w - allBorders * 2
|
|
|
|
|
var innerH = h - allBorders * 2
|
|
|
|
|
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
2018-10-09 21:07:53 +08:00
|
|
|
|
var shadowBg = (ctx, noForce) => {
|
|
|
|
|
this.shadow({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
fill: "rgba(0, 0, 0, 0.5)",
|
|
|
|
|
blur: 10,
|
|
|
|
|
x: 5,
|
|
|
|
|
y: 5,
|
|
|
|
|
force: !noForce
|
|
|
|
|
})
|
|
|
|
|
ctx.fillStyle = "#000"
|
|
|
|
|
ctx.fillRect(0, 0, w, h)
|
|
|
|
|
}
|
|
|
|
|
if(config.cached){
|
|
|
|
|
if(this.songFrameCache.w !== config.frameCache.w){
|
|
|
|
|
this.songFrameCache.resize(config.frameCache.w, config.frameCache.h, config.frameCache.ratio)
|
|
|
|
|
}
|
|
|
|
|
this.songFrameCache.get({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
x: x,
|
|
|
|
|
y: y,
|
|
|
|
|
w: w + 15,
|
|
|
|
|
h: h + 15,
|
|
|
|
|
id: "shadow" + config.cached
|
|
|
|
|
}, shadowBg)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.translate(x, y)
|
|
|
|
|
shadowBg(ctx, true)
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let _x = x + border
|
|
|
|
|
let _y = y + border
|
|
|
|
|
let _w = w - border * 2
|
|
|
|
|
let _h = h - border * 2
|
|
|
|
|
ctx.fillStyle = config.borderStyle[1]
|
|
|
|
|
ctx.fillRect(_x, _y, _w, _h)
|
|
|
|
|
ctx.fillStyle = config.borderStyle[0]
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(_x, _y)
|
|
|
|
|
ctx.lineTo(_x + _w, _y)
|
|
|
|
|
ctx.lineTo(_x + _w - innerBorder, _y + innerBorder)
|
|
|
|
|
ctx.lineTo(_x + innerBorder, _y + _h - innerBorder)
|
|
|
|
|
ctx.lineTo(_x, _y + _h)
|
|
|
|
|
ctx.fill()
|
|
|
|
|
}
|
|
|
|
|
ctx.fillStyle = config.background
|
|
|
|
|
ctx.fillRect(innerX, innerY, innerW, innerH)
|
|
|
|
|
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
ctx.strokeStyle = "rgba(255, 255, 255, 0.3)"
|
|
|
|
|
ctx.lineWidth = 3
|
|
|
|
|
ctx.strokeRect(innerX, innerY, innerW, innerH)
|
|
|
|
|
if(!config.noCrop){
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.rect(innerX, innerY, innerW, innerH)
|
|
|
|
|
ctx.clip()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
config.innerContent(innerX, innerY, innerW, innerH)
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
|
2018-11-02 18:26:46 +08:00
|
|
|
|
if(config.disabled){
|
|
|
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.5)"
|
|
|
|
|
ctx.fillRect(x, y, w, h)
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-01 15:33:43 +08:00
|
|
|
|
if(config.highlight){
|
|
|
|
|
this.highlight({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
x: x,
|
|
|
|
|
y: y,
|
|
|
|
|
w: w,
|
|
|
|
|
h: h,
|
|
|
|
|
animate: config.highlight === 2,
|
|
|
|
|
animateMS: config.animateMS,
|
|
|
|
|
opacity: config.highlight === 1 ? 0.8 : 1
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
highlight(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
var _x = config.x + 3.5
|
|
|
|
|
var _y = config.y + 3.5
|
|
|
|
|
var _w = config.w - 7
|
|
|
|
|
var _h = config.h - 7
|
|
|
|
|
if(config.animate){
|
|
|
|
|
ctx.globalAlpha = this.fade((this.getMS() - config.animateMS) % 2000 / 2000)
|
|
|
|
|
}else if(config.opacity){
|
|
|
|
|
ctx.globalAlpha = config.opacity
|
|
|
|
|
}
|
2018-11-12 18:32:02 +08:00
|
|
|
|
if(config.radius){
|
|
|
|
|
this.roundedRect({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
x: _x,
|
|
|
|
|
y: _y,
|
|
|
|
|
w: _w,
|
|
|
|
|
h: _h,
|
|
|
|
|
radius: config.radius
|
|
|
|
|
})
|
|
|
|
|
}else{
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.rect(_x, _y, _w, _h)
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.strokeStyle = "rgba(255, 249, 1, 0.45)"
|
|
|
|
|
ctx.lineWidth = 14
|
2018-11-12 18:32:02 +08:00
|
|
|
|
ctx.stroke()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.strokeStyle = "rgba(255, 249, 1, .8)"
|
|
|
|
|
ctx.lineWidth = 8
|
2018-11-12 18:32:02 +08:00
|
|
|
|
ctx.stroke()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.strokeStyle = "#fff"
|
|
|
|
|
ctx.lineWidth = 6
|
2018-11-12 18:32:02 +08:00
|
|
|
|
ctx.stroke()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
fade(pos){
|
|
|
|
|
if(pos < 0.5){
|
|
|
|
|
pos = 1 - pos
|
|
|
|
|
}
|
|
|
|
|
return (1 - Math.cos(Math.PI * pos * 2)) / 2
|
|
|
|
|
}
|
2018-10-01 19:48:25 +08:00
|
|
|
|
easeIn(pos){
|
|
|
|
|
return 1 - Math.cos(Math.PI / 2 * pos)
|
|
|
|
|
}
|
2018-10-13 06:09:42 +08:00
|
|
|
|
easeOut(pos){
|
|
|
|
|
return Math.sin(Math.PI / 2 * pos)
|
|
|
|
|
}
|
2019-02-21 04:48:21 +08:00
|
|
|
|
easeOutBack(pos){
|
|
|
|
|
return Math.sin(Math.PI / 1.74 * pos) * 1.03
|
|
|
|
|
}
|
2018-10-13 06:09:42 +08:00
|
|
|
|
easeInOut(pos){
|
|
|
|
|
return (Math.cos(Math.PI * pos) - 1) / -2
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
verticalText(config){
|
|
|
|
|
var ctx = config.ctx
|
2019-04-05 04:40:11 +08:00
|
|
|
|
var inputText = config.text.toString()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
var mul = config.fontSize / 40
|
2018-12-06 04:33:34 +08:00
|
|
|
|
var ura = false
|
|
|
|
|
var r = this.regex
|
|
|
|
|
|
|
|
|
|
var matches = inputText.match(r.ura)
|
|
|
|
|
if(matches){
|
|
|
|
|
inputText = inputText.slice(0, matches.index)
|
|
|
|
|
ura = matches[0]
|
|
|
|
|
}
|
2019-01-21 23:47:22 +08:00
|
|
|
|
var bold = this.bold(config.fontFamily)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
var string = inputText.split("")
|
|
|
|
|
var drawn = []
|
2019-02-03 20:04:25 +08:00
|
|
|
|
var quoteOpened = false
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
2018-10-28 02:35:04 +08:00
|
|
|
|
for(var i = 0; i < string.length; i++){
|
|
|
|
|
let symbol = string[i]
|
2018-10-01 15:33:43 +08:00
|
|
|
|
if(symbol === " "){
|
|
|
|
|
// Space
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, h: 18})
|
|
|
|
|
}else if(symbol === "ー"){
|
|
|
|
|
// Long-vowel mark
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: -1, y: -1, h: 33, rotate: true})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({realText: symbol, svg: this.longVowelMark, x: -4, y: 5, h: 33, scale: [mul, mul]})
|
|
|
|
|
}
|
2018-11-11 03:12:29 +08:00
|
|
|
|
}else if(symbol === "∀"){
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, h: 39, rotate: true})
|
|
|
|
|
}else if(symbol === "↓"){
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 12, h: 45})
|
2018-12-04 06:23:11 +08:00
|
|
|
|
}else if(symbol === "."){
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({realText: symbol, text: ".", x: 13, y: -15, h: 15})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({realText: symbol, text: ".", x: 13, y: -7, h: 15, scale: [1.2, 0.7]})
|
|
|
|
|
}
|
2018-12-06 04:33:34 +08:00
|
|
|
|
}else if(symbol === "…"){
|
2019-01-21 23:47:22 +08:00
|
|
|
|
drawn.push({text: symbol, x: bold ? 9 : 0, y: 5, h: 25, rotate: true})
|
2019-01-22 03:08:02 +08:00
|
|
|
|
}else if(symbol === '"'){
|
2019-02-03 20:04:25 +08:00
|
|
|
|
if(quoteOpened){
|
|
|
|
|
drawn.push({realText: symbol, text: "“", x: -25, y: 10, h: 20})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({realText: symbol, text: "”", x: 12, y: 15, h: 20})
|
|
|
|
|
}
|
|
|
|
|
quoteOpened = !quoteOpened
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.comma.test(symbol)){
|
|
|
|
|
// Comma, full stop
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: 13, y: -15, h: 15})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: 13, y: -7, h: 15, scale: [1.2, 0.7]})
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.ideographicComma.test(symbol)){
|
|
|
|
|
// Ideographic comma, full stop
|
|
|
|
|
drawn.push({text: symbol, x: 16, y: -16, h: 18})
|
|
|
|
|
}else if(r.apostrophe.test(symbol)){
|
|
|
|
|
// Apostrophe
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: 20, y: -25, h: 0})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({realText: symbol, text: ",", x: 20, y: -39, h: 0, scale: [1.2, 0.7]})
|
|
|
|
|
}
|
2018-11-11 03:12:29 +08:00
|
|
|
|
}else if(r.degree.test(symbol)){
|
|
|
|
|
// Degree
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: 16, y: 9, h: 25})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: 16, y: 3, h: 18})
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.brackets.test(symbol)){
|
|
|
|
|
// Rotated brackets
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, h: 35, rotate: true})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: -5, h: 25, rotate: true})
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.tilde.test(symbol)){
|
|
|
|
|
// Rotated hyphen, tilde
|
2018-10-28 02:35:04 +08:00
|
|
|
|
drawn.push({realText: symbol, text: symbol === "~" ? "~" : symbol, x: 0, y: 2, h: 35, rotate: true})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.tall.test(symbol)){
|
2018-11-18 20:30:06 +08:00
|
|
|
|
// Tall latin script lowercase
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 4, h: 34})
|
|
|
|
|
}else if(r.i.test(symbol)){
|
|
|
|
|
// Lowercase i
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 7, h: 34})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.uppercase.test(symbol)){
|
|
|
|
|
// Latin script upper case
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 8, h: 37})
|
|
|
|
|
}else if(r.lowercase.test(symbol)){
|
|
|
|
|
// Latin script lower case
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: -1, h: 28})
|
|
|
|
|
}else if(r.numbers.test(symbol)){
|
|
|
|
|
// Numbers
|
|
|
|
|
var number = this.numbersFullToHalf[symbol]
|
|
|
|
|
drawn.push({realText: symbol, text: number, x: 0, y: 4, h: 34})
|
2018-10-28 02:35:04 +08:00
|
|
|
|
}else if(r.exclamation.test(symbol)){
|
|
|
|
|
// Exclamation mark
|
|
|
|
|
var toDraw = [symbol]
|
|
|
|
|
for(var repeat = 1; repeat - 1 < i; repeat++){
|
|
|
|
|
if(!r.exclamation.test(string[i - repeat])){
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
toDraw.push(string[i - repeat])
|
|
|
|
|
}
|
|
|
|
|
if(repeat > 1){
|
|
|
|
|
drawn.splice(i - repeat + 1, repeat)
|
|
|
|
|
var allExclamations = !toDraw.find(a => a !== "!")
|
|
|
|
|
|
|
|
|
|
for(var j = 1; j < repeat + 1; j++){
|
|
|
|
|
var text = string[i - repeat + j]
|
|
|
|
|
if(allExclamations){
|
|
|
|
|
var y = 18
|
|
|
|
|
var h = 61
|
|
|
|
|
}else{
|
|
|
|
|
var y = 8
|
|
|
|
|
var h = 37
|
|
|
|
|
}
|
|
|
|
|
if(i === repeat - 1){
|
|
|
|
|
h -= y - 4
|
|
|
|
|
y = 4
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-30 00:10:56 +08:00
|
|
|
|
var addX = bold && (text === "!" || text === "?") ? 10 : 0
|
2018-10-28 02:35:04 +08:00
|
|
|
|
drawn.push({
|
|
|
|
|
text: text,
|
2019-01-30 00:10:56 +08:00
|
|
|
|
x: ((j - 1) - (repeat - 1) / 2) * 15 + addX,
|
2018-10-28 02:35:04 +08:00
|
|
|
|
y: y - (j === 1 ? 0 : h),
|
2018-11-18 20:30:06 +08:00
|
|
|
|
h: j === 1 ? h : 0
|
2018-10-28 02:35:04 +08:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}else{
|
2019-01-30 00:10:56 +08:00
|
|
|
|
var addX = bold && (symbol === "!" || symbol === "?") ? 10 : 0
|
|
|
|
|
drawn.push({text: symbol, x: addX, y: 8, h: 37})
|
2018-10-28 02:35:04 +08:00
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.smallHiragana.test(symbol)){
|
|
|
|
|
// Small hiragana, small katakana
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: -8, h: 25, right: true})
|
|
|
|
|
}else if(r.hiragana.test(symbol)){
|
|
|
|
|
// Hiragana, katakana
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 5, h: 38, right: r.todo.test(symbol)})
|
|
|
|
|
}else{
|
|
|
|
|
// Kanji, other
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 3, h: 39})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var drawnHeight = 0
|
|
|
|
|
for(let symbol of drawn){
|
|
|
|
|
if(config.letterSpacing){
|
|
|
|
|
symbol.h += config.letterSpacing
|
|
|
|
|
}
|
|
|
|
|
drawnHeight += symbol.h * mul
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
|
2018-10-28 02:35:04 +08:00
|
|
|
|
if(config.selectable){
|
|
|
|
|
config.selectable.innerHTML = ""
|
|
|
|
|
var scale = config.selectableScale
|
|
|
|
|
var style = config.selectable.style
|
|
|
|
|
style.left = (config.x - config.width / 2) * scale + "px"
|
|
|
|
|
style.top = config.y * scale + "px"
|
|
|
|
|
style.width = config.width * scale + "px"
|
|
|
|
|
style.height = (drawnHeight+15) * scale + "px"
|
|
|
|
|
style.fontSize = 40 * mul * scale + "px"
|
|
|
|
|
style.transform = ""
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-11 03:12:29 +08:00
|
|
|
|
var scaling = 1
|
2019-02-03 20:04:25 +08:00
|
|
|
|
var strokeScaling = 1
|
2018-12-06 04:33:34 +08:00
|
|
|
|
var height = config.height - (ura ? 52 * mul : 0)
|
|
|
|
|
if(height && drawnHeight > height){
|
2018-12-13 17:18:52 +08:00
|
|
|
|
scaling = height / drawnHeight
|
2018-11-11 03:12:29 +08:00
|
|
|
|
if(config.align === "bottom"){
|
2019-02-03 20:04:25 +08:00
|
|
|
|
strokeScaling = Math.max(0.6, height / drawnHeight)
|
2018-11-11 03:12:29 +08:00
|
|
|
|
ctx.translate(40 * mul, 0)
|
2019-02-03 20:04:25 +08:00
|
|
|
|
ctx.scale(strokeScaling, scaling)
|
2018-11-11 03:12:29 +08:00
|
|
|
|
ctx.translate(-40 * mul, 0)
|
|
|
|
|
}else{
|
2019-02-03 20:04:25 +08:00
|
|
|
|
strokeScaling = scaling
|
2018-11-11 03:12:29 +08:00
|
|
|
|
ctx.scale(1, scaling)
|
|
|
|
|
}
|
2018-10-28 02:35:04 +08:00
|
|
|
|
if(config.selectable){
|
|
|
|
|
style.transform = "scale(1, " + scaling + ")"
|
2018-12-06 04:33:34 +08:00
|
|
|
|
style.top = (config.y + (height - drawnHeight) / 2 - 15 / 2 * scaling) * scale + "px"
|
2018-10-28 02:35:04 +08:00
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-06 04:33:34 +08:00
|
|
|
|
if(ura){
|
|
|
|
|
// Circled ura
|
2018-12-13 17:18:52 +08:00
|
|
|
|
drawn.push({realText: ura, text: "裏", x: 0, y: 25, h: 52, ura: true, scale: [1, 1 / scaling]})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(config.align === "bottom"){
|
|
|
|
|
drawn.reverse()
|
2018-12-06 04:33:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-01 15:33:43 +08:00
|
|
|
|
var actions = []
|
|
|
|
|
if(config.outline){
|
|
|
|
|
actions.push("stroke")
|
|
|
|
|
}
|
|
|
|
|
if(config.fill){
|
|
|
|
|
actions.push("fill")
|
|
|
|
|
}
|
2018-10-28 02:35:04 +08:00
|
|
|
|
if(config.selectable){
|
|
|
|
|
actions.push("selectable")
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
for(let action of actions){
|
2019-01-21 23:47:22 +08:00
|
|
|
|
ctx.font = bold + config.fontSize + "px " + config.fontFamily
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.textBaseline = "top"
|
|
|
|
|
if(action === "stroke"){
|
|
|
|
|
ctx.strokeStyle = config.outline
|
|
|
|
|
ctx.lineWidth = config.outlineSize * mul
|
2018-11-11 03:12:29 +08:00
|
|
|
|
if(config.align === "bottom"){
|
2019-02-03 20:04:25 +08:00
|
|
|
|
ctx.lineWidth /= strokeScaling
|
2018-11-11 03:12:29 +08:00
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.lineJoin = "round"
|
|
|
|
|
ctx.miterLimit = 1
|
|
|
|
|
}else if(action === "fill"){
|
|
|
|
|
ctx.fillStyle = config.fill
|
|
|
|
|
}
|
2018-11-11 03:12:29 +08:00
|
|
|
|
if(config.align === "bottom"){
|
|
|
|
|
var offsetY = drawnHeight > config.height ? drawnHeight : config.height
|
|
|
|
|
}else{
|
|
|
|
|
var offsetY = 0
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
for(let symbol of drawn){
|
|
|
|
|
var saved = false
|
|
|
|
|
var currentX = symbol.x
|
|
|
|
|
if(symbol.right){
|
|
|
|
|
currentX += 20 * mul
|
|
|
|
|
}
|
|
|
|
|
var currentY = offsetY + symbol.y * mul
|
2018-11-11 03:12:29 +08:00
|
|
|
|
if(config.align === "bottom"){
|
|
|
|
|
currentY -= symbol.h * mul
|
|
|
|
|
}
|
|
|
|
|
offsetY = offsetY + symbol.h * mul * (config.align === "bottom" ? -1 : 1)
|
2018-10-28 02:35:04 +08:00
|
|
|
|
if(action === "selectable"){
|
|
|
|
|
let div = document.createElement("div")
|
|
|
|
|
div.classList.add("stroke-sub")
|
|
|
|
|
let text = symbol.realText || symbol.text
|
|
|
|
|
let textWidth = ctx.measureText(text).width
|
|
|
|
|
let transform = []
|
|
|
|
|
if(symbol.scale){
|
|
|
|
|
transform.push("scale(" + symbol.scale[0] + "," + symbol.scale[1] + ")")
|
|
|
|
|
}
|
|
|
|
|
if(symbol.rotate || symbol.realText === "ー"){
|
|
|
|
|
transform.push("rotate(90deg)")
|
|
|
|
|
}
|
|
|
|
|
if(transform.length){
|
|
|
|
|
div.style.transform = transform.join(" ")
|
|
|
|
|
}
|
|
|
|
|
if(symbol.right){
|
|
|
|
|
currentX = currentX + config.width / 2 - textWidth
|
|
|
|
|
}else{
|
|
|
|
|
currentX = currentX + config.width / 2 - textWidth / 2
|
|
|
|
|
}
|
2018-12-13 17:18:52 +08:00
|
|
|
|
if(symbol.ura){
|
|
|
|
|
div.style.font = (30 / (40 * mul)) + "em Meiryo, sans-serif"
|
|
|
|
|
}
|
2018-10-28 02:35:04 +08:00
|
|
|
|
div.style.left = currentX * scale + "px"
|
|
|
|
|
div.style.top = currentY * scale + "px"
|
|
|
|
|
div.appendChild(document.createTextNode(text))
|
|
|
|
|
div.setAttribute("alt", text)
|
|
|
|
|
config.selectable.appendChild(div)
|
|
|
|
|
continue
|
|
|
|
|
}
|
2018-12-06 04:33:34 +08:00
|
|
|
|
if(symbol.rotate || symbol.scale || symbol.svg || symbol.ura){
|
2018-10-01 15:33:43 +08:00
|
|
|
|
saved = true
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
if(symbol.rotate){
|
|
|
|
|
ctx.translate(currentX + 20 * mul, currentY + 20 * mul)
|
|
|
|
|
ctx.rotate(Math.PI / 2)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.translate(currentX, currentY)
|
|
|
|
|
}
|
|
|
|
|
if(symbol.scale){
|
|
|
|
|
ctx.scale(symbol.scale[0], symbol.scale[1])
|
|
|
|
|
ctx.lineWidth = ctx.lineWidth / symbol.scale[0]
|
|
|
|
|
}
|
|
|
|
|
currentX = 0
|
|
|
|
|
currentY = 0
|
|
|
|
|
}
|
|
|
|
|
if(symbol.svg){
|
|
|
|
|
ctx[action](symbol.svg)
|
|
|
|
|
}else{
|
|
|
|
|
if(symbol.right){
|
|
|
|
|
ctx.textAlign = "right"
|
|
|
|
|
}else{
|
|
|
|
|
ctx.textAlign = "center"
|
|
|
|
|
}
|
2018-12-06 04:33:34 +08:00
|
|
|
|
if(symbol.ura){
|
|
|
|
|
ctx.font = (30 * mul) + "px Meiryo, sans-serif"
|
2019-02-21 04:48:21 +08:00
|
|
|
|
ctx.textBaseline = "middle"
|
2018-12-06 04:33:34 +08:00
|
|
|
|
ctx.beginPath()
|
2018-12-13 17:18:52 +08:00
|
|
|
|
ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2)
|
2018-12-06 04:33:34 +08:00
|
|
|
|
if(action === "stroke"){
|
|
|
|
|
ctx.fillStyle = config.outline
|
|
|
|
|
ctx.fill()
|
|
|
|
|
}else if(action === "fill"){
|
|
|
|
|
ctx.strokeStyle = config.fill
|
|
|
|
|
ctx.lineWidth = 2.5 * mul
|
2019-02-21 04:48:21 +08:00
|
|
|
|
ctx.fillText(symbol.text, currentX, currentY + (17 * mul))
|
2018-12-06 04:33:34 +08:00
|
|
|
|
}
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
}else{
|
|
|
|
|
ctx[action + "Text"](symbol.text, currentX, currentY)
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
if(saved){
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layeredText(config, layers){
|
|
|
|
|
var ctx = config.ctx
|
2019-04-05 04:40:11 +08:00
|
|
|
|
var inputText = config.text.toString()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
var mul = config.fontSize / 40
|
2018-12-13 17:18:52 +08:00
|
|
|
|
var ura = false
|
|
|
|
|
var r = this.regex
|
|
|
|
|
|
|
|
|
|
var matches = inputText.match(r.ura)
|
|
|
|
|
if(matches){
|
|
|
|
|
inputText = inputText.slice(0, matches.index)
|
|
|
|
|
ura = matches[0]
|
|
|
|
|
}
|
2019-01-21 23:47:22 +08:00
|
|
|
|
var bold = this.bold(config.fontFamily)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
2018-12-13 17:18:52 +08:00
|
|
|
|
var string = inputText.split("")
|
2018-10-01 15:33:43 +08:00
|
|
|
|
var drawn = []
|
|
|
|
|
|
2018-10-28 02:35:04 +08:00
|
|
|
|
for(var i = 0; i < string.length; i++){
|
|
|
|
|
let symbol = string[i]
|
|
|
|
|
|
2018-10-01 15:33:43 +08:00
|
|
|
|
if(symbol === "-"){
|
2018-12-04 06:23:11 +08:00
|
|
|
|
drawn.push({text: symbol, x: -2, y: 0, w: 28})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(symbol === "™"){
|
|
|
|
|
drawn.push({text: symbol, x: -2, y: 0, w: 20, scale: [0.6, 0.5]})
|
|
|
|
|
}else if(symbol === " "){
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 10})
|
2019-01-30 00:10:56 +08:00
|
|
|
|
}else if(symbol === '"'){
|
|
|
|
|
drawn.push({text: symbol, x: 2, y: 0, w: 10})
|
2018-11-18 20:30:06 +08:00
|
|
|
|
}else if(symbol === "∀"){
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 40})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: -3, y: 0, w: 55})
|
|
|
|
|
}
|
2018-12-04 06:23:11 +08:00
|
|
|
|
}else if(symbol === "."){
|
|
|
|
|
drawn.push({text: symbol, x: -9, y: 0, w: 37})
|
2019-03-06 05:48:30 +08:00
|
|
|
|
}else if(r.apostrophe.test(symbol)){
|
|
|
|
|
drawn.push({text: ",", x: 0, y: -15, w: 7, scale: [1, 0.7]})
|
2018-11-21 17:02:53 +08:00
|
|
|
|
}else if(r.comma.test(symbol)){
|
|
|
|
|
// Comma, full stop
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: -3, y: 0, w: 13})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: -3, y: 13, w: 13, scale: [1.2, 0.7]})
|
|
|
|
|
}
|
2019-02-03 20:04:25 +08:00
|
|
|
|
}else if(r.tilde.test(symbol)){
|
|
|
|
|
// Hyphen, tilde
|
|
|
|
|
drawn.push({text: symbol === "~" ? "~" : symbol, x: 0, y: 0, w: 39})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.en.test(symbol)){
|
|
|
|
|
// n-width
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 28})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.em.test(symbol)){
|
|
|
|
|
// m-width
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 38})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.rWidth.test(symbol)){
|
|
|
|
|
// r-width
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 24})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.lWidth.test(symbol)){
|
|
|
|
|
// l-width
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 12})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.emCap.test(symbol)){
|
|
|
|
|
// m-width uppercase
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 38})
|
2018-11-21 17:02:53 +08:00
|
|
|
|
}else if(r.numbers.test(symbol)){
|
|
|
|
|
// Numbers
|
|
|
|
|
var number = this.numbersFullToHalf[symbol]
|
|
|
|
|
drawn.push({text: number, x: 0, y: 0, w: 32})
|
2018-11-18 20:30:06 +08:00
|
|
|
|
}else if(r.degree.test(symbol)){
|
|
|
|
|
// Degree
|
2019-01-21 23:47:22 +08:00
|
|
|
|
if(bold){
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 20})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: 5, y: 0, w: 0})
|
|
|
|
|
}
|
2018-11-21 17:02:53 +08:00
|
|
|
|
}else if(r.uppercase.test(symbol)){
|
|
|
|
|
// Latin script uppercase
|
2018-11-18 20:30:06 +08:00
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 32})
|
2018-10-28 02:35:04 +08:00
|
|
|
|
}else if(r.exclamation.test(symbol)){
|
|
|
|
|
// Exclamation mark
|
|
|
|
|
var nextExclamation = string[i + 1] ? r.exclamation.test(string[i + 1]) : false
|
|
|
|
|
drawn.push({
|
|
|
|
|
text: symbol,
|
|
|
|
|
x: nextExclamation ? 4 : -1,
|
|
|
|
|
y: 0,
|
2018-11-18 20:30:06 +08:00
|
|
|
|
w: nextExclamation ? 16 : 28
|
2018-10-28 02:35:04 +08:00
|
|
|
|
})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else if(r.smallHiragana.test(symbol)){
|
|
|
|
|
// Small hiragana, small katakana
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 30})
|
|
|
|
|
}else if(r.hiragana.test(symbol)){
|
|
|
|
|
// Hiragana, katakana
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 35})
|
|
|
|
|
}else{
|
|
|
|
|
drawn.push({text: symbol, x: 0, y: 0, w: 39})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var drawnWidth = 0
|
|
|
|
|
for(let symbol of drawn){
|
|
|
|
|
if(config.letterSpacing){
|
|
|
|
|
symbol.w += config.letterSpacing
|
|
|
|
|
}
|
2018-11-21 17:02:53 +08:00
|
|
|
|
drawnWidth += symbol.w * mul
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-13 17:18:52 +08:00
|
|
|
|
ctx.save()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.translate(config.x, config.y)
|
2018-12-13 17:18:52 +08:00
|
|
|
|
|
2018-10-25 22:18:41 +08:00
|
|
|
|
if(config.scale){
|
|
|
|
|
ctx.scale(config.scale[0], config.scale[1])
|
|
|
|
|
}
|
2018-12-13 17:18:52 +08:00
|
|
|
|
var scaling = 1
|
|
|
|
|
var width = config.width - (ura ? 55 * mul : 0)
|
|
|
|
|
if(width && drawnWidth > width){
|
|
|
|
|
scaling = width / drawnWidth
|
|
|
|
|
ctx.scale(scaling, 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ura){
|
|
|
|
|
// Circled ura
|
|
|
|
|
drawn.push({text: "裏", x: 0, y: 3, w: 55, ura: true, scale: [1 / scaling, 1]})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(config.align === "right"){
|
|
|
|
|
drawn.reverse()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
2018-12-13 17:18:52 +08:00
|
|
|
|
|
2019-01-21 23:47:22 +08:00
|
|
|
|
ctx.font = bold + config.fontSize + "px " + config.fontFamily
|
2018-11-21 18:50:48 +08:00
|
|
|
|
ctx.textBaseline = config.baseline || "top"
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.textAlign = "center"
|
|
|
|
|
|
|
|
|
|
for(let layer of layers){
|
2018-10-25 22:18:41 +08:00
|
|
|
|
var savedLayer = false
|
2018-10-01 15:33:43 +08:00
|
|
|
|
var action = "strokeText"
|
2018-10-25 22:18:41 +08:00
|
|
|
|
if(layer.scale){
|
|
|
|
|
savedLayer = true
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.scale(layer.scale[0], layer.scale[1])
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
if(layer.outline){
|
|
|
|
|
ctx.strokeStyle = layer.outline
|
|
|
|
|
ctx.lineJoin = "round"
|
|
|
|
|
ctx.miterLimit = 1
|
|
|
|
|
}
|
|
|
|
|
if(layer.letterBorder){
|
|
|
|
|
ctx.lineWidth = layer.letterBorder
|
|
|
|
|
}
|
|
|
|
|
if(layer.fill){
|
|
|
|
|
ctx.fillStyle = layer.fill
|
|
|
|
|
action = "fillText"
|
|
|
|
|
}
|
|
|
|
|
if(layer.shadow){
|
2018-10-25 22:18:41 +08:00
|
|
|
|
if(!savedLayer){
|
|
|
|
|
savedLayer = true
|
|
|
|
|
ctx.save()
|
|
|
|
|
}
|
2018-10-09 14:59:36 +08:00
|
|
|
|
this.shadow({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
fill: "rgba(0, 0, 0, " + (1 / (layer.shadow[3] || 2)) + ")",
|
|
|
|
|
blur: layer.shadow[2],
|
|
|
|
|
x: layer.shadow[0],
|
2018-10-09 21:07:53 +08:00
|
|
|
|
y: layer.shadow[1],
|
|
|
|
|
force: config.forceShadow
|
2018-10-09 14:59:36 +08:00
|
|
|
|
})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
var offsetX = 0
|
|
|
|
|
for(let symbol of drawn){
|
|
|
|
|
var saved = false
|
2018-11-21 17:02:53 +08:00
|
|
|
|
var currentX = offsetX + symbol.x * mul + (layer.x || 0) + symbol.w * mul / 2
|
2018-10-01 15:33:43 +08:00
|
|
|
|
var currentY = symbol.y + (layer.y || 0)
|
|
|
|
|
|
|
|
|
|
if(config.align === "center"){
|
|
|
|
|
currentX -= drawnWidth / 2
|
|
|
|
|
}else if(config.align === "right"){
|
|
|
|
|
currentX = -offsetX + symbol.x + (layer.x || 0) - symbol.w / 2
|
|
|
|
|
}
|
2018-12-13 17:18:52 +08:00
|
|
|
|
if(symbol.scale || symbol.ura){
|
2018-10-01 15:33:43 +08:00
|
|
|
|
saved = true
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.translate(currentX, currentY)
|
|
|
|
|
if(symbol.scale){
|
2018-12-04 06:23:11 +08:00
|
|
|
|
if(config.baseline === "middle"){
|
|
|
|
|
ctx.translate(0, -ctx.lineWidth * (2 / symbol.scale[1]))
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.scale(symbol.scale[0], symbol.scale[1])
|
|
|
|
|
ctx.lineWidth /= symbol.scale[0]
|
|
|
|
|
}
|
|
|
|
|
currentX = 0
|
|
|
|
|
currentY = 0
|
|
|
|
|
}
|
2018-12-13 17:18:52 +08:00
|
|
|
|
if(symbol.ura){
|
|
|
|
|
ctx.font = (30 * mul) + "px Meiryo, sans-serif"
|
2019-02-21 04:48:21 +08:00
|
|
|
|
ctx.textBaseline = "middle"
|
2018-12-13 17:18:52 +08:00
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.arc(currentX, currentY + (17 * mul), (18 * mul), 0, Math.PI * 2)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
if(action === "strokeText"){
|
2018-12-13 17:18:52 +08:00
|
|
|
|
ctx.fillStyle = layer.outline
|
|
|
|
|
ctx.fill()
|
|
|
|
|
}else if(action === "fillText"){
|
|
|
|
|
ctx.strokeStyle = layer.fill
|
|
|
|
|
ctx.lineWidth = 2.5 * mul
|
2019-02-21 04:51:45 +08:00
|
|
|
|
ctx.fillText(symbol.text, currentX, currentY + (17 * mul))
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
2018-12-13 17:18:52 +08:00
|
|
|
|
ctx.stroke()
|
|
|
|
|
}else{
|
|
|
|
|
ctx[action](symbol.text, currentX, currentY)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
if(saved){
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
offsetX += symbol.w * mul
|
|
|
|
|
}
|
2018-10-25 22:18:41 +08:00
|
|
|
|
if(savedLayer){
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffIcon(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
var scale = config.scale
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.lineWidth = config.border
|
|
|
|
|
ctx.strokeStyle = "#000"
|
2018-10-13 02:04:28 +08:00
|
|
|
|
var icon = this.diffIconPath[config.diff === 4 ? 3 : config.diff]
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.translate(config.x - icon[0].w * scale / 2, config.y - icon[0].h * scale / 2)
|
|
|
|
|
ctx.scale(scale, scale)
|
|
|
|
|
for(var i = 1; i < icon.length; i++){
|
|
|
|
|
if(!icon[i].noStroke){
|
|
|
|
|
ctx.stroke(icon[i].d)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!config.noFill){
|
|
|
|
|
for(var i = 1; i < icon.length; i++){
|
2018-10-13 02:04:28 +08:00
|
|
|
|
if(config.diff === 4 && icon[i].fill === "#db1885"){
|
|
|
|
|
ctx.fillStyle = "#7135db"
|
|
|
|
|
}else{
|
|
|
|
|
ctx.fillStyle = icon[i].fill
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.fill(icon[i].d)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffOptionsIcon(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
2018-10-25 22:18:41 +08:00
|
|
|
|
if(config.iconName === "back"){
|
|
|
|
|
ctx.translate(config.x - 21, config.y - 21)
|
|
|
|
|
|
|
|
|
|
var drawLine = y => {
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(12, y)
|
2018-11-18 20:30:06 +08:00
|
|
|
|
ctx.arc(20.5, 24, 8.5, Math.PI, Math.PI * 2, true)
|
2018-10-25 22:18:41 +08:00
|
|
|
|
ctx.lineTo(29, 18)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
}
|
|
|
|
|
var drawTriangle = noFill => {
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(29, 5)
|
|
|
|
|
ctx.lineTo(21, 19)
|
|
|
|
|
ctx.lineTo(37, 19)
|
|
|
|
|
ctx.closePath()
|
|
|
|
|
if(!noFill){
|
|
|
|
|
ctx.fill()
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
2018-10-25 22:18:41 +08:00
|
|
|
|
ctx.strokeStyle = "#000"
|
2018-11-18 20:30:06 +08:00
|
|
|
|
ctx.lineWidth = 13
|
|
|
|
|
drawLine(8)
|
|
|
|
|
ctx.lineWidth = 6
|
2018-10-25 22:18:41 +08:00
|
|
|
|
drawTriangle(true)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
ctx.lineWidth = 7
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
ctx.strokeStyle = "#fff"
|
|
|
|
|
drawLine(11)
|
|
|
|
|
drawTriangle()
|
|
|
|
|
ctx.translate(-1.5, -0.5)
|
|
|
|
|
ctx.fillStyle = "#23a6e1"
|
|
|
|
|
ctx.strokeStyle = "#23a6e1"
|
|
|
|
|
ctx.globalCompositeOperation = "darken"
|
|
|
|
|
drawLine(11)
|
|
|
|
|
drawTriangle()
|
|
|
|
|
}else if(config.iconName === "options"){
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
ctx.rotate(-55 * Math.PI / 180)
|
|
|
|
|
ctx.translate(-6, -20)
|
|
|
|
|
ctx.strokeStyle = "#000"
|
|
|
|
|
ctx.lineWidth = 6
|
|
|
|
|
ctx.stroke(this.optionsPath.main)
|
|
|
|
|
ctx.translate(-2, 2)
|
|
|
|
|
ctx.stroke(this.optionsPath.main)
|
|
|
|
|
ctx.fillStyle = "#7e7c76"
|
|
|
|
|
ctx.fill(this.optionsPath.shadow)
|
|
|
|
|
ctx.translate(2, -2)
|
|
|
|
|
ctx.fillStyle = "#d9d6ce"
|
|
|
|
|
ctx.fill(this.optionsPath.main)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffCursor(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
if(config.scale){
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
ctx.scale(config.scale, config.scale)
|
|
|
|
|
ctx.translate(-48, -64)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.translate(config.x - 48, config.y - 64)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.fillStyle = config.two ? "#65cdcd" : "#ff411c"
|
|
|
|
|
ctx.strokeStyle = "#000"
|
|
|
|
|
ctx.lineWidth = 6
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
if(!config.side){
|
2018-11-21 18:50:48 +08:00
|
|
|
|
var textX = config.two ? 22 : 20
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.moveTo(48, 120)
|
|
|
|
|
ctx.arc(48, 48.5, 45, Math.PI * 0.58, Math.PI * 0.42)
|
|
|
|
|
}else if(config.two){
|
2018-11-21 18:50:48 +08:00
|
|
|
|
var textX = 72
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.moveTo(56, 115)
|
|
|
|
|
ctx.arc(98, 48.5, 45, Math.PI * 0.75, Math.PI * 0.59)
|
|
|
|
|
}else{
|
2018-11-21 18:50:48 +08:00
|
|
|
|
var textX = -30
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.moveTo(39, 115)
|
|
|
|
|
ctx.arc(-2, 48.5, 45, Math.PI * 0.41, Math.PI * 0.25)
|
|
|
|
|
}
|
|
|
|
|
ctx.closePath()
|
|
|
|
|
ctx.fill()
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
this.layeredText({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
text: config.two ? "2P" : "1P",
|
|
|
|
|
fontSize: 43,
|
|
|
|
|
fontFamily: config.font,
|
|
|
|
|
x: textX,
|
|
|
|
|
y: 26,
|
|
|
|
|
width: 54,
|
|
|
|
|
letterSpacing: -4
|
|
|
|
|
}, [
|
|
|
|
|
{outline: "#fff", letterBorder: 11},
|
|
|
|
|
{fill: "#000"}
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
diffStar(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
2018-10-13 06:09:42 +08:00
|
|
|
|
if(config.songSel || config.ura){
|
2018-10-09 21:07:53 +08:00
|
|
|
|
if(this.diffStarCache.scale !== config.ratio){
|
2018-10-13 06:09:42 +08:00
|
|
|
|
this.diffStarCache.resize(62, 31, config.ratio)
|
2018-10-09 21:07:53 +08:00
|
|
|
|
}
|
|
|
|
|
var offset = 30 / 2 - 18 / 2
|
2018-10-13 06:09:42 +08:00
|
|
|
|
var big = config.ura && !config.songSel
|
2018-10-09 21:07:53 +08:00
|
|
|
|
this.diffStarCache.get({
|
2018-10-09 14:59:36 +08:00
|
|
|
|
ctx: ctx,
|
2018-10-09 21:07:53 +08:00
|
|
|
|
x: config.x - 9 - offset,
|
|
|
|
|
y: config.y - 9 - offset,
|
|
|
|
|
w: 30,
|
|
|
|
|
h: 30,
|
2018-10-13 06:09:42 +08:00
|
|
|
|
id: big ? "big" : "small"
|
2018-10-09 21:07:53 +08:00
|
|
|
|
}, ctx => {
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
this.shadow({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
fill: "#fff",
|
|
|
|
|
blur: 10,
|
|
|
|
|
force: true
|
|
|
|
|
})
|
2018-10-13 06:09:42 +08:00
|
|
|
|
if(big){
|
|
|
|
|
ctx.translate(30 / 2 - 21 / 2, 30 / 2 - 19 / 2)
|
|
|
|
|
ctx.scale(1.1, 1.1)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.translate(offset, offset)
|
|
|
|
|
}
|
2018-10-09 21:07:53 +08:00
|
|
|
|
ctx.fill(this.diffStarPath)
|
2018-10-09 14:59:36 +08:00
|
|
|
|
})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}else{
|
2018-10-09 21:07:53 +08:00
|
|
|
|
ctx.fillStyle = "#f72568"
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.translate(config.x - 10.5, config.y - 9.5)
|
|
|
|
|
ctx.scale(1.1, 1.1)
|
2018-10-09 21:07:53 +08:00
|
|
|
|
ctx.fill(this.diffStarPath)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pattern(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
var mul = config.scale || 1
|
|
|
|
|
|
|
|
|
|
if(mul !== 1){
|
|
|
|
|
ctx.scale(1 / mul, 1 / mul)
|
|
|
|
|
}
|
|
|
|
|
ctx.fillStyle = ctx.createPattern(config.img, "repeat")
|
2018-10-25 22:18:41 +08:00
|
|
|
|
if(config.shape){
|
|
|
|
|
config.shape(ctx, mul)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.rect(config.x * mul, config.y * mul, config.w * mul, config.h * mul)
|
|
|
|
|
}
|
|
|
|
|
ctx.translate(config.dx * mul, config.dy * mul)
|
2018-10-01 15:33:43 +08:00
|
|
|
|
ctx.fill()
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
score(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
if(config.scale){
|
|
|
|
|
ctx.scale(config.scale, config.scale)
|
|
|
|
|
}
|
|
|
|
|
ctx.strokeStyle = "#000"
|
|
|
|
|
ctx.lineWidth = 7
|
2019-01-22 03:08:02 +08:00
|
|
|
|
if(strings.good === "良"){
|
|
|
|
|
if(config.align === "center"){
|
|
|
|
|
ctx.translate(config.score === "bad" ? -49 / 2 : -23 / 2, 0)
|
|
|
|
|
}
|
|
|
|
|
if(config.score === "good"){
|
|
|
|
|
var grd = ctx.createLinearGradient(0, 0, 0, 29)
|
|
|
|
|
grd.addColorStop(0.3, "#f7fb00")
|
|
|
|
|
grd.addColorStop(0.9, "#ff4900")
|
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
|
ctx.stroke(this.diffPath.good)
|
|
|
|
|
ctx.fill(this.diffPath.good)
|
|
|
|
|
}else if(config.score === "ok"){
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
ctx.stroke(this.diffPath.ok)
|
|
|
|
|
ctx.fill(this.diffPath.ok)
|
|
|
|
|
}else if(config.score === "bad"){
|
|
|
|
|
var grd = ctx.createLinearGradient(0, 0, 0, 27)
|
|
|
|
|
grd.addColorStop(0.1, "#6B5DFF")
|
|
|
|
|
grd.addColorStop(0.7, "#00AEDE")
|
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
|
ctx.stroke(this.diffPath.bad)
|
|
|
|
|
ctx.fill(this.diffPath.bad)
|
|
|
|
|
ctx.translate(26, 0)
|
|
|
|
|
ctx.stroke(this.diffPath.ok)
|
|
|
|
|
ctx.fill(this.diffPath.ok)
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
ctx.font = this.bold(strings.font) + "26px " + strings.font
|
|
|
|
|
if(config.results){
|
|
|
|
|
ctx.textAlign = "left"
|
|
|
|
|
}else{
|
|
|
|
|
ctx.textAlign = "center"
|
|
|
|
|
}
|
|
|
|
|
ctx.textBaseline = "top"
|
|
|
|
|
ctx.miterLimit = 1
|
|
|
|
|
if(config.score === "good"){
|
|
|
|
|
if(config.results && strings.id === "en"){
|
|
|
|
|
ctx.scale(0.75, 1)
|
|
|
|
|
}
|
|
|
|
|
var grd = ctx.createLinearGradient(0, 0, 0, 29)
|
|
|
|
|
grd.addColorStop(0.3, "#f7fb00")
|
|
|
|
|
grd.addColorStop(0.9, "#ff4900")
|
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
|
ctx.strokeText(strings.good, 0, 4)
|
|
|
|
|
ctx.fillText(strings.good, 0, 4)
|
|
|
|
|
}else if(config.score === "ok"){
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
ctx.strokeText(strings.ok, 0, 4)
|
|
|
|
|
ctx.fillText(strings.ok, 0, 4)
|
|
|
|
|
}else if(config.score === "bad"){
|
|
|
|
|
var grd = ctx.createLinearGradient(0, 0, 0, 27)
|
|
|
|
|
grd.addColorStop(0.1, "#6B5DFF")
|
|
|
|
|
grd.addColorStop(0.7, "#00AEDE")
|
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
|
ctx.strokeText(strings.bad, 0, 4)
|
|
|
|
|
ctx.fillText(strings.bad, 0, 4)
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
crown(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
if(config.scale){
|
|
|
|
|
ctx.scale(config.scale, config.scale)
|
|
|
|
|
}
|
|
|
|
|
ctx.translate(-47, -39)
|
|
|
|
|
ctx.miterLimit = 1.7
|
|
|
|
|
|
2018-10-09 21:07:53 +08:00
|
|
|
|
if(!this.crownCache.w){
|
|
|
|
|
this.crownCache.resize(140, 140, config.ratio)
|
2018-10-09 14:59:36 +08:00
|
|
|
|
}
|
2018-10-09 21:07:53 +08:00
|
|
|
|
var offset = 140 / 2 - 94 / 2
|
|
|
|
|
this.crownCache.get({
|
|
|
|
|
ctx: ctx,
|
|
|
|
|
x: -offset,
|
|
|
|
|
y: -offset,
|
|
|
|
|
w: 140,
|
|
|
|
|
h: 140,
|
|
|
|
|
id: "crown"
|
|
|
|
|
}, ctx => {
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.translate(offset, offset)
|
|
|
|
|
ctx.strokeStyle = "#fff"
|
|
|
|
|
ctx.lineWidth = 35
|
|
|
|
|
ctx.miterLimit = 1.7
|
|
|
|
|
ctx.filter = "blur(1.5px)"
|
|
|
|
|
ctx.stroke(this.crownPath)
|
|
|
|
|
ctx.restore()
|
|
|
|
|
})
|
2018-10-01 15:33:43 +08:00
|
|
|
|
|
|
|
|
|
if(config.shine){
|
|
|
|
|
ctx.strokeStyle = "#fff"
|
|
|
|
|
ctx.lineWidth = 18
|
|
|
|
|
ctx.stroke(this.crownPath)
|
|
|
|
|
ctx.globalAlpha = 1 - config.shine
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.strokeStyle = "#000"
|
|
|
|
|
ctx.lineWidth = 18
|
|
|
|
|
ctx.stroke(this.crownPath)
|
|
|
|
|
|
|
|
|
|
if(config.shine){
|
|
|
|
|
ctx.globalAlpha = 1
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
ctx.fill(this.crownPath)
|
|
|
|
|
ctx.globalAlpha = 1 - config.shine
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var grd = ctx.createLinearGradient(0, 0, 94, 0)
|
|
|
|
|
if(config.type === "gold"){
|
|
|
|
|
grd.addColorStop(0, "#ffffc5")
|
|
|
|
|
grd.addColorStop(0.23, "#ffff44")
|
|
|
|
|
grd.addColorStop(0.53, "#efbd12")
|
|
|
|
|
grd.addColorStop(0.83, "#ffff44")
|
|
|
|
|
grd.addColorStop(1, "#efbd12")
|
|
|
|
|
}else if(config.type === "silver"){
|
|
|
|
|
grd.addColorStop(0, "#d6efef")
|
|
|
|
|
grd.addColorStop(0.23, "#bddfde")
|
|
|
|
|
grd.addColorStop(0.53, "#97c1c0")
|
|
|
|
|
grd.addColorStop(0.83, "#bddfde")
|
|
|
|
|
grd.addColorStop(1, "#97c1c0")
|
|
|
|
|
}
|
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
|
ctx.fill(this.crownPath)
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-25 22:18:41 +08:00
|
|
|
|
gauge(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
if(config.scale){
|
|
|
|
|
ctx.scale(config.scale, config.scale)
|
|
|
|
|
}
|
|
|
|
|
ctx.translate(-788, 0)
|
|
|
|
|
|
|
|
|
|
var firstTop = config.multiplayer ? 0 : 30
|
|
|
|
|
var secondTop = config.multiplayer ? 0 : 8
|
|
|
|
|
|
2019-02-18 00:26:46 +08:00
|
|
|
|
config.percentage = Math.max(0, Math.min(1, config.percentage))
|
2018-10-25 22:18:41 +08:00
|
|
|
|
var cleared = config.percentage - 1 / 50 >= config.clear
|
|
|
|
|
|
|
|
|
|
var gaugeW = 14 * 50
|
|
|
|
|
var gaugeClear = gaugeW * config.clear
|
|
|
|
|
var gaugeFilled = gaugeW * config.percentage
|
|
|
|
|
|
|
|
|
|
ctx.fillStyle = "#000"
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
if(config.scoresheet){
|
|
|
|
|
ctx.moveTo(-4, 26)
|
|
|
|
|
ctx.lineTo(gaugeClear - 4, 26)
|
|
|
|
|
this.roundedCorner(ctx, gaugeClear - 4, 4, 13, 0)
|
|
|
|
|
this.roundedCorner(ctx, 760, 4, 13, 1)
|
|
|
|
|
ctx.lineTo(760, 56)
|
|
|
|
|
ctx.lineTo(-4, 56)
|
|
|
|
|
}else if(config.multiplayer){
|
|
|
|
|
ctx.moveTo(gaugeClear - 7, 27)
|
|
|
|
|
ctx.lineTo(788, 27)
|
|
|
|
|
ctx.lineTo(788, 52)
|
|
|
|
|
this.roundedCorner(ctx, gaugeClear - 7, 52, 18, 3)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.moveTo(gaugeClear - 7, 24)
|
|
|
|
|
this.roundedCorner(ctx, gaugeClear - 7, 0, 18, 0)
|
|
|
|
|
ctx.lineTo(788, 0)
|
|
|
|
|
ctx.lineTo(788, 24)
|
|
|
|
|
}
|
|
|
|
|
ctx.fill()
|
|
|
|
|
|
|
|
|
|
if(gaugeFilled <= gaugeClear){
|
2018-11-07 03:26:58 +08:00
|
|
|
|
ctx.fillStyle = config.blue ? "#184d55" : "#680000"
|
2018-10-25 22:18:41 +08:00
|
|
|
|
var x = Math.max(0, gaugeFilled - 5)
|
|
|
|
|
ctx.fillRect(x, firstTop, gaugeClear - x + 2, 22)
|
|
|
|
|
}
|
|
|
|
|
if(gaugeFilled > 0){
|
|
|
|
|
var w = Math.min(gaugeClear + 1, gaugeFilled - 4)
|
2018-11-07 03:26:58 +08:00
|
|
|
|
ctx.fillStyle = config.blue ? "#00edff" : "#ff3408"
|
2018-10-25 22:18:41 +08:00
|
|
|
|
ctx.fillRect(0, firstTop + 2, w, 20)
|
2018-11-07 03:26:58 +08:00
|
|
|
|
ctx.fillStyle = config.blue ? "#9cffff" : "#ffa191"
|
2018-10-25 22:18:41 +08:00
|
|
|
|
ctx.fillRect(0, firstTop, w, 3)
|
|
|
|
|
}
|
|
|
|
|
if(gaugeFilled < gaugeW - 4){
|
2018-11-07 03:26:58 +08:00
|
|
|
|
ctx.fillStyle = "#684900"
|
2018-10-25 22:18:41 +08:00
|
|
|
|
var x = Math.max(gaugeClear + 9, gaugeFilled - gaugeClear + 9)
|
|
|
|
|
ctx.fillRect(x, secondTop, gaugeW - 4 - x, 44)
|
|
|
|
|
}
|
|
|
|
|
if(gaugeFilled > gaugeClear + 14){
|
|
|
|
|
var w = Math.min(gaugeW - 4, gaugeFilled - gaugeClear - 14)
|
|
|
|
|
ctx.fillStyle = "#ff0"
|
|
|
|
|
ctx.fillRect(gaugeClear + 9, secondTop + 2, w, 42)
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
ctx.fillRect(gaugeClear + 9, secondTop, w, 3)
|
|
|
|
|
}
|
2018-11-07 03:26:58 +08:00
|
|
|
|
ctx.fillStyle = cleared ? "#ff0" : "#684900"
|
2018-10-25 22:18:41 +08:00
|
|
|
|
ctx.beginPath()
|
|
|
|
|
if(config.multiplayer){
|
|
|
|
|
this.roundedCorner(ctx, gaugeClear, secondTop + 44, 10, 3)
|
|
|
|
|
ctx.lineTo(gaugeClear, secondTop)
|
|
|
|
|
ctx.lineTo(gaugeClear + 10, secondTop)
|
|
|
|
|
}else{
|
|
|
|
|
ctx.moveTo(gaugeClear, secondTop + 44)
|
|
|
|
|
this.roundedCorner(ctx, gaugeClear, secondTop, 10, 0)
|
|
|
|
|
ctx.lineTo(gaugeClear + 10, secondTop + 44)
|
|
|
|
|
}
|
|
|
|
|
ctx.fill()
|
|
|
|
|
if(cleared){
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.clip()
|
|
|
|
|
ctx.fillStyle = "#fff"
|
|
|
|
|
ctx.fillRect(gaugeClear, secondTop, 10, 3)
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx.strokeStyle = "rgba(0, 0, 0, 0.16)"
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.lineWidth = 5
|
|
|
|
|
for(var i = 0; i < 49; i++){
|
|
|
|
|
var x = 14 + i * 14 - ctx.lineWidth / 2
|
|
|
|
|
if(i === 26){
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.lineWidth = 4
|
|
|
|
|
}
|
|
|
|
|
ctx.moveTo(x, x < gaugeClear ? firstTop : secondTop)
|
|
|
|
|
ctx.lineTo(x, x < gaugeClear ? firstTop + 22 : secondTop + 44)
|
|
|
|
|
}
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
this.layeredText({
|
|
|
|
|
ctx: ctx,
|
2019-01-05 15:44:28 +08:00
|
|
|
|
text: strings.clear,
|
2018-10-25 22:18:41 +08:00
|
|
|
|
fontSize: 18,
|
|
|
|
|
fontFamily: config.font,
|
2018-11-21 17:02:53 +08:00
|
|
|
|
x: gaugeClear + 3,
|
2018-10-25 22:18:41 +08:00
|
|
|
|
y: config.multiplayer ? 22 : 11,
|
|
|
|
|
letterSpacing: -2
|
|
|
|
|
}, [
|
|
|
|
|
{scale: [1.1, 1.01], outline: "#000", letterBorder: 6},
|
|
|
|
|
{scale: [1.11, 1], fill: cleared ? "#fff" : "#737373"}
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
soul(config){
|
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
ctx.save()
|
|
|
|
|
|
|
|
|
|
ctx.translate(config.x, config.y)
|
|
|
|
|
if(config.scale){
|
|
|
|
|
ctx.scale(config.scale, config.scale)
|
|
|
|
|
}
|
|
|
|
|
ctx.translate(-23, -21)
|
|
|
|
|
|
|
|
|
|
ctx.fillStyle = config.cleared ? "#fff" : "#737373"
|
|
|
|
|
ctx.fill(this.soulPath)
|
|
|
|
|
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
slot(ctx, x, y, size){
|
|
|
|
|
var mul = size / 106
|
|
|
|
|
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.globalAlpha = 0.7
|
|
|
|
|
ctx.globalCompositeOperation = "screen"
|
|
|
|
|
ctx.fillStyle = "#444544"
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.arc(x, y, 26 * mul, 0, Math.PI * 2)
|
|
|
|
|
ctx.fill()
|
|
|
|
|
ctx.lineWidth = 3
|
|
|
|
|
ctx.strokeStyle = "#9c9e9c"
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.arc(x, y, 33.5 * mul, 0, Math.PI * 2)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
ctx.lineWidth = 3.5
|
|
|
|
|
ctx.strokeStyle = "#5d5e5d"
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.arc(x, y, 51.5 * mul, 0, Math.PI * 2)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-30 00:10:56 +08:00
|
|
|
|
alpha(amount, ctx, callback, winW, winH){
|
2018-10-01 15:33:43 +08:00
|
|
|
|
if(amount >= 1){
|
|
|
|
|
return callback(ctx)
|
|
|
|
|
}else if(amount >= 0){
|
2019-01-30 00:10:56 +08:00
|
|
|
|
this.tmpCanvas.width = winW || ctx.canvas.width
|
|
|
|
|
this.tmpCanvas.height = winH || ctx.canvas.height
|
2018-10-01 15:33:43 +08:00
|
|
|
|
callback(this.tmpCtx)
|
|
|
|
|
ctx.save()
|
|
|
|
|
ctx.globalAlpha = amount
|
|
|
|
|
ctx.drawImage(this.tmpCanvas, 0, 0)
|
|
|
|
|
ctx.restore()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-09 14:59:36 +08:00
|
|
|
|
shadow(config){
|
2018-10-09 21:07:53 +08:00
|
|
|
|
if(!disableBlur || config.force){
|
2018-10-09 14:59:36 +08:00
|
|
|
|
var ctx = config.ctx
|
|
|
|
|
if(config.fill){
|
|
|
|
|
ctx.shadowColor = config.fill
|
|
|
|
|
}
|
|
|
|
|
if(config.blur){
|
|
|
|
|
ctx.shadowBlur = config.blur
|
|
|
|
|
}
|
|
|
|
|
if(config.x){
|
|
|
|
|
ctx.shadowOffsetX = config.x
|
|
|
|
|
}
|
|
|
|
|
if(config.y){
|
|
|
|
|
ctx.shadowOffsetY = config.y
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 23:47:22 +08:00
|
|
|
|
bold(font){
|
|
|
|
|
return font === "Microsoft YaHei, sans-serif" ? "bold " : ""
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-01 15:33:43 +08:00
|
|
|
|
getMS(){
|
2018-12-13 17:18:52 +08:00
|
|
|
|
return Date.now()
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|
2018-10-09 21:07:53 +08:00
|
|
|
|
|
|
|
|
|
clean(){
|
|
|
|
|
this.songFrameCache.clean()
|
|
|
|
|
this.diffStarCache.clean()
|
|
|
|
|
this.crownCache.clean()
|
|
|
|
|
delete this.tmpCtx
|
|
|
|
|
delete this.tmpCanvas
|
|
|
|
|
}
|
2018-10-01 15:33:43 +08:00
|
|
|
|
}
|