Calculate how much text to render based on height and font styles - javascript

I am trying to render a novel and I want to add snap based navigation other then scroll.
This is a little tricky as the text should be rendered and fit the screen for each view. I have no idea how to calculate this.
I am using this in react-native and those need this in JavaScript.
Here is the fonts style I am using; this is based on user settings.
const htmlStyle = () => {
const item = {
lineHeight: nContext.state.novelReaderSettings.fontSize * 1.7,
fontSize: nContext.state.novelReaderSettings.fontSize,
fontFamily: (NovelReaderSettings.fontFamily as any)[nContext.state.novelReaderSettings.fontFamily],
backgroundColor: Background.getColor(nContext.state.novelReaderSettings.backGroundColor).backGroundColor,
color: Background.getColor(nContext.state.novelReaderSettings.backGroundColor).color,
zIndex: 9999999999,
paddingLeft: nContext.state.novelReaderSettings.marginLeft,
paddingRight: nContext.state.novelReaderSettings.marginRight,
paddingTop: nContext.state.viewPlayer || nContext.state.novelReaderSettings.navigation === "Swap" ? 0 : startPosition.withAds,
}
as any;
if (nContext.state.viewPlayer) {
item.minHeight = globalContext.windowDimension.height - 65;
item.textAlignVertical = "center";
}
return item;
}

Related

Cytoscape.js warning: "The style value of `label` is deprecated for `width`" when trying to have a node with same width of label

I'm using Cytoscape.js to render a dagre layout graph.
When styling the node, I use the property width: label as you can see in the following code:
const cy = cytoscape({
container: document.getElementById('cyGraph'),
maxZoom: 3,
minZoom: 0.3,
elements: dataForCytoscape,
style: [
{
selector: 'node',
style: {
'shape': 'round-rectangle',
'background-color': '#fff',
'label': 'data(name)',
'text-valign': 'center',
'color': '#333333',
'border-width': 1,
'border-color': '#2E1A61',
'width': 'label',
'font-size': '10px',
"padding-left": '5px',
"padding-right": '5px',
"padding-top": '5px',
"padding-bottom": '5px'
}
},
{
selector: 'edge',
style: {
...
}
}
],
layout: {
name: 'dagre'
}
});
Code is working and nodes get the same width of the inner labels, but I get the following warning in console:
The style value of `label` is deprecated for `width`
Question: Is there another way to let Cytoscape nodes to have a width that is the same of the inner label?
After some tests, I found a solution by myself: I decided to calculate the width starting from the data(name) field.
So, I changed 'width': 'label' with the following arrow function:
'width': (node:any) => { return node.data('name').length * 7 }
As you can see, I'm taking the length of the string of the label (that will contain name field) and I am multiplying it for a constant (I started from 10 but then I realized that 7 is the best in my case).
This way, I don't have any warning and the graph nodes fit the label (name) width.
Another solution is the one suggested by canbax in the comments to my question:
You can set a dynamic width using data properties. For example
'width': 'data(label_width)' Here every node should have a data
property called label_width
I remembered another approach. Here you can dynamically generate a canvas element and set font and then measure the text.
'width': (node) => {
const ctx = document.createElement('canvas').getContext("2d");
const fStyle = node.pstyle('font-style').strValue;
const size = node.pstyle('font-size').pfValue + 'px';
const family = node.pstyle('font-family').strValue;
const weight = node.pstyle('font-weight').strValue;
ctx.font = fStyle + ' ' + weight + ' ' + size + ' ' + family;
return ctx.measureText(node.data('name'));
}
This approach might be more costly but it might give you more exact measurements

pixijs text is cutted

I'm trying to draw text in pixijs app stage and the text is cut off a bit. See the screenshot below.
I've tried to put it inside container but I can't fix it.
const style = new PIXI.TextStyle({
fontFamily: 'Bangers',
fontSize: 256,
fontWeight: 'bold',
fill: ['#ffa512', '#ff9e00'], // gradient
stroke: '#fff',
strokeThickness: 5,
dropShadow: true,
dropShadowColor: '#000000',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 2,
});
const richText = new PIXI.Text('Nagitto', style);
richText.x = 50;
richText.y = 250;
app.stage.addChild(richText);
No exceptions.
I'm using a font from google fonts.
Use padding property inside style.
padding: 5,
I suggest you can use https://pixijs.io/pixi-text-style/# to dynamically create text with a preview.
The text is hardly cut from the code you wrote to create it. In my experience, this is only happening when there is a mask on the stage.
Please show the code for your container where you add the text in.

Fabric.Js - Making the text that has been added to the canvas editable

