Permalink
Cannot retrieve contributors at this time
231 lines (196 sloc)
7.4 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
| --- | |
| title: Venn Diagram Generator | |
| layout: page | |
| --- | |
| <!-- THIS FILE IS NOT COVERED BY THE LICENSE IN THIS REPOSITORY! --> | |
| <!-- This page is a modification of: https://www.inf.ed.ac.uk/teaching/courses/inf1/cl/tools/venn/ --> | |
| <!-- The creator of this page is unknown. Please send an email to the repository owner if you would like this taken down. --> | |
| <style> | |
| circle.light.amber.on{fill:yellow} | |
| circle.light.red.on{fill:red} | |
| circle.light.green.on{fill:green} | |
| /*body { | |
| font: 12pt sans-serif; | |
| }*/ | |
| #vennimage { width:20%; float:left;} | |
| hr {clear:both} | |
| i {font-weight:lighter} | |
| code {font-size:14pt;font-style:normal} | |
| circle { stroke:black;stroke-width:3pt; fill: none;} | |
| circle.universe {stroke-width:5pt;} | |
| path {stroke:black; fill: none;fill-rule:evenodd;} | |
| path.true {fill:red} | |
| input[type=text] {width:500px} | |
| input:invalid { color:red } | |
| </style> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.7/d3.min.js" charset="utf-8"></script> | |
| <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> | |
| <section> | |
| <p>This is a tool for exploring Venn diagrams. It is based on <a href="https://www.inf.ed.ac.uk/teaching/courses/inf1/cl/tools/venn/">the official tool provided by The School of Informatics</a>.</p> | |
| <br> | |
| <p><strong>Heads up!</strong> Only WebKit based browsers (Chrome, Safari, Opera, etc) are supported.</p> | |
| <h3>Instructions</h3> | |
| <p><a href="https://betterinformatics.com/resources/inf1-cl/venn/venn.png">This diagram</a> shows the state represented by each region.</p> | |
| <p>Your boolean expression is parsed as JavaScript, and so must be written in valid <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">JS syntax</a>. However, to make things convenient, words like "AND" are automatically converted to the JavaScript equivalents.</p> | |
| Here's a quick overview (note, lowercase equivalents are valid): | |
| <ul> | |
| <li> | |
| The three propositional letters: | |
| <span class="label label-danger">R</span> | |
| <span class="label label-warning">A</span> | |
| <span class="label label-success">G</span> (may also be written as "red", etc.) | |
| </li> | |
| <li>∨: | |
| <span class="label label-info">or</span> | |
| <span class="label label-info">||</span> | |
| </li> | |
| <li>∧: | |
| <span class="label label-info">and</span> | |
| <span class="label label-info">&&</span> | |
| </li> | |
| <li>¬: | |
| <span class="label label-info">not</span> | |
| <span class="label label-info">!</span> | |
| </li> | |
| <li>T: | |
| <span class="label label-info">true</span> | |
| <span class="label label-info">1</span> | |
| <span class="label label-info">T</span> | |
| </li> | |
| <li>⊥: | |
| <span class="label label-info">false</span> | |
| <span class="label label-info">0</span> | |
| <span class="label label-info">F</span> | |
| </li> | |
| <li>⊕: | |
| <span class="label label-info">xor</span> | |
| <span class="label label-info">^</span> | |
| </li> | |
| <li>↔ (if and only if): | |
| <span class="label label-info">iff</span> | |
| <span class="label label-info">==</span> | |
| </li> | |
| <li> | |
| The <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator"> | |
| ternary operator</a> | |
| <code>A ? B : C</code> essentially represents <code>if A then B else C</code> | |
| </li> | |
| </ul> | |
| </section> | |
| <section style="text-align: center;"> | |
| <h3 style="text-align: left">Output</h3> | |
| <div id="errs" style="display: none; text-align: left; color: red;"></div> | |
| <form> | |
| <input type="text" id="prop" | |
| inputmode="verbatim" | |
| pattern="((\|\|)|(&&)|(==)|([aA][Nn][dD])|([rR][Ee][Dd])|([Aa][Mm][Bb][Ee][Rr])|([Gg][Rr][Ee][Ee][Nn])|([Ii][Ff][Ff])|([Xx]?[Oo][Rr])|([Nn][Oo][Tt])|[RrAaGgTtFf!01^ ()?:]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])*" | |
| placeholder="type your expression here" autofocus> | |
| <input type="submit" value="render" onclick="return renderDiagram()"> | |
| </form> | |
| <br> | |
| <svg width="256" height="256"> </svg> | |
| </section> | |
| <script type="text/javascript"> | |
| const x = 256; | |
| const I = 128; | |
| const R = 2 * I; | |
| const R3 = I * Math.sqrt(3); | |
| const circles = { red: [-I,-R3/3], amber: [I, -R3/3], green: [0, 2*R3/3] }; | |
| const s0 = [R,0], | |
| s1 = [-I, R3], | |
| s2 = [-I, -R3]; | |
| function onClick(){ | |
| var d = (X,Y) => Math.sqrt(Math.pow(X[0]-Y[0],2) + Math.pow(X[1]-Y[1],2)); | |
| for (light in circles){ | |
| d3.selectAll("circle.light." + light) | |
| .classed("on",d(circles[light],[d3.event.clientX-512,d3.event.clientY-512]) < R) | |
| console.log(light + d(circles[light],[d3.event.clientX-512,d3.event.clientY-512])); | |
| } | |
| } | |
| var double = (xy) => [2*xy[0],2*xy[1]]; | |
| var neg = (xy) => [-xy[0],-xy[1]]; | |
| var move = (d) => "M" + d.m + (d.c.map((xy) => " a" + [[R,R] , 0, xy[1], xy[0]].join(", "))) + (d.neg == 1 ? ("M" +[0,3.5*I]+ "a" + [3*I ,3*I ,0,0,0,0,-7*I] + "a" + [3*I ,3*I ,0,0,0,0,7*I]) : ""); | |
| var svg = d3.select("svg") | |
| .on('click', onClick) | |
| .selectAll("g") | |
| .data(d3.range(1)) | |
| .enter() | |
| .append("g") | |
| .attr("id", d=> "g"+d) | |
| .attr("transform", d => "translate(" + [(0.5+d) * x, 0.5 * x] +")scale(0.25)") | |
| .call(venn) | |
| function venn(svg){ | |
| svg.selectAll("circle.prop") | |
| .data( ["red","amber","green"]) | |
| .enter() | |
| .append("circle") | |
| .attr("class", d => d) | |
| .classed("prop",true) | |
| .attr("cx", d => circles[d][0]) | |
| .attr("cy", d => circles[d][1]) | |
| .attr("r", R) | |
| svg.append("circle") | |
| .attr("cx", 0) | |
| .attr("cy",0) | |
| .attr("r", 3.5*I) | |
| .classed("universe",true) | |
| // svg.selectAll("circle.light") | |
| // .data(["red","amber","green"]) | |
| // .enter() | |
| // .append("circle") | |
| // .attr("class", d => d) | |
| // .classed("light",true) | |
| // .attr("r", 40) | |
| // .attr("cx", 60-512) | |
| // .attr("cy",(d,i) => 60 + 90*i -512) | |
| svg | |
| .selectAll("path") | |
| .data([{m:[-I,-R3/3],c:[[s0,[0,1]],[s1,[0,1]],[s2,[0,1]]],neg:0,id:"111"}, | |
| {m:[R,2*R3/3],c:[[s2,[0,0]],[s1,[0,1]],[s0,[0,0]]],neg:0,id:"011"}, | |
| {m:[-R,2*R3/3],c:[[neg(s1),[0,1]],[neg(s2),[0,0]],[neg(s0),[0,1]]],neg:0,id:"101"}, | |
| {m:[-I,-R3/3],c:[[s0,[0,1]],[s2,[0,0]],[s1,[0,0]]],neg:0,id:"110"}, | |
| {m:[0,2*R3/3],c:[[s0,[0,0]],[double(neg(s0)),[1,1]],[s0,[0,0]]],neg:0,id:"001"}, | |
| {m:[-I,-R3/3],c:[[s1,[0,0]],[double(neg(s1)),[1,1]],[s1,[0,0]]],neg:0,id:"100"}, | |
| {m:[I,-R3/3],c:[[s2,[0,0]],[double(neg(s2)),[1,1]],[s2,[0,0]]],neg:0,id:"010"}, | |
| {m:[R,2*R3/3],c:[[double((s2)),[0,0]],[double((s1)),[0,0]],[double((s0)),[0,0]]],neg:1,id:"000"} | |
| ]) | |
| .enter() | |
| .append("path") | |
| .attr("d",move) | |
| } | |
| function bval (expression, id) { | |
| var r = red = id.charAt(0) == 1; | |
| var a = amber = id.charAt(1) == 1; | |
| var g = green = id.charAt(2) == 1; | |
| var t = 1; | |
| var f = 0; | |
| return eval(expression.toString()); | |
| } | |
| function renderDiagram(ev) { | |
| var expression = document.getElementById("prop").value.toLowerCase(); | |
| expression = replaceAll(expression, "and", "&&") | |
| expression = replaceAll(expression, "xor", "^") | |
| expression = replaceAll(expression, "or", "||") | |
| expression = replaceAll(expression, "not", "!") | |
| expression = replaceAll(expression, "iff", "==") | |
| console.log("Expression", expression); | |
| try { | |
| bval(expression, "000"); | |
| } catch (e) { | |
| $("#errs").show() | |
| $("#errs").html("<strong>" + e.name + ":</strong> " + e.message) | |
| return false; | |
| } | |
| $("#errs").hide() | |
| d3.selectAll("#g0 path").classed("true", d => { | |
| // console.log({e:expression,id: d.id, v:bval(expression, d.id)}); | |
| return bval (expression, d.id); | |
| } | |
| ); | |
| return false; | |
| } | |
| function replaceAll(str, find, replace) { | |
| const escaped = find.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); | |
| return str.replace(new RegExp(escaped, 'g'), replace); | |
| } | |
| </script> |