Size of character in pixels - javascript

I am trying to create text box in the HTML5 canvas, I know you can't actually do this, so I am creating a box and creating some text at the same location. But, I want to make sure the text stays in the box so I need to know when part of the text is extending out of the box. I figure I should be able to measure the text in terms of pixels and then compare it to the box. My question is, using javascript, how can I measure the size of the characters for any given font?

You can use context.measureText to get the width of your specified text:
// set the font
context.font = "14px verdana";
// use measureText to get the text width
var textWidth = context.measureText("Measure this!").width;
Text wrap would look something like this:
function wrapText(context, text, x, y, maxWidth, fontSizeFace) {
var words = text.split(' ');
var line = '';
var lineHeight=measureTextHeight(fontSizeFace);
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);
}

You can use as markE mention in his answer the measureText() function.
The specifications defines its result (a TextMetrix):
interface TextMetrics {
// x-direction
readonly attribute double width; // advance width
readonly attribute double actualBoundingBoxLeft;
readonly attribute double actualBoundingBoxRight;
// y-direction
readonly attribute double fontBoundingBoxAscent;
readonly attribute double fontBoundingBoxDescent;
readonly attribute double actualBoundingBoxAscent;
readonly attribute double actualBoundingBoxDescent;
readonly attribute double emHeightAscent;
readonly attribute double emHeightDescent;
readonly attribute double hangingBaseline;
readonly attribute double alphabeticBaseline;
readonly attribute double ideographicBaseline;
};
The problem however is that only width is implemented in the major browsers so you cannot get the height (ascent + descent) with this function yet (and I wouldn't be surprised if a canvas based word processor from at least one of the "major 3" shows up right before this gets fully implemented... but that's a regression and a speculation :-) ).
In order to measure the font you will have to use a DOM element, and this little trick will allow you to measure a font's width and height:
Online demo here (open console to see result).
function measureText(font, txt) {
var el = document.createElement('div'),
cs, res;
el.style.cssText = 'position:fixed;left:-4000px;top:-4000px;padding:0;margin:0;font:' + font;
el.innerHTML = txt;
document.body.appendChild(el);
cs = getComputedStyle(el);
res = {width: cs.getPropertyValue('width'),
height: cs.getPropertyValue('height')};
document.body.removeChild(el);
return res;
}
The function creates a div element, applies some basic styles to it to place it outside window. This is because we have to attach it to the DOM tree in order to use getComputedStyle() - we also have to get the property values before we remove the element again.
Pass arguments for font as you would with the context (ie. 20px sans-serif) and the text.
It comes with a small performance penalty obviously (though using fixed positioned elements won't cause any re-flow so it's not so bad) so use sparsely.

Related

Set width of ace editor instance according to the length of characters in it

I am working on the project where I have created a custom Rich Text Editor using contenteditable attribute. In this rich text editor I want insert single line ace editor instance of which width will be set according to the number of characters in it.
For restricting the ace editor instance to single line I have handled the "Enter" key event which does not let the ace instance to insert new line.
var editor = ace.edit(script_editor);
editor.commands.on("exec", function (e) {
editor.container.querySelector(".ace_content").style.transform = "none";
if (e.args && e.args.charCodeAt(0) == 10) {
e.preventDefault();
e.stopPropagation();
console.log("vdgscript-mode.js")
}
});
Now, the problem I am facing is that I want the ace instance width to adjust according to the number of character in it instead to have full width.
For that I am taking a canvas object and calculating the width of the text. But the problem with this code is, it is giving me the expected width on every key press but the css left property of the ace editor does not stay '0px' which makes the text in the ace editor instance to hide at the left side.
Code for setting the width is as follows:
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
ctx.font = "15px sans-serif";
var width = ctx.measureText(code).width;
editor.container.style.width = (width + 3) + "px";
Actual Result: .
Expected Result: .
The black in the below image the ace instance in which I have entered an array.
you can use a method similar to the one used by the tree rename editor in cloud9 https://github.com/c9/core/blob/master/plugins/node_modules/ace_tree/lib/ace_tree/edit.js
<style>
#inlineEditor {
display: inline-block;
vertical-align: middle;
}
</style>
<div>inline editor <span id=inlineEditor>txt</span></div>
<script src=https://ajaxorg.github.io/ace-builds/src-noconflict/ace.js>
</script>
<script>
var inlineEditor = ace.edit("inlineEditor", {
maxLines: 1,
showGutter: false,
showPrintMargin: false,
theme: "ace/theme/solarized_light",
})
// make cursor movement nicer for
inlineEditor.renderer.screenToTextCoordinates = function(x, y) {
var pos = this.pixelToScreenCoordinates(x, y);
return this.session.screenToDocumentPosition(
Math.min(this.session.getScreenLength() - 1, Math.max(pos.row, 0)),
Math.max(pos.column, 0)
);
};
inlineEditor.renderer.on("beforeRender", updateSize)
function updateSize(e, renderer) {
var text = renderer.session.getLine(0);
var chars = renderer.session.$getStringScreenWidth(text)[0];
var width = Math.max(chars, 2) * renderer.characterWidth // text size
+ 2 * renderer.$padding // padding
+ 2 // little extra for the cursor
+ 0 // add border width if needed
// update container size
renderer.container.style.width = width + "px";
// update computed size stored by the editor
renderer.onResize(false, 0, width, renderer.$size.height);
}
updateSize(null, inlineEditor.renderer)
</script>