I seem to be having problems with making the text that is added to the canvas editable. I expect when you double click on the object for it to then change into an editable field but this doesn't seem to happen.
Below is the code that I am using and have read that you should be using for this to work:
service.addEditableType = function () {
service.canvas.add(new fabric.Text('Double tab here to type', {
fontFamily: 'Delicious_500',
fontSize: 30,
left: 100,
top: 100
}));
};
So this is what I'm using to add the text 'Double tab here to type' to the canvas. But if you then double click on the text it doesn't turn into an editable field.
Let me know your thoughts
Being a complete plonker...
I forgot the 'I' in 'Text'
The working code is as below:
service.addEditableType = function () {
service.canvas.add(new fabric.IText('Double tab here to type', {
fontFamily: 'Delicious_500',
fontSize: 30,
left: 100,
top: 100
}));
};

Surface order is messed when switching back with famo.us RenderController

A beginner question. I'm trying to put up a famo.us app. So far, I had nice results on a simple experiment.
Now that my app is growing, I want to allow moving between "screens" : landing screen -> info screen -> back to landing screen -> etc.
My "screens" are View() with surfaces, modifiers, etc. added to the View()
I use RenderController() to switch between screens, with its hide() and show() functions.
The problem is that when going back to a previously used screen, surfaces no longer show up !
Code :
var app_render_controller = new RenderController();
app_render_controller.show(landing_screen); // ok
app_render_controller.hide(landing_screen); // ok
app_render_controller.show(info_screen); // ok
app_render_controller.hide(info_screen); // ok
app_render_controller.show(landing_screen); // NOK -> I only see my background surface !
When examining the DOM, I'm able to see the outline of my surfaces at the place they should be, but they are hidden. It seems the background surface is now in front of the content surfaces (a ScrollView). If I hide the background, I see the Scrollview again.
I read that the overlap of elements was corresponding to the order they were added to the rendering tree. So since the tree under my View()-based "screen" hasn't changed, the Scrollview should still be drawn on top of the background like the 1st time ?
Is this expected ? Am I doing something wrong ? Am I missinq something ?
------- edit ------
my code (roughly) :
var main_context = Engine.createContext();
var root_render_controller = new RenderController();
main_context.add(root_render_controller);
var landing_screen = new View();
landing_screen.add(new Surface(...background texture...));
var scrollview = new Scrollview();
landing_screen.add(scrollview);
// (add stuff to the scrollview)
var info_screen = new View();
info_screen.add(new Surface(...background texture...));
info_screen.add(new Surface(...some message...));
root_render_controller.show(landing_screen);
// display is fine
root_render_controller.hide(landing_screen);
root_render_controller.show(info_screen);
// display is fine
root_render_controller.hide(info_screen);
root_render_controller.show(landing_screen); // again
// display is wrecked : the background surface is now hiding the scrollview !
When looking at the DOM, we can see the flip :
1st display of the landing screen : background then the scrollview and its 6 elements
2nd display of the landing screen : scrollview and its 6 elements then the background !
I read that the overlap of elements was corresponding to the order they were added to the rendering tree
From what I've seen, overlap of elements is set by the inverse of the order of creation (e.g., last one on top), not addition to the render tree.
When a Surface is created, it is registered with Entity:
https://github.com/Famous/core/blob/master/Surface.js#L60
function Surface(options) {
...
this.id = Entity.register(this);
...
}
When changes on a RenderNode are committed, they are applied based on the creation order (as Object.keys returns indices from an array back in numerical order):
https://github.com/Famous/core/blob/master/RenderNode.js#L106
function _applyCommit(spec, context, cacheStorage) {
var result = SpecParser.parse(spec, context);
var keys = Object.keys(result);
for (var i = 0; i < keys.length; i++) {
var id = keys[i];
var childNode = Entity.get(id);
....
}
You can test this out by creating two Surfaces and adding the one you created second to a Context before the first. It will still be on top:
define(function(require, exports, module) {
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var mainContext = Engine.createContext();
var surface1 = new Surface({
size: [200, 200],
content: "Red",
properties: {
lineHeight: "200px",
textAlign: "center",
backgroundColor: "#f00"
}
});
var surface2 = new Surface({
size: [200, 200],
content: "Green",
properties: {
lineHeight: "200px",
textAlign: "center",
backgroundColor: "#0f0"
}
});
// Doesn't matter what order you add these - surface2 will be on top
mainContext.add(surface2);
mainContext.add(surface1);
});
Hopefully that gives you a good place to start looking. It would help if you shared where your background is added to the Context to get a sense of why it is now in front.
It looks like you've found a bug in RenderController. The simple example below is exhibiting the same behavior you described. I've filed it against their repo at https://github.com/Famous/views/issues/42.
Note: If you don't hide the current view before showing the next, you get the same behavior. Interestingly, if you wait between the hide/show operations, you see different incorrect behavior.
define(function(require, exports, module) {
var Engine = require("famous/core/Engine");
var Surface = require("famous/core/Surface");
var View = require("famous/core/View");
var RenderController = require("famous/views/RenderController");
var Timer = require("famous/utilities/Timer");
var mainContext = Engine.createContext();
var renderController = new RenderController();
mainContext.add(renderController);
var view1 = new View();
var view2 = new View();
var surface1 = new Surface({
size: [200, 200],
content: "Red Background",
properties: {
lineHeight: "200px",
textAlign: "center",
backgroundColor: "#f00"
}
});
var surface2 = new Surface({
size: [200, 200],
content: "Green Foreground",
properties: {
lineHeight: "200px",
textAlign: "center",
backgroundColor: "#0f0"
}
});
var surface3 = new Surface({
size: [200, 200],
content: "Blue Background",
properties: {
lineHeight: "200px",
textAlign: "center",
backgroundColor: "#00f"
}
});
var surface4 = new Surface({
size: [200, 200],
content: "Black Foreground",
properties: {
lineHeight: "200px",
textAlign: "center",
backgroundColor: "#000",
color: "white"
}
});
view1.add(surface1);
view1.add(surface2);
view2.add(surface3);
view2.add(surface4);
// If performing hide/show on same tick (or not hiding before show),
// you get green-fg, black-fg, red-bg (wrong)
renderController.show(view1);
Timer.setTimeout(function() {
renderController.hide(view1); // <- commenting this out results in same behavior
renderController.show(view2);
Timer.setTimeout(function() {
renderController.hide(view2); // <- commenting this out results in same behavior
renderController.show(view1);
}, 1000);
}, 1000);
// If waiting between each hide/show
// you get green-fg, blue-bg (wrong), green-fg
// renderController.show(view1);
// Timer.setTimeout(function() {
// renderController.hide(view1);
// Timer.setTimeout(function() {
// renderController.show(view2);
// Timer.setTimeout(function() {
// renderController.hide(view2);
// Timer.setTimeout(function() {
// renderController.show(view1);
// }, 1000)
// }, 1000)
// }, 1000)
// }, 1000)
});
A View has no idea the order in which Surfaces should be layered in. When something is hidden with a RenderController it frees up the document fragment that the Surface is managing. When that View is brought back into the scene graph, the Surfaces get a document fragment to fill with its content from the pool of unused elements if any exist, if the pool is empty, it creates new ones.
Due to the way that browsers implement layering, newly created DOM nodes exist on top of old DOM nodes if they exist at the same transform in Z and have the same CSS zIndex. You should not be relying on the creation order if you need explicit layering. Try getting around this by either adding Modifiers to transform them in z-space or add explicit CSS zIndexing to denote what your layers should be.

Android window - view animation

Hello I'm new to titanium studio I'm reading the docs 2 days now and trying to make a simple slide animation or even any animation of any kind except opening a modal window. but I can't make it work.Here is what I was trying now but fails:
var slide_it_left = Titanium.UI.createAnimation();
slide_it_left.left = 500;
slide_it_left.duration = 500;
var mainWinOpts = {
backgroundColor:'#fff',
fullscreen:true,
navBarHidden: true
}
var animWinOpts = {
navBarHidden: true,
backgroundColor:'#000',
top:0,
left:0,
width: Ti.Platform.displayCaps.platformWidth,
height: Ti.Platform.displayCaps.platformHeight,
fullscreen:false,
animated:true
}
var mainWin = Ti.UI.createWindow(mainWinOpts);
var animWin = Ti.UI.createWindow(animWinOpts);
var labelOpts = {
text: 'click me!',
textAlign: Ti.UI.TEXT_ALIGNMENT_CENTER,
font: {
fontFamily: 'monospace',
fontSize: 24
},
borderWidth: 1,
color: '#2e2e2e',
borderColor: '#2e2e2e',
backgroundColor: '#dedede',
top: 50,
left: 50,
width: Ti.Platform.displayCaps.platformWidth,
height: Ti.Platform.displayCaps.platformHeight,
opacity: 1.00,
width: Ti.UI.SIZE,
height: Ti.UI.SIZE
};
var label = Ti.UI.createLabel(labelOpts);
label.addEventListener('click',function(){
animWin.open(slide_it_left);
})
mainWin.add(label);
mainWin.open();
This among other snippets I tried from their docs - forums isn't working.
Could someone please provide me some working samples or references for android window or view animation. Or point out what I'm doing wrong. Thank you in advance.
Please try changing your code to the following:
label.addEventListener('click',function(){
animWin.open();
animWin.animate(slide_it_left);
});
You cannot use the animation object as a parameter for open().
Have a look at the valid params here.
Moreover, the docs give an example for sliding in a window on Android, which is very likely what you are trying to achieve:
var win2 = Ti.UI.createWindow({fullscreen:false});
win2.open({
activityEnterAnimation: Ti.Android.R.anim.slide_in_left,
activityExitAnimation: Ti.Android.R.anim.slide_out_right
});
You can find the animations for the Android platform here.

Categories

Resources