I use Ext.daw.* to draw svg text. The root element has size 200x300.
If some element has larger size than size of root element then everything scales properly except the text: text appears to have larger size.
Check out this demo. How to make text scale properly?
Ext.create('Ext.draw.Component', {
renderTo: Ext.getBody(),
width: 200,
height: 300,
items: [{
type: 'path',
path: 'M0 0 V200',
'stroke-width': 3,
stroke: 'green'
},{
type: 'path',
// if I set path to 'M200 0 V700' then text goes crazy
path: 'M200 0 V200',
'stroke-width': 3,
stroke: 'green'
},{
type: 'text',
x: 0,
y: 50,
// text is located accurately between two lines
// but when one of the lines exceeds size of the canvas
// text's size changes
text: 'wwwwwwwwwwwwwwwwwww',
font: "18px monospace"
}]
});
Text is subject to hinting and kerning that happen differently at different point sizes and so does not normally scale uniformly. There is a hint available to indicate you would like this overridden:
text-rendering="geometricPrecision"
Changing your code to
},{
type: 'text',
x: 0,
y: 50,
text: 'wwwwwwwwwwwwwwwwwww',
'text-rendering': 'geometricPrecision',
font: "17px monospace"
}]
Should make it work more like you want it too, although it will display less clearly at small point sizes.
Related
I have an issue with OpenLayers (v 6.14.1 from npm) where the text on the text label is rather fuzzy.
See the attached image. Compare the text labels with the text in the dialog to the right.
I create the map with pixelRatio: 1, but that shouldn't affect this (?)
const map = new Map({
target: div,
view: new View({
center: fromLonLat ([startLocation.lon, startLocation.lat]),
zoom: startLocation.zoom,
constrainResolution: true,
}),
pixelRatio: 1, //Important, otherwise tiles (WMS) with strange size will be requested
});
I create the text label thus:
export default function (feature, resolution, options) {
return new Text ({
font: 'Normal 14px serif', // Normal 14px Arial
text: getText (feature, resolution, options),
fill: new Fill ({ color: 'black' }),
stroke: new Stroke ({ color: 'white', width: 2 }),
offsetX: -12,
offsetY: -8,
textAlign: 'right',
textBaseline: 'bottom',
placement: 'point',
});
}
I've already tried other fonts (e.g. a sans-serif).
I did as #Mike suggested - see their comment under the question - here's the result:
I think the labels are now a fair bit sharper. Picture doesn't show this too well tho'.
I have a problem in Rappid/jointJS
I have in stencil.js 4 shapes(2 basic.Circle and 2 basic.Rect) with names START(basic.Circle), END(basic.Circle), Activity(basic.Rect) and Workitem( basic.Rect) and I want in my main.js from all my graph to get the basic shape with name(I mean with attrs text ) "Activity".
This is the Stencil description for "Activity" :
new joint.shapes.basic.Rect({ size: { width: 5, height: 3 },
attrs: {
rect: {
rx: 2, ry: 2, width: 50, height: 30,
fill: '#0000FF'
},
text: { text: 'Activity', fill: '#ffffff', 'font-size': 10,
stroke: '#000000', 'stroke-width': 0 }
}
}),
How wil I get it? The only way I can search in my graph so far is if a cell has type basic.Circle(use of get('type') === 'basic.Circle')). but with type Circle I have two items:Activity and Workitem.
Is it so difficult to search for the graph element with name : "Activity"?
Thank you in advance
You can obtain all the elements (except for links) from following method
var allElement = graph.getElements()
Next if you want to obtain elements with 'Activity' do as follows
var activityElements = [];
allElement.forEach(elem => {
var textVal = elem.attributes.attrs.text.text;
if(textVal !== undefined && textVal === 'Activity') {
activityElements.push(elem);
}
});
Now the activityElements array will contain all the elements you require.
I solved my problem by taking element data in JSON format:
_.each(this.graph.getElements(), function(element) {
if(element.attributes.attrs["text"]["text"] == "Activity"){
//alert("YEAHHHHHH");
}
});
you could use the api on element as well, element.attr('text') returns the text object from the shape: { text: 'Activity', fill: '#ffffff', 'font-size': 10,
stroke: '#000000', 'stroke-width': 0 }
You could also set an "id" attribute to your shape and use graph.getCell('id_name_goes_here'); which would be much simpler if you didn't mind adding an id field to each shape.
I am developing a navigation application, which draws planned route on a map. Planned route consists of points connected with a line. Each point is labelled with distance and direction. When I initially draw the route on the map, I calculate text position in a way, where it doesn't interfere with the line - I use offsetX, offsetY and rotation style attributes. Unfortunately, when the map view is rotated, not of the mentioned attributes is changed - text is not rotated. Is there a way, how to rotate the text with the view, so it will remain on it's position relative to the point? I have already tried rotateWithView: true with both image and text parts.
My style is defined like:
return [new ol.style.Style({
image: new ol.style.Circle({
radius: 20,
fill: new ol.style.Fill({color: 'black'}),
stroke: new ol.style.Stroke({color: 'black', width: 1})
}),
text: new ol.style.Text({
textAlign: "center",
textBaseline: "middle",
font: 'normal 1.5rem Arial',
text: "This is my text",
fill: new ol.style.Fill({color: 'black'}),
stroke: new ol.style.Stroke({color: 'black', width: 1}),
offsetX: 10,
offsetY: 15,
rotation: 0.3
})
})];
Update feature rotation on map view property change event.
map.getView().on('propertychange', function(event) {
textStyle.setRotation(this.getRotation());
mySource.changed();
});
var textStyle = new ol.style.Text({
// ...
});
var layer = new ol.layer.Vector({
source: mySource,
style: new ol.style.Style({
text: textStyle,
// ...
})
});
I have to perform a very simple task: I want to display a piece of text inside a rectangle and the size of that rectangle should precisely be the width of the text.
In C++, it's fairly easy to do. Just define the QString and apply the QFontMetrics to get its width. Then define the rectangle graphics element to have that size. It's done within five minutes.
I have heard that QML is easier to use. Therefore, I was expecting to solve that problem in less than five minutes. I didn't, and I'm still stuck at it. Here's what I have tried:
Rectangle {
width: myText.contentWidth
height: myText.contentHeight
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
This doesn't work for some reason I don't understand. I have found a way to do it in a way that doesn't exactly suits my needs:
Rectangle {
width: 100
height: 100
MouseArea {
id: myMouseArea
anchors.fill: parent
onClicked: parent.width=myText.contentWidth
hoverEnabled: true
}
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
In this case, when I click the rectangle, it gets the correct width. Nevertheless, I am not interested in this solution, because I don't want to have to click to get a rectangle with the correct size.
I want that the rectangle's size gets the correct size whenever myText changes text. The use of onTextChanged in the Text item doesn't work either.
What am I missing here?
As far as I know, Font metrics were made available to developers in Qt 5.4, so they are relatively new, in QML. You got mainly FontMetrics and TextMetrics. A simple usage example:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
width: 280; height: 150
TextMetrics {
id: textMetrics
font.family: "Arial"
font.pixelSize: 50
text: "Hello World"
}
Rectangle {
width: textMetrics.width
height: textMetrics.height
color: "steelblue"
Text {
text: textMetrics.text
font: textMetrics.font
}
}
}
As noted by Phrogz in the comment below, the TextMetrics type does not support measuring wrapped text.
EDIT
For what is worth I've never ever had the need to use metrics in QML. For me content* or painted* properties served the purpose and, as of Qt 5.12, they seem to work fine. Aka the following two solutions generate the correct visual behaviour:
// solution 1
Rectangle {
width: myText.contentWidth
height: myText.contentHeight
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
// solution 2
Rectangle {
width: myText.paintedWidth
height: myText.paintedHeight
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
I would prefer those solutions to the usage of metrics for such a simple use case as the one proposed by the OP. For the opposite case - fitting a text in a specific size - a combination of properties can do the trick, e.g.:
Rectangle {
anchors.centerIn: parent
width: 200
height: 30
Text {
anchors.fill: parent
text: "Wonderful Text"
minimumPixelSize: 2
fontSizeMode: Text.Fit
font.pixelSize: 200
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Here the pixel size is simply over the top but the text still fits because a minimum size of 2 is set and the text has a clear fitting policy and clear boundaries, defined by the anchoring.
I'm sure Label component will do the job:
import QtQuick 2.1
import QtQuick.Controls 2.4
ApplicationWindow {
visible: true
Column {
Repeater {
model: [
{"color": "red", "radius": 1},
{"color": "green", "radius": 2},
{"color": "blue", "radius": 3}
]
Label {
padding: 0
text: modelData.color
font.family: "Helvetica"
font.pointSize: 50
background: Rectangle {
color: modelData.color
radius: modelData.radius
}
}
}
}
}
You don't need to use anchors.fill: parent for Text item because size of Text's parent depends on size of Text itself. It's cause binding loop.
This must works fine.
Rectangle {
width: myText.contentWidth
height: myText.contentHeight
Text {
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
Imagine I have Rect element and I wish to decorate it with a small (say 16x16) PNG image in the upper left. I am unable to determine how to achieve that task. I have studied the docs but have (so far) been unable to find a sample or reference on how to achieve that task. Does anyone have a recipe or a sample pointer that they would be willing to share to help me achieve my goal?
Better is to create your own custom shape that has a rectangle, image and text. This gives you much more flexibility and you don't have to have two elements in order to express one shape. Your shape decorated with a little image in the top left corner may look like:
joint.shapes.basic.DecoratedRect = joint.shapes.basic.Generic.extend({
markup: '<g class="rotatable"><g class="scalable"><rect/></g><image/><text/></g>',
defaults: joint.util.deepSupplement({
type: 'basic.DecoratedRect',
size: { width: 100, height: 60 },
attrs: {
'rect': { fill: '#FFFFFF', stroke: 'black', width: 100, height: 60 },
'text': { 'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black' },
'image': { 'ref-x': 2, 'ref-y': 2, ref: 'rect', width: 16, height: 16 }
}
}, joint.shapes.basic.Generic.prototype.defaults)
});
And you can use it like this in your diagrams:
var decoratedRect = new joint.shapes.basic.DecoratedRect({
position: { x: 150, y: 80 },
size: { width: 100, height: 60 },
attrs: {
text: { text: 'My Element' },
image: { 'xlink:href': 'http://placehold.it/16x16' }
}
});
graph.addCell(decoratedRect);
Note how is the shape specified, the important bits are the markup, type and the attrs object that references the SVG elements in the markup by normal CSS selectors (here just tag selectors but you can use classes if you want). For the image tag, we take advantage of the JointJS special attributes for relative positioning (ref, ref-x and ref-y). With these attributes, we position the image relatively to the top left corner of the rect element and we offset it by 2px from the top edge (ref-y) and 2px from the left edge (ref-x).
One note: It is important that the type attribute ('basic.DecoratedRect') matches the namespace the shape is defined in (joint.shapes.basic.DecoratedRect). This is because when JointJS re-constructs graphs from JSON, it looks at the type attribute and makes a simple lookup to the joint.shapes namespace to see if there is a shape defined for this type.
We can create an element type for an image using the following recipe:
var image = new joint.shapes.basic.Image({
position : {
x : 100,
y : 100
},
size : {
width : 16,
height : 16
},
attrs : {
image : {
"xlink:href" : "images/myImage.png",
width : 16,
height : 16
}
}
});
graph.addCell(image);
This will position the image at x=100,y=100. It is important to make the size width/height match the attrs/image width/height and be the width/height of the image itself.
Although this doesn't decorate a previous element, it can be positioned over a previous element achieving the desired effect.