const ctx = canvas.getContext("2d");
const textScrollBox = {
dirty : true, // indicates that variouse setting need update
cleanit(dontFitText){
if(this.dirty){
this.setFont();
this.getTextPos();
this.dirty = false;
if(!dontFitText){
this.fitText();
}
}
},
scrollY : 0,
fontSize : 24,
font : "Arial",
align : "left",
background : "#999",
border : {
lineWidth : 4,
style : "black",
corner : "round",
},
scrollBox : {
width : 10,
background : "#568",
color : "#78a",
},
fontStyle : "black",
setOptions(options){
Object.keys(this).forEach((key) =>{
if(options[key] !== undefined){
this[key] = options[key];
this.dirty = true;
}
})
},
setFont(){
this.fontStr = this.fontSize + "px " + this.font;
this.textHeight = this.fontSize + Math.ceil(this.fontSize * 0.05);
},
getTextPos(){
if(this.align === "left"){ this.textPos = 0 }
else if(this.align === "right"){ this.textPos = Math.floor(this.width - this.scrollBox.width -this.fontSize/4) }
else { this.textPos = Math.floor((this.width- - this.scrollBox.width)/2) }
},
fitText(){
this.cleanit(true); // MUST PASS TRUE or will recurse to call stack overflow
ctx.font = this.fontStr;
ctx.textAlign = this.align;
ctx.textBaseline = "top";
var words = this.text.split(" ");
this.lines.length = 0;
var line = "";
var space = "";
while(words.length > 0){
var word = words.shift();
var width = ctx.measureText(line + space + word).width;
if(width < this.width - this.scrollBox.width - this.scrollBox.width){
line += space + word;
space = " ";
}else{
if(space === ""){ // if one word too big put it in anyways
line += word;
}else{
words.unshift(word);
}
this.lines.push(line);
space = "";
line = "";
}
}
if(line !== ""){
this.lines.push(line);
}
this.maxScroll = ((this.lines.length + 0.5) * this.textHeight) - this.height;
},
drawBorder(){
var bw = this.border.lineWidth/2;
ctx.lineJoin = this.border.corner;
ctx.lineWidth = this.border.lineWidth;
ctx.strokeStyle = this.border.style;
ctx.strokeRect(this.x - bw,this.y - bw,this.width + 2 * bw,this.height + 2 * bw);
},
drawScrollBox(){
var displayHeight = this.height;
var scale = this.height/(this.lines.length * this.textHeight);
ctx.fillStyle = this.scrollBox.background;
ctx.fillRect(
this.x + this.width - this.scrollBox.width,
this.y,this.scrollBox.width,this.height
)
ctx.fillStyle = this.scrollBox.color;
ctx.fillRect(
this.x + this.width - this.scrollBox.width,
this.y - (this.scrollY * scale),
this.scrollBox.width,this.height * scale
)
},
scroll(pos){
this.cleanit();
this.scrollY = -pos;
if(this.scrollY > 0){
this.scrollY = 0;
}else if(this.scrollY < -this.maxScroll){
this.scrollY = -this.maxScroll ;
}
},
render(){
this.cleanit();
ctx.font = this.fontStr;
ctx.textAlign = this.align;
this.drawBorder();
ctx.save(); // need this to reset the clip area
ctx.fillStyle = this.background;
ctx.fillRect(this.x,this.y,this.width,this.height);
this.drawScrollBox();
ctx.beginPath();
ctx.rect(this.x,this.y,this.width-this.scrollBox.width,this.height);
ctx.clip();
// Important text does not like being place at fractions of a pixel
// make sure you round the y pos;
ctx.setTransform(1,0,0,1,this.x, Math.floor(this.y + this.scrollY));
ctx.fillStyle = this.fontStyle;
for(var i = 0; i < this.lines.length; i ++){
// Important text does not like being place at fractions of a pixel
// make sure you round the y pos;
ctx.fillText(this.lines[i],this.textPos,Math.floor(i * this.textHeight));
}
ctx.restore(); // remove the clipping
}
}
function createScrollText(text, x, y, width, height, options = {}){
return Object.assign({},
textScrollBox,{
text,x, y, width, height,
lines : [],
},
options
);
}
const text = "This is some random text added to the canvas via 2d API as a simple scroll box example at Stackoverflow. If you like any of the answers you find at stackoverflow and any of the other stack sites don't forget to upvote as a way to show your appreciation to all those that put in their free time to help others. Happy rendering "
var scrollText = createScrollText(text, 10, 10, 200, 180);
var scrollText1 = createScrollText(text, 220, 10, 270, 180);
scrollText1.setOptions({ // set only the properties you want to change
fontStyle : "white",
scrollBox : { // if you add scrollbox you must put all property in for it
width : 5,
background : "#DDD",
color : "#555",
},
border : { // if you add border you must put all property in for it
lineWidth : 4,
style : "black",
corner : "round",
},
font : "Comic Sans MS",
fontSize : 36,
align :"center",
})
function mainLoop(time){
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,canvas.width,canvas.height);
scrollText.scroll((Math.sin(time/3000) + 1) * scrollText.maxScroll * 0.5);
scrollText1.scroll((Math.sin(time/3462) + 1) * scrollText1.maxScroll * 0.5);
scrollText.render();
scrollText1.render();
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
canvas {
border : 2px solid black;
}
<canvas id="canvas" width=500 height=200></canvas>
#Blindman67:この大きなデモと素晴らしいコード、感謝の男。マウスを動かすとマウスの動きにイベントを追加しようとします。 – Mimouni