Diagram created with Nativescript shows no values (=empty diagram) - nativescript

When creating a diagram in Nativescript using the RadCartesianChart framework, an empty diagram is generated only --> the diagram does not contain anything anything representing the input data.
In a Nativescript mobile app I want to display near-real-time data obtained from a wearable. Data acquisition and data handling are working fine.
However, I did not achieve to create a viewgraph representing the input data. I can modify its axes, but the graph always stays empty.
Do you have any ideas?
My data.component.html (relevant parts are extracted):
<StackLayout class="page page-content">
<RadCartesianChart tkExampleTitle tkToggleNavButton>
<LinearAxis tkCartesianHorizontalAxis></LinearAxis>
<LinearAxis tkCartesianVerticalAxis></LinearAxis>
<LineSeries tkCartesianSeries [items]="collectedData" categoryProperty="time" valueProperty="value">
</LineSeries>
</RadCartesianChart>
</StackLayout>
My data.component.ts (relevant parts extracted):
import { Injectable, Component, OnInit, OnDestroy } from "#angular/core";
import { PlotDatapoint } from "./PlotDatapoint";
#Component({
selector: "Data",
moduleId: module.id,
templateUrl: "./data.component.html"
})
#Injectable()
export class DataComponent implements OnInit, OnDestroy {
constructor() {}
ngOnInit(): void {
this.collectedData = new ObservableArray<PlotDatapoint (this.dataSource);
console.log (collectedData);
}
get dataSource() {
return [
{ time: 1, value: 10},
{ time: 2, value: 10},
{ time: 3, value: 1},
{ time: 4, value: 3}
];
}
}
Actual result --> I get an empty viewgraph.
Expected result -->
The viewgraph should contain lines or points representing the input data.
My assumption: The communication between the data.component.ts and the data.component.html is not working.
UPDATE
I prepared a playgroud link here:
https://play.nativescript.org/?template=play-ng&id=8zpRGL&v=4
In the meantime, I was quite successful in generating quite meaningful viewgraphs. Main problem was the excellent but quite complex Telerik-framework (especially the question "which axis type goes along with which '...Series'").
However, the goal is to display data received from our wearable according to their timestamps. Dropouts should be recognizable:
-- a "CatigoricalAxis" would not be useful.
Instead, the x-axis should be a "LinearAxis" or better "DateTimeContinuousAxis".
My current problem: I did not achieve getting a reasonable x-axis-labelling such as "HH:MM". Instead, the Unix-timestamp ALWAYS persists.

Related

How to set condition in ngstyle or ngclass

I have 2 different pages which is going to display the same data and both are sharing the same components. But both pages has different resolution one is the size with the alert box and one is similarly A4 size. how to set dynamic height and width for them. I tried using ngstyle not sure how to implement it correctly
in normal html
<tbody class="classname" style="height: 60px; width: fit-content;">
i added this and it works but both pages taking the same resolution.
so with ngstyle i tried this again same thing both pages has been set to same 60
[ngStyle]="{'height.px': 'Height' ? '60' : '200' }"
or it there any solution using ngclass?
So your problem breaks-down in two steps. One is to calculate the page height which is not an angular field and rather browser-specific issue. Although browsers do expose clientHeight or scrollHeight properties but there is a difference on how different browsers understand the actual height of the page.
So the best practice (as its also used by famous jQuery library) is to get the different document-level height properties and get the maximum value out of those.
You'll have to inject the DOCUMENT constant to access the DOM document into your component. Please find the below example angular component code.
import { Component, OnInit, Inject } from '#angular/core';
import { DOCUMENT } from '#angular/common';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
public height = 0;
constructor(#Inject(DOCUMENT) private document: any){
}
ngOnInit() {
this.height = Math.max( this.document.body.scrollHeight, this.document.body.offsetHeight,
this.document.documentElement.clientHeight, this.document.documentElement.scrollHeight, this.document.documentElement.offsetHeight );
}
}
Now simply on the html side you could test the height property of component and apply the style as desired. Somethink like this..
<div [ngStyle]="{'height': height>=200 ? '200px' : '60px' }"></div>
Thanks.

NativeScript nativescript-drop-down doesn't read list items correctly