In PaperJS allow the user to edit a TextItem like regular text input field?

I am using PaperJS to make a canvas app that generates balloons with text inside each balloon. However I would like to allow the user to edit the text inside each balloon to whatever they want it to say.
Is it possible to allow a user to edit a PaperJS TextItem just like a HTML text input field?
The short answer is no, unless you implement parallel functionality from scratch. The solution I have used is to let the user draw a rectangle then overlay the rectangle on the canvas with a textbox or textarea at the same location using absolute positioning. It requires an additional level of abstraction but can work quite well.
It's non-trivial, but here's a basic framework that shows a bit about how it works. I may get around to making it available online at some point but it will take a bit so I'm not sure when. I'm also extracting this on-the-fly from a larger system so if you spot any errors let me know.
var rect;
var tool = new paper.Tool();
// create a paper rectangle. it's just a visual indicator of where the
// text will go.
tool.onMouseDown = function(e) {
rect = new paper.Path.Rectangle(
from: e.downPoint,
to: e.downPoint,
strokeColor: 'red',
);
}
tool.onMouseDrag = function(3) {
if (rect) {
rect.remove();
}
rect = new paper.path.Rectangle({
from: e.downPoint,
to: e.point,
strokeColor: 'red'
});
}
tool.onMouseUp = function(e) {
var bounds = rect.bounds;
var textarea = $("<textarea class='dynamic-textarea' " +
"style='position:absolute; left:" + bounds.x +
"px; top:" + bounds.y + "px; width: " + bounds.width +
"px; height: " + bounds.height +
"px; resize;' placeholder='Enter text'></textarea>");
// make the paper rectangle invisible for now. may want to show on
// mouseover or when selected.
rect.visible = false;
// add the text area to the DOM then remember it in the path
$("#parent-div").append(textarea);
rect.data.textarea = textarea;
// you may want to give the textarea focus, assign tab indexes, etc.
};

Word wrapping in JointJS

