chore: Switch formatter.
This commit is contained in:
parent
bd5bdb9cd0
commit
b86deafefd
583
lib/\
583
lib/\
|
@ -1,583 +0,0 @@
|
|||
/* Imports */
|
||||
import Head from "next/head";
|
||||
import React, { useState } from "react";
|
||||
import { DrawGraph, removeOldSvg } from "./labeledGraph";
|
||||
import { SubmitSliderButton } from "./slider";
|
||||
import { DisplayElement } from "./displayElement";
|
||||
import { DisplayAsMarkdown } from "./displayAsMarkdown";
|
||||
import { CreateTable, buildRows } from "./findPaths";
|
||||
import { DataSetChanger } from "./datasetChanger";
|
||||
import { ComparisonsChanger } from "./comparisonsChanger";
|
||||
import { pushToMongo } from "./pushToMongo.js";
|
||||
import {
|
||||
increasingList,
|
||||
maxMergeSortSteps,
|
||||
expectedNumMergeSortSteps,
|
||||
conservativeNumMergeSortSteps,
|
||||
} from "./utils.js";
|
||||
|
||||
/* DEFINTIONS */
|
||||
const DEFAULT_COMPARE = () => 1; // 1/Math.random() - 1
|
||||
|
||||
/* Misc. helpers */
|
||||
let buildLinks = (quantitativeComparisons) =>
|
||||
quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({
|
||||
source: element1,
|
||||
target: element2,
|
||||
distance: distance,
|
||||
reasoning: reasoning,
|
||||
}));
|
||||
|
||||
Array.prototype.containsArray = function (val) {
|
||||
var hash = {};
|
||||
for (var i = 0; i < this.length; i++) {
|
||||
hash[this[i]] = i;
|
||||
}
|
||||
return hash.hasOwnProperty(val);
|
||||
};
|
||||
|
||||
let checkIfListIsOrdered = (arr, binaryComparisons) => {
|
||||
let l = arr.length;
|
||||
let isOrdered = true;
|
||||
for (let i = 0; i < l - 1; i++) {
|
||||
isOrdered =
|
||||
isOrdered && binaryComparisons.containsArray([arr[i], arr[i + 1]]);
|
||||
}
|
||||
return isOrdered;
|
||||
};
|
||||
|
||||
let nicelyFormatLinks = (quantitativeComparisons, listOfElements) =>
|
||||
quantitativeComparisons.map(([element1, element2, distance, reasoning]) => ({
|
||||
source: listOfElements[element1].name,
|
||||
target: listOfElements[element2].name,
|
||||
distance: distance,
|
||||
reasoning: reasoning,
|
||||
}));
|
||||
|
||||
// Main react component
|
||||
export default function ComparisonView({ listOfElementsForView }) {
|
||||
/* State */
|
||||
// initial state values
|
||||
let initialListOfElements = listOfElementsForView.map((element, i) => ({
|
||||
...element,
|
||||
id: i,
|
||||
}));
|
||||
let initialPosList = increasingList(listOfElementsForView.length); // [0,1,2,3,4]
|
||||
let initialComparePair = [
|
||||
initialPosList[initialPosList.length - 2],
|
||||
initialPosList[initialPosList.length - 1],
|
||||
];
|
||||
let initialSliderValue = 1;
|
||||
let initialReasoning = "";
|
||||
let initialBinaryComparisons = [];
|
||||
let initialQuantitativeComparisons = [];
|
||||
let initialIsListOdered = false;
|
||||
let initialOrderedList = [];
|
||||
let initialShowAdvancedOptions = false;
|
||||
let initialShowComparisons = false;
|
||||
let initialShowLoadComparisons = false;
|
||||
let initialShowChangeDataSet = false;
|
||||
let initialNumSteps = 0;
|
||||
let initialMaxSteps = maxMergeSortSteps(listOfElementsForView.length);
|
||||
let initialExpectedSteps = expectedNumMergeSortSteps(
|
||||
listOfElementsForView.length
|
||||
);
|
||||
let initialTableRows = [];
|
||||
let initialDontPushSubmitButtonAnyMore = false;
|
||||
|
||||
// state variables and functions
|
||||
const [listOfElements, setListOfElements] = useState(initialListOfElements);
|
||||
const [posList, setPosList] = useState(initialPosList);
|
||||
const [toComparePair, setToComparePair] = useState(initialComparePair);
|
||||
const [sliderValue, setSliderValue] = useState(initialSliderValue);
|
||||
const [reasoning, setReasoning] = useState(initialReasoning);
|
||||
const [binaryComparisons, setBinaryComparisons] = useState(
|
||||
initialBinaryComparisons
|
||||
);
|
||||
const [quantitativeComparisons, setQuantitativeComparisons] = useState(
|
||||
initialQuantitativeComparisons
|
||||
); // More expressive, but more laborious to search through. For the ordering step, I only manipulate the binaryComparisons.
|
||||
|
||||
const [isListOrdered, setIsListOrdered] = useState(initialIsListOdered);
|
||||
const [orderedList, setOrderedList] = useState(initialOrderedList);
|
||||
const [dontPushSubmitButtonAnyMore, setDontPushSubmitButtonAnyMore] =
|
||||
useState(initialDontPushSubmitButtonAnyMore);
|
||||
|
||||
let [showAdvancedOptions, changeShowAdvanceOptions] = useState(
|
||||
initialShowAdvancedOptions
|
||||
);
|
||||
let [showComparisons, changeShowComparisons] = useState(
|
||||
initialShowComparisons
|
||||
);
|
||||
let [showLoadComparisons, changeShowLoadComparisons] = useState(
|
||||
initialShowLoadComparisons
|
||||
);
|
||||
let [showChangeDataSet, changeshowChangeDataSet] = useState(
|
||||
initialShowChangeDataSet
|
||||
);
|
||||
let [numSteps, changeNumSteps] = useState(initialNumSteps);
|
||||
let [maxSteps, changeMaxSteps] = useState(initialMaxSteps);
|
||||
let [expectedSteps, changeExpectedSteps] = useState(initialExpectedSteps);
|
||||
let [tableRows, setTableRows] = useState(initialTableRows);
|
||||
|
||||
/* Convenience utils: restart + changeDataSet */
|
||||
let restart = (
|
||||
posList,
|
||||
initialBinaryComparisons2,
|
||||
initialQuantitativeComparisons2
|
||||
) => {
|
||||
//({posList, initialBinaryComparisons2, initialQuantitativeComparisons2}) => {
|
||||
setToComparePair([
|
||||
posList[posList.length - 2],
|
||||
posList[posList.length - 1],
|
||||
]);
|
||||
setSliderValue(initialSliderValue);
|
||||
setBinaryComparisons(initialBinaryComparisons2 || initialBinaryComparisons);
|
||||
setQuantitativeComparisons(
|
||||
initialQuantitativeComparisons2 || initialQuantitativeComparisons
|
||||
);
|
||||
setIsListOrdered(initialIsListOdered);
|
||||
setOrderedList(initialOrderedList);
|
||||
changeNumSteps(initialNumSteps);
|
||||
removeOldSvg();
|
||||
setTableRows(initialTableRows);
|
||||
setDontPushSubmitButtonAnyMore(initialDontPushSubmitButtonAnyMore);
|
||||
};
|
||||
|
||||
let changeDataSet = (listOfElementsNew) => {
|
||||
listOfElementsNew = listOfElementsNew.map((element, i) => ({
|
||||
...element,
|
||||
id: i,
|
||||
}));
|
||||
let newPosList = increasingList(listOfElementsNew.length);
|
||||
let newListLength = listOfElementsNew.length;
|
||||
|
||||
setListOfElements(listOfElementsNew);
|
||||
setPosList(increasingList(listOfElementsNew.length));
|
||||
setToComparePair([
|
||||
newPosList[newPosList.length - 2],
|
||||
newPosList[newPosList.length - 1],
|
||||
]);
|
||||
|
||||
changeExpectedSteps(expectedNumMergeSortSteps(newListLength));
|
||||
changeMaxSteps(maxMergeSortSteps(newListLength));
|
||||
|
||||
restart(newPosList);
|
||||
// restart({posList: newPosList})
|
||||
};
|
||||
|
||||
let changeComparisons = async (links) => {
|
||||
let quantitativeComparisons2 = [];
|
||||
let binaryComparisons2 = [];
|
||||
links.shift();
|
||||
for (let link of links) {
|
||||
let { source, target, distance, reasoning } = link;
|
||||
let searchByName = (name, candidate) => candidate.name == name;
|
||||
let testForSource = (candidate) => searchByName(source, candidate);
|
||||
let testForTarget = (candidate) => searchByName(target, candidate);
|
||||
let element1 = listOfElements.findIndex(testForSource);
|
||||
let element2 = listOfElements.findIndex(testForTarget);
|
||||
if (element1 == -1 || element2 == -1) {
|
||||
console.log("link", link);
|
||||
console.log(source);
|
||||
console.log(target);
|
||||
throw new Error("Comparisons include unknown elements, please retry");
|
||||
}
|
||||
quantitativeComparisons2.push([element1, element2, distance, reasoning]);
|
||||
binaryComparisons2.push([element1, element2]);
|
||||
}
|
||||
// return ({quantitativeComparisons: quantitativeComparisons2, binaryComparisons: binaryComparisons2})
|
||||
//restart({posList, initialBinaryComparisons2=initialBinaryComparisons, initialQuantitativeComparisons2=initialQuantitativeComparisons})
|
||||
// restart(posList, binaryComparisons2, quantitativeComparisons2)
|
||||
setQuantitativeComparisons(quantitativeComparisons2);
|
||||
setBinaryComparisons(binaryComparisons2);
|
||||
};
|
||||
|
||||
// Manipulations
|
||||
let compareTwoElements = (newBinaryComparisons, element1, element2) => {
|
||||
let element1Greater = newBinaryComparisons.containsArray([
|
||||
element1,
|
||||
element2,
|
||||
]);
|
||||
let element2Greater = newBinaryComparisons.containsArray([
|
||||
element2,
|
||||
element1,
|
||||
]);
|
||||
if (element1Greater || element2Greater) {
|
||||
return element1Greater && !element2Greater;
|
||||
} else {
|
||||
setToComparePair([element1, element2]);
|
||||
//console.log(`No comparison found between ${element1} and ${element2}`)
|
||||
//console.log(`Comparisons:`)
|
||||
//console.log(JSON.stringify(newBinaryComparisons, null, 4));
|
||||
return "No comparison found";
|
||||
}
|
||||
};
|
||||
|
||||
function merge(newBinaryComparisons, left, right) {
|
||||
let sortedArr = []; // the sorted elements will go here
|
||||
|
||||
while (left.length && right.length) {
|
||||
// insert the biggest element to the sortedArr
|
||||
let comparison = compareTwoElements(
|
||||
newBinaryComparisons,
|
||||
left[0],
|
||||
right[0]
|
||||
);
|
||||
if (comparison == "No comparison found") {
|
||||
return "No comparison found; unable to proceed";
|
||||
} else if (comparison) {
|
||||
// left[0] > right[0]
|
||||
sortedArr.push(left.shift());
|
||||
} else {
|
||||
sortedArr.push(right.shift());
|
||||
}
|
||||
}
|
||||
|
||||
// use spread operator and create a new array, combining the three arrays
|
||||
return [...sortedArr, ...left, ...right]; // if they don't have the same size, the remaining ones will be greater than the ones before
|
||||
}
|
||||
|
||||
function mergeSort({ array, comparisons }) {
|
||||
if (array == "No comparison found; unable to proceed") {
|
||||
return "No comparison found; unable to proceed";
|
||||
}
|
||||
const half = array.length / 2;
|
||||
|
||||
// the base case is array length <=1
|
||||
if (array.length <= 1) {
|
||||
return array;
|
||||
}
|
||||
|
||||
const left = array.slice(0, half); // the first half of the array
|
||||
const right = array.slice(half, array.length); // Note that splice is destructive.
|
||||
let orderedFirstHalf = mergeSort({ array: left, comparisons });
|
||||
let orderedSecondHalf = mergeSort({ array: right, comparisons });
|
||||
if (
|
||||
orderedFirstHalf != "No comparison found; unable to proceed" &&
|
||||
orderedSecondHalf != "No comparison found; unable to proceed"
|
||||
) {
|
||||
let result = merge(comparisons, orderedFirstHalf, orderedSecondHalf);
|
||||
return result;
|
||||
} else {
|
||||
return "No comparison found; unable to proceed";
|
||||
}
|
||||
}
|
||||
|
||||
let nextStepSimple = (posList, binaryComparisons, element1, element2) => {
|
||||
//console.log("Binary comparisons: ")
|
||||
//console.log(JSON.stringify(binaryComparisons, null, 4));
|
||||
|
||||
let newComparison = [element1, element2]; // [element1, element2]
|
||||
let newBinaryComparisons = [...binaryComparisons, newComparison];
|
||||
//console.log("New binaryComparisons: ")
|
||||
//console.log(JSON.stringify(newBinaryComparisons, null, 4));
|
||||
setBinaryComparisons(newBinaryComparisons);
|
||||
|
||||
let result = mergeSort({
|
||||
array: posList,
|
||||
comparisons: newBinaryComparisons,
|
||||
});
|
||||
//console.log(result)
|
||||
if (
|
||||
result != "No comparison found; unable to proceed" &&
|
||||
checkIfListIsOrdered(result, newBinaryComparisons)
|
||||
) {
|
||||
// console.log(`isListOrdered: ${isListOrdered}`)
|
||||
console.log("poslist@nextStepSimple");
|
||||
console.log(posList);
|
||||
console.log("result@nextStepSimple");
|
||||
console.log(result);
|
||||
|
||||
return [true, result];
|
||||
} else {
|
||||
return [false, result];
|
||||
}
|
||||
};
|
||||
|
||||
let nextStepSlider = async ({
|
||||
posList,
|
||||
binaryComparisons,
|
||||
sliderValue,
|
||||
reasoning,
|
||||
element1,
|
||||
element2,
|
||||
}) => {
|
||||
if (!dontPushSubmitButtonAnyMore) {
|
||||
if (sliderValue < 1 && sliderValue > 0) {
|
||||
sliderValue = 1 / sliderValue;
|
||||
[element1, element2] = [element2, element1];
|
||||
}
|
||||
console.log(`posList@nextStepSlider:`);
|
||||
console.log(posList);
|
||||
let [successStatus, result] = nextStepSimple(
|
||||
posList,
|
||||
binaryComparisons,
|
||||
element1,
|
||||
element2
|
||||
);
|
||||
|
||||
let newQuantitativeComparison = [
|
||||
element1,
|
||||
element2,
|
||||
sliderValue,
|
||||
reasoning,
|
||||
];
|
||||
let newQuantitativeComparisons = [
|
||||
...quantitativeComparisons,
|
||||
newQuantitativeComparison,
|
||||
];
|
||||
setQuantitativeComparisons(newQuantitativeComparisons);
|
||||
|
||||
setSliderValue(DEFAULT_COMPARE());
|
||||
setReasoning("");
|
||||
changeNumSteps(numSteps + 1);
|
||||
if (successStatus) {
|
||||
setDontPushSubmitButtonAnyMore(true);
|
||||
|
||||
let jsObject = nicelyFormatLinks(
|
||||
quantitativeComparisons,
|
||||
listOfElements
|
||||
);
|
||||
await pushToMongo(jsObject);
|
||||
console.log(jsObject);
|
||||
|
||||
alert(
|
||||
"Comparisons completed. Background work might take a while, or straight-out fail"
|
||||
);
|
||||
setIsListOrdered(true);
|
||||
setOrderedList(result);
|
||||
|
||||
await buildRows({
|
||||
isListOrdered: true,
|
||||
orderedList: result,
|
||||
listOfElements,
|
||||
links: buildLinks(newQuantitativeComparisons),
|
||||
rows: tableRows,
|
||||
setTableRows,
|
||||
});
|
||||
/*
|
||||
setTimeout(async () => {
|
||||
// Make sure to do this after the
|
||||
|
||||
}, 100);
|
||||
*/
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Html
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen py-2">
|
||||
{/* Webpage name & favicon */}
|
||||
<div className="mt-20">
|
||||
<Head>
|
||||
<title>Utility Function Extractor</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
</div>
|
||||
<main className="flex flex-col items-center w-full flex-1 px-20 text-center">
|
||||
{/* Heading */}
|
||||
<h1 className="text-6xl font-bold">Utility Function Extractor</h1>
|
||||
{/* Approximate progress indicator */}
|
||||
|
||||
<p>{`${numSteps} out of ~${expectedSteps} (max ${maxSteps}) comparisons`}</p>
|
||||
|
||||
{/* Comparison section */}
|
||||
<div className={isListOrdered ? "hidden" : ""}>
|
||||
<div className="flex flex-wrap items-center max-w-4xl sm:w-full mt-10">
|
||||
{/* Element 1 */}
|
||||
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
|
||||
<div className="block m-auto text-center">
|
||||
<DisplayElement
|
||||
element={listOfElements[toComparePair[0]]}
|
||||
></DisplayElement>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Comparison actuator (text, previously slider) */}
|
||||
<div className="flex m-auto w-72">
|
||||
<div className="block m-auto text-center">
|
||||
<br />
|
||||
<label>
|
||||
{`... is `}
|
||||
<br />
|
||||
<input
|
||||
type="number"
|
||||
className="text-center text-blueGray-600 bg-white rounded text-lg border-0 shadow outline-none focus:outline-none focus:ring w-8/12 h-10 m-2"
|
||||
value={sliderValue}
|
||||
onChange={(event) => {
|
||||
//console.log(event)
|
||||
//console.log(event.target.value)
|
||||
setSliderValue(event.target.value);
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
{`times as valuable as ...`}
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<SubmitSliderButton
|
||||
posList={posList}
|
||||
binaryComparisons={binaryComparisons}
|
||||
sliderValue={sliderValue}
|
||||
reasoning={reasoning}
|
||||
toComparePair={toComparePair}
|
||||
nextStepSlider={nextStepSlider}
|
||||
dontPushSubmitButtonAnyMore={dontPushSubmitButtonAnyMore}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Element 2 */}
|
||||
<div className="flex m-auto border-gray-300 border-4 h-72 w-72 p-5">
|
||||
<div className="block m-auto text-center">
|
||||
<DisplayElement
|
||||
element={listOfElements[toComparePair[1]]}
|
||||
></DisplayElement>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<label className="">
|
||||
Reasoning (optional):
|
||||
<textarea
|
||||
className="mt-2 px-3 py-4 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-base border-0 shadow outline-none focus:outline-none focus:ring w-full"
|
||||
value={reasoning}
|
||||
onChange={(event) => setReasoning(event.target.value)}
|
||||
/>
|
||||
</label>
|
||||
<br />
|
||||
<div></div>
|
||||
{/* Old slider element (previous actuator)
|
||||
|
||||
<div className={`flex row-start-3 row-end-3 col-start-1 col-end-4 md:col-start-3 md:col-end-3 md:row-start-1 md:row-end-1 lg:col-start-3 lg:col-end-3 lg:row-start-1 lg:row-end-1 items-center justify-center mb-4 mt-10 ${isListOrdered ? "hidden" : ""}`}>
|
||||
<SliderElement
|
||||
className="flex items-center justify-center"
|
||||
onChange={(event) => (setSliderValue(event[0]))}
|
||||
value={sliderValue}
|
||||
displayFunction={displayFunctionSlider}
|
||||
domain={domain}
|
||||
/>
|
||||
</div>
|
||||
*/}
|
||||
</div>
|
||||
|
||||
{/* Results section */}
|
||||
<div className={isListOrdered ? "" : "hidden"}>
|
||||
{/* Graph */}
|
||||
<div className="flex items-center text-center ">
|
||||
<DrawGraph
|
||||
isListOrdered={isListOrdered}
|
||||
orderedList={orderedList}
|
||||
listOfElements={listOfElements}
|
||||
links={buildLinks(quantitativeComparisons)}
|
||||
></DrawGraph>
|
||||
</div>
|
||||
|
||||
{/* Comparison table */}
|
||||
<div className="flex items-center text-center ">
|
||||
<CreateTable
|
||||
isListOrdered={isListOrdered}
|
||||
orderedList={orderedList}
|
||||
listOfElements={listOfElements}
|
||||
links={buildLinks(quantitativeComparisons)}
|
||||
tableRows={tableRows}
|
||||
setTableRows={setTableRows}
|
||||
></CreateTable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Convenience functions */}
|
||||
<div className="w-2/12 flex justify-center mt-10">
|
||||
<button
|
||||
className="text-gray-500 text-sm"
|
||||
onClick={() => changeShowAdvanceOptions(!showAdvancedOptions)}
|
||||
>
|
||||
Advanced options ▼
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={
|
||||
showAdvancedOptions
|
||||
? "flex flex-wrap -mx-4 overflow-hidden"
|
||||
: "hidden"
|
||||
}
|
||||
>
|
||||
{/* Button: Restart */}
|
||||
<div className="my-4 px-4 w-1/4 overflow-hidden">
|
||||
<button
|
||||
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
|
||||
onClick={() => restart(posList)}
|
||||
>
|
||||
{/* onClick={() => restart({posList})}> */}
|
||||
Restart
|
||||
</button>
|
||||
</div>
|
||||
{/* Button: Show comparisons */}
|
||||
<div className="my-4 px-4 w-1/4 overflow-hidden">
|
||||
<button
|
||||
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
|
||||
onClick={() => changeShowComparisons(!showComparisons)}
|
||||
>
|
||||
Show comparisons
|
||||
</button>
|
||||
</div>
|
||||
{/* Button: Load comparisons */}
|
||||
<div className="my-4 px-4 w-1/4 overflow-hidden">
|
||||
<button
|
||||
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
|
||||
onClick={() => changeShowLoadComparisons(!showLoadComparisons)}
|
||||
>
|
||||
Load comparisons
|
||||
</button>
|
||||
</div>
|
||||
{/* Button: Change dataset */}
|
||||
<div className="my-4 px-4 w-1/4 overflow-hidden">
|
||||
<button
|
||||
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
|
||||
onClick={() => changeshowChangeDataSet(!showChangeDataSet)}
|
||||
>
|
||||
Use your own data
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/* Change dataset section */}
|
||||
<div className={showChangeDataSet ? "inline mt-5" : "hidden"}>
|
||||
<DataSetChanger handleSubmit={changeDataSet} />
|
||||
</div>
|
||||
|
||||
{/* Show comparisons section */}
|
||||
<div className={showComparisons ? "inline mt-5" : "hidden"}>
|
||||
<div className="text-left">
|
||||
<DisplayAsMarkdown
|
||||
markdowntext={`
|
||||
${
|
||||
"" /*
|
||||
## Comparisons
|
||||
### Binary comparisons
|
||||
${JSON.stringify(binaryComparisons, null, 4)}
|
||||
*/
|
||||
}
|
||||
### Numerical comparisons
|
||||
${JSON.stringify(
|
||||
nicelyFormatLinks(quantitativeComparisons, listOfElements),
|
||||
null,
|
||||
4
|
||||
)}
|
||||
`}
|
||||
className={""}
|
||||
></DisplayAsMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
{/* Load comparisons section */}
|
||||
<div className={showLoadComparisons ? "inline mt-5" : "hidden"}>
|
||||
<ComparisonsChanger handleSubmit={changeComparisons} />
|
||||
{/*<ComparisonsChanger handleSubmit={changeComparisons} />*/}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,38 +1,39 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useState } from "react";
|
||||
|
||||
export function ComparisonsChanger({handleSubmit}){
|
||||
export function ComparisonsChanger({ handleSubmit }) {
|
||||
// let defaultText=JSON.stringify(nicelyFormatLinks(quantitativeComparisons, listOfElements), null, 4)
|
||||
|
||||
let [value, setValue] = useState(``)
|
||||
const [displayingDoneMessage, setDisplayingDoneMessage] = useState(false)
|
||||
const [displayingDoneMessageTimer, setDisplayingDoneMessageTimer] = useState(null)
|
||||
let [value, setValue] = useState(``);
|
||||
const [displayingDoneMessage, setDisplayingDoneMessage] = useState(false);
|
||||
const [displayingDoneMessageTimer, setDisplayingDoneMessageTimer] =
|
||||
useState(null);
|
||||
|
||||
let handleChange = (event) => {
|
||||
setValue(event.target.value)
|
||||
}
|
||||
setValue(event.target.value);
|
||||
};
|
||||
|
||||
let handleSubmitInner = (event) => {
|
||||
clearTimeout(displayingDoneMessageTimer)
|
||||
clearTimeout(displayingDoneMessageTimer);
|
||||
event.preventDefault();
|
||||
//console.log(event)
|
||||
console.log("value@handleSubmitInner@ComparisonsChanger")
|
||||
console.log("value@handleSubmitInner@ComparisonsChanger");
|
||||
//console.log(typeof(value));
|
||||
console.log(value);
|
||||
try{
|
||||
let newData = JSON.parse(value)
|
||||
try {
|
||||
let newData = JSON.parse(value);
|
||||
//console.log(typeof(newData))
|
||||
//console.log(newData)
|
||||
handleSubmit(newData)
|
||||
handleSubmit(newData);
|
||||
/*
|
||||
if(!newData.length || newData.length < 2){
|
||||
throw Error("Not enough objects")
|
||||
}
|
||||
*/
|
||||
setDisplayingDoneMessage(true)
|
||||
setDisplayingDoneMessage(true);
|
||||
let timer = setTimeout(() => setDisplayingDoneMessage(false), 3000);
|
||||
setDisplayingDoneMessageTimer(timer)
|
||||
}catch(error){
|
||||
setDisplayingDoneMessage(false)
|
||||
setDisplayingDoneMessageTimer(timer);
|
||||
} catch (error) {
|
||||
setDisplayingDoneMessage(false);
|
||||
//alert(error)
|
||||
//console.log(error)
|
||||
let substituteText = `Error: ${error.message}
|
||||
|
@ -59,35 +60,40 @@ Try something like:
|
|||
}
|
||||
]
|
||||
|
||||
Your old input was: ${value}`
|
||||
setValue(substituteText)
|
||||
Your old input was: ${value}`;
|
||||
setValue(substituteText);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
return (
|
||||
<form onSubmit={handleSubmitInner} className="inline">
|
||||
<p>Load comparisons in the same style as in "Show comparisons".</p>
|
||||
<p>These will override your current comparisons.</p>
|
||||
<br/>
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
rows="10" cols="50"
|
||||
<br />
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
rows="10"
|
||||
cols="50"
|
||||
className=""
|
||||
/>
|
||||
<br/>
|
||||
<button
|
||||
<br />
|
||||
<button
|
||||
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5 p-10"
|
||||
onClick={handleSubmitInner}>
|
||||
onClick={handleSubmitInner}
|
||||
>
|
||||
Change comparisons
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={displayingDoneMessage ? "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5 p-10" : "hidden"}
|
||||
className={
|
||||
displayingDoneMessage
|
||||
? "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5 p-10"
|
||||
: "hidden"
|
||||
}
|
||||
>
|
||||
Done!
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
518
lib/d3experiment.js
vendored
518
lib/d3experiment.js
vendored
|
@ -1,262 +1,280 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import * as d3 from 'd3';
|
||||
import * as d3 from "d3";
|
||||
|
||||
export function drawChart(height, width){
|
||||
|
||||
d3.select("#chart")
|
||||
.append("svg")
|
||||
.attr("width", width)
|
||||
.attr("height", height)
|
||||
.style("border", "1px solid black")
|
||||
.append("text")
|
||||
.attr("fill", "green")
|
||||
.attr("x", 50)
|
||||
.attr("y", 50)
|
||||
.text("Hello D3")
|
||||
}
|
||||
|
||||
export function drawCircles(){
|
||||
var svg = d3.select("#circles")
|
||||
.append("svg")
|
||||
.attr("width", 960)
|
||||
.attr("height", 500)
|
||||
.attr("bgcolor", "blue")
|
||||
|
||||
var background = svg.append("rect")
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("fill", "blue")
|
||||
|
||||
var ball = svg.append("circle")
|
||||
.attr("r", 73)
|
||||
.attr("cx", 480)
|
||||
.attr("cy", 250)
|
||||
.style("fill", "#ffe41e");
|
||||
}
|
||||
|
||||
export function drawGraph(){
|
||||
let margin = {top: 20, right: 30, bottom: 20, left: 30};
|
||||
let width = 900 - margin.left - margin.right;
|
||||
let height = 600 - margin.top - margin.bottom;
|
||||
|
||||
var svg = d3.select("#graph")
|
||||
.append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||
|
||||
let data = ({
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "B"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "C"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "D"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "E"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "F"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "G"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "H"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "I"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "J"
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
|
||||
{
|
||||
"source": 1,
|
||||
"target": 2
|
||||
},
|
||||
{
|
||||
"source": 1,
|
||||
"target": 5
|
||||
},
|
||||
{
|
||||
"source": 1,
|
||||
"target": 6
|
||||
},
|
||||
|
||||
{
|
||||
"source": 2,
|
||||
"target": 3
|
||||
},
|
||||
{
|
||||
"source": 2,
|
||||
"target": 7
|
||||
}
|
||||
,
|
||||
|
||||
{
|
||||
"source": 3,
|
||||
"target": 4
|
||||
},
|
||||
{
|
||||
"source": 8,
|
||||
"target": 3
|
||||
}
|
||||
,
|
||||
{
|
||||
"source": 4,
|
||||
"target": 5
|
||||
}
|
||||
,
|
||||
|
||||
{
|
||||
"source": 4,
|
||||
"target": 9
|
||||
},
|
||||
{
|
||||
"source": 5,
|
||||
"target": 10
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
console.log(data)
|
||||
// List of node names
|
||||
var allNodes = data.nodes.map(function(d){return d.name})
|
||||
|
||||
// A linear scale to position the nodes on the X axis
|
||||
var x = d3.scalePoint()
|
||||
.range([0, width])
|
||||
.domain(allNodes)
|
||||
|
||||
// Add the circle for the nodes
|
||||
svg
|
||||
.selectAll("mynodes")
|
||||
.data(data.nodes)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", function(d){ return(x(d.name))})
|
||||
.attr("cy", height-30)
|
||||
.attr("r", 8)
|
||||
.style("fill", "#69b3a2")
|
||||
|
||||
// And give them a label
|
||||
svg
|
||||
.selectAll("mylabels")
|
||||
.data(data.nodes)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", function(d){ return(x(d.name))})
|
||||
.attr("y", height-10)
|
||||
.text(function(d){ return(d.name)})
|
||||
.style("text-anchor", "middle")
|
||||
|
||||
// Add links between nodes. Here is the tricky part.
|
||||
// In my input data, links are provided between nodes -id-, NOT between node names.
|
||||
// So I have to do a link between this id and the name
|
||||
var idToNode = {};
|
||||
data.nodes.forEach(function (n) {
|
||||
idToNode[n.id] = n;
|
||||
});
|
||||
// Cool, now if I do idToNode["2"].name I've got the name of the node with id 2
|
||||
|
||||
// Add the links
|
||||
svg
|
||||
.selectAll('mylinks')
|
||||
.data(data.links)
|
||||
.enter()
|
||||
.append('path')
|
||||
.attr('d', function (d) {
|
||||
let start = x(idToNode[d.source].name)
|
||||
// X position of start node on the X axis
|
||||
let end = x(idToNode[d.target].name)
|
||||
// X position of end node
|
||||
return ['M',
|
||||
start,
|
||||
height-30,
|
||||
// the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
|
||||
'A',
|
||||
// This means we're gonna build an elliptical arc
|
||||
(start - end)/2, ',',
|
||||
// Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
|
||||
(start - end)/2, 0, 0, ',',
|
||||
start < end ? 1 : 0, end, ',', height-30]
|
||||
// We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
|
||||
.join(' ');
|
||||
})
|
||||
.style("fill", "none")
|
||||
.attr("stroke", "black")
|
||||
|
||||
// labels for links
|
||||
svg
|
||||
.selectAll('mylinks')
|
||||
.data(data.links)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", function(d){
|
||||
let start = x(idToNode[d.source].name)
|
||||
// X position of start node on the X axis
|
||||
let end = x(idToNode[d.target].name)
|
||||
// X position of end node
|
||||
return start + (end-start)/2
|
||||
})
|
||||
.attr("y", function(d){
|
||||
let start = x(idToNode[d.source].name)
|
||||
// X position of start node on the X axis
|
||||
let end = x(idToNode[d.target].name)
|
||||
// X position of end node
|
||||
return height-30-(Math.abs(start-end)/2)//height-30
|
||||
})
|
||||
.text(function(d){ return(`${idToNode[d.source].name}-${idToNode[d.target].name}`)})
|
||||
.style("text-anchor", "top")
|
||||
|
||||
svg.selectAll("text").data(data.links).enter()
|
||||
export function drawChart(height, width) {
|
||||
d3.select("#chart")
|
||||
.append("svg")
|
||||
.attr("width", width)
|
||||
.attr("height", height)
|
||||
.style("border", "1px solid black")
|
||||
.append("text")
|
||||
.attr("x", function(d) { return d.source.x + (d.target.x - d.source.x)/2; })
|
||||
.attr("y", function(d) { return d.source.y + (d.target.y - d.source.y)/2; })
|
||||
.text(function(d) { return d.something; });
|
||||
.attr("fill", "green")
|
||||
.attr("x", 50)
|
||||
.attr("y", 50)
|
||||
.text("Hello D3");
|
||||
}
|
||||
|
||||
export function drawCircles() {
|
||||
var svg = d3
|
||||
.select("#circles")
|
||||
.append("svg")
|
||||
.attr("width", 960)
|
||||
.attr("height", 500)
|
||||
.attr("bgcolor", "blue");
|
||||
|
||||
var background = svg
|
||||
.append("rect")
|
||||
.attr("width", "100%")
|
||||
.attr("height", "100%")
|
||||
.attr("fill", "blue");
|
||||
|
||||
var ball = svg
|
||||
.append("circle")
|
||||
.attr("r", 73)
|
||||
.attr("cx", 480)
|
||||
.attr("cy", 250)
|
||||
.style("fill", "#ffe41e");
|
||||
}
|
||||
|
||||
export function drawGraph() {
|
||||
let margin = { top: 20, right: 30, bottom: 20, left: 30 };
|
||||
let width = 900 - margin.left - margin.right;
|
||||
let height = 600 - margin.top - margin.bottom;
|
||||
|
||||
var svg = d3
|
||||
.select("#graph")
|
||||
.append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||
|
||||
let data = {
|
||||
nodes: [
|
||||
{
|
||||
id: 1,
|
||||
name: "A",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "B",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "C",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "D",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "E",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "F",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "G",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "H",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "I",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "J",
|
||||
},
|
||||
],
|
||||
links: [
|
||||
{
|
||||
source: 1,
|
||||
target: 2,
|
||||
},
|
||||
{
|
||||
source: 1,
|
||||
target: 5,
|
||||
},
|
||||
{
|
||||
source: 1,
|
||||
target: 6,
|
||||
},
|
||||
|
||||
{
|
||||
source: 2,
|
||||
target: 3,
|
||||
},
|
||||
{
|
||||
source: 2,
|
||||
target: 7,
|
||||
},
|
||||
{
|
||||
source: 3,
|
||||
target: 4,
|
||||
},
|
||||
{
|
||||
source: 8,
|
||||
target: 3,
|
||||
},
|
||||
{
|
||||
source: 4,
|
||||
target: 5,
|
||||
},
|
||||
{
|
||||
source: 4,
|
||||
target: 9,
|
||||
},
|
||||
{
|
||||
source: 5,
|
||||
target: 10,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
console.log(data);
|
||||
// List of node names
|
||||
var allNodes = data.nodes.map(function (d) {
|
||||
return d.name;
|
||||
});
|
||||
|
||||
// A linear scale to position the nodes on the X axis
|
||||
var x = d3.scalePoint().range([0, width]).domain(allNodes);
|
||||
|
||||
// Add the circle for the nodes
|
||||
svg
|
||||
.selectAll("mynodes")
|
||||
.data(data.nodes)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", function (d) {
|
||||
return x(d.name);
|
||||
})
|
||||
.attr("cy", height - 30)
|
||||
.attr("r", 8)
|
||||
.style("fill", "#69b3a2");
|
||||
|
||||
// And give them a label
|
||||
svg
|
||||
.selectAll("mylabels")
|
||||
.data(data.nodes)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", function (d) {
|
||||
return x(d.name);
|
||||
})
|
||||
.attr("y", height - 10)
|
||||
.text(function (d) {
|
||||
return d.name;
|
||||
})
|
||||
.style("text-anchor", "middle");
|
||||
|
||||
// Add links between nodes. Here is the tricky part.
|
||||
// In my input data, links are provided between nodes -id-, NOT between node names.
|
||||
// So I have to do a link between this id and the name
|
||||
var idToNode = {};
|
||||
data.nodes.forEach(function (n) {
|
||||
idToNode[n.id] = n;
|
||||
});
|
||||
// Cool, now if I do idToNode["2"].name I've got the name of the node with id 2
|
||||
|
||||
// Add the links
|
||||
svg
|
||||
.selectAll("mylinks")
|
||||
.data(data.links)
|
||||
.enter()
|
||||
.append("path")
|
||||
.attr("d", function (d) {
|
||||
let start = x(idToNode[d.source].name);
|
||||
// X position of start node on the X axis
|
||||
let end = x(idToNode[d.target].name);
|
||||
// X position of end node
|
||||
return (
|
||||
[
|
||||
"M",
|
||||
start,
|
||||
height - 30,
|
||||
// the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
|
||||
"A",
|
||||
// This means we're gonna build an elliptical arc
|
||||
(start - end) / 2,
|
||||
",",
|
||||
// Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
|
||||
(start - end) / 2,
|
||||
0,
|
||||
0,
|
||||
",",
|
||||
start < end ? 1 : 0,
|
||||
end,
|
||||
",",
|
||||
height - 30,
|
||||
]
|
||||
// We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
|
||||
.join(" ")
|
||||
);
|
||||
})
|
||||
.style("fill", "none")
|
||||
.attr("stroke", "black");
|
||||
|
||||
// labels for links
|
||||
svg
|
||||
.selectAll("mylinks")
|
||||
.data(data.links)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", function (d) {
|
||||
let start = x(idToNode[d.source].name);
|
||||
// X position of start node on the X axis
|
||||
let end = x(idToNode[d.target].name);
|
||||
// X position of end node
|
||||
return start + (end - start) / 2;
|
||||
})
|
||||
.attr("y", function (d) {
|
||||
let start = x(idToNode[d.source].name);
|
||||
// X position of start node on the X axis
|
||||
let end = x(idToNode[d.target].name);
|
||||
// X position of end node
|
||||
return height - 30 - Math.abs(start - end) / 2; //height-30
|
||||
})
|
||||
.text(function (d) {
|
||||
return `${idToNode[d.source].name}-${idToNode[d.target].name}`;
|
||||
})
|
||||
.style("text-anchor", "top");
|
||||
|
||||
svg
|
||||
.selectAll("text")
|
||||
.data(data.links)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", function (d) {
|
||||
return d.source.x + (d.target.x - d.source.x) / 2;
|
||||
})
|
||||
.attr("y", function (d) {
|
||||
return d.source.y + (d.target.y - d.source.y) / 2;
|
||||
})
|
||||
.text(function (d) {
|
||||
return d.something;
|
||||
});
|
||||
}
|
||||
|
||||
export function D3Experiment() {
|
||||
useEffect(() => {
|
||||
drawGraph();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
drawGraph();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id="chart">
|
||||
</div>
|
||||
<div id="circles">
|
||||
</div>
|
||||
<div id="graph">
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id="chart"></div>
|
||||
<div id="circles"></div>
|
||||
<div id="graph"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default D3Experiment;
|
||||
|
||||
export default D3Experiment;
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useState } from "react";
|
||||
|
||||
export function DataSetChanger({handleSubmit}){
|
||||
export function DataSetChanger({ handleSubmit }) {
|
||||
let [value, setValue] = useState(`[
|
||||
{
|
||||
"name": "Some element. The name field is necessary",
|
||||
|
@ -18,34 +18,35 @@ export function DataSetChanger({handleSubmit}){
|
|||
"isReferenceValue": true,
|
||||
"somethirdfield": "c"
|
||||
}
|
||||
]`)
|
||||
const [displayingDoneMessage, setDisplayingDoneMessage] = useState(false)
|
||||
const [displayingDoneMessageTimer, setDisplayingDoneMessageTimer] = useState(null)
|
||||
]`);
|
||||
const [displayingDoneMessage, setDisplayingDoneMessage] = useState(false);
|
||||
const [displayingDoneMessageTimer, setDisplayingDoneMessageTimer] =
|
||||
useState(null);
|
||||
|
||||
let handleChange = (event) => {
|
||||
setValue(event.target.value)
|
||||
}
|
||||
setValue(event.target.value);
|
||||
};
|
||||
|
||||
let handleSubmitInner = (event) => {
|
||||
clearTimeout(displayingDoneMessageTimer)
|
||||
clearTimeout(displayingDoneMessageTimer);
|
||||
event.preventDefault();
|
||||
//console.log(event)
|
||||
console.log("value@handleSubmitInner@DataSetChanger")
|
||||
console.log("value@handleSubmitInner@DataSetChanger");
|
||||
//console.log(typeof(value));
|
||||
console.log(value);
|
||||
try{
|
||||
let newData = JSON.parse(value)
|
||||
try {
|
||||
let newData = JSON.parse(value);
|
||||
//console.log(typeof(newData))
|
||||
//console.log(newData)
|
||||
handleSubmit(newData)
|
||||
if(!newData.length || newData.length < 2){
|
||||
throw Error("Not enough objects")
|
||||
handleSubmit(newData);
|
||||
if (!newData.length || newData.length < 2) {
|
||||
throw Error("Not enough objects");
|
||||
}
|
||||
setDisplayingDoneMessage(true)
|
||||
setDisplayingDoneMessage(true);
|
||||
let timer = setTimeout(() => setDisplayingDoneMessage(false), 3000);
|
||||
setDisplayingDoneMessageTimer(timer)
|
||||
}catch(error){
|
||||
setDisplayingDoneMessage(false)
|
||||
setDisplayingDoneMessageTimer(timer);
|
||||
} catch (error) {
|
||||
setDisplayingDoneMessage(false);
|
||||
//alert(error)
|
||||
//console.log(error)
|
||||
let substituteText = `Error: ${error.message}
|
||||
|
@ -70,34 +71,39 @@ Try something like:
|
|||
}
|
||||
]
|
||||
|
||||
Your old input was: ${value}`
|
||||
setValue(substituteText)
|
||||
Your old input was: ${value}`;
|
||||
setValue(substituteText);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
return (
|
||||
<form onSubmit={handleSubmitInner} className="inline">
|
||||
<br/>
|
||||
<br/>
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
rows="10" cols="50"
|
||||
<br />
|
||||
<br />
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
rows="10"
|
||||
cols="50"
|
||||
className=""
|
||||
/>
|
||||
<br/>
|
||||
<button
|
||||
<br />
|
||||
<button
|
||||
className="bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5 p-10"
|
||||
onClick={handleSubmitInner}>
|
||||
onClick={handleSubmitInner}
|
||||
>
|
||||
Change dataset
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={displayingDoneMessage ? "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5 p-10" : "hidden"}
|
||||
className={
|
||||
displayingDoneMessage
|
||||
? "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5 p-10"
|
||||
: "hidden"
|
||||
}
|
||||
>
|
||||
Done!
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,25 +3,28 @@ import ReactMarkdown from "react-markdown";
|
|||
import gfm from "remark-gfm";
|
||||
|
||||
if (!String.prototype.replaceAll) {
|
||||
String.prototype.replaceAll = function(str, newStr){
|
||||
String.prototype.replaceAll = function (str, newStr) {
|
||||
// If a regex pattern
|
||||
if (
|
||||
Object.prototype.toString.call(str).toLowerCase() === "[object regexp]"
|
||||
) {
|
||||
return this.replace(str, newStr);
|
||||
}
|
||||
|
||||
// If a regex pattern
|
||||
if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
|
||||
return this.replace(str, newStr);
|
||||
}
|
||||
|
||||
// If a string
|
||||
return this.replace(new RegExp(str, 'g'), newStr);
|
||||
|
||||
};
|
||||
// If a string
|
||||
return this.replace(new RegExp(str, "g"), newStr);
|
||||
};
|
||||
}
|
||||
|
||||
export function DisplayAsMarkdown({ markdowntext, className }) {
|
||||
//console.log(markdowntext)
|
||||
markdowntext = markdowntext.replaceAll("\n", "\n\n");
|
||||
return (
|
||||
<ReactMarkdown
|
||||
plugins={[gfm]}
|
||||
children={markdowntext}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function DisplayAsMarkdown({markdowntext, className}){
|
||||
//console.log(markdowntext)
|
||||
markdowntext = markdowntext.replaceAll("\n", "\n\n")
|
||||
return( <ReactMarkdown
|
||||
plugins={[gfm]}
|
||||
children={markdowntext}
|
||||
className={className}
|
||||
/>)
|
||||
}
|
|
@ -1,31 +1,44 @@
|
|||
import React from "react";
|
||||
|
||||
let capitalizeFirstLetter = (string) => string.charAt(0).toUpperCase() + string.slice(1)
|
||||
let capitalizeFirstLetter = (string) =>
|
||||
string.charAt(0).toUpperCase() + string.slice(1);
|
||||
|
||||
export function DisplayElement({ element }) {
|
||||
let otherkeys = Object.keys(element).filter(
|
||||
(key) =>
|
||||
key != "name" && key != "url" && key != "id" && key != "isReferenceValue"
|
||||
);
|
||||
let othervalues = otherkeys.map((key) => element[key]);
|
||||
let otherpairs = otherkeys.map((key, i) => ({
|
||||
key: capitalizeFirstLetter(key),
|
||||
value: othervalues[i],
|
||||
}));
|
||||
|
||||
if (element.url) {
|
||||
return (
|
||||
<div>
|
||||
{/*<a href={element.url} target="_blank">*/}
|
||||
<h2>{`${element.name}`}</h2>
|
||||
{/*</a>*/}
|
||||
{otherpairs.map((pair) => (
|
||||
<p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>
|
||||
))}
|
||||
<p>
|
||||
<a href={element.url} target="_blank">
|
||||
More info
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<h2>{`${element.name}`}</h2>
|
||||
{otherpairs.map((pair) => (
|
||||
<p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function DisplayElement({element}){
|
||||
let otherkeys = Object.keys(element).filter(key => key!="name" && key!="url" && key != "id" && key != "isReferenceValue")
|
||||
let othervalues = otherkeys.map(key => element[key])
|
||||
let otherpairs = otherkeys.map((key,i) => ({key: capitalizeFirstLetter(key), value: othervalues[i]}))
|
||||
|
||||
if(element.url){
|
||||
return(
|
||||
<div>
|
||||
{/*<a href={element.url} target="_blank">*/}
|
||||
<h2>{`${element.name}`}</h2>
|
||||
{/*</a>*/}
|
||||
{otherpairs.map(pair => <p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>)}
|
||||
<p>
|
||||
<a href={element.url} target="_blank">More info</a>
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return(
|
||||
<div>
|
||||
<h2>{`${element.name}`}</h2>
|
||||
{otherpairs.map(pair => <p key={pair.value}>{`${pair.key}: ${pair.value}`}</p>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,14 +1,17 @@
|
|||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const CONNECTION_IS_ACTIVE = true
|
||||
const CONNECTION_IS_ACTIVE = true;
|
||||
|
||||
export async function pushToMongo(data){
|
||||
if(CONNECTION_IS_ACTIVE){
|
||||
let response = await axios.post('https://server.loki.red/utility-function-extractor', {
|
||||
data: data
|
||||
})
|
||||
console.log(response)
|
||||
}
|
||||
|
||||
export async function pushToMongo(data) {
|
||||
if (CONNECTION_IS_ACTIVE) {
|
||||
let response = await axios.post(
|
||||
"https://server.loki.red/utility-function-extractor",
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
// pushToMongo()
|
||||
// pushToMongo()
|
||||
|
||||
|
|
123
lib/slider.js
123
lib/slider.js
|
@ -1,34 +1,34 @@
|
|||
/* Imports */
|
||||
import { Slider, Rail, Handles, Tracks, Ticks } from "react-compound-slider";
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState } from "react";
|
||||
// https://sghall.github.io/react-compound-slider/#/getting-started/tutorial
|
||||
|
||||
/* Definitions */
|
||||
|
||||
const sliderStyle = { // Give the slider some width
|
||||
position: 'relative',
|
||||
width: '40em',
|
||||
const sliderStyle = {
|
||||
// Give the slider some width
|
||||
position: "relative",
|
||||
width: "40em",
|
||||
height: 40,
|
||||
border: '5em',
|
||||
}
|
||||
border: "5em",
|
||||
};
|
||||
|
||||
const railStyle = {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
position: "absolute",
|
||||
width: "100%",
|
||||
height: 15,
|
||||
marginTop: 32.5,
|
||||
borderRadius: 5,
|
||||
backgroundColor: 'lightgrey',
|
||||
}
|
||||
backgroundColor: "lightgrey",
|
||||
};
|
||||
|
||||
/* Support functions */
|
||||
function Handle({
|
||||
handle: { id, value, percent },
|
||||
getHandleProps,
|
||||
displayFunction,
|
||||
handleWidth
|
||||
handleWidth,
|
||||
}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="justify-center text-center text-gray-600 text-xs">
|
||||
|
@ -37,50 +37,56 @@ function Handle({
|
|||
<div
|
||||
style={{
|
||||
left: `${percent}%`,
|
||||
position: 'absolute',
|
||||
position: "absolute",
|
||||
marginLeft: -10,
|
||||
marginTop: 2.5,
|
||||
zIndex: 2,
|
||||
width: 30,
|
||||
height: 30,
|
||||
cursor: 'pointer',
|
||||
borderRadius: '0%',
|
||||
backgroundColor: '#374151',
|
||||
color: '#374151',
|
||||
cursor: "pointer",
|
||||
borderRadius: "0%",
|
||||
backgroundColor: "#374151",
|
||||
color: "#374151",
|
||||
}}
|
||||
{...getHandleProps(id)}
|
||||
>
|
||||
</div>
|
||||
></div>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function Track({ source, target, getTrackProps }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
position: "absolute",
|
||||
height: 17.5,
|
||||
zIndex: 1,
|
||||
marginTop: 8.25,
|
||||
backgroundColor: ' #3B82F6',
|
||||
backgroundColor: " #3B82F6",
|
||||
borderRadius: 5,
|
||||
cursor: 'pointer',
|
||||
cursor: "pointer",
|
||||
left: `${source.percent}%`,
|
||||
width: `${target.percent - source.percent}%`,
|
||||
}}
|
||||
{...getTrackProps() /* this will set up events if you want it to be clickeable (optional) */}
|
||||
{
|
||||
...getTrackProps() /* this will set up events if you want it to be clickeable (optional) */
|
||||
}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/* Body */
|
||||
// Two functions, essentially identical.
|
||||
// Two functions, essentially identical.
|
||||
export function SliderElement({ onChange, value, displayFunction, domain }) {
|
||||
let toLogDomain = (arr) => [Math.log(arr[0]) / Math.log(10), Math.log(arr[1]) / Math.log(10)]
|
||||
let toLogDomain = (arr) => [
|
||||
Math.log(arr[0]) / Math.log(10),
|
||||
Math.log(arr[1]) / Math.log(10),
|
||||
];
|
||||
return (
|
||||
<Slider
|
||||
rootStyle={sliderStyle /* inline styles for the outer div. Can also use className prop. */}
|
||||
rootStyle={
|
||||
sliderStyle /* inline styles for the outer div. Can also use className prop. */
|
||||
}
|
||||
domain={toLogDomain([1 / domain, domain])}
|
||||
values={[value]}
|
||||
step={0.0001}
|
||||
|
@ -88,14 +94,12 @@ export function SliderElement({ onChange, value, displayFunction, domain }) {
|
|||
reversed={true}
|
||||
>
|
||||
<Rail>
|
||||
{({ getRailProps }) => (
|
||||
<div style={railStyle} {...getRailProps()} />
|
||||
)}
|
||||
{({ getRailProps }) => <div style={railStyle} {...getRailProps()} />}
|
||||
</Rail>
|
||||
<Handles>
|
||||
{({ handles, getHandleProps }) => (
|
||||
<div className="slider-handles">
|
||||
{handles.map(handle => (
|
||||
{handles.map((handle) => (
|
||||
<Handle
|
||||
key={handle.id}
|
||||
handle={handle}
|
||||
|
@ -122,33 +126,54 @@ export function SliderElement({ onChange, value, displayFunction, domain }) {
|
|||
)}
|
||||
</Tracks>
|
||||
</Slider>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function SubmitSliderButton({ posList, binaryComparisons, sliderValue, reasoning, toComparePair, nextStepSlider, dontPushSubmitButtonAnyMore }) {
|
||||
export function SubmitSliderButton({
|
||||
posList,
|
||||
binaryComparisons,
|
||||
sliderValue,
|
||||
reasoning,
|
||||
toComparePair,
|
||||
nextStepSlider,
|
||||
dontPushSubmitButtonAnyMore,
|
||||
}) {
|
||||
// This element didn't necessarily have to exist, but it made it easier for debugging purposes
|
||||
let onClick = (event) => {
|
||||
if(!dontPushSubmitButtonAnyMore){
|
||||
if (!dontPushSubmitButtonAnyMore) {
|
||||
//event.preventDefault();
|
||||
let obj = { posList, binaryComparisons, sliderValue, reasoning, element1: toComparePair[1], element2: toComparePair[0] }
|
||||
let obj = {
|
||||
posList,
|
||||
binaryComparisons,
|
||||
sliderValue,
|
||||
reasoning,
|
||||
element1: toComparePair[1],
|
||||
element2: toComparePair[0],
|
||||
};
|
||||
//
|
||||
console.log("input@SubmitSliderButton")
|
||||
console.log(obj)
|
||||
console.log("input@SubmitSliderButton");
|
||||
console.log(obj);
|
||||
if (!!Number(sliderValue) && sliderValue >= 0) {
|
||||
nextStepSlider(obj)
|
||||
nextStepSlider(obj);
|
||||
} else if (!!Number(sliderValue) && sliderValue < 0) {
|
||||
alert("Negative numbers not yet allowed")
|
||||
alert("Negative numbers not yet allowed");
|
||||
} else {
|
||||
alert("Your input is not a number")
|
||||
alert("Your input is not a number");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
return (<button
|
||||
className={!dontPushSubmitButtonAnyMore ? "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5" : "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5"}
|
||||
onClick={onClick}>
|
||||
Submit
|
||||
</button>)
|
||||
return (
|
||||
<button
|
||||
className={
|
||||
!dontPushSubmitButtonAnyMore
|
||||
? "bg-transparent hover:bg-blue-500 text-blue-700 font-semibold hover:text-white py-2 px-4 border border-blue-500 hover:border-transparent rounded mt-5"
|
||||
: "bg-transparent text-blue-700 font-semibold py-2 px-4 border border-blue-500 rounded mt-5"
|
||||
}
|
||||
onClick={onClick}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,53 +1,42 @@
|
|||
[
|
||||
{
|
||||
"source": 3,
|
||||
|
||||
"target": 4,
|
||||
|
||||
"distance": 5
|
||||
},
|
||||
|
||||
{
|
||||
"source": 2,
|
||||
|
||||
"target": 3,
|
||||
|
||||
"distance": 4
|
||||
},
|
||||
|
||||
{
|
||||
"source": 0,
|
||||
|
||||
"target": 1,
|
||||
|
||||
"distance": 4
|
||||
},
|
||||
|
||||
{
|
||||
"source": 0,
|
||||
|
||||
"target": 2,
|
||||
|
||||
"distance": 5
|
||||
},
|
||||
|
||||
{
|
||||
"source": 1,
|
||||
|
||||
"target": 2,
|
||||
|
||||
"distance": 5
|
||||
}
|
||||
]
|
||||
|
||||
{
|
||||
|
||||
"source": 3,
|
||||
|
||||
"target": 4,
|
||||
|
||||
"distance": 5
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"source": 2,
|
||||
|
||||
"target": 3,
|
||||
|
||||
"distance": 4
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"source": 0,
|
||||
|
||||
"target": 1,
|
||||
|
||||
"distance": 4
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"source": 0,
|
||||
|
||||
"target": 2,
|
||||
|
||||
"distance": 5
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
"source": 1,
|
||||
|
||||
"target": 2,
|
||||
|
||||
"distance": 5
|
||||
|
||||
}
|
||||
|
||||
]
|
|
@ -5,25 +5,28 @@
|
|||
|
||||
/* Imports */
|
||||
import React from "react";
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import ComparisonView from '../lib/comparisonView.js'
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import ComparisonView from "../lib/comparisonView.js";
|
||||
|
||||
/* Definitions */
|
||||
const elementsDocument = '../data/listOfMoralGoods.json'
|
||||
const elementsDocument = "../data/listOfMoralGoods.json";
|
||||
|
||||
/* React components */
|
||||
export async function getStaticProps() {
|
||||
const directory = path.join(process.cwd(), "pages")
|
||||
let listOfElementsForView = JSON.parse(fs.readFileSync(path.join(directory, elementsDocument), 'utf8'));
|
||||
const directory = path.join(process.cwd(), "pages");
|
||||
let listOfElementsForView = JSON.parse(
|
||||
fs.readFileSync(path.join(directory, elementsDocument), "utf8")
|
||||
);
|
||||
return {
|
||||
props: {
|
||||
listOfElementsForView
|
||||
listOfElementsForView,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Main react component
|
||||
export default function Home({ listOfElementsForView }) {
|
||||
return(<ComparisonView listOfElementsForView={listOfElementsForView}/>)
|
||||
}
|
||||
return <ComparisonView listOfElementsForView={listOfElementsForView} />;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,4 +26,4 @@ export async function getStaticProps() {
|
|||
// Main react component
|
||||
export default function Home({ listOfElementsForView }) {
|
||||
return(<ComparisonView listOfElementsForView={listOfElementsForView}/>)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user