I am trying to create a dendrogram using a D3 JavaScript component I found on Github. Here's the link: https://www.npmjs.com/package/react-d3-tree
I am fairly new to this whole thing, so I am having difficulty figuring out how to use this to create a web application that I can actually run, like what's shown in the demo (https://bkrem.github.io/react-d3-tree-demo/)
Ideally I would like to import my own .json data, but once I have it running I'm sure I can figure that out fairly easily.
Any advice would be greatly appreciated, thank you.
Attempted running the application by finding the directory in Windows command prompt and using the command npm start.
I think that I don't have the proper scripts for executing a program that will display on my localhost server.
I tried running the code from the Example given on www.npmjs.com/package/react-d3-tree on Codesandbox.io. It worked Perfectly as expected. I am sure it will work on localhost as well.
Here is the Code
import React from 'react';
import Tree from 'react-d3-tree';
//Static JSON you can always use json from a different file
const myTreeData = [
{
name: 'Top Level',
attributes: {
keyA: 'val A',
keyB: 'val B',
keyC: 'val C',
},
children: [
{
name: 'Level 2: A',
attributes: {
keyA: 'val A',
keyB: 'val B',
keyC: 'val C',
},
},
{
name: 'Level 2: B',
},
],
},
];
export default class MyTree extends React.Component {
render() {
return (
//Wrapper
<div id="treeWrapper" style={{width: '50em', height: '20em'}}>
//Calling the actual library with json as a prop
<Tree data={myTreeData} />
</div>
);
}
}
Related
I have an app which pretty much looks like this:
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
tags: [
{ id: 1, name: "Apples" },
{ id: 2, name: "Pears" }
],
suggestions: [
{ id: 3, name: "Bananas" },
{ id: 4, name: "Mangos" },
{ id: 5, name: "Lemons" },
{ id: 6, name: "Apricots" }
]
}
}
handleDelete (i) {
const tags = this.state.tags.slice(0)
tags.splice(i, 1)
this.setState({ tags })
}
handleAddition (tag) {
const tags = [].concat(this.state.tags, tag)
this.setState({ tags })
}
render () {
return (
<ReactTags
tags={this.state.tags}
suggestions={this.state.suggestions}
handleDelete={this.handleDelete.bind(this)}
handleAddition={this.handleAddition.bind(this)} />
)
}
}
It's based on this npm module.
I am not sure if I am missing something, but when I type in a tag, whilst I do see the suggestions pop up, I would also like to be able to press the TAB key and autocomplete the rest of the tag, whenever there is only one option left. Similar to the stackoverflow tag functionality.
My main question is this: How could I use a package like this, installed via npm, and extend its functionality? What would I do to make this my own, change things around etc.? I do not want to fiddle around in my npm modules folder!
You can fork the plugin and install it in your project as below
npm i {github_project_link}
If you want to contribute to the community. You can raise PR to the origin repo.
I'm trying to loop through the SOURCE array with the map method, but I keep getting this error:
Unknown named module: '../images/one.jpeg'
Anyone know why this is happening? The file path in the require is definitely correct.
var SECTIONS = [
{
title: 'One',
fileName: 'one.jpeg',
},
{
title: 'Two',
fileName: 'two.jpeg',
},
{
title: 'Three',
fileName: 'three.jpeg',
},
{
title: 'Four',
fileName: 'four.jpeg',
},
];
{SECTIONS.map((section, i) => (
<CategoryCard
key={i}
source={require(`../images/${section.fileName}`)}
title={section.title}
/>
))}
I don't think this is possible because react native needs to know what to bundle ahead of time (AFAIK). However, you can require all the files in your array:
var SECTIONS = [
{
title: 'One',
file: require('../images/one.jpeg'),
},
{
title: 'Two',
file: require('../images/two.jpeg'),
},
{
title: 'Three',
file: require('../images/three.jpeg'),
},
{
title: 'Four',
file: require('../images/four.jpeg'),
},
];
{SECTIONS.map((section, i) => (
<CategoryCard
key={i}
source={section.file}
title={section.title}
/>
))}
You can't use dynamic links. The best hack that i found to solve this is this:
var SECTIONS = {
One: {
title: 'One',
file: require('../images/one.jpeg'),
},
Two: {
title: 'Two',
file: require('../images/two.jpeg'),
},
Three: {
title: 'Three',
file: require('../images/three.jpeg'),
},
Four: {
title: 'Four',
file: require('../images/four.jpeg'),
},
};
{SECTIONS.map((section, i) => (
<CategoryCard
key={i}
source={section.file}
title={section.title}
/>
))}
That way, you can just use the files and if you have some kind of dynamic image selection, you can just use something like this
<Image source={SECTIONS[image.type]} />
try opening the file in separate browser using direct URL something like
http://<><>/imgages/one.jpg
You can also do something like this as well:
One working example for displaying dynamic images using react :
Example Click Here
Got a working solution, though not recommended for large images, works perfectly for (a lot of)small images.
Steps:
Convert the icon(s) to base64 string(s).
Create a JSON file with filename as the keys and the base64 strings as values.
(You can also store them to a local database)
e.g.
ImageData.json
{
"icon1": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQ.......==",
"icon2": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQ.......=="
}
3.Import the json file to the place where you require the images dynamically.
e.g.
const imageData = require("./images/ImageData.json")
4: Get/generate the key/filename at runtime. and get the image source.
e.g.
const imageSrc = imageData[keyname]
5: Generate a image dynamically at runtime.
e.g.
<Image style={{ width: 70, height: 70, resizeMode: Image.resizeMode.contain }} source={ uri: imageSrc } />
Done..
Extra..
Written a helper python script to automate the json file creation.
import base64
import os
directory = os.fsencode('.')
with open('ImagesData.json', 'wb') as jsonFile:
jsonFile.write(bytes('{', 'utf-8'))
written = False
for file in os.listdir(directory):
filename = os.fsdecode(file)
if filename.endswith('.png'):
with open(filename, "rb") as image_file:
if written:
jsonFile.write(bytes(',\n','utf-8'))
encoded_string = base64.b64encode(image_file.read())
jsonFile.write(bytes(('"' +filename+ '":'), 'utf-8'))
jsonFile.write(bytes('"data:image/png;base64,', 'utf-8') + encoded_string + bytes('"', 'utf-8'))
written = True
jsonFile.write(bytes('}', 'utf-8'))
Copy the script to the image folder and run the script (requires python 3.6).
A json file will the created with image name as key and base64 string as values.
Copy the file to project and use (You can delete the images after that).
Use the json file as mentioned above.
I had the same problem but my situation was a little different. I had an array of different objects that needed dynamic images. I was already mapping the array, but I needed to match the images to that array based off of name. It was a little hacky, but this is how I went about it.
First, in my parent component I created a function to render a component for my array of objects. I passed the objects data into a prop called "object".
In my case I knew what my data was and I needed to match the corresponding image to the object that was being pulled off of an external api that I was grabbing my data from.
renderObjects() {
return this.state.objects.map(object => (
<ObjectListDetail
key={object.id}
next
props={this.props}
object={object}
/>
));
}
In my ObjectListDetail component, I created a variable called icons, which was another array of objects. This time, I created a name property that would match the object being passed to the component from the parent and then had a second key called source in which I provided the path to the image. It went something like this.
var icons = [
{ name: "BTC", source: Images.btc },
{ name: "ETH", source: Images.eth },
{ name: "ETC", source: Images.etc },
{ name: "ZRX", source: Images.zrx },
{ name: "USDC", source: Images.usdc },
{ name: "LTC", source: Images.ltc },
{ name: "BCH", source: Images.bch },
{ name: "USD", source: Images.usd }
];
NOTE *** I had already required all of my images into a separate file for my entire app and imported them at the top.
I then created a variable called imgSrc and filtered the result to match the name of the object i was passing to the child component.
var imgSrc = icons.filter(
icon => icon.name === props.wallet.name
)
I then created an Image component and in the source requirement I called the result of the filter and pointed it to the source.
<Image source={imgSrc[0].source} />
That is how I achieved dynamic image rendering within my application.
Its probably not the best way to do things, and I am still kinda new at this, but I would love any criticism
Ember novice here. I have been following along with the tutorial on the Ember website here.
I have been R&D'ing the example to the word and everything works...until I try implementing Mirage. The data just never shows up on the index.hbs page.
Here's my model hook:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return this.store.findAll('rental');
},
});
And my model: rental.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
owner: DS.attr('string'),
city: DS.attr('string'),
type: DS.attr('string'),
image: DS.attr('string'),
bedrooms: DS.attr('number')
});
My index.hbs:
<h1> Welcome to Super Rentals </h1>
We hope you find exactly what you're looking for in a place to stay.
{{#each model as |rentalUnit|}}
{{rental-listing rental=rentalUnit}}
{{/each}}
{{#link-to "about"}}About{{/link-to}}
{{#link-to "contact"}}Click here to contact us.{{/link-to}}
and lastly my app/mirage/config.js:
export default function() {
this.get('/rentals', function() {
return {
data: [{
type: 'rentals',
id: 1,
attributes: {
title: 'Grand Old Mansion',
owner: 'Veruca Salt',
city: 'San Francisco',
type: 'Estate',
bedrooms: 15,
image: 'https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg'
}
}, {
type: 'rentals',
id: 2,
attributes: {
title: 'Urban Living',
owner: 'Mike Teavee',
city: 'Seattle',
type: 'Condo',
bedrooms: 1,
image: 'https://upload.wikimedia.org/wikipedia/commons/0/0e/Alfonso_13_Highrise_Tegucigalpa.jpg'
}
}, {
type: 'rentals',
id: 3,
attributes: {
title: 'Downtown Charm',
owner: 'Violet Beauregarde',
city: 'Portland',
type: 'Apartment',
bedrooms: 3,
image: 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Building_-_Portland_Oregon.jpg'
}
}]
};
});
}
I get two messages in Chrome developer console:
Mirage: Your Ember app tried to GET 'http://localhost:4200/assets/vendor.js', but there was no route defined to handle this request. Define a route that matches this path in your mirage/config.js file. Did you forget to add your namespace?
and this warning:
WARNING: Encountered "data" in payload, but no model was found for model name "datum" (resolved model name using super-rentals#serializer:-rest:.modelNameFromPayloadKey("data"))
However it looks like the info was sucessfully retrieved as I see a:
Successful request: GET /rentals
Object {data: Array[3]}
which reflects the proper data. It just is breaking somewhere between that and the index.hbs and I am to novice to figure it out. I'm sure it's just a small misunderstanding on my part. Any help would be appreciated!
You have the wrong version of Ember Data installed. Also make sure you restart the server any time you install a dependency.
The error message that you are getting means that your application is using RESTAdapter (the default adapter for Ember Data 1.x). That is why it looks at the top-level data key and tries to singularize and find the related model.
You can update by following the instructions on the latest Ember CLI release. Or, you can npm install -g ember-cli#beta and start from scratch.
I'm having a strange issue that I can't pin down with React (I'm using CoffeeScript as well, but I highly doubt this is a factor). Basically, I'm following along with a tutorial in which a message feed is built using a Feed component (the parent), FeedList component (child), and a FeedItem (grandchild)...sorry if my terminology is incorrect. The relevant code is:
Feed.cjsx
getInitialState: ->
FEED_ITEMS = [
{ key: 1, title: 'Realtime data!', description: 'Firebase is cool', voteCount: 49 }
{ key: 2, title: 'JavaScript is fun', description: 'Lexical scoping FTW', voteCount: 34 }
{ key: 3, title: 'Coffee makes you awake', description: 'Drink responsibly', voteCount: 15 }
]
{
items: FEED_ITEMS
formDisplayed: false
}
...
render: ->
...
<FeedList items={#state.items} onVote={#onVote} />
FeedList.cjsx
render: ->
feedItems = #props.items.map ((item) ->
<FeedItem key={item.key} ... />
).bind(#)
<ul className='list-group container'>
{feedItems}
</ul>
FeedItem.cjsx
render: ->
<li key={#props.key} className='list-group-item'>
...
</li>
If I console.log "#props.key" in the render method for FeedItem, I get undefined. But if I log "item.key" from inside the map function of FeedList's render method, I get 1, 2, 3, as I should. So it seems to me that, for whatever reason, React doesn't want to pass the "key" prop to the FeedItem. Any thoughts?
For anyone else stumbling across this, react only has a few reserved props but they are worth noting. key, ref, __self and __source.
var RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true
};
^^ Taken from the react source.
Also worth noting __self={this} is really useful if you're receiving invariant violation errors and would like to be able to debug them down to a component level.
Since react treats key as a special attribute (http://facebook.github.io/react/docs/special-non-dom-attributes.html), it cannot be accessed via the props. The react documentation also warns against setting keys within plain html tags (http://facebook.github.io/react/docs/multiple-components.html#dynamic-children), and suggests wrapping multiple components in a react component.
If you rename key to something non-reserved, it should work:
Feed.cjsx:
FEED_ITEMS = [
{ itemId: 1, title: 'Realtime data!', description: 'Firebase is cool', voteCount: 49 }
{ itemId: 2, title: 'JavaScript is fun', description: 'Lexical scoping FTW', voteCount: 34 }
{ itemId: 3, title: 'Coffee makes you awake', description: 'Drink responsibly', voteCount: 15 }
]
then you can access the itemId via #props.itemId in the child component (FeedList).
FeedList:
feedItems = #props.items.map ((item) ->
<FeedItem key={item.itemId} ... />
).bind(#)
Note that the keys for each component need to be unique for each component, or node in the DOM, which is why it makes sense that keys cannot be inherited, as setting both parent and child to the same key would not allow react to identify them as separate entities when rendering the DOM.
I apologize for being new with backbone but I think I get the concepts.
For example: you have models for a Bookstore > Bookshelf > Book > Page
How would you organize this so the views can be controlled like this:
Bookstore.render() //to view the bookstore
Bookstore.bookshelf.get(shelfId).render() //to view shelf
Bookstore.bookshelf.get(shelfId).book.get(bookId).render() //to view book
Bookstore.bookshelf.get(shelfId).books.get(bookId).pages.at(0).render() //to view page
Is this the correct way to do it?
Yes It's possible and I created for you a working example, I think It's just an other method to organize your Backbone JS architecture and I think It's a pretty good idea.
Explications
All the models must have :
a render method which call the render method of its view. I create a base model that I extend for the Bookshelf, Book and Page model.
a initialize method, It create the collection (books for bookshelves, pages for book...)
Finally I instanced the Bookstore model and It's done !
Code
The demonstration : http://jsfiddle.net/Atinux/DvbA3/show/
Try in the console :
Bookstore.render()
Bookstore.bookshelves.get(1).render()
Bookstore.bookshelves.get(1).books.get(2).render()
Bookstore.bookshelves.get(1).books.get(2).pages.at(0).render()
The code with comments is available here : http://jsfiddle.net/Atinux/DvbA3/
I think the best thing is to understand how the code work. Feel free to ask me if you have problems to understand perfectly my code.
The JSON data
The JSON data have to look like :
var data = {
bookshelves: [{
id: 1,
name: 'Science',
books: [{
id: 1,
name: 'Abstract Algebra',
pages: [
{ content: 'Page 1 Abstract'},
{ content: 'Page 2 Abstract'},
{ content: 'Page 3 Abstract'}
]
}, {
id: 2,
name: 'Chemistry and Technology of Fertilizers',
pages: [
{ content: 'Chemistry page 1' },
{ content: 'Chemistry page 2' },
{ content: 'Chemistry page 3' }
]
}
]
}, {
id: 2,
name: 'Psychology',
books: [{
id: 1,
name: 'How to Think Straight About Psychology',
pages: [
{ content: 'Psychology page 1' },
{ content: 'Psychology page 2' },
]
}
]
}
]
};
#Alley, what you want to do goes against the MVC pattern since your model objects must be agnostic to the view.
#Atinux answer probably works but introduces a direct dependency between your view and model objects.
All presentational methods must reside in you view objects. Communication between view and models must be done using events.
So, instead of doing: Bookstore.bookshelf.get(shelfId).render()
You shall do something along this lines: bookshelfView.render()