NativeScript newbie here. Trying to add a dropdown / combobox style widget. Looks like nativescript-drop-down should be close. The Demo runs fine but the plugin has two problems in our app. First, the selection items show in the picker as [object Object],[object Object], ... instead of: Item 1,Item 2, Item 3, ...
Second, the contents of the scroll wheel shows just one character per "row", so above [object Object] actually shows on spinner as:
[
o
j
e
c
t
O
b
j
e
c
t
]
,
[
o
...
Related, if we store just strings instead of ValueItems into the ValueList, we get similar results, just one character (instead of one item) on each spinner "row."
Key code snippets:
From page layout:
<DropDown row="0" col="2" class="time-button-selected" hint="Time?" items="{{ hourItems }}"></DropDown>
From component typescript:
<deletia...>
#Component({
selector: "Order",
templateUrl: "./order.component.html",
styleUrls: ['./order.component.scss']
})
export class OrderComponent implements OnInit {
<deletia...>
hourItems = new ValueList<string>();
constructor(private platformHelper: PlatformHelperService,
private appStateService: AppStateService) {
<deletia...>
for (let loop = 0; loop < 20; loop++) {
let vi:ValueItem<string> = { value: `I${loop}`, display: `Item ${loop}`};
this.hourItems.push(vi);
}
}
<deletia...>
}
Any recommendations would be greatly appreciated!

How to get the initial device orientation in NativeScript with Angular 2

I am getting started with NativeScript + Angular 2 and I'd like to implement a component that activates different routes depending on the device orientation. After much search, I was able to get this working but I haven't yet figured out how to get the initial device orientation, which sounds like it should be easier.
Here's my AppComponent code. Look at ngAfterViewInit:
import {Component, OnInit, OnDestroy, AfterViewInit} from "#angular/core";
import {Router} from "#angular/router";
import _application = require('application');
#Component({
selector: "my-app",
templateUrl: "app.component.html",
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
constructor(private router: Router) {}
ngOnInit() {
_application.on(_application.orientationChangedEvent, this.setOrientation.bind(this));
}
ngAfterViewInit() {
// How do I get the initial orientation here instead of hardcoding to 'portrait'?
this.setOrientation({newValue: 'portrait'})
}
ngOnDestroy() {
_application.off(_application.orientationChangedEvent, this.setOrientation);
}
setOrientation(args) {
if (args.newValue === 'landscape') {
this.router.navigate(['/landscape']);
} else {
this.router.navigate(['/portrait']);
}
}
}
private activity:any = application.android.foregroundActivity;
this.activity.getResources().getConfiguration().orientation;
You could use this plugin. In order to get access to the up-to-date version, you will need to pay a monthly subscription to the developers that maintain ProPlugins.
You can installed the last free version of it using:
npm i nativescript-orientation
This comes with no guaranties that it will work, especially in {N} 6+.
Once installed, you can get the current screen orientation like this:
const orientation = require("nativescript-orientation");
console.log(orientation.getOrientation());
While there is no helper to determine the initial orientation that I know of, you can still get the current screen dimensions. You may import the screen module from the core library.
import { screen } from 'tns-core-modules/platform';
Then on application initialization determine the orientation by determining if the screen height is larger than the width:
this.orientation = screen.mainScreen.heightPixels > screen.mainScreen.widthPixels ? 'portrait' : 'landscape';
Edit: This may be inconsistent and is not fully tested (meaning the screen height might not always be the height of the screen in portrait mode). If this is the case, on page load, you may use the same strategy to measure the main Page element and compare the height and width of the view to determine orientation.

Angular2 access another components methods without loading its template with #ViewChild

