Do padding in canvas instead of CSS

box-drawing
cpsdqs 7 years ago
parent 57a295b544
commit 4c1da9aaac
Signed by untrusted user: cpsdqs
GPG Key ID: 3F59586BB7448DD1
  1. 25
      js/term/screen.js
  2. 62
      js/term/screen_renderer.js
  3. 1
      sass/pages/_term.scss

@ -55,6 +55,7 @@ module.exports = class TermScreen extends EventEmitter {
devicePixelRatio: 1, devicePixelRatio: 1,
fontFamily: '"DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace', fontFamily: '"DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace',
fontSize: 20, fontSize: 20,
padding: 6,
gridScaleX: 1.0, gridScaleX: 1.0,
gridScaleY: 1.2, gridScaleY: 1.2,
fitIntoWidth: 0, fitIntoWidth: 0,
@ -67,11 +68,15 @@ module.exports = class TermScreen extends EventEmitter {
// scaling caused by fitIntoWidth/fitIntoHeight // scaling caused by fitIntoWidth/fitIntoHeight
this._windowScale = 1 this._windowScale = 1
// actual padding, as it may be disabled by fullscreen mode etc.
this._padding = 0
// properties of this.window that require updating size and redrawing // properties of this.window that require updating size and redrawing
this.windowState = { this.windowState = {
width: 0, width: 0,
height: 0, height: 0,
devicePixelRatio: 0, devicePixelRatio: 0,
padding: 0,
gridScaleX: 0, gridScaleX: 0,
gridScaleY: 0, gridScaleY: 0,
fontFamily: '', fontFamily: '',
@ -313,8 +318,8 @@ module.exports = class TermScreen extends EventEmitter {
let cellSize = this.getCellSize() let cellSize = this.getCellSize()
return [ return [
Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width), Math.floor((x - this._padding + (rounded ? cellSize.width / 2 : 0)) / cellSize.width),
Math.floor(y / cellSize.height) Math.floor((y - this._padding) / cellSize.height)
] ]
} }
@ -328,7 +333,7 @@ module.exports = class TermScreen extends EventEmitter {
gridToScreen (x, y, withScale = false) { gridToScreen (x, y, withScale = false) {
let cellSize = this.getCellSize() let cellSize = this.getCellSize()
return [x * cellSize.width, y * cellSize.height].map(v => withScale ? v * this._windowScale : v) return [x * cellSize.width, y * cellSize.height].map(v => this._padding + (withScale ? v * this._windowScale : v))
} }
/** /**
@ -378,13 +383,14 @@ module.exports = class TermScreen extends EventEmitter {
width, width,
height, height,
fitIntoWidth, fitIntoWidth,
fitIntoHeight fitIntoHeight,
padding
} = this.window } = this.window
const cellSize = this.getCellSize() const cellSize = this.getCellSize()
// real height of the canvas element in pixels // real height of the canvas element in pixels
let realWidth = width * cellSize.width let realWidth = width * cellSize.width + 2 * padding
let realHeight = height * cellSize.height let realHeight = height * cellSize.height + 2 * padding
if (fitIntoWidth && fitIntoHeight) { if (fitIntoWidth && fitIntoHeight) {
let terminalAspect = realWidth / realHeight let terminalAspect = realWidth / realHeight
@ -409,13 +415,16 @@ module.exports = class TermScreen extends EventEmitter {
// store new window scale // store new window scale
this._windowScale = realWidth / (width * cellSize.width) this._windowScale = realWidth / (width * cellSize.width)
// and padding
// TODO: disable in fullscreen mode
this._padding = padding
// the DPR must be rounded to a very nice value to prevent gaps between cells // the DPR must be rounded to a very nice value to prevent gaps between cells
let devicePixelRatio = this._window.devicePixelRatio = Math.round(this._windowScale * (window.devicePixelRatio || 1) * 2) / 2 let devicePixelRatio = this._window.devicePixelRatio = Math.round(this._windowScale * (window.devicePixelRatio || 1) * 2) / 2
this.canvas.width = width * devicePixelRatio * cellSize.width this.canvas.width = (width * cellSize.width + 2 * padding) * devicePixelRatio
this.canvas.style.width = `${realWidth}px` this.canvas.style.width = `${realWidth}px`
this.canvas.height = height * devicePixelRatio * cellSize.height this.canvas.height = (height * cellSize.height + 2 * padding) * devicePixelRatio
this.canvas.style.height = `${realHeight}px` this.canvas.style.height = `${realHeight}px`
// the screen has been cleared (by changing canvas width) // the screen has been cleared (by changing canvas width)

@ -159,9 +159,26 @@ module.exports = class ScreenRenderer {
*/ */
drawBackground ({ x, y, cellWidth, cellHeight, bg }) { drawBackground ({ x, y, cellWidth, cellHeight, bg }) {
const ctx = this.ctx const ctx = this.ctx
const { width, height } = this.screen.window
ctx.fillStyle = this.getColor(bg) ctx.fillStyle = this.getColor(bg)
ctx.clearRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) let screenX = x * cellWidth + this.screen._padding
ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) let screenY = y * cellHeight + this.screen._padding
let isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1
if (isBorderCell) {
let left = screenX
let top = screenY
let right = screenX + cellWidth
let bottom = screenY + cellHeight
if (x === 0) left -= this.screen._padding
else if (x === width - 1) right += this.screen._padding
if (y === 0) top -= this.screen._padding
else if (y === height - 1) bottom += this.screen._padding
ctx.clearRect(left, top, right - left, bottom - top)
ctx.fillRect(left, top, right - left, bottom - top)
} else {
ctx.clearRect(screenX, screenY, cellWidth, cellHeight)
ctx.fillRect(screenX, screenY, cellWidth, cellHeight)
}
} }
/** /**
@ -194,12 +211,15 @@ module.exports = class ScreenRenderer {
ctx.fillStyle = this.getColor(fg) ctx.fillStyle = this.getColor(fg)
let screenX = x * cellWidth + this.screen._padding
let screenY = y * cellHeight + this.screen._padding
let codePoint = text.codePointAt(0) let codePoint = text.codePointAt(0)
if (codePoint >= 0x2580 && codePoint <= 0x259F) { if (codePoint >= 0x2580 && codePoint <= 0x259F) {
// block elements // block elements
ctx.beginPath() ctx.beginPath()
const left = x * cellWidth const left = screenX
const top = y * cellHeight const top = screenY
const cw = cellWidth const cw = cellWidth
const ch = cellHeight const ch = cellHeight
const c2w = cellWidth / 2 const c2w = cellWidth / 2
@ -251,16 +271,16 @@ module.exports = class ScreenRenderer {
for (let dx = 0; dx < cw; dx += dotSpacingX) { for (let dx = 0; dx < cw; dx += dotSpacingX) {
// prevent overflow // prevent overflow
let dotSizeY = Math.min(dotSize, ch - dy) let dotSizeY = Math.min(dotSize, ch - dy)
ctx.rect(x * cw + (alignRight ? cw - dx - dotSize : dx), y * ch + dy, dotSize, dotSizeY) ctx.rect(left + (alignRight ? cw - dx - dotSize : dx), top + dy, dotSize, dotSizeY)
} }
alignRight = !alignRight alignRight = !alignRight
} }
} else if (codePoint === 0x2594) { } else if (codePoint === 0x2594) {
// upper one eighth block >▔< // upper one eighth block >▔<
ctx.rect(x * cw, y * ch, cw, ch / 8) ctx.rect(left, top, cw, ch / 8)
} else if (codePoint === 0x2595) { } else if (codePoint === 0x2595) {
// right one eighth block >▕< // right one eighth block >▕<
ctx.rect((x + 7 / 8) * cw, y * ch, cw / 8, ch) ctx.rect(left + (7 / 8) * cw, top, cw / 8, ch)
} else if (codePoint === 0x2596) { } else if (codePoint === 0x2596) {
// left bottom quadrant >▖< // left bottom quadrant >▖<
ctx.rect(left, top + c2h, c2w, c2h) ctx.rect(left, top + c2h, c2w, c2h)
@ -302,7 +322,7 @@ module.exports = class ScreenRenderer {
ctx.fill() ctx.fill()
} else { } else {
// Draw other characters using the text renderer // Draw other characters using the text renderer
ctx.fillText(text, (x + 0.5) * cellWidth, (y + 0.5) * cellHeight) ctx.fillText(text, screenX + 0.5 * cellWidth, screenY + 0.5 * cellHeight)
} }
// -- line drawing - a reference for a possible future rect/line implementation --- // -- line drawing - a reference for a possible future rect/line implementation ---
@ -324,21 +344,21 @@ module.exports = class ScreenRenderer {
ctx.beginPath() ctx.beginPath()
if (underline) { if (underline) {
let lineY = Math.round(y * cellHeight + charSize.height) + 0.5 let lineY = Math.round(screenY + charSize.height) + 0.5
ctx.moveTo(x * cellWidth, lineY) ctx.moveTo(screenX, lineY)
ctx.lineTo((x + 1) * cellWidth, lineY) ctx.lineTo(screenX + cellWidth, lineY)
} }
if (strike) { if (strike) {
let lineY = Math.round((y + 0.5) * cellHeight) + 0.5 let lineY = Math.round(screenY + 0.5 * cellHeight) + 0.5
ctx.moveTo(x * cellWidth, lineY) ctx.moveTo(screenX, lineY)
ctx.lineTo((x + 1) * cellWidth, lineY) ctx.lineTo(screenX + cellWidth, lineY)
} }
if (overline) { if (overline) {
let lineY = Math.round(y * cellHeight) + 0.5 let lineY = Math.round(screenY) + 0.5
ctx.moveTo(x * cellWidth, lineY) ctx.moveTo(screenX, lineY)
ctx.lineTo((x + 1) * cellWidth, lineY) ctx.lineTo(screenX + cellWidth, lineY)
} }
ctx.stroke() ctx.stroke()
@ -570,17 +590,19 @@ module.exports = class ScreenRenderer {
if (isCursor && !inSelection) { if (isCursor && !inSelection) {
ctx.save() ctx.save()
ctx.beginPath() ctx.beginPath()
let screenX = x * cellWidth + this.screen._padding
let screenY = y * cellHeight + this.screen._padding
if (this.screen.cursor.style === 'block') { if (this.screen.cursor.style === 'block') {
// block // block
ctx.rect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) ctx.rect(screenX, screenY, cellWidth, cellHeight)
} else if (this.screen.cursor.style === 'bar') { } else if (this.screen.cursor.style === 'bar') {
// vertical bar // vertical bar
let barWidth = 2 let barWidth = 2
ctx.rect(x * cellWidth, y * cellHeight, barWidth, cellHeight) ctx.rect(screenX, screenY, barWidth, cellHeight)
} else if (this.screen.cursor.style === 'line') { } else if (this.screen.cursor.style === 'line') {
// underline // underline
let lineHeight = 2 let lineHeight = 2
ctx.rect(x * cellWidth, y * cellHeight + charSize.height, cellWidth, lineHeight) ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight)
} }
ctx.clip() ctx.clip()

@ -18,7 +18,6 @@ body.term {
#screen { #screen {
white-space: nowrap; white-space: nowrap;
background: #111213; background: #111213;
padding: 6px;
display: inline-block; display: inline-block;
border: 2px solid #3983CD; border: 2px solid #3983CD;
position: relative; position: relative;

Loading…
Cancel
Save