我要在画布中插入一个大文本。
首先我将文本换行,现在我试图让它在画布中滚动。
context.wrapText = function(text, x, y, maxWidth, lineHeight) {
var y_initial = y;
var cars = text.split("\n");
for (var ii = 0; ii < cars.length; ii++) {
var line = "";
var words = cars[ii].split(" ");
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n] + " ";
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth) {
context.fillText(line, x, y);
line = words[n] + " ";
y += lineHeight;
}
else {
line = testLine;
}
}
context.fillText(line, x, y);
y += lineHeight;
}
return y - y_initial;
}
context.wrapText("hello dear friends\nhere is\na sample of text\nthis is juste an example\nthanks\nbut need to be scrollable\n it works?\nlet's try.", 120, 80, 200, 15);
谢谢你的帮助。
答案 0 :(得分:1)
画布只是一个像素商店。它不记得除了像素之外绘制的内容。要进行滚动框,每次移动时都需要渲染整个滚动框。
上下文允许您设置剪辑区域。您可以使用它来确保不显示超出边界的文本。
使用ctx.setTransform设置滚动位置进行渲染。如果向上滚动,滚动位置必须进入否定状态。
演示是文本滚动框的一个非常基本的示例。它没有优化,文本拟合没有真正的智慧。
请参阅代码了解详细信息,它是非常基本的代码,所以没有那么多评论。如果您有疑问,请在评论中提出。
没有鼠标或用户互动,我留给你。
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);
&#13;
canvas {
border : 2px solid black;
}
&#13;
<canvas id="canvas" width=500 height=200></canvas>
&#13;