I am trying to access a child components method with #ViewChild, and it works, but I am forced to load its template as well, which I don't want to do, because that also forces that child components OnInit, AfterViewInit and other system functions to run.
I want them to run only when I call this child component in a different scenario, but I want to access this childs custom methods on demand in AppComponent.
So how do I do it?
This is a plunker which depicts the problem: http://plnkr.co/edit/FT6GTJ8mmUnyFxJAPbGV
You can see that dashboards test() function is called, thats what I want, however, its ngOnInit function is also initialized, which I don't want.
template: <h1>AppComponent</h1><my-dashboard></my-dashboard>
I though it was pretty obvious to remove <my-dashboard></my-dashboard> from AppComponent template, to not load dashboards template, but then I get error that dashboard itself is not defined (you can see the error if u remove <my-dashboard></my-dashboard> and run the plunker again) even though I have included it through import statement.
What am I missing?
EDIT-----------------------------------------------------------------------------------------------------------------
So, in the end, you have to use a service to store reusable data/functions to work without a hick up.
Not entirely sure why you would want this, but you can try and use the Component as a provider. Although i fail to see how this can fall under the, "if it looks stupid, but it works, it ain't stupid", rule.
import { Component, OnInit, AfterViewInit, ViewChild } from '#angular/core';
import { DashboardComponent } from './dashboard.component';
#Component({
selector: 'my-app',
template: `
<h1>AppComponent</h1>
`,
providers: [DashboardComponent]
})
export class AppComponent implements OnInit {
constructor(public dashboardComponent: DashboardComponent){}
ngOnInit() {
this.dashboardComponent.test();
}
}
plnkr
Another way I assume, could be to simply initiate a new class instance, this would result in something like this:
import { Component, OnInit, AfterViewInit, ViewChild } from '#angular/core';
import { DashboardComponent } from './dashboard.component';
#Component({
selector: 'my-app',
template: `
<h1>AppComponent</h1>
`
})
export class AppComponent implements OnInit {
public dashboardComponent: DashboardComponent = new DashboardComponent();
constructor(){}
ngOnInit() {
this.dashboardComponent.test();
}
}
plnkr
But again I fail to see why you would want to do something like this. Apparently there is logic in your component which shouldn't be there

Animated page transitions in react