I am working on JointJS. I have various elements with text in it. However the element's width increases with increase in text. I want to dynamically set the size of element such that there is a maximum height and width that the box can attain and expands accordingly by text wrapping. If the text os unable to fit in the maximum height and width element, then the fontsize may be reduced dynamically.
I hav tried using style="word-wrap: break-word;" in my div id. However there is no effect.
<div id="myholder" style="word-wrap: break-word;"> </div>
My holder is defined in the JS file as follows:
var paper = new joint.dia.Paper({
el: $('#myholder'),
width: 1200,
height: 700,
model: graph
});
What strategy may I follow?
It is also possible (if you don't want to bother with extra shapes) to use the
joint.util.breakText()
utility. It works like this:
var wraptext = joint.util.breakText('My text here', {
width: holderElement.size.width,
height: optionalHeight
});
After that you can add wraptext to your holderElement as into attrs when creating it. Like this:
var holder = joint.shapes.basic.Rect({
//position, size blablabla
attrs: {
text: {
text: wraptext,
//text styling
}
}
});
I have to say it's a bit strange that your holder is an entire paper, but you can probably use it the same way, just put the attrs when you define it.
To get word wrap working you can use joint.shapes.basic.TextBlock.
Now, to work with TextBlock you are going to set a top level map entry for "content" (instead of including "text" inside of "attrs" => "text" map entry)
graph.addCell (
new joint.shapes.basic.TextBlock({
position: { x:100, y:100 },
size: { width: 100, height: 100 },
attrs: { rect: { fill: 'green' }},
content: "<p style='color:white;'>asdf asdf asdf asdf this needs to word wrap</p>"
})
);
As you can see, the "content" entry can be raw html and will be rendered as such.
For this to work your browser needs to have SVG ForeignObject support, which most browsers these days have. To first check that this is the case you can run this in your console:
document.implementation.hasFeature("w3.org/TR/SVG11/feature#Extensibility","1.1")
I made a javascript function to wrap words based on the Line size and Max size of the shape you want the sentence wrap in.
If the sentence is very long then the function trim it and put 3 duts instead of the rest of the sentence.
Every Line size of the sentence the function put a '\n' (newline ASCII).
var sentenceWrapped = function (sentence, lineSize, maxSize) {
var descriptionTrim = "";
if (sentence.length + 3 > maxSize) {
descriptionTrim = sentence.substring(0, maxSize - 3);
descriptionTrim = descriptionTrim + '...';
}
else {
descriptionTrim = sentence
}
var splitSentence = descriptionTrim.match(new RegExp('.{1,' + lineSize + '}', 'g'));
var sentenceWrapped = "";
for (i = 0; i < splitSentence.length; i++)
{
sentenceWrapped = sentenceWrapped + splitSentence[i] + '\n';
}
return sentenceWrapped;
}
LineSize = the max size of characters for every line you want inside
your shape
MaxSize = the max size of characters you want inside your
shape
sentence = description you want to put in your shape
If you are interested in creating custom element you can create like this
joint.shapes.devs.Model = joint.shapes.basic.TextBlock.extend( {
markup: ['>',
joint.env.test('svgforeignobject') ? '' : '',
''].join(''),
defaults: joint.util.deepSupplement({
content: 'A content of the Activity'
}});

svg appending text element - gives me wrong width

i'm appending a text element to a svg via javascript. After appending i wanna set x and y coordinate, however, it returns me the wrong width of the text element when using it to calculate x.
Interesting:
In Chrome, when actualize the page via F5 or button it returns wrong width, when pressing enter in the adress bar, the width is right - strange!
Here is the small code:
var capt = document.createElementNS("http://www.w3.org/2000/svg", "text");
// Set any attributes as desired
capt.setAttribute("id","capt");
capt.setAttribute("font-family","Righteous");
capt.setAttribute("font-size","30px");
capt.setAttribute("fill", "rgb(19,128,183)");
var myText = document.createTextNode(this.options.captTxt);
capt.appendChild(myText);
this.elements.jSvgElem.append(capt);
capt.setAttribute("x", this.options.windowWidth-this.options.spacer-document.getElementById("capt").offsetWidth);
capt.setAttribute("y", this.options.captY+$('#capt').height());
OK, the problem seems to be that the browser doesn't calculate the correct width when using an other font. Not setting a font results in a correct width.
I solved the problem by setting the reference point ("alignment-point") to the upper right corner ot the text element by setting attributes:
capt.setAttribute("text-anchor", "end");
capt.setAttribute("alignment-baseline", "hanging");
This way i do not have to subtract the width and add the height of the element!
There is a bug:http://code.google.com/p/chromium/issues/detail?id=140472
it just pre init some functions that calculates text width so you should call this function before(i'm sure that there is several extra lines that can be deleted):
fixBug = function () {
var text = makeSVG("text", { x: 0, y: 0, fill: "#ffffff", stroke: '#ffffff'});
text.textContent = "";
var svg = $("svg")[0];
svg.appendChild(text);
var bbox = text.getBBox();
var Twidth = bbox.width;
var Theight = bbox.height;
svg.removeChild(text);
}
$("svg") - Jquery selector

javascript font size not working

why this don´t work:
function rp_insertTable() {
FM_log(3,"rp_insertTable() called");
var farmTable = dom.cn("table");
var ftableBody = dom.cn("tbody");
var i;
var maximize = GM_getValue("Maximize_" + suffixGlobal, 0);
farmTable.className = "FMtbg";
farmTable.id = "farmMachineTable";
farmTable.setAttribute('cellpadding', 2);
farmTable.setAttribute('cellspacing', 1);
farmTable.style.marginBotton = "12px";
farmTable.style.font = "bold 12px arial,serif";
the font does change in format, but the font size is not working, I can put 100px and it deosn´t change anything, why is that?
Why don't you try doing:
farmTable.style.fontSize = "12px"; ?
Accordingly XHTML.com your syntax is off:
Edit, more descriptive: You missed the font-style property in the list, you only had font-weight.
http://xhtml.com/en/css/reference/font/
Also, font is a shorthand, if you just want to set one indeed use the fontSize property.
It probably changes because your font is now no longer well-formed CSS and it sets it back to default.

Categories

Resources