Holiday Tree
- Enter your full name in the text box and press Render Tree.
- Based on your name, a unique, force-directed graph will be generated. While the structure will always be the same, the position of the nodes may (slightly) differ every time.
- After render, you may make adjustments by dragging nodes around.
- Right-click on the tree and choose View as PNG.
- Right-click again and save your holiday tree.
Enjoy! Happy Holidays from ZingChart!
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ZingChart Demo: Xmas Tree</title> <script nonce="undefined" src="https://cdn.zingchart.com/zingchart.min.js"></script> <style> .zc-body { margin: 10px; padding: 10px; background: #fbfbfb; } .zc-info { margin-bottom: 10px; border-bottom: 1px solid #ccc; } .zc-info ol { margin: 0 0 22px; padding: 0 0 0 1rem; font-size: 14px; } .zc-info p { color: #dc1257; } .zc-controls { padding: 5px 0; } .zc-controls input { height: 40px; border: 1px solid #ebebeb; border-radius: 4px; box-sizing: border-box; font-size: 1rem; padding: 0 10px; } .zc-controls input:focus { font-size: 1rem; } .zc-controls button { color: #fff; background: #073c4e; border: 1px solid #ebebeb; border-radius: 4px; cursor: pointer; font-size: .8125rem; padding: 0 10px; height: 40px; } .zc-controls button[disabled] { cursor: not-allowed; } </style> </head> <body class="zc-body"> <div class="zc-info"> <ol> <li>Enter your full name in the text box and press <strong>Render Tree</strong>.</li> <li>Based on your name, a unique, force-directed graph will be generated. While the structure will always be the same, the position of the nodes may (slightly) differ every time.</li> <li>After render, you may make adjustments by dragging nodes around.</li> <li>Right-click on the tree and choose <strong>View as PNG</strong>.</li> <li>Right-click again and save your holiday tree.</li> </ol> <p>Enjoy! Happy Holidays from ZingChart!</p> </div> <div class="zc-controls"> <input type="text" id="renderInput" placeholder="Your full name here" value="world"> <button id="renderBtn">Render Tree</button> </div> <div id="myChart"></div> <script> ZC.LICENSE = ["569d52cefae586f634c54f86dc99e6a9", "b55b025e438fa8a98e32482b5f768ff5"]; // INIT // ----------------------------- // Define Module Location zingchart.MODULESDIR = "https://cdn.zingchart.com/modules/"; // DEFINE CHART // ----------------------------- // Main chart render location let chartId = 'myChart'; // DOM ELEMENTS // ----------------------------- let renderBtn = document.querySelector('#renderBtn'); let renderInput = document.querySelector('#renderInput'); // RENDER BUTTON EVENTS // ----------------------------- renderBtn.addEventListener('click', renderChart); // HELPER FNS // ----------------------------- // Render Chart function renderChart() { // Disable render button renderBtn.setAttribute('disabled', 'disabled') // Define constants const COLORS = [ '#99ccff #336699', '#6CB359 #0F4800', '#9A5E9A #430443', '#FFA153 #AC4E00', '#FF653D #A62300', '#57B8C6 #095B67', '#FFE66D #AF930B', '#EF668F #9D0A36' ]; const NAME = renderInput.value.trim() || 'Santa Claus'; let width = '100%'; let height = 560; let colorSequence = 0; let sequence = 0; let tick = null; // Define data let chartConfig = { type: 'tree', title: { text: 'Hello ' + NAME + ', here\'s your holiday tree', color: '#333333', fontSize: '17px', padding: '25px' }, options: { aspect: 'graph', attractionConstant: 0.1, minSize: '16px', maxSize: '16px', minLinkWidth: '1px', maxLinkWidth: '1px', repulsionConstant: 400, repulsionDistanceFactor: 5, springLength: '35px', textAttr: 'id', weightedLinks: 1, weightedNodes: 1, link: { lineColor: '#000000' }, node: { backgroundColor: 'none', backgroundPosition: '45% 45%', backgroundRepeat: 'no-repeat', borderWidth: 0, fillOffsetX: '-5px', fillOffsetY: '-5px', fillType: 'radial', label: { visible: false }, tooltip: { visible: false } } }, plotarea: { margin: '60px 40px 40px 60px' }, images: [{ src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas0.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas1.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas2.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas3.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas4.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas5.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas6.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas7.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas8.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas9.png', visible: false } ], shapes: [], source: { fontSize: '12px', margin: 'auto 25px 25px 25px', text: 'Happy Holidays from ZingChart!' }, series: [] }; // Build layout let rows = Math.round(height / 20); let cols = Math.round(width / 20); let iCharCode; for (let row = 0; row < rows; row++) { iCharCode = NAME.charCodeAt(row % NAME.length); chartConfig.shapes.push({ type: 'star5', flat: true, backgroundColor: COLORS[iCharCode % COLORS.length], size: 4 + iCharCode % 4, x: 10, y: 10 + row * 20 }, { type: 'star5', flat: true, backgroundColor: COLORS[iCharCode % COLORS.length], size: 4 + iCharCode % 4, x: width - 10, y: 10 + row * 20 }); } for (let col = 1; col < cols - 1; col++) { iCharCode = NAME.charCodeAt(col % NAME.length); chartConfig.shapes.push({ type: 'star5', flat: true, backgroundColor: COLORS[iCharCode % COLORS.length], size: 4 + iCharCode % 4, x: 10 + col * 20, y: 10 }, { type: 'star5', flat: true, backgroundColor: COLORS[iCharCode % COLORS.length], size: 4 + iCharCode % 4, x: 10 + col * 20, y: height - 10 }); } // Render the chart zingchart.render({ id: chartId, width, height, output: 'canvas', data: chartConfig, events: { load: function() { tick = window.setInterval(fnStep, 150); } } }); function fnStep() { let i, sSource, sTarget, aPairs, oLink; let iCharCode = NAME.charCodeAt((sequence + colorSequence) % NAME.length); let iColorCharCode = NAME.charCodeAt(colorSequence % NAME.length); // get data from graph let aData = zingchart.exec(chartId, 'tree.getdata') || []; // count links for each node let oNodesLinks = {}, aNodesIds = [], aLinksIds = []; for (i = 0; i < aData.length; i++) { if (aData[i].type === 'link') { oNodesLinks[aData[i].source] = ++oNodesLinks[aData[i].source] || 1; oNodesLinks[aData[i].target] = ++oNodesLinks[aData[i].target] || 1; aLinksIds.push(aData[i].source + '-' + aData[i].target); aLinksIds.push(aData[i].target + '-' + aData[i].source); } else if (aData[i].type === 'node') { aNodesIds.push(aData[i].id); } } // remove all nodes with no links if (aNodesIds.length > 2) { for (i = 0; i < aNodesIds.length; i++) { if (!oNodesLinks[aNodesIds[i]]) { zingchart.exec(chartId, 'tree.removenode', { id: aNodesIds[i] }); } } } // from time to time remove oldest leaves if (sequence % 5 === 0 && aNodesIds.length > 5) { for (i = 0; i < aNodesIds.length; i++) { if (oNodesLinks[aNodesIds[i]] === 1) { zingchart.exec(chartId, 'tree.removenode', { id: aNodesIds[i] }); sequence++; return; } } } // from time to time remove nodes with too many links if (sequence % 13 === 0 && aNodesIds.length > 5) { for (i = 0; i < aNodesIds.length; i++) { if (oNodesLinks[aNodesIds[i]] > 3) { zingchart.exec(chartId, 'tree.removenode', { id: aNodesIds[i] }); sequence++; return; } } } // from time to time just create a link between existing nodes if (sequence % 7 === 0 && aNodesIds.length > 3) { aPairs = []; for (i = 0; i < aNodesIds.length; i++) { if (oNodesLinks[aNodesIds[i]] === 1) { aPairs.push(aNodesIds[i]); if (aPairs.length === 2) { oLink = { source: aPairs[0], target: aPairs[1], value: 1 + iCharCode % 2 }; zingchart.exec(chartId, 'tree.addlink', { data: oLink, update: true }); sequence++; return; } } } } // otherwise, create a new node sTarget = 'n' + sequence; oNode = { id: sTarget, text: sTarget, value: 1, style: { backgroundImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas' + (sequence % 10) + '.png', backgroundColor: COLORS[iColorCharCode % COLORS.length] } }; colorSequence++; zingchart.exec(chartId, 'tree.addnode', { data: oNode, update: (aNodesIds.length === 0) }); if (aNodesIds.length > 0) { sSource = aNodesIds[iCharCode % aNodesIds.length]; oLink = { source: sSource, target: sTarget, value: 1 + iCharCode % 2 }; zingchart.exec(chartId, 'tree.addlink', { data: oLink, update: (aNodesIds.length > 0) }); } sequence++; if (sequence > 99) { window.clearInterval(tick); renderBtn.removeAttribute('disabled'); } }; } window.addEventListener('load', function() { renderChart(); }); </script> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ZingChart Demo: Xmas Tree</title> <script src="https://cdn.zingchart.com/zingchart.min.js"></script> </head> <body class="zc-body"> <div class="zc-info"> <ol> <li>Enter your full name in the text box and press <strong>Render Tree</strong>.</li> <li>Based on your name, a unique, force-directed graph will be generated. While the structure will always be the same, the position of the nodes may (slightly) differ every time.</li> <li>After render, you may make adjustments by dragging nodes around.</li> <li>Right-click on the tree and choose <strong>View as PNG</strong>.</li> <li>Right-click again and save your holiday tree.</li> </ol> <p>Enjoy! Happy Holidays from ZingChart!</p> </div> <div class="zc-controls"> <input type="text" id="renderInput" placeholder="Your full name here" value="world"> <button id="renderBtn">Render Tree</button> </div> <div id="myChart"></div> </body> </html>
// INIT // ----------------------------- // Define Module Location zingchart.MODULESDIR = "https://cdn.zingchart.com/modules/"; // DEFINE CHART // ----------------------------- // Main chart render location let chartId = 'myChart'; // DOM ELEMENTS // ----------------------------- let renderBtn = document.querySelector('#renderBtn'); let renderInput = document.querySelector('#renderInput'); // RENDER BUTTON EVENTS // ----------------------------- renderBtn.addEventListener('click', renderChart); // HELPER FNS // ----------------------------- // Render Chart function renderChart() { // Disable render button renderBtn.setAttribute('disabled', 'disabled') // Define constants const COLORS = [ '#99ccff #336699', '#6CB359 #0F4800', '#9A5E9A #430443', '#FFA153 #AC4E00', '#FF653D #A62300', '#57B8C6 #095B67', '#FFE66D #AF930B', '#EF668F #9D0A36' ]; const NAME = renderInput.value.trim() || 'Santa Claus'; let width = '100%'; let height = 560; let colorSequence = 0; let sequence = 0; let tick = null; // Define data let chartConfig = { type: 'tree', title: { text: 'Hello ' + NAME + ', here\'s your holiday tree', color: '#333333', fontSize: '17px', padding: '25px' }, options: { aspect: 'graph', attractionConstant: 0.1, minSize: '16px', maxSize: '16px', minLinkWidth: '1px', maxLinkWidth: '1px', repulsionConstant: 400, repulsionDistanceFactor: 5, springLength: '35px', textAttr: 'id', weightedLinks: 1, weightedNodes: 1, link: { lineColor: '#000000' }, node: { backgroundColor: 'none', backgroundPosition: '45% 45%', backgroundRepeat: 'no-repeat', borderWidth: 0, fillOffsetX: '-5px', fillOffsetY: '-5px', fillType: 'radial', label: { visible: false }, tooltip: { visible: false } } }, plotarea: { margin: '60px 40px 40px 60px' }, images: [ { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas0.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas1.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas2.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas3.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas4.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas5.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas6.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas7.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas8.png', visible: false }, { src: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas9.png', visible: false } ], shapes: [], source: { fontSize: '12px', margin: 'auto 25px 25px 25px', text: 'Happy Holidays from ZingChart!' }, series: [] }; // Build layout let rows = Math.round(height / 20); let cols = Math.round(width / 20); let iCharCode; for (let row=0;row<rows;row++) { iCharCode = NAME.charCodeAt(row%NAME.length); chartConfig.shapes.push({ type: 'star5', flat: true, backgroundColor: COLORS[iCharCode%COLORS.length], size: 4 + iCharCode%4, x: 10, y: 10 + row * 20 }, { type: 'star5', flat: true, backgroundColor: COLORS[iCharCode%COLORS.length], size: 4 + iCharCode%4, x: width - 10, y: 10 + row * 20 }); } for (let col=1;col<cols-1;col++) { iCharCode = NAME.charCodeAt(col%NAME.length); chartConfig.shapes.push({ type: 'star5', flat: true, backgroundColor: COLORS[iCharCode%COLORS.length], size: 4 + iCharCode%4, x: 10 + col * 20, y: 10 }, { type: 'star5', flat: true, backgroundColor: COLORS[iCharCode%COLORS.length], size: 4 + iCharCode%4, x: 10 + col * 20, y: height - 10 }); } // Render the chart zingchart.render({ id: chartId, width, height, output: 'canvas', data: chartConfig, events: { load: function() { tick = window.setInterval(fnStep, 150); } } }); function fnStep() { let i, sSource, sTarget, aPairs, oLink; let iCharCode = NAME.charCodeAt((sequence+colorSequence)%NAME.length); let iColorCharCode = NAME.charCodeAt(colorSequence%NAME.length); // get data from graph let aData = zingchart.exec(chartId, 'tree.getdata') || []; // count links for each node let oNodesLinks = {}, aNodesIds = [], aLinksIds = []; for (i=0;i<aData.length;i++) { if (aData[i].type === 'link') { oNodesLinks[aData[i].source] = ++oNodesLinks[aData[i].source] || 1; oNodesLinks[aData[i].target] = ++oNodesLinks[aData[i].target] || 1; aLinksIds.push(aData[i].source + '-' + aData[i].target); aLinksIds.push(aData[i].target + '-' + aData[i].source); } else if (aData[i].type === 'node') { aNodesIds.push(aData[i].id); } } // remove all nodes with no links if (aNodesIds.length > 2) { for (i=0;i<aNodesIds.length;i++) { if (!oNodesLinks[aNodesIds[i]]) { zingchart.exec(chartId, 'tree.removenode', { id: aNodesIds[i] }); } } } // from time to time remove oldest leaves if (sequence%5 === 0 && aNodesIds.length > 5) { for (i=0;i<aNodesIds.length;i++) { if (oNodesLinks[aNodesIds[i]] === 1) { zingchart.exec(chartId, 'tree.removenode', { id: aNodesIds[i] }); sequence++; return; } } } // from time to time remove nodes with too many links if (sequence%13 === 0 && aNodesIds.length > 5) { for (i=0;i<aNodesIds.length;i++) { if (oNodesLinks[aNodesIds[i]] > 3) { zingchart.exec(chartId, 'tree.removenode', { id: aNodesIds[i] }); sequence++; return; } } } // from time to time just create a link between existing nodes if (sequence%7 === 0 && aNodesIds.length > 3) { aPairs = []; for (i=0;i<aNodesIds.length;i++) { if (oNodesLinks[aNodesIds[i]] === 1) { aPairs.push(aNodesIds[i]); if (aPairs.length === 2) { oLink = { source: aPairs[0], target: aPairs[1], value: 1 + iCharCode%2 }; zingchart.exec(chartId, 'tree.addlink', { data: oLink, update: true }); sequence++; return; } } } } // otherwise, create a new node sTarget = 'n' + sequence; oNode = { id: sTarget, text: sTarget, value: 1, style: { backgroundImage: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/xmas' + (sequence%10) + '.png', backgroundColor: COLORS[iColorCharCode%COLORS.length] } }; colorSequence++; zingchart.exec(chartId, 'tree.addnode', { data: oNode, update: (aNodesIds.length === 0) }); if (aNodesIds.length > 0) { sSource = aNodesIds[iCharCode%aNodesIds.length]; oLink = { source: sSource, target: sTarget, value: 1 + iCharCode%2 }; zingchart.exec(chartId, 'tree.addlink', { data: oLink, update: (aNodesIds.length > 0) }); } sequence++; if (sequence > 99) { window.clearInterval(tick); renderBtn.removeAttribute('disabled'); } }; } window.addEventListener('load', function() { renderChart(); });
.zc-body { margin:10px; padding:10px; background: #fbfbfb; } .zc-info { margin-bottom: 10px; border-bottom: 1px solid #ccc; } .zc-info ol { margin: 0 0 22px; padding: 0 0 0 1rem; font-size: 14px; } .zc-info p { color: #dc1257; } .zc-controls { padding: 5px 0; } .zc-controls input { height: 40px; border: 1px solid #ebebeb; border-radius: 4px; box-sizing: border-box; font-size: 1rem; padding:0 10px; } .zc-controls input:focus { font-size: 1rem; } .zc-controls button { color: #fff; background: #073c4e; border: 1px solid #ebebeb; border-radius: 4px; cursor: pointer; font-size: .8125rem; padding:0 10px; height: 40px; } .zc-controls button[disabled] { cursor: not-allowed; }