From 401fa043b6f981da24433397683327465f70a8d0 Mon Sep 17 00:00:00 2001 From: Isaiah Odhner Date: Sat, 5 Nov 2016 19:52:44 +0000 Subject: [PATCH] Wrap when rasterizing text --- README.md | 7 +- TODO.md | 8 +-- src/TextBox.js | 130 ++++++++++++++++++++++++++++++++++++-- src/image-manipulation.js | 8 +-- 4 files changed, 131 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c5660ac..ec77d0a 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ A nice web-based MS Paint remake and more... [Try it out!][jspaint web app] -You can also install it as a Chrome app. - + + The goal is to remake MS Paint (including its [little-known features](#did-you-know)), @@ -76,7 +76,7 @@ I want to bring good old paint into the modern era. * [Extended Editing](#extended-editing) * Proportionally resize the selection or canvas by holding Shift * After adding text, save as SVG or HTML with selectable text - (invisible text positioned over an embeded bitmap image) + (invisible text positioned over an embedded bitmap image) * Alt as a shortcut for the eyedropper, as long as it doesn't conflict with keyboard navigation of menus * Alternate themes (You can already theoretically style it with browser extensions like Stylebot or Stylish) * Noncontiguous fill (Probably by holding Shift when using the fill tool) @@ -89,7 +89,6 @@ I want to bring good old paint into the modern era. * The Magnifier's viewport preview * Shape styles on most of the shape tools * The polygon tool needs some work -* Handles on selections and text boxes * [This entire document full of things to do](TODO.md) Clipboard support is somewhat limited. diff --git a/TODO.md b/TODO.md index e25427d..deb8b79 100644 --- a/TODO.md +++ b/TODO.md @@ -33,15 +33,10 @@ * `*.htm` to `*.html` -* Make storage quota dialogue clearer - * Also add a message like "All cleaned up!" (probably with an additional Close button) - - * Visual * Warning sign for "Save changes to X?" dialogue * Error symbol for error message dialogues * The window close button uses text; font rendering is not consistent - * The menus use text; the arrow character is converted to an icon on some mobile devices * The progress bar (Rendering GIF) is left native * Use win98 default scrollbar size * Menu separator spacing @@ -183,9 +178,8 @@ * Text - * Wrapping! * Underline - * Expanding to new lines + * Expand box to make room for new lines * Minimum size of 3em x 1em * Store position of FontBox * Keep an old TextBox while drawing a new one diff --git a/src/TextBox.js b/src/TextBox.js index 89a02c5..434c0d7 100644 --- a/src/TextBox.js +++ b/src/TextBox.js @@ -29,7 +29,7 @@ function TextBox(x, y, width, height){ webkitWritingMode: font.vertical ? "vertical-lr" : "", linesupWritingMode: font.vertical ? "vertical-lr" : "", nonsenseWritingMode: font.vertical ? "vertical-lr" : "", - totesfakeWritingMode: font.vertical ? "vertical-lr" : "", + quitefakeWritingMode: font.vertical ? "vertical-lr" : "", lineHeight: font.size * font.line_scale * magnification + "px", color: font.color, background: font.background, @@ -134,6 +134,117 @@ TextBox.prototype.instantiate = function(){ } }; +// var wrap = function(ctx, text, x, y, maxWidth, lineHeight) { +// var original_lines = text.split(/(\r\n|[\n\v\f\r\x85\u2028\u2029])/); +// var lines = []; +// for(var i = 0; i < original_lines.length; i++){ +// var original_line = original_lines[i]; +// var words = original_line.split(' '); +// var line = ''; +// for(var n = 0, len = words.length; n < len; n++){ +// var word = words[n]; +// var testLine = line + word + ' '; +// var metrics = ctx.measureText(testLine); +// var testWidth = metrics.width; +// if (testWidth > maxWidth) { +// // we need to break this, +// // but let's see if we can start the next line with this word, +// // or if we need to break the word +// testLine = word + ' '; +// metrics = ctx.measureText(testLine); +// testWidth = metrics.width; +// if (testWidth > maxWidth) { +// // break this word +// console.log("breaking word", word); +// // if(word.indexOf('-') > -1){ + +// // } +// var remaining_word = word; +// var include_start_of_line = true; +// while(remaining_word.length){ +// for(var slice_index = remaining_word.length; slice_index >= 0; slice_index--){ +// testLine = remaining_word.slice(0, slice_index); +// if (include_start_of_line) { +// testLine = line + testLine; +// } +// console.log(include_start_of_line, slice_index, line, testLine); +// metrics = ctx.measureText(testLine); +// testWidth = metrics.width; +// if (testWidth <= maxWidth) { +// line = testLine; +// lines.push({ text: line, x: x, y: y }); +// remaining_word = remaining_word.slice(slice_index); +// y += lineHeight; +// break; +// } +// if (slice_index === 0) { +// console.log("discarding", remaining_word); +// remaining_word = ""; +// } +// } +// include_start_of_line = false; +// } +// line = remaining_word + ' '; +// // lines.push({ text: line, x: x, y: y }); +// // line = word + ' '; +// // y += lineHeight; +// } else { +// // start the next line with this word +// lines.push({ text: line, x: x, y: y }); +// line = testLine; +// y += lineHeight; +// } +// } else { +// line = testLine; +// } +// } + +// lines.push({ text: line, x: x, y: y }); +// y += lineHeight; +// } +// return lines; +// }; + +function draw_text_wrapped(ctx, text, x, y, maxWidth, lineHeight) { + var original_lines = text.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/); + // console.log("original_lines", original_lines); + for(var j = 0; j < original_lines.length; j++){ + var original_line = original_lines[j]; + var words = original_line.split(' '); + var line = ''; + var test; + var metrics; + // ctx.fillRect(x-5, y, 5, 5); + for (var i = 0; i < words.length; i++) { + test = words[i]; + metrics = ctx.measureText(test); + // TODO: break words on hyphens and perhaps other characters + while (metrics.width > maxWidth) { + // Determine how much of the word will fit + test = test.substring(0, test.length - 1); + metrics = ctx.measureText(test); + } + if (words[i] != test) { + words.splice(i + 1, 0, words[i].substr(test.length)); + words[i] = test; + } + + test = line + words[i] + ' '; + metrics = ctx.measureText(test); + + if (metrics.width > maxWidth && i > 0) { + ctx.fillText(line, x, y); + line = words[i] + ' '; + y += lineHeight; + } else { + line = test; + } + } + ctx.fillText(line, x, y); + y += lineHeight; + } +} + TextBox.prototype.draw = function(){ var tb = this; var text = tb.$editor.val(); @@ -145,11 +256,18 @@ TextBox.prototype.draw = function(){ ctx.fillStyle = font.color; var style_ = (font.bold ? (font.italic ? "italic bold " : "bold ") : (font.italic ? "italic " : "")); ctx.font = style_ + font.size + "px " + font.family; - ctx.textBaseline = "middle"; - var lines = text.split("\n") - for(var i=0; i