I have a variable count that triggers a function positiveBar if the value of count is > 0. If the value of count is < 0, it triggers a function negativeBar.
positiveBar changes a div's position using
progressBar.style.left = '50%';
negativeBar changes that same div's position using
progressBar.style.right = '50%';
This gives me the result I want; however, if at any point count becomes greater than 0, the positioning on negativeBar stops working, and it uses the positioning of the positiveBar function instead.
Video to explain:
var count = 0;
// Show count on the page
document.getElementById("countDisplay").innerHTML = count;
// Update count
function updateDisplay() {
countDisplay.innerHTML = count;
};
// Change negative count to an absolute
function absCount() {
return Math.abs(count);
};
function positiveBar() {
progressBar.style.backgroundColor = "#77eb90";
progressBar.style.width = (count * 10) + 'px';
progressBar.style.left = '50%';
};
function negativeBar() {
progressBar.style.backgroundColor = "#ef5c3f";
progressBar.style.width = (absCount() * 10) + 'px';
progressBar.style.right = '50%';
};
// Count up and down when + and - buttons are clicked and edit bar
add1.addEventListener("click", () => {
count++;
updateDisplay();
if (count > 0) {
positiveBar();
} else {
negativeBar();
}
});
subtract1.addEventListener("click", () => {
count--;
updateDisplay();
if (count > 0) {
positiveBar();
} else {
negativeBar();
}
});
.progressBar__Container {
height: 10px;
margin: 20px auto;
border: 1px solid black;
position: relative;
}
#progressBar {
height: 10px;
width: 0;
position: absolute;
}
<div id="countDisplay"></div>
<button id="add1">+</button>
<button id="subtract1">-</button>
<div class="progressBar__Container">
<div id="progressBar"> </div>
</div>
I tried reordering statements. I also tried creating a condition for if count = 0, but that didn't change the result. I'm very confused because it initially works how I intend, but if count becomes greater than 0 at any point, progressBar.style.right = '50%'; stops being applied.
You aren't clearing any previously set left or right styles when you switch from negative to positive and vice versa.
I would use CSS classes to control the position and colour as it's easier to toggle them based on the state of count.
let count = 0;
const countDisplay = document.getElementById("countDisplay");
const progressBar = document.getElementById("progressBar");
// Update count
function updateDisplay() {
countDisplay.textContent = count;
progressBar.style.width = `${absCount() * 10}px`;
progressBar.classList.toggle("positive", count > 0);
progressBar.classList.toggle("negative", count < 0);
};
// Change negative count to an absolute
function absCount() {
return Math.abs(count);
};
// Count up and down when + and - buttons are clicked and edit bar
add1.addEventListener("click", () => {
count++;
updateDisplay();
});
subtract1.addEventListener("click", () => {
count--;
updateDisplay();
});
.progressBar__Container {
height: 10px;
margin: 20px auto;
border: 1px solid black;
position: relative;
}
#progressBar {
height: 10px;
width: 0;
position: absolute;
}
#progressBar.positive {
background-color: #77eb90;
left: 50%;
}
#progressBar.negative {
background-color: #ef5c3f;
right: 50%;
}
<div id="countDisplay">0</div>
<button id="add1">+</button>
<button id="subtract1">-</button>
<div class="progressBar__Container">
<div id="progressBar"> </div>
</div>
See MDN:
When both left and right are defined, if not prevented from doing so by other properties, the element will stretch to satisfy both. If the element cannot stretch to satisfy both — for example, if a width is declared — the position of the element is over-constrained. When this is the case, the left value has precedence when the container is left-to-right; the right value has precedence when the container is right-to-left.
Because you are setting style.left when you then come to set style.right the above applies - i.e. the style.right setting will get overridden.
This is a function where you click on a character and it heals them by the amount specified in the switch. I need the listener to trigger only one time per function call but the removal doesn't seem to be doing anything. As in you can just keep clicking and it keeps going through the switch. I've tested and ensured that the function itself is only being called once so I have no idea what's going on here. Tried removing the listener like document.removeEventListener('click', addAllyTargets) as well, no change. Angels_Grace_Part2() is purely imagery/text and has nothing to do with the listener.
var ally_targets = []
//make the list of targets
function makeAllyTargets() {
let maketargets = document.getElementsByClassName('ally_img')
for (let i = 0; i < maketargets.length; i++) {
ally_targets.push(maketargets[i])
};
};
var amt_healed;
function Angels_Grace() { //moderate healing spell on one ally
makeAllyTargets();
for (let i = 0; i < ally_targets.length; i++) {
//add the listener to each target
ally_targets[i].addEventListener('click', function addAllyTargets() {
//amt healed is 55% of the target's max.
const selected_ally = ally_targets.indexOf(this);
switch (selected_ally) {
case 0: //knight
amt_healed = 303;
//ensure it doesn't go over max
if (warrior_hp.value + amt_healed > 550) {
Angels_Grace_Part2()
warrior_hp.value = 550;
} else {
Angels_Grace_Part2()
warrior_hp.value += amt_healed;
};
//remove the listener
ally_targets[i].removeEventListener('click', addAllyTargets)
break;
//the other cases follow the same logic
default:
console.log("heal switch - shits fucked")
break;
};
});
};
};
I went overboard in my answer.
There were a lot of things going on in your code that, in my opinion, could have been made simpler.
And so rather than go into a deep explanation as to why, I offer this for your consideration.
function AngelsGrace(event) {
//amt healed is 55% of the target's max.
let ds = event.target.dataset;
let hp = +ds.hp;
let maxHp = +ds.maxHp;
let healingRate = +ds.healingRate;
let amtHealed = maxHp * healingRate;
let excessiveHealing = hp + amtHealed > maxHp;
if (excessiveHealing)
amtHealed = maxHp - hp;
ds.hp = hp + amtHealed;
if (amtHealed) {
console.log(`${ds.class} hp was ${hp}. Healed for ${amtHealed}, now ${ds.hp}/${maxHp}`);
} else {
console.log(`${ds.class} is at Full Health`);
}
console.log("casting Angels_Grace_Part2()");
event.target.nextElementSibling.classList.toggle("angels-grace");
}
function CastAngelsGrace() { //moderate healing spell on one ally
var oneTimeOnly = {
once: true
};
let htmlCollection = document.getElementsByClassName('ally_img');
for (const tgt of htmlCollection) {
tgt.addEventListener('click', AngelsGrace, oneTimeOnly)
tgt.nextElementSibling.classList.toggle("angels-grace");
};
}
.character {
display: inline-block;
position: relative;
height: 100px;
width: 100px;
border: 1px solid grey;
margin: 10px;
}
.ally_img {
height: 70px;
width: 70px;
}
.spell-container {
position: absolute;
top: 0;
right: 0;
}
.spell-container:after {
opacity: 0;
}
.spell-container.angels-grace:after {
content: "AG";
opacity: 1;
}
<div class="character">
<image src="https://picsum.photos/id/718/200" class="ally_img"
data-class="knight"
data-healing-class="warrior"
data-healing-rate="0.55"
data-max-hp="1000"
data-hp="200" />
<span class="spell-container"></span>
</div>
<div class="character">
<image src="https://picsum.photos/id/237/200" class="ally_img"
data-class="rogue"
data-healing-class="sneaky"
data-healing-rate="0.35"
data-max-hp="500"
data-hp="100" />
<span class="spell-container"></span>
</div>
<button onclick="CastAngelsGrace()">Cast Angel Grace</button>
Once a draggable element's been dropped into a valid target i.e the user's answered the question correctly s/he can move on to the next one. I'd like the next question to be positioned at the exact same place as the previous one. In order to do so I've created the newElement() function. But it's not working as it should be. I've tried to use different methods such as insertBefore() but the console keep throwing message like: "Uncaught DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node". appendChild() isn't working either. I know it's something to do with DOM manipulation but I haven't the foggiest how to go about solving this issue. Help please.
const questionQuiz = document.querySelector(".question");
const answerChoices = document.querySelector(".answerchoices");
const allChoices = Array.from(document.querySelector(".answerchoices").children);
const choiceA = document.querySelector(".choiceA");
const choiceB = document.querySelector(".choiceB");
const choiceC = document.querySelector(".choiceC");
const start = document.querySelector(".start");
const quizSection = document.querySelector(".quizSection");
const choices = document.querySelectorAll(".choice");
const answerSection = document.querySelector(".answerSection");
const counter = document.querySelector(".counter");
const timerBar = document.querySelector(".timerBar");
const finalScore = document.querySelector(".finalScore");
const parent = document.querySelector(".parent");
console.log(quizSection)
let questions = [
{
question: "How many Grand Slam men's singles titles has he won?",
choiceA: 10,
choiceB: 15,
choiceC: 20,
questionImg: "url(images/federer.jpeg)",
correctAnswer: 20,
},
{
question: "How many Formula One World Championship has he won?",
choiceA: 5,
choiceB: 7,
choiceC: 10,
questionImg: "url(images/hamilton.jpeg)",
correctAnswer: 7,
},
{
question: "How many NBA title has Lebron won?",
choiceA: 6,
choiceB: 3,
choiceC: 4,
questionImg: "url(images/LeBron.png)",
correctAnswer: 4,
},
{
question: "How many Ballon D'or has the Argentinina won?",
choiceA: 5,
choiceB: 6,
choiceC: 7,
questionImg: "url(images/LeBron.png)",
correctAnswer: 7,
},
]
let lastQuestion = questions.length - 1;
let activeQuestion = 0;
let count = 0;
let score = 0;
let x = 0;
let timeUp = 10;
let timerBarLength = 800;
let unitBar = timerBarLength / timeUp;
let dragged;
start.addEventListener("click", startQuiz)
function startQuiz() {
start.style.visibility = "hidden";
parent.style.visibility = "visible";
renderQuestion();
progressBar();
setInterval(timerBarFunction, 1000);
setInterval(counterFunction, 1000);
}
function timerBarFunction() {
if(count < timeUp) {
timerBar.style.width = `${count*unitBar}px`
count++;
} else {
count = 0;
}
}
function progressBar() {
for(var questionIndex = 0; questionIndex < questions.length; questionIndex++) {
answerSection.innerHTML += `<div class="progress-boxes" id=${questionIndex}></div>`
}
}
function counterFunction() {
if(x <= timeUp) {
counter.innerHTML = x;
x++;
} else {
x = 0;
nextQuestion();
wrongAnswer();
}
}
function renderQuestion() {
let q = questions[activeQuestion]
choiceA.innerHTML = q.choiceA;
choiceB.innerHTML = q.choiceB;
choiceC.innerHTML = q.choiceC;
questionQuiz.innerHTML = q.question;
// document.body.style.backgroundImage = q.questionImg
}
questionQuiz.addEventListener("drag", function(e) {
})
questionQuiz.addEventListener("dragstart", function(e) {
console.log("start");
dragged = e.target;
console.log(dragged.innerHTML)
});
questionQuiz.addEventListener("dragend", function() {
console.log('end')
});
allChoices.forEach((choice) => {
choice.addEventListener("dragover", dragOver)
});
allChoices.forEach(choice => {
choice.addEventListener("dragenter", dragEnter)
});
allChoices.forEach(choice => {
choice.addEventListener("dragleave", dragLeave)
});
allChoices.forEach(choice => {
choice.addEventListener("drop", drop)
})
function dragOver(e) {
e.preventDefault()
console.log("dragover")
}
function dragEnter(e) {
e.preventDefault();
console.log("dragenter");
}
function dragLeave() {
console.log("dragleave")
}
function drop(e) {
e.preventDefault()
if(parseInt(e.target.innerHTML) !== questions[activeQuestion].correctAnswer) {
wrongAnswer();
nextQuestion()
} else {
correctAnswer();
score++;
e.target.appendChild(dragged);
nextQuestion();
newElement();
}
}
function correctAnswer() {
document.getElementById(activeQuestion).style.backgroundColor = "green";
}
function wrongAnswer() {
document.getElementById(activeQuestion).style.backgroundColor = "red";
}
function nextQuestion() {
count = 0;
if(activeQuestion < lastQuestion) {
activeQuestion++
renderQuestion();
} else {
renderScore();
}
}
function renderScore() {
finalScore.innerHTML = score;
finalScore.style.visibility = "visible";
}
function newElement() {
let newDiv = document.createElement("div");
newDiv.setAttribute("class", "question");
newDiv.setAttribute("draggable", "true");
newDiv.innerHTML = questions[activeQuestion].question;
parent.appendChild(newDiv);
// document.body.insertBefore(newDiv, answerChoices.nextSibling);
}
body {
background-repeat: no-repeat;:
}
.answerchoices > *{
margin-bottom: 15px;
}
.answerSection {
display: grid;
grid-template-columns: repeat(4, 1fr);
justify-items: center;
}
.start {
width: 100px;
height: 100px;
border: 1px solid black;
}
.finalScore {
visibility: hidden;
}
.quizSection {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.question,
.answerchoices > *{
height: 100px;
width: 100px;
border: 1px black solid;
}
.progress-boxes {
height: 30px;
width: 30px;
color: grey;
background-color: grey;
margin: 10px;
}
.timerBar {
height: 5px;
/* width: 800px; */
color: blue;
background-color: purple;
border: 1px black solid;
}
.parent {
visibility: hidden;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
<title>Drag And Drop</title>
</head>
<body>
<div class="parent">
<div class="quizSection">
<div class="question" draggable="true"></div>
<div class=answerchoices>
<div class="choiceA">choiceA</div>
<div class="choiceB">choiceB</div>
<div class="choiceC">choiceC</div>
</div>
</div>
<div class="answerSection"></div>
<div class="counter"></div>
<div class="timerBar"></div>
<div class="finalScore"></div>
</div>
<div class="start">Cick here to start quizz</div>
<script src="index.js" type="text/javascript"></script>
</body>
</html>
I've been trying to add 1% to the width of the div using JS. I want to make it so that the bar's width increases in a smooth way ( I thought about using animations but it didn't work cause I need to specify conditions).
window.onload = function(){
for (let i = 0; i < 5; i++) {
const bar = document.querySelectorAll(".child-bar")[i];
for (let j = 0; j < 82; j++) {
//alert("j" + j);
console.log("bar width: "+ bar.style.width)
bar.style.width += '1%';
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="skill">
<label for="HTML">HTML</label>
<div class="parent-bar">
<span class="child-bar"></span>
<h4>82%</h4>
</div>
</div>
Maybe this example will help you?
window.onload = function() {
document.querySelectorAll(".parent-bar").forEach((el) => {
const barNode = el.querySelector(".child-bar");
const valueNode = el.querySelector("h4");
const max = 82;
const duration = 100;
let value = 0;
const tick = () => {
barNode.style.width = `${value}%`;
valueNode.innerHTML = `${value}%`;
if (value++ < max) setTimeout(tick, duration);
}
tick();
})
}
.child-bar {
display: block;
background: black;
height: 1rem;
width: 0;
transition: 0.1s 0s linear;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="skill">
<label for="HTML">HTML</label>
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
</div>
Here's a solution with verbose code and commentary for clarity, using setInterval.
(Note that span elements have display: inline by default, which is why setting their width has no effect.)
// Sets options and calls main function
const myOptions = {
MAX_WIDTH_PERCENT: 82,
FRAME_COUNT: 100,
FRAME_DURATION: 20
};
animateBars(myOptions);
// Defines main function
function animateBars(options){
const
// Destructures options object to make local variables
{ MAX_WIDTH_PERCENT, FRAME_COUNT, FRAME_DURATION } = options,
// Defines function to increment width
increment = (value) => value += MAX_WIDTH_PERCENT / FRAME_COUNT,
// Defines function to update bar (after incrementing width)
incrementAndupdateBar = (bar, oldWidth, timerId) => {
newWidth = Math.min(increment(oldWidth), MAX_WIDTH_PERCENT);
bar.style.width = newWidth + "%";
bar.nextElementSibling.textContent = Math.floor(newWidth) + "%"; // (For demo)
// Stops repeating the setInterval's function
if(newWidth == MAX_WIDTH_PERCENT){
clearInterval(timerId);
}
return newWidth; // Returns updated value
};
// Loops through bars
for(let bar of document.querySelectorAll(".child-bar")){
// Repeatedly updates current bar, keeping track of width as we go
let
width = 0, // Initializes width for the current bar
timerId; // ID for use by setInterval & clearInterval
timerId = setInterval( // (Returns an ID for later use)
// Takes 2 args: a func and a duration (in ms) to delay inbetween
function(){width = incrementAndupdateBar(bar, width, timerId);},
FRAME_DURATION
);
}
}
.parent-bar{ width: 300px; border: 1px dotted grey; }
/* spans ignore "width" by default; "inline-block" solves this */
.child-bar{ display: inline-block; height: 1em; background-color: lightgreen; }
h4{ margin: 0; text-align: center; }
<div class="parent-bar">
<span class="child-bar"></span>
<h4></h4>
</div>
I want to show the very hard array and hard array in the textarea. Right now, it shows under the textarea as I don't know how to show it in the textarea. The user gives the input and the server response with the hard and very hard sentences from the user input. The hard sentences have a yellow background and the very hard have red background. For now, only the hard and very hard sentences with yellow and red background respectively is shown below the textarea and not the whole thing but I think it isn't intuitive as the user would have to go and search for the sentences in the textarea again as where the sentence exactly lies. So I want the whole thing to be shown in the textarea itself with the hard and very hard sentences highlighted in yellow and red background.
Right now my code looks something like this:
state={
hardArray: [],
vhardArray: []
}
performHard = async () => {
const { enteredText } = this.state;
const body = { text: enteredText };
const stringifiedBody = JSON.stringify(body);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: stringifiedBody
};
const url = "api/same";
try {
const response = await fetch(url, options);
const result = await response.json();
this.setState(prevState => ({
hardArray: [...prevState.hardArray, ...result.hard]
}));
} catch (error) {
console.error("error");
}
};
performVHard = async () => {
const { enteredText } = this.state;
const body = { text: enteredText };
const stringifiedBody = JSON.stringify(body);
const options = {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: stringifiedBody
};
const url ="api/same";
try {
const response = await fetch(url, options);
const result = await response.json();
this.setState(prevState => ({
vhardArray: [...prevState.vhardArray, ...result.very_hard]
}));
} catch (error) {
console.error("error");
}
};
performAnalysis = () => {
this.performHard();
this.performVHard();
};
<textarea
name="enteredText"
className="textareaclass"
placeholder="Enter your text here"
onChange={this.handleChange}
value={enteredText}
></textarea>
<Button
className="rectangle-3"
onClick={this.performAnalysis}>Analyse
</Button>
<div>
{this.state.hardArray.map((word, i) => (
<span className="hardColor">{word}</span>
))}
{this.state.vhardArray.map((word, i) => (
<span className="vhardColor">{word}</span>
))}
</div>
edit: this is how I receive the respond from the server
{
"hard": [
"It's the possibility of having a dream come true that makes life interesting",
"I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation.",
]
"very_hard": [
“He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even
without looking.”
]
}
I want to show all the text in the same textarea where the user wrote his content instead of showing anywhere else in the browser as it will make everything look ugly.
You can only give a textarea one background color, but you can make it transparent and put things behind it to add some color, yea this is a total hack and you will need to fiddle with the sizes and the blank lines to move the text down a bit - I will leave that exercise to you.
This also does not show how to get your values into the textarea but that is simple JavaScript/react code perhaps.
I altered this with some functions to illustrate where you MIGHT simply add/remove blank lines in the textarea to match the height of the background color - would probably have to adjust that background to match when this overflows the size, OR you might adjust the background to make it smaller for the colors.
I will leave it to you to determine which is the better option, I used "|" and "||" as the line/section separators as once it is in the textarea and edited you will need something like that.
All I have time for right now to enhance this but should give a starting point for this somewhat edge case without a clear standard solution.
.message {
width: 300px;
height: 150px;
display: block;
position: absolute;
}
textarea.format-custom,
.custom-underlay,
.underlay {
margin: 0;
box-sizing: border-box;
vertical-align: top;
display: block;
position: absolute;
border: lime solid 1px;
}
textarea.format-custom {
width: 100%;
height: 100%;
background: transparent;
resize: none;
display: block;
}
.underlay {
width: 100%;
height: 100%;
background: transparent;
display: block;
z-index: -1;
}
.custom-underlay {
width: 100%;
height: 50%;
margin: 0;
box-sizing: border-box;
vertical-align: top;
}
.custom-underlay.top {
background-color: #FFDDDD;
top: 0;
left: 0;
}
.custom-underlay.bottom {
background-color: #DDDDFF;
top: 50%;
left: 0;
}
<div class="message">
<label for="msg">Your message:</label>
<textarea id="msg" name="user_message" class="format-custom">howdy, I am here
bottom of here</textarea>
<div class="underlay">
<div class="custom-underlay top"></div>
<div class="custom-underlay bottom"></div>
</div>
</div>
Alternate idea from question, put text on the div's behind:
'use strict';
// borrowed code from https://stackoverflow.com/a/17590149/125981
// makeClass - By Hubert Kauker (MIT Licensed)
// original by John Resig (MIT Licensed).
var makeClass = (function(Void) {
return function() {
var constructor = function() {
var init = constructor.prototype.init,
hasInitMethod = (typeof init == "function"),
instance;
if (this instanceof constructor) {
if (hasInitMethod) init.apply(this, arguments);
} else {
Void.prototype = constructor.prototype;
instance = new Void();
if (hasInitMethod) init.apply(instance, arguments);
return instance;
}
};
return constructor;
};
})(function() {});
//make a class MyApp using above
var MyApp = makeClass();
// create MyApp functional part using the init:
MyApp.prototype.init = function(myItem, showmeClass = "showme", separator = "|", groupSeparator = "||") {
let eventChangeName = "change";
let textElement = document.getElementById(myItem);
let showme = textElement.closest(".container").getElementsByClassName(showmeClass)[0];
let lineSep = "|\n";
let myData = {
hard: [],
very_hard: []
};
this.sentData = {
hard: [],
very_hard: []
};
//so we can tell the lines
function getStyle(elId, styleProp) {
var x = document.getElementById(elId);
let y = {};
if (x.currentStyle) {
y = x.currentStyle[styleProp];
} else if (window.getComputedStyle) {
y = document.defaultView.getComputedStyle(x, null).getPropertyValue(styleProp);
}
return y;
}
function getTextareaThings(myTextarea) {
let taComputedStyles = window.getComputedStyle(myTextarea);
return {
height: myTextarea.style.height,
rows: myTextarea.rows,
clientHeight: myTextarea.clientHeight,
lineHeight: taComputedStyles.getPropertyValue('line-height'),
font: taComputedStyles.getPropertyValue('font-size')
};
}
function getLinesInString(myString) {
/* new line things: /r old Mac, /cr/lf some, /n some
all the "new line": regex: /\r\n|\n|\r/gm
above reduced regex: g and m are for global and multiline flags */
let nl = /[\r\n]+/gm;
let lines = [];
lines = myString.split(nl);
return lines;
}
function splitGroupString(myString, separator) {
let strings = [];
strings = myString.split(separator);
return strings;
}
function getGroupsInString(myString) {
return splitGroupString(myString, groupSeparator);
}
function getGroupItemsInString(myString) {
return splitGroupString(myString, separator);
}
function getCurrentValue() {
return textElement.value;
}
function addNewLines(text, count) {
let newLine = "\n";
return text + newLine.repeat(count);
}
// make stuff obvious
function onFocusTextareaValue(event) {
showForDebug(event);
}
function onChangeTextareaValue(event) {
if (event.type == eventChangeName) {
event.stopPropagation();
event.stopImmediatePropagation();
}
showForDebug(event);
}
function showForDebug(event) {
let what = "Event: " + event.type;
let b = "<br />";
let tat = getTextareaThings(event.target);
let v = getCurrentValue().replace(what, "");
showme.innerHTML = what + b + ": lines:" + getLinesInString(v).length + b + v;
}
function getStringLineCount(arr) {
arr.length;
}
function getGroupItems() {
let groups = getGroupsInString(getCurrentValue());
let groupItems = {
count: groups.length, // how many groups, two in the definition (top/bottom)
groups: []
};
groups.forEach(function(group, index, groupsArr) {
let items = getGroupItemsInString(group);
// determine how to define "group name", I use a string and the index here
let gname = "group" + index;
let g = {
itemCount: items.length // number in this group
};
g[gname] = {
items: []
};
items.forEach(function(item, itemindex, itemsArr) {
let itemName = "item" + itemindex;
let itemobj = {};
itemobj[itemName] = {
items: item
};
g[gname].items.push(itemobj);
});
groupItems.groups.push(g);
});
return groupItems;
}
// setup events
textElement.addEventListener(eventChangeName, onChangeTextareaValue, false);
textElement.addEventListener("focus", onFocusTextareaValue, false);
this.getGeometry = function() {
let geometry = {};
let element = textElement;
let rect = element.getBoundingClientRect();
geometry.top = rect.top;
geometry.right = rect.right;
geometry.bottom = rect.bottom;
geometry.left = rect.left;
geometry.offsetHeight = element.offsetHeight;
geometry.rows = element.rows;
geometry.clientHeight = element.clientHeight;
geometry.fontSize = this.getStyleProperty("font-size");
geometry.lineCount = this.getLines().length;
geometry.lineHeight = this.getLineHeight();
geometry.height = geometry.bottom - geometry.top;
geometry.width = geometry.right - geometry.left;
console.log("Geometry:",geometry);
};
this.getMetrics = function() {
let fSize = this.getStyleProperty("font-size");
let lineCount = this.getLines().length;
let lineHeight = this.getLineHeight();
let yh = lineHeight / lineCount;
let yfhPixel = parseInt(fSize, 10);
let yLineY = yh * yfhPixel;
console.log("LH:", lineHeight, "font:", fSize, "Lines:", lineCount, "lineHeight:", lineHeight, "yh:", yh, "yfPixel:", yfhPixel, "yLineY:", yLineY);
};
this.getStyleProperty = function(propertyName) {
return getStyle(textElement.id, propertyName)
};
// public functions and objects
this.getLines = function() {
return getLinesInString(getCurrentValue());
};
this.getGroups = function() {
return getGroupsInString(getCurrentValue());
};
this.setText = function(content) {
if (!content) {
content = this.sentData;
}
let hard = content.hard.join(lineSep);
let veryHard = content.very_hard.join(lineSep);
this.textElement.value = hard.concat("|" + lineSep, veryHard);
};
this.getLineHeight = function(element) {
if (!element) {
element = textElement;
}
let temp = document.createElement(element.nodeName);
temp.setAttribute("style", "margin:0px;padding:0px;font-family:" + element.style.fontFamily + ";font-size:" + element.style.fontSize);
temp.innerHTML = "test";
temp = element.parentNode.appendChild(temp);
let lineHeight = temp.clientHeight;
temp.parentNode.removeChild(temp);
return lineHeight;
};
this.getGroupItems = function() {
return getGroupItems();
};
this.textElement = textElement;
this.showme = showme;
};
let sentData = {
hard: [
"It's the possibility of having a dream come true that makes life interesting",
"I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation."
],
very_hard: ["He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even without looking."]
};
// create instances and use our app, pass the id
var containerApp = MyApp("textThing"); //default last three parameters
containerApp.sentData = sentData;
containerApp.setText();
let groups = containerApp.getGroups();
let groupItems = containerApp.getGroupItems();
containerApp.getMetrics();
containerApp.getGeometry();
// create instances and use our app, pass the id
var containerApp2 = MyApp("msgTwo", "showme", "|", "||");
//console.log("Second One Lines:", containerApp2.getLines().length);
//containerApp2.getMetrics();
//containerApp2.getGeometry();
.page-container {
display: flex;
/* center and stack the containers*/
justify-content: center;
flex-direction: column;
align-items: center;
font-size: 62.5%;
}
.container {
border: solid 1px black;
}
.container-block {
border: 2px dashed #AAAAAA;
}
.container-items {
width: 500px;
position: relative;
}
.container-items .format-custom,
.container-items label {
width: 100%;
}
.container-items .format-custom {
height: 10em
}
.message-hr {
border: 1px solid blue;
background-color: blue;
height: 0.05em;
width: 450px;
align-items: center;
margin: 0.5em;
}
.showme {
border: dotted 2px dodgerblue;
background-color: #EEEEEE;
padding: 1em;
}
textarea.format-custom,
.custom-underlay,
.underlay {
margin: 0;
box-sizing: border-box;
vertical-align: top;
display: block;
border: lime solid 1px;
}
textarea.format-custom {
width: 100%;
height: 3em;
background: transparent;
resize: none;
border: red solid 1px;
padding: 0.5em;
}
.underlay {
border: 1px solid #fff;
width: 100%;
height: 100%;
background: transparent;
top: 1em;
left: 0;
display: block;
z-index: -1;
position: absolute;
}
.custom-underlay {
width: 100%;
height: 50%;
margin: 0;
box-sizing: border-box;
vertical-align: top;
position: absolute;
}
.custom-underlay.top {
background-color: #FFFF00;
top: 0;
left: 0;
}
.custom-underlay.bottom {
background-color: #FFAAAA;
top: 50%;
left: 0;
}
<div class="page-container">
<div class="container">
<div class="container-block">
<div class="container-items">
<label for="textThing">Your message:</label>
<textarea id="textThing" name="textThing" class="format-custom">howdy, I am here|another one | cheese burgers
fries and a drink
||
bottom of here| bottom second</textarea>
<div class="underlay">
<div class="custom-underlay top"></div>
<div class="custom-underlay bottom"></div>
</div>
</div>
</div>
<div class="showme">xxxone</div>
</div>
<div class="container">
<div class="container-block">
<div class="message-hr container-items">
</div>
</div>
</div>
<div class="container">
<div class="container-block">
<div class="container-items">
<label for="msgTwo">Second message:</label>
<textarea id="msgTwo" name="msgTwo" class="format-custom">Not the same|Nxxt one
||
bottom of next</textarea>
<div class="underlay">
<div class="custom-underlay top"></div>
<div class="custom-underlay bottom"></div>
</div>
</div>
</div>
<div class="showme">xxxtwo</div>
</div>
</div>
its not with color but in this code you can set a lable like this (hard: veryhard :)
state = {
value: "",
hard: [],
veryHard: []
};
handleChange = ({ target }) => {
const { value, name } = target;
console.log(value, name);
this.setState({ value });
};
performAnalysis = () => {
let hard = [
//this state ,get from performHard function (you should set state it )
"It's the possibility of having a dream come true that makes life interesting",
"I cannot fix on the hour, or the spot, or the look or the words, which laid the foundation."
];
let veryHard = [
//this state ,get from performVHard function (you should set state it )
"“He stepped down, trying not to look long at her, as if she were the sun, yet he saw her, like the sun, even without looking.“"
];
this.setState({ hard, veryHard });
// you shoud setState like this in these 2 function
// this.performHard();
// this.performVHard();
};
render() {
return (
<div className="App">
<header className="App-header">
<textarea
value={
this.state.value.length
? this.state.value
: " Hard : " +
" " +
this.state.hard +
" " +
"very Hard : " +
this.state.veryHard
}
onChange={this.handleChange}
/>
<button onClick={this.performAnalysis}>analise</button>
</header>
</div>
);
}
its not exactly that you want,but you can get help from this code