Skip to content

Instantly share code, notes, and snippets.

@maxkfranz
Last active March 8, 2020 09:24
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save maxkfranz/cde4db55e581d10405f5 to your computer and use it in GitHub Desktop.
Save maxkfranz/cde4db55e581d10405f5 to your computer and use it in GitHub Desktop.
wine-and-cheese-demo
dummy file to create gist
/*
This demo visualises wine and cheese pairings.
*/
$(function(){
var layoutPadding = 50;
var layoutDuration = 500;
// get exported json from cytoscape desktop via ajax
var graphP = $.ajax({
url: 'https://cdn.rawgit.com/maxkfranz/3d4d3c8eb808bd95bae7/raw', // wine-and-cheese.json
type: 'GET',
dataType: 'json'
});
// also get style via ajax
var styleP = $.ajax({
url: 'https://cdn.rawgit.com/maxkfranz/9210c03a591f8736b82d/raw', // wine-and-cheese-style.cycss
type: 'GET',
dataType: 'text'
});
var infoTemplate = Handlebars.compile([
'<p class="ac-name">{{name}}</p>',
'<p class="ac-node-type"><i class="fa fa-info-circle"></i> {{NodeTypeFormatted}} {{#if Type}}({{Type}}){{/if}}</p>',
'{{#if Milk}}<p class="ac-milk"><i class="fa fa-angle-double-right"></i> {{Milk}}</p>{{/if}}',
'{{#if Country}}<p class="ac-country"><i class="fa fa-map-marker"></i> {{Country}}</p>{{/if}}',
'<p class="ac-more"><i class="fa fa-external-link"></i> <a target="_blank" href="https://duckduckgo.com/?q={{name}}">More information</a></p>'
].join(''));
// when both graph export json and style loaded, init cy
Promise.all([ graphP, styleP ]).then(initCy);
function highlight( node ){
var nhood = node.closedNeighborhood();
cy.batch(function(){
cy.elements().not( nhood ).removeClass('highlighted').addClass('faded');
nhood.removeClass('faded').addClass('highlighted');
var npos = node.position();
var w = window.innerWidth;
var h = window.innerHeight;
cy.stop().animate({
fit: {
eles: cy.elements(),
padding: layoutPadding
}
}, {
duration: layoutDuration
}).delay( layoutDuration, function(){
nhood.layout({
name: 'concentric',
padding: layoutPadding,
animate: true,
animationDuration: layoutDuration,
boundingBox: {
x1: npos.x - w/2,
x2: npos.x + w/2,
y1: npos.y - w/2,
y2: npos.y + w/2
},
fit: true,
concentric: function( n ){
if( node.id() === n.id() ){
return 2;
} else {
return 1;
}
},
levelWidth: function(){
return 1;
}
});
} );
});
}
function clear(){
cy.batch(function(){
cy.$('.highlighted').forEach(function(n){
n.animate({
position: n.data('orgPos')
});
});
cy.elements().removeClass('highlighted').removeClass('faded');
});
}
function showNodeInfo( node ){
$('#info').html( infoTemplate( node.data() ) ).show();
}
function hideNodeInfo(){
$('#info').hide();
}
function initCy( then ){
var loading = document.getElementById('loading');
var expJson = then[0];
var styleJson = then[1];
var elements = expJson.elements;
elements.nodes.forEach(function(n){
var data = n.data;
data.NodeTypeFormatted = data.NodeType;
if( data.NodeTypeFormatted === 'RedWine' ){
data.NodeTypeFormatted = 'Red Wine';
} else if( data.NodeTypeFormatted === 'WhiteWine' ){
data.NodeTypeFormatted = 'White Wine';
}
n.data.orgPos = {
x: n.position.x,
y: n.position.y
};
});
loading.classList.add('loaded');
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
layout: { name: 'preset', padding: layoutPadding },
style: styleJson,
elements: elements,
motionBlur: true,
selectionType: 'single',
boxSelectionEnabled: false,
autoungrabify: true
});
cy.on('free', 'node', function( e ){
var n = e.cyTarget;
var p = n.position();
n.data('orgPos', {
x: p.x,
y: p.y
});
});
cy.on('tap', function(){
$('#search').blur();
});
cy.on('select', 'node', function(e){
var node = this;
highlight( node );
showNodeInfo( node );
});
cy.on('unselect', 'node', function(e){
var node = this;
clear();
hideNodeInfo();
});
}
$('#search').typeahead({
minLength: 2,
highlight: true,
},
{
name: 'search-dataset',
source: function( query, cb ){
function matches( str, q ){
str = (str || '').toLowerCase();
q = (q || '').toLowerCase();
return str.match( q );
}
var fields = ['name', 'NodeType', 'Country', 'Type', 'Milk'];
function anyFieldMatches( n ){
for( var i = 0; i < fields.length; i++ ){
var f = fields[i];
if( matches( n.data(f), query ) ){
return true;
}
}
return false;
}
function getData(n){
var data = n.data();
return data;
}
function sortByName(n1, n2){
if( n1.data('name') < n2.data('name') ){
return -1;
} else if( n1.data('name') > n2.data('name') ){
return 1;
}
return 0;
}
var res = cy.nodes().stdFilter( anyFieldMatches ).sort( sortByName ).map( getData );
cb( res );
},
templates: {
suggestion: infoTemplate
}
}).on('typeahead:selected', function(e, entry, dataset){
var n = cy.getElementById(entry.id);
n.select();
showNodeInfo( n );
});
$('#reset').on('click', function(){
cy.animate({
fit: {
eles: cy.elements(),
padding: layoutPadding
},
duration: layoutDuration
});
});
$('#filters').on('click', 'input', function(){
var soft = $('#soft').is(':checked');
var semiSoft = $('#semi-soft').is(':checked');
var na = $('#na').is(':checked');
var semiHard = $('#semi-hard').is(':checked');
var hard = $('#hard').is(':checked');
var red = $('#red').is(':checked');
var white = $('#white').is(':checked');
var cider = $('#cider').is(':checked');
cy.batch(function(){
cy.nodes().forEach(function( n ){
var type = n.data('NodeType');
n.removeClass('filtered');
var filter = function(){
n.addClass('filtered');
};
if( type === 'Cheese' ){
var cType = n.data('Type');
if(
(cType === 'Soft' && !soft)
|| (cType === 'Semi-soft' && !semiSoft)
|| (cType === undefined && !na)
|| (cType === 'Semi-hard' && !semiHard)
|| (cType === 'Hard' && !hard)
){
filter();
}
} else if( type === 'RedWine' ){
if( !red ){ filter(); }
} else if( type === 'WhiteWine' ){
if( !white ){ filter(); }
} else if( type === 'Cider' ){
if( !cider ){ filter(); }
}
});
});
});
$('#filter').qtip({
position: {
my: 'top center',
at: 'bottom center'
},
show: {
event: 'click'
},
hide: {
event: 'unfocus'
},
style: {
classes: 'qtip-bootstrap',
tip: {
width: 16,
height: 8
}
},
content: $('#filters')
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<title>Wine and cheese</title>
<link href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">-->
<link href="style.css" rel="stylesheet">
</head>
<body>
<div id="cy"></div>
<div id="loading">
<span class="fa fa-refresh fa-spin"></span>
</div>
<div id="search-wrapper">
<input type="text" class="form-control" id="search" autofocus placeholder="Search">
</div>
<div id="info">
</div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.3/fastclick.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://cytoscape.github.io/cytoscape.js/api/cytoscape.js-latest/cytoscape.min.js"></script>
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.js"></script>
<link href="http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-qtip/2.2.3/cytoscape-qtip.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/bluebird/1.2.2/bluebird.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.10.4/typeahead.bundle.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.2/handlebars.min.js"></script>
<script src="demo.js"></script>
<button id="reset" class="btn btn-default"><i class="fa fa-arrows-h"></i></button>
<button id="filter" class="btn btn-default"><i class="fa fa-filter"></i></button>
<div id="filters">
<strong>Cheese</strong>
<input id="soft" type="checkbox" checked></input><label for="soft">Soft</label><br />
<input id="semi-soft" type="checkbox" checked></input><label for="semi-soft">Semi-soft</label><br />
<input id="na" type="checkbox" checked></input><label for="na">N/A</label><br />
<input id="semi-hard" type="checkbox" checked></input><label for="semi-hard">Semi-hard</label><br />
<input id="hard" type="checkbox" checked></input><label for="hard">Hard</label>
<hr />
<strong>Drink</strong>
<input id="white" type="checkbox" checked></input><label for="white">White wine</label><br />
<input id="red" type="checkbox" checked></input><label for="red">Red wine</label><br />
<input id="cider" type="checkbox" checked></input><label for="cider">Cider</label>
</div>
<a target="_blank" id="linkout" href="http://www.amazon.ca/Cheese-Connoisseurs-Guide-Worlds-Best/dp/1400050340/ref=sr_1_3?s=books&ie=UTF8&qid=1416109370&sr=1-3">Reference <i class="fa fa-external-link"></i></a>
</body>
</html>
html, body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
width: 100%;
height: 100%;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
background: #000;
}
#loading {
position: absolute;
left: 0;
top: 50%;
width: 100%;
text-align: center;
margin-top: -0.5em;
font-size: 2em;
color: #fff;
}
#loading.loaded {
display: none;
}
/*
button {
font-size: 2em;
background-color: #FC4C4C;
color: #fff;
border: 0;
cursor: pointer;
border-radius: 0.25em;
font-family: helvetica neue, helvetica, arial, sans-serif;
outline: 0;
}
*/
#clear {
position: absolute;
right: 0;
top: 0;
margin: 0.25em;
visibility: hidden;
}
#search-wrapper {
position: absolute;
left: 0;
top: 0;
z-index: 9999;
margin: 0.5em;
width: 14em;
}
#search {
width: 14em;
}
body.has-start #clear {
visibility: visible;
}
#end {
display: none;
}
body.has-start:not(.has-end) #end {
display: inline;
}
body.has-start:not(.has-end) #start {
display: none;
}
body.calc #loading {
display: block;
}
.tt-dropdown-menu {
background: #fff;
width: 14em;
border-radius: 0.25em;
border: 1px solid #ccc;
max-height: 20em;
overflow: auto;
margin-top: 0.5em;
}
.tt-dropdown-menu * {
margin: 0;
padding: 0;
}
.tt-suggestion {
margin: 0;
padding: 0;
cursor: pointer;
}
.tt-suggestion + .tt-suggestion {
border-top: 1px solid #ccc;
}
.ac-name {
font-size: 1.25em;
}
.ac-node-type,
.ac-milk,
.ac-country,
.ac-more {
font-size: 0.8em;
}
#info {
position: absolute;
left: 0;
top: 3em;
margin: 0.5em;
background: #bbdbf7;
border-radius: 0.25em;
border: 1px solid #ccc;
width: 14em;
display: none;
}
#info p {
margin: 0;
}
#linkout {
position: absolute;
left: 0;
bottom: 0;
margin: 0.25em;
z-index: 999;
}
#reset,
#filter {
width: 3em;
margin: 0.5em;
position: absolute;
top: 0;
z-index: 999;
}
#reset {
right: 0;
}
#filter {
right: 4em;
}
#reset i {
transform: rotate(45deg);
}
#filters label {
font-weight: normal;
padding: 0 0.25em;
}
#filters strong {
display: block;
}
#filters hr {
margin: 0.25em 0;
}
@Gabber
Copy link

Gabber commented May 30, 2016

Hi your handlebar reference in the index.html file seems broken (line 39), you can update it with
https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.js
I've forked to try and seems to work as expected (usually i would make a pull request but gist don't support them), thanks for the example anyway!

@Albertbut
Copy link

Hey I am newbee to use this, with database record of relations how to use in asp.net.
Can you help on this?
Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment