Alright, what I'm looking for is something that could generate a graphical tree-style map of a web pages nodes.
So essentially it could theoretically transform something like this:
<aside id="leftCol">
<section class="container">
<header class="child1">
<hgroup>
<h1 class="title">Demo Project</h1>
<h3 class="subTitle">WEBSITE 2011</h3>
</hgroup>
</header>
<div class="child2" id="thisDiv">
<div class="subChild1">
<div class="anotherChild1"></div>
<div class="anotherChild2"></div>
<div class="anotherChild3"></div>
</div>
<div class="subChild2">
<p>Some Text</p>
</div>
</div>
<footer class="child3">
Link to project here
</footer>
</section>
</aside>
(This would of course be inside the HTML and BODY tags but for the sake of an example I'm going to use a snippet from my portfolio page with some generated text)
Into something like this:
Example http://www.deviantart.com/download/287437946/node_map_by_wild_fire126-d4r4sje.png
There's absolutely no design thought put into this so don't criticize it, purely for the example purpose. I made this image in photoshop quickly just to illustrate exactly what I'm talking about. All of this could be easily generated with CSS for the most part. It does not by any means have to be this graphical but for the sake of me being bored, it is.
I'm looking for a plugin or a piece of software that can do this for me. I would prefer that it would generate this map in HTML or as an image. I guess any map type would be okay as long as it would be easy to follow.
As a last resort if I can't find quite what I'm looking for I might end up just writing it myself, if that happens, I would be happy to be looking for some people to help with the coding of the plugin.
You could retrieve all children of a certain element and return their tag, class, id and depth. Then you can get creative with css to create a visual tree. Something like this should work. Example at http://jsfiddle.net/elclanrs/UHbMa/.
jQuery plugin:
$.fn.buildTree = function() {
var tree = {};
this.find('*').andSelf().each(function(i, v) {
var parents = $(this).parents().length - 1;
for (var i = 0; i < parents; i++) {
tree[v.tagName.toLowerCase()] = {
id: v.id,
className: v.className,
depth: i
}
}
});
return tree;
};
And then you call it like:
var tree= $('aside').buildTree(),
html = '';
for (tag in tree) {
html += '<p><strong>Tag:</strong> ' + tag +
' | <strong>Class:</strong> ' + tree[tag].className +
' | <strong>Depth:</strong> ' + tree[tag].depth;
}
$('#tree').append(html);
Graphviz is a nice tool for doing such a thing.
You could use a piece of Javascript to generate a Graphviz file and generate a png with the tool.
The javascript should recursively visit all Elements and Generate unique IDs for every Element and write them out in the fairly easy to understand Graphviz format.
Here's a Bookmarklet to convert a page to the Graphviz format.
javascript:void((function() {var f = function(pid, e) { var id = "id" + Math.round(Math.random()*1000000), c = e.childNodes, r = id+'[label="'+(e.tagName ? e.tagName : e.nodeValue.replace(/[\n\r]+/g," "))+'"];\n'; for(var i = 0; i < c.length; i++) { r+=f(id, c[i]); }; if(pid) {r += pid + "->" + id + ";\n";}; return r;}; document.body.innerText = "digraph {\n" + f(false, document.getElementsByTagName("html")[0]) + "}"})())
Here's a quick workthrough to the format: http://www.orient-lodge.com/node/3408
Then generate a png file: (example works under Unix)
dot -Tpng < graph.dot > g.png
There's a Javascript Renderer for Graphviz, too. Canviz I haven't tried it yet, but looks promising.
Related
I have some problems with my code. I want to create an XML Document with JQuery / JavaScript. I am now at the point, where I want to create a few Tags and populate them each with the same tags but different content inside the tags.
Here is the code for better understand
function setItems(xmlDoc, channelTag){
const itemList = [];
const itemTitle = xmlDoc.createElement("title");
const itemLink = xmlDoc.createElement("link");
const itemGuid = xmlDoc.createElement("guid");
const itemMediaContent = xmlDoc.createElement("media:content");
const itemMediaDescription = xmlDoc.createElement("media:description");
itemList.push(itemTitle, itemLink, itemGuid, itemMediaContent, itemMediaDescription);
for (var i = 0; i < jsonObj.length; i++){
var item = xmlDoc.createElement("item");
channelTag.appendChild(item);
//Populate the <item> with the tags from "itemList" and content from "jsonObj"
$.each(itemList, function(index) {
$(channelTag).children('item')[i].appendChild(itemList[index]).textContent = jsonObj[0].title;
})
}
}
The Output of the code looks like this:
<item></item>
<item></item>
<item>
<title>Something</title>
<guid>Something</guid>
<link>Something</link>
<media:content>Something</media:description>
<media:description>Something</media:description>
</item>
It always populates the last item-Tag but not the ones above. What I want is that every item-Tag has the same child-Tags (e.g. title, link, guid and so on). Is there something i am missing some unique tags or something like that?
Edited:
Here is some minimal HTML and XML. The values for the function "xmlDoc" and "channelTag" just contains some Document Elements, where my items should be appended, like so:
<rss>
<channel>
<title>SomeTitle</title>
<atom:link href="Link" rel="self" type="application/rss+xml"/>
<link>SomeLink</link>
<description>SomeDesc</description>
<item></item>
<item></item>
<item></item>
</channel>
</rss>
<div class="col-5 col-sm-5 col-lg-3 order-2 count">
<a class="guid1"><img class="card-img image1"></a>
</div>
<div class="col-7 col-sm-7 col-lg-5 order-2">
<div class="card-body">
<a class="guid1">
<h5 class="card-title title1 overflow-title"></h5>
</a>
<p class="card-text body1 text-body overflow-body"></p>
<div class="card-body subtitle">
</div>
</div>
</div>
There are several issues with your code but the area we mostly want to focus on is this:
for (var i = 0; i < jsonObj.length; i++){
var item = xmlDoc.createElement("item");
channelTag.appendChild(item); // you're adding a node here
$.each(itemList, function(index) {
$(channelTag).children('item')[i].appendChild(... // and here
})
}
Instead of appending nodes multiple times per iteration, you should create and populate your node before add it it to channelTag.
Here's a way your could do it:
// use a "$" sign as a variable name prefix, so you know it's a Document Element and not a regular javascript variable
var $item = xmlDoc.createElement("item");
// you don't need jQuery for this iteration
itemList.forEach(function (item, index) {
$item.appendChild(itemList[index]).textContent = jsonObj[0].title;
});
// if "channelTag" is a Document Element, rename it "$channelTag"
$channelTag.appendChild(item);
Couple things about the code above:
you don't need jQuery, use forEach instead
there is no way telling what type is channelTag. If it is a selector (of type string), use $(selector), but you are using the appendChild() method before, suggesting it's actually a Document Element. In that case you don't need to wrap it with $()
I don't have the context needed to test this code, so no guarantee it'll work out of the box. But try and re-read your code and go through it top-to-bottom. For each variable, describe its type and value. I found that to be helpful when I'm lost in code.
I appreciate any time you spend on this question of mine.
The Project
My mom is an art teacher that spends a lot of time creating paper-cutting guides for her projects. I am working on a tool for her that will allow her to quickly build and share guides through her website. Her site is built with wordpress, so I built the tool using jQuery and jQuery UI. Here is what it looks like in action:
https://i.stack.imgur.com/z3Y5C.gif
The UI is working well enough to move onto saving the data, and that is where I am having trouble.
The Problem
I want to create an array based on the DOM elements created by jquery. The plan is to save the array to WordPress and then use it to rebuild the guide for viewing / editing.
The basic DOM structure goes like this:
function saveGuide() {
numberOfSheets = $(".sheet").length;
console.log("number of sheets:", numberOfSheets);
sheetCounter = 1;
for (i = 0; i < numberOfSheets; i++) {
var saveSheets = $(".sheet")
.map(function() {
return {
sheetName: $(this).attr("data-id"),
width: ($(this).width() + 1) / 80,
height: ($(this).height() + 1) / 80,
// Map the pieces in the sheet
pieces: (saveSheets = $(
".sheet[data-sheetnumber='" + sheetCounter + "'] .piece"
)
.map(function() {
return {
pieceName: $(this).attr("data-name"),
pieceColor: $(this).attr("data-color"),
pieceWidth: ($(this).width() + 4) / 80,
pieceHeight: ($(this).height() + 4) / 80,
pieceXPOS: $(this).position().left / 80,
pieceYPOS: $(this).position().top / 80
};
})
.get())
};
})
.get();
sheetCounter++;
}
myJSON = JSON.stringify(saveSheets);
console.log(myJSON);
}
saveGuide();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sheet">
<div class="piece"></div>
<div class="piece"></div>
<div class="line"></div>
</div>
<div class="sheet">
<div class="piece"></div>
<div class="piece"></div>
<div class="line"></div>
</div>
So each sheet gets entered into the array just fine, but the pieces are always the same and from the last sheet. I'm guessing the variable overwrites itself with each loop...
Here is a link to what the data looks like on save: https://codebeautify.org/jsonviewer/cbff77c4
You can see that both sheets have the same pieces listed.
I am either very close to getting to work or I am way way way off on how I built the function. But I feel like my brain is melting a little right now and could use help or suggestions on what I need to look at.
Much appreciated.
You can use .children([selector]) to get the children of a specific element. If you set the selector, only matching children will be returned.
In your case you should use $(this).children('.piece') (or $sheet.children('.piece') in the example) to get the pieces related to each sheet:
function saveGuide() {
return $(".sheet")
.map(function() {
var $sheet = $(this);
return {
sheetName: $sheet.attr("data-id"),
width: ($sheet.width() + 1) / 80,
height: ($sheet.height() + 1) / 80,
// Map the pieces in the sheet
pieces: $sheet.children('.piece')
.map(function() {
var $piece = $(this);
return {
pieceName: $piece.attr("data-name"),
pieceColor: $piece.attr("data-color"),
pieceWidth: ($piece.width() + 4) / 80,
pieceHeight: ($piece.height() + 4) / 80,
pieceXPOS: $piece.position().left / 80,
pieceYPOS: $piece.position().top / 80
};
})
.get()
};
})
.get();
}
var saveSheets = saveGuide();
console.log("number of sheets:", saveSheets.length);
var myJSON = JSON.stringify(saveSheets);
console.log(myJSON);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="sheet">
<div class="piece" data-name="sheet1-1"></div>
<div class="piece" data-name="sheet1-2"></div>
<div class="line"></div>
</div>
<div class="sheet">
<div class="piece" data-name="sheet2-1"></div>
<div class="piece" data-name="sheet2-2"></div>
<div class="line"></div>
</div>
I am having an issue with a project I'm working on. I am using an API to return an array of platforms a video game is on. The array is returning the correct results, however I am having trouble displaying those values in my HTML. The result is just showing undefined.
// Renders platform information for each game
const renderPlatformInfo = function (platformResult) {
const gamePlatform = [];
for (let i = 0; i <= `${platformResult.length - 1}`; i++) {
let getPlatforms = gamePlatform.push(platformResult[i].name);
}
gamePlatform.forEach(function (platformItem) {
$('.platforms').append(`<li>${platformItem}</li>`)
});
console.log(gamePlatform);
};
// Renders game information for the searched game
const renderGameInfo = function (gameInfoResult) {
return `<div class="js-game-data row">
<h2 class="game-name col-12">${gameInfoResult.name}</h2>
<img src="${gameInfoResult.image.medium_url}" class="game-image col-4" alt="Box art for ${gameInfoResult.name}">
<ul class="platforms col-6">
<h3 class="col-12">Original release date:</h3>${gameInfoResult.original_release_date}
<h3>Platforms:</h3>
${renderPlatformInfo(gameInfoResult.platforms)}
</ul>
<p class="game-description col-6">${gameInfoResult.deck} <br> <br> <span class="game-details col-12"><b>For more details about the game: Click Here</b></span></p>
</div>
`;
}
renderPlatformInfo can't append children to a DOM element that doesn't exist yet. The UL it's trying to select isn't rendered at the time you're trying to append. Additionally, since renderPlatformInfo doesn't return anything, it will always evaluate to undefined inside a template literal. If you return an HTML string inside renderPlatformInfo, your code should work. Try something like:
let str = '';
gamePlatform.forEach(function(platformItem){
str += `<li>${platformItem}</li>`;
});
return str;
Should renderPlatformInfo return something. Are you missing the return there?
I have a div, #containerDiv, which contains elements related to users like first name, last name etc. in separate divs. I need to sort the contents of the container div based on the last name, first name etc. values.
On searching google the examples I got all are appending the sorted results and not changing the entire HTML being displayed. They are also not sorting by specific fields (first name, last name).
So please help me in sorting the entire content of #containerDiv based on specific fields and also displaying it.
The Page looks Like something as mentioned Below:
<div id="containerDiv">
<div id="lName_1">dsaf</div><div id="fName_1">grad</div>
<div id="lName_2">sdaf</div><div id="fName_2">radg</div>
<div id="lName_3">asdf</div><div id="fName_3">drag</div>
<div id="lName_4">fasd</div><div id="fName_4">gard</div>
<div id="lName_5">dasf</div><div id="fName_5">grda</div>
<div id="lName_6">asfd</div><div id="fName_6">drga</div>
</div>
On getting sorted by last name div values, the resulted structure of the container div should look like:
<div id="containerDiv">
<div id="lName_3">asdf</div><div id="fName_3">drag</div>
<div id="lName_6">asfd</div><div id="fName_6">drga</div>
<div id="lName_5">dasf</div><div id="fName_5">grda</div>
<div id="lName_1">dsaf</div><div id="fName_1">grad</div>
<div id="lName_4">fasd</div><div id="fName_4">gard</div>
<div id="lName_2">sdaf</div><div id="fName_2">radg</div>
</div>
Now I think you all can help me in a better way.
this is a sample example:
html:
<div id="containerDiv">
<div>2</div>
<div>3</div>
<div>1</div>
</div>
js
$(function() {
var container, divs;
divs = $("#containerDiv>div").clone();
container = $("#containerDiv");
divs.sort(function(divX, divY) {
return divX.innerHTML > divY.innerHTML;
});
container.empty();
divs.appendTo(container);
});
you may set your divs.sort function param depend on your goal.
jsFiddle.
and a jQuery Plugin is suitable
I suggest you read the div values so you get an array of objects (persons for example) or just names and perform a sort operation on that. Than...output the result to the initial div (overwriting the default values).
I have built a jQuery sort function in which you can affect the sort field.
(it rebuilds the html by moving the row to another location).
function sortTableJquery()
{
var tbl =$("#tbl tr");
var store = [];
var sortElementIndex = parseFloat($.data(document.body, "sortElement"));
for (var i = 0, len = $(tbl).length; i < len; i++)
{
var rowDom = $(tbl).eq(i);
var rowData = $.trim($("td",$(rowDom)).eq(sortElementIndex).text());
store.push([rowData, rowDom]);
}
store.sort(function (x, y)
{
if (x[0].toLowerCase() == y[0].toLowerCase()) return 0;
if (x[0].toLowerCase() < y[0].toLowerCase()) return -1 * parseFloat($.data(document.body, "sortDir"));
else return 1 * parseFloat($.data(document.body, "sortDir"));
});
for (var i = 0, len = store.length; i < len; i++)
{
$("#tbl").append(store[i][1]);
}
store = null;
}
Every time I need to sort lists I use ListJs.
It's well documented, has good performance even for large lists and it's very lightweight (7KB, despite being library agnostic).
I'm having a "list" that I want to populate with a background-json request.
Items have different headings and traffic should be minimal (mobile webapp),
DOM-structure something like:
<div id="deckStart">
<div id="cardContacts">
<h2>Contacts</h2>
<div id="cardContactsContent">nothing here until JSON</div>
</div>
<div id="cardTodo">
<h2>To do</h2>
<div id="cardTodoContent">nothing here until JSON</div>
....
//EDIT
OK, this works:
x$(window).on('load', function() {
x$(window).xhr('json.txt', {
async: true,
callback: function() {
var t = eval('(' + this.responseText + ')');
for(var key in t) {
var obj = t[key];
x$('#' + key).html('inner',obj);
}
}
});
but why doesn't JSON.parse work on chrome? Eval seems dirty..
//end edit
What would be the most efficient way to populate the respective content-divs with one single JSON-request?
Temp load into JS-array?
Temp load into hidden DOM-part?
Some regexp-trick or other I cannot think of?
The network stability / speed is unreliable.
regards,
Can you get jQuery on there? You could do it in a heartbeat with jQuery...