I am using Raphael js to draw circled numbers. The problem is that each number has a different width/height so using one set of coordinates to center the text isn't working. The text displays differently between IE, FF, and safari. Is there a dynamic way to find the height/width of the number and center it accordingly?
Here is my test page:
http://jesserosenfield.com/fluid/test.html
and my code:
function drawcircle(div, text) {
var paper = Raphael(div, 26, 26); //<<
var circle = paper.circle(13, 13, 10.5);
circle.attr("stroke", "#f1f1f1");
circle.attr("stroke-width", 2);
var text = paper.text(12, 13, text); //<<
text.attr({'font-size': 15, 'font-family': 'FranklinGothicFSCondensed-1, FranklinGothicFSCondensed-2'});
text.attr("fill", "#f1f1f1");
}
window.onload = function () {
drawcircle("c1", "1");
drawcircle("c2", "2");
drawcircle("c3", "3");
};
Thanks very much!
(Answer rewritten): Raphael.js centers text nodes both horizontally and vertically by default.
"Centering" here means that the x, y argument of paper.text() method expects the center of the text's bounding box.
So, just specifying the same x, y value as the circle should produce the desired result:
var circle = paper.circle(13, 13, 10.5);
var text = paper.text(13, 13, "10");
(jsFiddle)
Relevant source code:
source line responsible for vertical alignment
source line responsible for horizontal alignment
Maybe this:
var paper = Raphael(div, 26, 26); //<<
var circle = paper.circle(13, 13, 10.5);
circle.attr("stroke", "#f1f1f1");
circle.attr("stroke-width", 2);
var text = paper.text(0, 0, text); //<<
text.attr({'font-size': 15, 'font-family': 'FranklinGothicFSCondensed-1, FranklinGothicFSCondensed-2'});
text.attr("fill", "#f1f1f1");
text.translate((35 - text.getBBox().width)/2, (45 - text.getBBox().height)/2);
Use this attribute: 'text-anchor':'start':
paper.text( x, y, text ).attr( {'text-anchor':'start'} );
The Rotating Text Exactly example (listed in the right-hand column of the page, or here in github), discusses putting text in a precise position, along with, as usual, extra steps required to make things work in IE.
It does find a bounding box for the text; I imagine it is straightforward to move the text by half the bounding box as Jan suggested.
Related
In SkiaSharp I can nicely fill the space between two curves by using SKPathFillType.EvenOdd. Below I show a simplified excerpt from the code.
My question is how can I give a certain pattern to this filled area between the curves ? Here I can only fill it with a color and give it a transparency. I'm interested in applying a pattern, such as hatch or dots.
Thank you for any support.
Greetings,
Sorin
SKPath path = new SKPath();
path.FillType = SKPathFillType.EvenOdd;
// start the first curve
path.MoveTo(....);
path.LineTo(....); // draw the curve and close it
....
path.AddCircle(....); // add a second curve as a circle
SKPaint paint = new SKPaint(new SKFont(SKTypeface.Default)) {
IsAntialias = true,
Style = SKPaintStyle.Fill,
Color = SKColors.Blue.WithAlpha((byte)(0xFF * (1 - 0.5))),
StrokeWidth = 1
};
canvas.DrawPath(path, paint);
I've managed to fix this with a trick.
First of all, I do all I wrote above, i.e.
canvas.DrawPath(path, paint)
.... will draw a filled area between the two curves, with a certain transparency.
On top of that (literally), I draw another pattern:
var hatch = new SKPath();
hatch.AddCircle(0, 0, 1);
var hatchPaint = new SKPaint {
PathEffect = SKPathEffect.Create2DPath(SKMatrix.MakeScale(7, 7), hatch),
Color = SKColors.RosyBrown,
Style = SKPaintStyle.Stroke,
StrokeWidth = 3
};
And again:
canvas.DrawPath(path, hatchPaint);
This draws a nice hatch pattern on top of the filled area between the curves.
Note: the size of the pattern is essential - here AddCircle(0, 0, 1), where the circle ray is 1 pixel. If you have a larger one, the hatch pattern will spill out the filled area, which is not what you want. To me this looks like a bug in SKIA.
Is there a way to move dynamical text multiline to the center if there is only 1 line left, because veritcal center cannot be adjusted in the properties panel.
Image 3 Lines text and 1 line text
There's no default option for that, but you can emulate it.
// Let's assume this is your TextField you need to v-align.
var TF:TextField;
// Lets also assume that TextField is still in its original place.
// Record its upper Y-coordinate and height.
var atop:Number = TF.y;
var aheight:Number = TF.height;
// These lines instruct the TextField to adjust its lower
// border so that it exactly fits the text inside.
TF.wordWrap = true;
TF.autoSize = TextFieldAutoSize.LEFT;
// Now, math time.
// The difference between original height and new (autosized) height.
var adiff:Number = aheight - TF.height;
// To vertically position the resized TextField into the center of its original
// place, you need to shift it down by half of the height difference.
// It actually works if new height is larger than original too:
// the "adiff" value will be negative and it still works out.
TF.y = atop + adiff / 2;
Can html5 canvas do the following? If yes, how...
Be places behind bottom layer place behind HTML text
Can you accurately find the coordinates specified HTML texts (perhaps identified with span ID) regardless the of browser zoom size, or line wrap
I am trying to create the following with HTML/CSS/JS:
(please excuse the green squiggly underlines)
The highlighted text could obviously be set with background-color:
The tricky part is connecting the highlighted text with arrows, I would think it might be able to be done with HTLM canvas, but I am open to any ideas.
Also nice little bonus would be the have highlighting/arrows appear on hover or maybe on off button.
PS a little background, the text is some simplified JCL (sort of scripting language for Mainframes) and the highlighted items are files. I am attempting to make it easier to trace the data flow through a job (script). This is pretty simple version but many jobs can be 100s of lines long with lot details that make it hard to trace the which steps related to each other. If there other ideas or tools to help trace the data flow in JCL let me know.
//COBLPGM EXEC PGM=COBLPGM
//INPUT DD DSN=&&SORT,DISP=(OLD,DELETE)
//NACHA DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORT2 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=&&SORT2,DISP=(,PASS)
//SYSIN DD DSN=NODE.OPER.PROCLIB(MEM)
//UNRELATE EXEC PGM=UNPGM
//INPUT DD DSN=NODE.OPER.UNRELATED.FILE
//REPORT DD DSN=&&REPORT
//TSTEMPT1 EXEC PGM=SPOPNCLO
//IN DD DSN=&&SORT2,DISP=(OLD,DELETE)
// IF TSTEMPT1.RC=0 THEN
//SORT3 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=&&SORT3,DISP=(,PASS),LRECL=141
//SYSIN DD DSN=NODE.OPER.CNTRLCDS(PARM)
// ENDIF
This is just a "conceptual" answer showing that you can track HTML to synchronize a canvas element.
The following code has the text itself in a <pre> tag in HTML. There is a canvas in the background set with fixed size. The canvas is updated on scrolling so the boxes are drawn relative to page (it should also be updated on resize, not shown).
As we can track the text you can see we would also be able to place any other graphics relative to it as well such as arrows and lines. I have not shown this here as I feel it would be too broad, but you should get the gist of it as it shows how to calculate the text line and char positions.
The basis is:
Get absolute position of the <pre> tag
Count number of lines (be careful to place text right after the tag and not on a new line, as well as placing end-tag at the same line as the last text-line)
Dividing absolute height on number of lines will give the line-height in pixels for each line
Use measureText() of context to measure the width of each line by setting context to use the same font and size as the <pre> tag
Use the rectangle from previous pre-tag to offset x and y for the line position.
Each char is calculate using the chars preceding the current, with measureText() (cell being this position and that of the next char).
The text is kept selectable with the canvas marking areas in the background.
Note that special chars in the text-line may throw off measureText (such as && in the example text). These chars must be encoded or replaced before measuring. Replacing is not a problem with a monospaced font such as in this case.
Demo
var pre = document.querySelector("pre"), // get pre ele,ent
rect = pre.getBoundingClientRect(), // get its absolute position
lines = pre.innerHTML.split("\n"), // split text lines
count = lines.length, // count lines
lineH = rect.height / count, // line height
canvas = document.querySelector("canvas"), // setup canvas
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth; // todo: update on resize
canvas.height = window.innerHeight;
ctx.font = "14px monospace"; // use same font in canvas as for pre
ctx.strokeStyle = "#d00";
ctx.translate(0.5, 0.5); // makes lines sharper for demo
window.onscroll = drawBoxes; // we need to track scrolling
drawBoxes();
function drawBoxes() { // render line boxes (y)
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < count; i++) {
var w = ctx.measureText(lines[i]).width;
if (w) ctx.strokeRect(rect.left, rect.top + i * lineH - window.scrollY, w, lineH - 1);
showChars(lines[i], rect.top + i * lineH - window.scrollY, lineH);
}
}
function showChars(line, y, h) { // render char lines (x)
ctx.beginPath();
for(var i = 0, ch, x, s = ""; ch = line[i]; i++) {
s += ch;
x = ctx.measureText(s).width;
ctx.moveTo(x, y); ctx.lineTo(x, y + h - 1);
}
ctx.globalAlpha = 0.2;
ctx.stroke();
ctx.globalAlpha = 1;
}
canvas {position:fixed;left:0;top:0;z-index:-1}
pre {font:14px monospace}
<canvas></canvas>
<pre>//COBLPGM EXEC PGM=COBLPGM
//INPUT DD DSN=SORT,DISP=(OLD,DELETE)
//NACHA DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORT2 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=SORT2,DISP=(,PASS)
//SYSIN DD DSN=NODE.OPER.PROCLIB(MEM)
//UNRELATE EXEC PGM=UNPGM
//INPUT DD DSN=NODE.OPER.UNRELATED.FILE
//REPORT DD DSN=REPORT
//TSTEMPT1 EXEC PGM=SPOPNCLO
//IN DD DSN=SORT2,DISP=(OLD,DELETE)
// IF TSTEMPT1.RC=0 THEN
//SORT3 EXEC PGM=SORT
//SORTIN DD DSN=NODE.OPER.COBLPGM.OUT(+1)
//SORTOUT DD DSN=SORT3,DISP=(,PASS),LRECL=141
//SYSIN DD DSN=NODE.OPER.CNTRLCDS(PARM)
// ENDIF</pre>
How to draw shadow only in right and bottom side of object in createjs. there is no shadow over the object or on top and left side.
the shadow contains only 4 parameters
1. color of shadow
2. x
3. y
4. blur effect
but it didn't tell anything about 4 different sides.
var box = createjs.Shape();
box.shadow = new createjs.shadow('#000',4,4,5);
the above code generates some blur portion over top and left part of object.
Your example is working for me, I've tested on fiddle.net using firefox and chrome.
http://jsfiddle.net/by1vf7oc/
var box = new createjs.Shape();
box.graphics.beginFill("red").drawRect(100, 100, 100, 100);
box.shadow = new createjs.Shadow('#000', 4, 4, 5);
Try to test on these browsers, using the last version of the createjs.
Try this:
var box = new createjs.Shape();
box.graphics.beginFill("red").drawRect(0, 0, 100, 100);
box.shadow = new createjs.Shadow("#000000", 10, 10, 0);
this is giving dark black color with outline of shadow box over object. i need blurred shadow on right and bottom with no effect on object.
Is it possible to write image on canvas and write text with background?
For example like this:
How text works in canvas
Unfortunately no, you can't produce text with background with the text methods - only fill or outline the text itself.
This is because the glyphs from the typeface (font) are converted to individual shapes or paths if you want, where the background of it would be the inner part of the glyph itself (the part you see when using fill). There is no layer for the black-box (the rectangle which the glyph fits within) the glyph is using besides from using its geometric position, so we need to provide a sort-of black-box and bearings ourselves.
On the old computer systems most fonts where binary font which where setting or clearing a pixels. Instead of just clearing the background one could opt to provide a background instead. This is not the case with vector based typefaces by default (a browser has direct access to the glyphs geometry and can therefor provide a background this way).
Creating custom background
In order to create a background you would need to draw it first using other means such as shapes or an image.
Examples:
ctx.fillRect(x, y, width, height);
or
ctx.drawImage(image, x, y [, width, height]);
then draw the text on top:
ctx.fillText('My text', x, y);
You can use measureText to find out the width of the text (in the future also the height: ascend + descend) and use that as a basis:
var width = ctx.measureText('My text').width; /// width in pixels
You can wrap all this in a function. The function here is basic but you can expand it with color and background parameters as well as padding etc.
/// expand with color, background etc.
function drawTextBG(ctx, txt, font, x, y) {
/// lets save current state as we make a lot of changes
ctx.save();
/// set font
ctx.font = font;
/// draw text from top - makes life easier at the moment
ctx.textBaseline = 'top';
/// color for background
ctx.fillStyle = '#f50';
/// get width of text
var width = ctx.measureText(txt).width;
/// draw background rect assuming height of font
ctx.fillRect(x, y, width, parseInt(font, 10));
/// text color
ctx.fillStyle = '#000';
/// draw text on top
ctx.fillText(txt, x, y);
/// restore original state
ctx.restore();
}
ONLINE DEMO HERE
Just note that this way of "measuring" height is not accurate. You can measure height of a font by using a temporary div/span element and get the calculated style from that when font and text is set for it.
I simpler solution is to call fillText twice. First a string of Unicode+2588 █ which is a black rectangle repeated the same length as the text using the background color. And then call fillText as normal with the foreground color.
This function gives you vertically and horizontally centered text with a background. It only works well with monospaced fonts (characters with the same width). The function counts the number of character in the string you which to print and multiplies them with 0.62 (assuming that the width of the font is slightly less than 0.62 times the height). The background is 1.5 times bigger than the font size. Change this to fit your needs.
function centeredText(string, fontSize, color) {
var i = string.length;
i = i*fontSize*0.62;
if (i > canvas.width) {
i = canvas.width;
}
ctx.fillStyle = "RGBA(255, 255, 255, 0.8)";
ctx.fillRect(canvas.width / 2 - i / 2,canvas.height / 2 - (fontSize * 1.5) / 2, i, (fontSize * 1.5) );
ctx.font = fontSize.toString() + "px monospace";
ctx.fillStyle = color;
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillText(string, canvas.width / 2, canvas.height / 2);
}
So calling the function would look something like this.
centeredText("Hello World", 30, "red");