The past couple of weeks I've been working on an app using React. So far everything is working fine, but now I want to add some transitions to it. These transitions are a bit more complex than any examples I managed to find.
I've got 2 pages, an overview and a detail page which I'd like to transition between.
I'm using react-router to manage my routes:
<Route path='/' component={CoreLayout}>
<Route path=':pageSlug' component={Overview} />
<Route path=':pageSlug/:detailSlug' component={DetailView} />
</Route>
Overview looks like this:
Detailview looks like this:
The idea of the transition is that you click on one of the elements of the Overview. This element which has been clicked moves towards the position it should have on the detailView. The transition should be initiated by a route change (I think) and should also be able to happen in reverse.
I've already tried using ReactTransitionGroup on the Layout, which has a render method which looks like this:
render () {
return (
<div className='layout'>
<ReactTransitionGroup>
React.cloneElement(this.props.children, { key: this.props.location.pathname })
</ReactTransitionGroup>
</div>
)
}
This will give the child component the ability to receive the special lifecycle hooks. But I'd like to access the child components somehow during these hooks and still keep doing things the React way.
Could someone point me in the right direction for the next step to take? Or maybe point me to an example which I may have missed somewhere? In previous projects I used Ember together with liquid fire to get these kinds of transitions, is there maybe something like this for React?
I'm using react/react-redux/react-router/react-router-redux.
Edit: Added a working example
https://lab.award.is/react-shared-element-transition-example/
(Some issues in Safari for macOS for me)
The idea is to have the elements to be animated wrapped in a container that stores its positions when mounted. I created a simple React Component called SharedElement that does exactly this.
So step by step for your example (Overview view and Detailview):
The Overview view gets mounted. Each item (the squares) inside the Overview is wrapped in the SharedElement with a unique ID (for example item-0, item-1 etc). The SharedElement component stores the position for each item in a static Store variable (by the ID you gave them).
You navigate to the Detailview. The Detailview is wrapped into another SharedElement that has the same ID as the item you clicked on, so for example item-4.
Now this time, the SharedElement sees that an item with the same ID is already registered in its store. It will clone the new element, apply the old elements position to it (the one from the Detailview) and animates to the new position (I did it using GSAP). When the animation has completed, it overwrites the new position for the item in the store.
Using this technique, it's actually independent from React Router (no special lifecycle methods but componentDidMount) and it will even work when landing on the Overview page first and navigating to the Overview page.
I will share my implementation with you, but be aware that it has some known bugs. E.g. you have to deal with z-indeces and overflows yourself; and it doesn't handle unregistering element positions from the store yet. I'm pretty sure if someone can spend some time on this, you can make a great little plugin out of it.
The implementation:
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import Overview from './Overview'
import DetailView from './DetailView'
import "./index.css";
import { Router, Route, IndexRoute, hashHistory } from 'react-router'
const routes = (
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Overview} />
<Route path="detail/:id" component={DetailView} />
</Route>
</Router>
)
ReactDOM.render(
routes,
document.getElementById('root')
);
App.js
import React, {Component} from "react"
import "./App.css"
export default class App extends Component {
render() {
return (
<div className="App">
{this.props.children}
</div>
)
}
}
Overview.js - Note the ID on the SharedElement
import React, { Component } from 'react'
import './Overview.css'
import items from './items' // Simple array containing objects like {title: '...'}
import { hashHistory } from 'react-router'
import SharedElement from './SharedElement'
export default class Overview extends Component {
showDetail = (e, id) => {
e.preventDefault()
hashHistory.push(`/detail/${id}`)
}
render() {
return (
<div className="Overview">
{items.map((item, index) => {
return (
<div className="ItemOuter" key={`outer-${index}`}>
<SharedElement id={`item-${index}`}>
<a
className="Item"
key={`overview-item`}
onClick={e => this.showDetail(e, index + 1)}
>
<div className="Item-image">
<img src={require(`./img/${index + 1}.jpg`)} alt=""/>
</div>
{item.title}
</a>
</SharedElement>
</div>
)
})}
</div>
)
}
}
DetailView.js - Note the ID on the SharedElement
import React, { Component } from 'react'
import './DetailItem.css'
import items from './items'
import { hashHistory } from 'react-router'
import SharedElement from './SharedElement'
export default class DetailView extends Component {
getItem = () => {
return items[this.props.params.id - 1]
}
showHome = e => {
e.preventDefault()
hashHistory.push(`/`)
}
render() {
const item = this.getItem()
return (
<div className="DetailItemOuter">
<SharedElement id={`item-${this.props.params.id - 1}`}>
<div className="DetailItem" onClick={this.showHome}>
<div className="DetailItem-image">
<img src={require(`./img/${this.props.params.id}.jpg`)} alt=""/>
</div>
Full title: {item.title}
</div>
</SharedElement>
</div>
)
}
}
SharedElement.js
import React, { Component, PropTypes, cloneElement } from 'react'
import { findDOMNode } from 'react-dom'
import TweenMax, { Power3 } from 'gsap'
export default class SharedElement extends Component {
static Store = {}
element = null
static props = {
id: PropTypes.string.isRequired,
children: PropTypes.element.isRequired,
duration: PropTypes.number,
delay: PropTypes.number,
keepPosition: PropTypes.bool,
}
static defaultProps = {
duration: 0.4,
delay: 0,
keepPosition: false,
}
storeNewPosition(rect) {
SharedElement.Store[this.props.id] = rect
}
componentDidMount() {
// Figure out the position of the new element
const node = findDOMNode(this.element)
const rect = node.getBoundingClientRect()
const newPosition = {
width: rect.width,
height: rect.height,
}
if ( ! this.props.keepPosition) {
newPosition.top = rect.top
newPosition.left = rect.left
}
if (SharedElement.Store.hasOwnProperty(this.props.id)) {
// Element was already mounted, animate
const oldPosition = SharedElement.Store[this.props.id]
TweenMax.fromTo(node, this.props.duration, oldPosition, {
...newPosition,
ease: Power3.easeInOut,
delay: this.props.delay,
onComplete: () => this.storeNewPosition(newPosition)
})
}
else {
setTimeout(() => { // Fix for 'rect' having wrong dimensions
this.storeNewPosition(newPosition)
}, 50)
}
}
render() {
return cloneElement(this.props.children, {
...this.props.children.props,
ref: element => this.element = element,
style: {...this.props.children.props.style || {}, position: 'absolute'},
})
}
}
I actually had a similar problem, where I had a search bar and wanted it to move and wrap to a different size and place on a specific route (like a general search in the navbar and a dedicated search page). For that reason, I created a component very similar to SharedElement above.
The component expects as props, a singularKey and a singularPriority and than you render the component in serval places, but the component will only render the highest priority and animate to it.
The component is on npm as react-singular-compoment
And here is the GitHub page for the docs.

Resources