Related
I am trying to build a simple editor using fabricjs.
I did the following:
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.9.0/font/bootstrap-icons.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
<style>
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
body {
touch-action: none;
background-image: linear-gradient(to bottom left, rgb(214, 240, 201) 10%, rgba(255, 231, 191, 1) 80%);
-webkit-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
.input-group {
padding: 4px;
}
.canvas-container {
margin: 0 auto;
width: 100%;
overflow: hidden;
background: url(./transparent.png);
background-size: 15px 15px;
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
}
.actived {
background: #fff9a8;
}
.list-group {
line-height: 35px;
}
.svg-icon {
width: 1em;
height: 1em;
}
.svg-icon path,
.svg-icon polygon,
.svg-icon rect {
fill: #4691f6;
}
.svg-icon circle {
stroke: #4691f6;
stroke-width: 1;
}
.fl {
float: left;
}
.fr {
float: right;
}
.input-group-text {
background-color: #f4f4f4;
}
.list-group-item {
padding: 2px 10px;
;
cursor: pointer;
}
.list-group {
border-radius: 0;
text-align: left;
}
</style>
</head>
<body>
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-sm-3 border-end text-center h-100 overflow-scroll bg-light py-3">
<hr>
<div class="form-floating w-100 mb-3 tour5">
<h6 class="mb-3">Add Element</h6>
<button class="btn btn-outline-primary" onclick="addText();" data-toggle="tooltip" data-placement="top" title="" data-bs-original-title="Add Text" aria-label="Add Text"><i
class="fa fa-font"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Circle({ name: genNextName(), originX:'center', originY:'center', radius: 30, fill: '#000', top: 100, left: 100 }));" data-bs-original-title="Add Circle"
aria-label="Add Circle"><i
class="fa fa-circle"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Triangle({ name: genNextName(), originX:'center', originY:'center', height:100, width:100, fill: '#000', top: 100, left: 100 }));"
data-bs-original-title="Add Triangle">
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="triangle" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class=""
style="height: 16px;top: 9px;">
<path fill="currentColor"
d="M329.6 24c-18.4-32-64.7-32-83.2 0L6.5 440c-18.4 31.9 4.6 72 41.6 72H528c36.9 0 60-40 41.6-72l-240-416z"
class=""></path>
</svg>
</button>
</div>
<hr>
</div>
<div class="col-sm-6 my-auto py-4 overflow-hidden">
<div class="canvas-container" style="width: 329px; height: 329px; position: relative; user-select: none;"><canvas id="c" class="lower-canvas" width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas><canvas class="upper-canvas " width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: manipulation; user-select: none; cursor: default;"></canvas>
</div>
</div>
<div class="col-sm-3 border-start py-3 h-100 overflow-scroll bg-light text-center">
<form class="form-inline pt-4" id="f" onsubmit="return false;" style="display: none;">
<div class="form-floating w-100 mb-4" style="">
<textarea type="text" class="form-control form-control-sm" name="text" oninput="canvas.getActiveObject().set({'text':this.value}); canvas.renderAll();" onmouseover="this.style.height = (this.scrollHeight)+'px';" rows="10" autocomplete="off"></textarea>
<label for="floatingInput" class="lable-sm">Text</label>
</div>
<div class="input-group input-group-sm mb-3 w-100 tour13">
<span class="input-group-text" id="inputGroup-sizing-sm">MaxHeight to Fit Text</span>
<input type="number" class="form-control" name="maxHeight" onkeyup="hide_mh_box(); show_mh_box();" onblur="hide_mh_box();" onfocus="show_mh_box();" autocomplete="off">
</div>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<script src="https://unpkg.com/fabric#5.2.1/dist/fabric.min.js"></script>
<script src="https://rawcdn.githack.com/lyzerk/fabric-history/8c223cbdc8305307b4a8f8710f97da54d9146ffa/src/index.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/centering_guidelines.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
<script>
var canvas;
var apiUrl;
var startedLoadingFamilies = false;
var to;
var scale;
fabric.Text.prototype.set({
_getNonTransformedDimensions() {
return new fabric.Point(this.width, this.height).scalarAdd(this.padding);
},
_calculateCurrentDimensions() {
return fabric.util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true);
}
});
function fitCanvas(w, h) {
var scaleW = (document.querySelectorAll(".col-sm-6")[0].offsetWidth - 100) / w;
var scaleH = (document.querySelectorAll("body")[0].offsetHeight - 100) / h;
scale = Math.min(scaleH, scaleW);
if (scale > 1) {
scale = 1;
}
canvas.setZoom(scale);
canvas.setWidth(w * scale);
canvas.setHeight(h * scale);
initAligningGuidelines(canvas);
initCenteringGuidelines(canvas);
canvas.renderAll();
console.log("finished!!");
}
(function() {
canvas = new fabric.Canvas('c', {
allowTouchScrolling: true
});
WebFont.load({
google: {
families: ["Inter:200"]
},
active: function() {
canvas.loadFromJSON({
"height": "500",
"width": "500",
"edit": "yes",
"objects": [],
"backgroundImage": {
"crossOrigin": "anonymous"
}
}, function() {
fitCanvas(500, 500);
})
}
});
canvas.on('before:render', function(opt) {
canvas.getObjects().map(function(o, i) {
if (o.type.toLowerCase() == "textbox") {
var maxH = (o.maxHeight) ? (o.maxHeight) : (canvas.height);
o.set({
'maxHeight': maxH
});
if (o.fontSize > 0 && (maxH > o.fontSize)) {
while (o.height > maxH) {
o.set({
'fontSize': o.fontSize - 1
});
}
}
}
if (o.circleFrame) {
o.set({
clipPath: new fabric.Circle({
radius: o.width / 2,
originX: 'center',
originY: 'center'
})
});
}
if ((o.rx || o.ry) && o.type == "image") {
let rx = (o.rx || 0);
let ry = (o.ry || 0);
o.set({
clipPath: new fabric.Rect({
rx: rx,
ry: ry,
height: o.height,
width: o.width,
originX: 'center',
originY: 'center'
})
});
}
});
});
})();
</script>
<script>
fabric.Object.prototype.objectCaching = false;
function changeDim() {
fitCanvas($("#widthC").val(), $("#heightC").val());
}
function setCanvasBI(src, o = "1") {
if (!src) {
src = $("#canvasBI").val();
}
if (src.length == 0) {
src = new fabric.Image('');
}
canvas.setBackgroundImage(src, canvas.renderAll.bind(canvas), {
opacity: o
});
}
(function() {
$(document).on("mouseenter", "[data-label]", function() {
$("#font-search").val($(this).data("label"));
loadFont($(this).data("label"));
});
fabric.Canvas.prototype.getItemByAttr = function(attr, name) {
var object = null,
objects = this.getObjects();
for (var i = 0, len = this.size(); i < len; i++) {
if (objects[i][attr] && objects[i][attr] == name) {
object = objects[i];
break;
}
}
return object;
};
$("form#f").hide();
var activeObject;
$("#f input, #f select").on("input", function() {
if (["height", "width", "top", "left", "strokeWidth", "charSpacing"].includes(this.name)) {
canvas.getActiveObject().set(this.name, parseFloat(this.value)).setCoords();
} else {
canvas.getActiveObject().set(this.name, this.value).setCoords();
}
canvas.renderAll();
});
canvas.preserveObjectStacking = true;
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name,
text: this.text
});
};
})(fabric.Object.prototype.toObject);
canvas.on('object:scaling', function(e) {
if (e.target.toObject().type != "image" && e.target.toObject().type != "circle") {
e.target.set({
width: e.target.width * e.target.scaleX,
height: e.target.height * e.target.scaleY,
scaleX: 1,
scaleY: 1
})
}
});
canvas.on('object:modified', function(opt) {
document.body.style.cursor = 'progress';
});
canvas.on("after:render", function() {
canvas.includeDefaultValues = false;
canvas.toObject().objects.forEach(function(layer, id) {
if (typeof layer.name !== 'undefined') {
canvas.getItemByAttr(`name`, layer.name).set({
"name": String.fromCharCode(65 + id).toLowerCase()
})
var actived = '';
if (canvas.getActiveObject()) {
actived = (canvas.getActiveObject().name == layer.name) ? " actived" : "";
}
}
});
document.body.style.cursor = 'default'
});
canvas.on("selection:created", function(obj) {
if ("image" == obj.target.type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
$("form#f input[type!='hidden'], #f select").parent().hide();
$("form#f").hide();
canvas.renderAll();
showForm();
});
canvas.on("selection:updated", function(obj) {
if ("image" == obj.target.type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'] , #f select, #f textarea").parent().hide();
showForm();
});
canvas.on("selection:cleared", function() {
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'], #f select, #f textarea").parent().hide();
});
canvas.hoverCursor = 'default';
canvas.on('mouse:over', function(e) {
if (e.target) {
e.target._renderControls(canvas.contextTop, {
hasControls: false
})
}
});
canvas.on('mouse:out', function(e) {
canvas.clearContext(canvas.contextTop);
});
canvas.on('mouse:down', function(e) {
canvas.clearContext(canvas.contextTop);
});
function showForm() {
$("form#f").show();
activeObject = canvas.getActiveObject();
var v;
for (i in activeObject) {
v = activeObject[i];
if (typeof v != "undefined") {
$("textarea[name='" + i + "']").val(v).parent().show();
$("input[name='" + i + "']").val(v).parent().show();
$("select[name='" + i + "']").val(v).parent().show();
}
}
}
addText = function() {
var text = new fabric.Textbox("Edit this Text", {
name: genNextName(),
left: canvas.getWidth() / canvas.getZoom() / 2,
top: canvas.getHeight() / canvas.getZoom() / 2,
width: (canvas.getWidth() / canvas.getZoom()) / 2,
fill: "#000000",
originX: "center",
originY: "center",
fontFamily: "Inter",
fontWeight: 400,
fontSize: 60,
padding: 20
});
text.setControlsVisibility({
mt: false,
mb: false,
ml: true,
mr: true,
tl: true,
tr: true,
bl: true,
br: true
});
canvas.add(text);
canvas.setActiveObject(text);
canvas.renderAll();
};
})();
function hide_mh_box() {
canvas.remove(canvas.getItemByAttr("isBB", true));
}
function show_mh_box() {
var h = parseInt($("[name=maxHeight]").val());
var n = new fabric.Rect({
top: canvas.getActiveObject().get('top'),
left: canvas.getActiveObject().get('left'),
width: canvas.getActiveObject().get('width'),
height: h,
originX: canvas.getActiveObject().get('originX'),
originY: canvas.getActiveObject().get('originY'),
angle: canvas.getActiveObject().get('angle'),
opacity: 1,
strokeWidth: 2,
stroke: "#FF00FF",
fill: "rgba(0,0,0,0)",
evented: !1,
isBB: true
});
canvas.add(n);
canvas.renderAll();
}
var visited = [];
</script>
<script>
function genNextName() {
canvas.renderAll();
var total = canvas.getObjects().length;
return String.fromCharCode(65 + total).toLowerCase()
}
</script>
</body>
</html>
When I click on an element f.ex. the triangle it is added to the canvas. When I click on the added triangle a menu on the right should go up. However, the element does not get selected.
Any suggestions what I am doing wrong?
I appreciate your replies!
you have second canvas element next to your canvas, it prevents from clicking on first canvas element, removing this second canvas solves this issue
<canvas class="upper-canvas " width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: manipulation; user-select: none; cursor: default;"></canvas>
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.9.0/font/bootstrap-icons.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
<style>
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
body {
touch-action: none;
background-image: linear-gradient(to bottom left, rgb(214, 240, 201) 10%, rgba(255, 231, 191, 1) 80%);
-webkit-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
.input-group {
padding: 4px;
}
.canvas-container {
margin: 0 auto;
width: 100%;
overflow: hidden;
background: url(./transparent.png);
background-size: 15px 15px;
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
}
.actived {
background: #fff9a8;
}
.list-group {
line-height: 35px;
}
.svg-icon {
width: 1em;
height: 1em;
}
.svg-icon path,
.svg-icon polygon,
.svg-icon rect {
fill: #4691f6;
}
.svg-icon circle {
stroke: #4691f6;
stroke-width: 1;
}
.fl {
float: left;
}
.fr {
float: right;
}
.input-group-text {
background-color: #f4f4f4;
}
.list-group-item {
padding: 2px 10px;
;
cursor: pointer;
}
.list-group {
border-radius: 0;
text-align: left;
}
</style>
</head>
<body>
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-sm-3 border-end text-center h-100 overflow-scroll bg-light py-3">
<hr>
<div class="form-floating w-100 mb-3 tour5">
<h6 class="mb-3">Add Element</h6>
<button class="btn btn-outline-primary" onclick="addText();" data-toggle="tooltip" data-placement="top" title="" data-bs-original-title="Add Text" aria-label="Add Text"><i
class="fa fa-font"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Circle({ name: genNextName(), originX:'center', originY:'center', radius: 30, fill: '#000', top: 100, left: 100 }));" data-bs-original-title="Add Circle"
aria-label="Add Circle"><i
class="fa fa-circle"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Triangle({ name: genNextName(), originX:'center', originY:'center', height:100, width:100, fill: '#000', top: 100, left: 100 }));"
data-bs-original-title="Add Triangle">
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="triangle" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class=""
style="height: 16px;top: 9px;">
<path fill="currentColor"
d="M329.6 24c-18.4-32-64.7-32-83.2 0L6.5 440c-18.4 31.9 4.6 72 41.6 72H528c36.9 0 60-40 41.6-72l-240-416z"
class=""></path>
</svg>
</button>
</div>
<hr>
</div>
<div class="col-sm-6 my-auto py-4 overflow-hidden">
<div class="canvas-container" style="width: 329px; height: 329px; position: relative; user-select: none;"><canvas id="c" class="lower-canvas" width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas>
</div>
</div>
<div class="col-sm-3 border-start py-3 h-100 overflow-scroll bg-light text-center">
<form class="form-inline pt-4" id="f" onsubmit="return false;" style="display: none;">
<div class="form-floating w-100 mb-4" style="">
<textarea type="text" class="form-control form-control-sm" name="text" oninput="canvas.getActiveObject().set({'text':this.value}); canvas.renderAll();" onmouseover="this.style.height = (this.scrollHeight)+'px';" rows="10" autocomplete="off"></textarea>
<label for="floatingInput" class="lable-sm">Text</label>
</div>
<div class="input-group input-group-sm mb-3 w-100 tour13">
<span class="input-group-text" id="inputGroup-sizing-sm">MaxHeight to Fit Text</span>
<input type="number" class="form-control" name="maxHeight" onkeyup="hide_mh_box(); show_mh_box();" onblur="hide_mh_box();" onfocus="show_mh_box();" autocomplete="off">
</div>
</form>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<script src="https://unpkg.com/fabric#5.2.1/dist/fabric.min.js"></script>
<script src="https://rawcdn.githack.com/lyzerk/fabric-history/8c223cbdc8305307b4a8f8710f97da54d9146ffa/src/index.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/centering_guidelines.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
<script>
var canvas;
var apiUrl;
var startedLoadingFamilies = false;
var to;
var scale;
fabric.Text.prototype.set({
_getNonTransformedDimensions() {
return new fabric.Point(this.width, this.height).scalarAdd(this.padding);
},
_calculateCurrentDimensions() {
return fabric.util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true);
}
});
function fitCanvas(w, h) {
var scaleW = (document.querySelectorAll(".col-sm-6")[0].offsetWidth - 100) / w;
var scaleH = (document.querySelectorAll("body")[0].offsetHeight - 100) / h;
scale = Math.min(scaleH, scaleW);
if (scale > 1) {
scale = 1;
}
canvas.setZoom(scale);
canvas.setWidth(w * scale);
canvas.setHeight(h * scale);
initAligningGuidelines(canvas);
initCenteringGuidelines(canvas);
canvas.renderAll();
console.log("finished!!");
}
(function() {
canvas = new fabric.Canvas('c', {
allowTouchScrolling: true
});
WebFont.load({
google: {
families: ["Inter:200"]
},
active: function() {
canvas.loadFromJSON({
"height": "500",
"width": "500",
"edit": "yes",
"objects": [],
"backgroundImage": {
"crossOrigin": "anonymous"
}
}, function() {
fitCanvas(500, 500);
})
}
});
canvas.on('before:render', function(opt) {
canvas.getObjects().map(function(o, i) {
if (o.type.toLowerCase() == "textbox") {
var maxH = (o.maxHeight) ? (o.maxHeight) : (canvas.height);
o.set({
'maxHeight': maxH
});
if (o.fontSize > 0 && (maxH > o.fontSize)) {
while (o.height > maxH) {
o.set({
'fontSize': o.fontSize - 1
});
}
}
}
if (o.circleFrame) {
o.set({
clipPath: new fabric.Circle({
radius: o.width / 2,
originX: 'center',
originY: 'center'
})
});
}
if ((o.rx || o.ry) && o.type == "image") {
let rx = (o.rx || 0);
let ry = (o.ry || 0);
o.set({
clipPath: new fabric.Rect({
rx: rx,
ry: ry,
height: o.height,
width: o.width,
originX: 'center',
originY: 'center'
})
});
}
});
});
})();
</script>
<script>
fabric.Object.prototype.objectCaching = false;
function changeDim() {
fitCanvas($("#widthC").val(), $("#heightC").val());
}
function setCanvasBI(src, o = "1") {
if (!src) {
src = $("#canvasBI").val();
}
if (src.length == 0) {
src = new fabric.Image('');
}
canvas.setBackgroundImage(src, canvas.renderAll.bind(canvas), {
opacity: o
});
}
(function() {
$(document).on("mouseenter", "[data-label]", function() {
$("#font-search").val($(this).data("label"));
loadFont($(this).data("label"));
});
fabric.Canvas.prototype.getItemByAttr = function(attr, name) {
var object = null,
objects = this.getObjects();
for (var i = 0, len = this.size(); i < len; i++) {
if (objects[i][attr] && objects[i][attr] == name) {
object = objects[i];
break;
}
}
return object;
};
$("form#f").hide();
var activeObject;
$("#f input, #f select").on("input", function() {
if (["height", "width", "top", "left", "strokeWidth", "charSpacing"].includes(this.name)) {
canvas.getActiveObject().set(this.name, parseFloat(this.value)).setCoords();
} else {
canvas.getActiveObject().set(this.name, this.value).setCoords();
}
canvas.renderAll();
});
canvas.preserveObjectStacking = true;
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name,
text: this.text
});
};
})(fabric.Object.prototype.toObject);
canvas.on('object:scaling', function(e) {
if (e.target.toObject().type != "image" && e.target.toObject().type != "circle") {
e.target.set({
width: e.target.width * e.target.scaleX,
height: e.target.height * e.target.scaleY,
scaleX: 1,
scaleY: 1
})
}
});
canvas.on('object:modified', function(opt) {
document.body.style.cursor = 'progress';
});
canvas.on("after:render", function() {
canvas.includeDefaultValues = false;
canvas.toObject().objects.forEach(function(layer, id) {
if (typeof layer.name !== 'undefined') {
canvas.getItemByAttr(`name`, layer.name).set({
"name": String.fromCharCode(65 + id).toLowerCase()
})
var actived = '';
if (canvas.getActiveObject()) {
actived = (canvas.getActiveObject().name == layer.name) ? " actived" : "";
}
}
});
document.body.style.cursor = 'default'
});
canvas.on("selection:created", function(obj) {
if ("image" == obj.target?.type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
$("form#f input[type!='hidden'], #f select").parent().hide();
$("form#f").hide();
canvas.renderAll();
showForm();
});
canvas.on("selection:updated", function(obj) {
if ("image" == obj.target?.type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'] , #f select, #f textarea").parent().hide();
showForm();
});
canvas.on("selection:cleared", function() {
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'], #f select, #f textarea").parent().hide();
});
canvas.hoverCursor = 'default';
canvas.on('mouse:over', function(e) {
if (e.target) {
e.target._renderControls(canvas.contextTop, {
hasControls: false
})
}
});
canvas.on('mouse:out', function(e) {
canvas.clearContext(canvas.contextTop);
});
canvas.on('mouse:down', function(e) {
canvas.clearContext(canvas.contextTop);
});
function showForm() {
$("form#f").show();
activeObject = canvas.getActiveObject();
var v;
for (i in activeObject) {
v = activeObject[i];
if (typeof v != "undefined") {
$("textarea[name='" + i + "']").val(v).parent().show();
$("input[name='" + i + "']").val(v).parent().show();
$("select[name='" + i + "']").val(v).parent().show();
}
}
}
addText = function() {
var text = new fabric.Textbox("Edit this Text", {
name: genNextName(),
left: canvas.getWidth() / canvas.getZoom() / 2,
top: canvas.getHeight() / canvas.getZoom() / 2,
width: (canvas.getWidth() / canvas.getZoom()) / 2,
fill: "#000000",
originX: "center",
originY: "center",
fontFamily: "Inter",
fontWeight: 400,
fontSize: 60,
padding: 20
});
text.setControlsVisibility({
mt: false,
mb: false,
ml: true,
mr: true,
tl: true,
tr: true,
bl: true,
br: true
});
canvas.add(text);
canvas.setActiveObject(text);
canvas.renderAll();
};
})();
function hide_mh_box() {
canvas.remove(canvas.getItemByAttr("isBB", true));
}
function show_mh_box() {
var h = parseInt($("[name=maxHeight]").val());
var n = new fabric.Rect({
top: canvas.getActiveObject().get('top'),
left: canvas.getActiveObject().get('left'),
width: canvas.getActiveObject().get('width'),
height: h,
originX: canvas.getActiveObject().get('originX'),
originY: canvas.getActiveObject().get('originY'),
angle: canvas.getActiveObject().get('angle'),
opacity: 1,
strokeWidth: 2,
stroke: "#FF00FF",
fill: "rgba(0,0,0,0)",
evented: !1,
isBB: true
});
canvas.add(n);
canvas.renderAll();
}
var visited = [];
</script>
<script>
function genNextName() {
canvas.renderAll();
var total = canvas.getObjects().length;
return String.fromCharCode(65 + total).toLowerCase()
}
</script>
</body>
</html>
I am using FabricJS 5 and have implemented a simple display for my layers.
When I press the pencil button I open a prompt and rename the layer using the following function:
function RenameLayer(name) {
let layerObj = canvas.getItemByAttr("name", name);
let newName = prompt("Rename Layer?", layerObj.name);
while (checkIfNameExists(newName)) {
alert("Your layer name: " + layerObj.name + " is NOT unique please rename your layer differently.")
newName = prompt("Rename Layer?", layerObj.name);
}
layerObj.name = newName;
canvas.renderAll();
}
function checkIfNameExists(newName) {
count = 0;
canvas.forEachObject(function(obj, i) {
if (obj.name == newName) {
count++;
}
});
if (count > 0) {
return true;
} else {
return false;
}
}
However, after renaming I get an error.
Find below my example:
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.9.0/font/bootstrap-icons.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
<style>
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
body {
touch-action: none;
background-image: linear-gradient(to bottom left, rgb(214, 240, 201) 10%, rgba(255, 231, 191, 1) 80%);
-webkit-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
.input-group {
padding: 4px;
}
.canvas-container {
margin: 0 auto;
width: 100%;
overflow: hidden;
background: url(./transparent.png);
background-size: 15px 15px;
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
}
.actived {
background: #fff9a8;
}
#sortable {
max-height: 200px;
overflow: scroll;
}
.list-group {
line-height: 35px;
}
.svg-icon {
width: 1em;
height: 1em;
}
.svg-icon path,
.svg-icon polygon,
.svg-icon rect {
fill: #4691f6;
}
.svg-icon circle {
stroke: #4691f6;
stroke-width: 1;
}
#bkboxXX {
background: url(transparent.png);
border: 1px solid rgba(0, 0, 0, 0.3);
display: inline-block;
height: 19px;
width: 20px;
}
.bk-btn {
background: url(/transparent.png);
}
.fl {
float: left;
}
.fr {
float: right;
}
.input-group-text {
background-color: #f4f4f4;
}
.input-group-sm>.input-group-text {
/*
padding: .2rem .3rem !important;
*/
}
.list-group-item {
padding: 2px 10px;
;
cursor: pointer;
}
.list-group {
border-radius: 0;
text-align: left;
}
</style>
</head>
<body>
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-sm-3 border-end text-center h-100 overflow-scroll bg-light py-3">
<div class="form-floating w-100 mb-3 tour5">
<h6 class="mb-3">Add Element</h6>
<button class="btn btn-outline-primary" onclick="addText();" data-toggle="tooltip" data-placement="top" title="" data-bs-original-title="Add Text" aria-label="Add Text"><i
class="fa fa-font"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Circle({ name: genNextName(), originX:'center', originY:'center', radius: 30, fill: 'green', top: 100, left: 100 }));" data-bs-original-title="Add Circle"
aria-label="Add Circle"><i
class="fa fa-circle"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Triangle({ name: genNextName(), originX:'center', originY:'center', height:100, width:100, fill: 'red', top: 100, left: 100 }));"
data-bs-original-title="Add Triangle">
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="triangle" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class=""
style="height: 16px;top: 9px;">
<path fill="currentColor"
d="M329.6 24c-18.4-32-64.7-32-83.2 0L6.5 440c-18.4 31.9 4.6 72 41.6 72H528c36.9 0 60-40 41.6-72l-240-416z"
class=""></path>
</svg>
</button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick="canvas.add(new fabric.Rect({ name: genNextName(), originX:'center', originY:'center', left: 110, top: 110, fill: '#000', width: 50, height: 50 }))" data-bs-original-title="Add Rectangle"><i class="fa fa-square-full"></i> </button>
</div>
<hr>
<div class="w-100 tour7 Xd-none Xd-sm-block">
<h6 class="mb-3">Elements</h6>
<ul class="list-group" id="sortable"></ul>
</div>
</div>
<div class="col-sm-6 my-auto py-4 overflow-hidden">
<div class="canvas-container" style="width: 329px; height: 329px; position: relative; user-select: none;"><canvas id="c" class="lower-canvas" width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas>
</div>
</div>
<div class="col-sm-3 border-start py-3 h-100 overflow-scroll bg-light text-center">
right map
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<script src="https://unpkg.com/fabric#5.2.1/dist/fabric.min.js"></script>
<script src="https://rawcdn.githack.com/lyzerk/fabric-history/8c223cbdc8305307b4a8f8710f97da54d9146ffa/src/index.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/centering_guidelines.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
<script>
const rgba2hex = (rgba) => `#${rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/).slice(1).map((n, i) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n)).toString(16).padStart(2, '0').replace('NaN', '')).join('')}`
function cn2h(cn) {
if (!cn) {
return 'transparent';
}
d = document.createElement("span");
d.style.display = "none";
d.style.color = cn
document.body.appendChild(d)
return rgba2hex(window.getComputedStyle(d).color);
}
</script>
<script>
var canvas;
var apiUrl;
var startedLoadingFamilies = false;
var to;
var scale;
fabric.Text.prototype.set({
_getNonTransformedDimensions() { // Object dimensions
return new fabric.Point(this.width, this.height).scalarAdd(this.padding);
},
_calculateCurrentDimensions() { // Controls dimensions
return fabric.util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true);
}
});
function fitCanvas(w, h) {
var scaleW = (document.querySelectorAll(".col-sm-6")[0].offsetWidth - 100) / w;
var scaleH = (document.querySelectorAll("body")[0].offsetHeight - 100) / h;
scale = Math.min(scaleH, scaleW);
if (scale > 1) {
scale = 1;
}
canvas.setZoom(scale);
canvas.setWidth(w * scale);
canvas.setHeight(h * scale);
initAligningGuidelines(canvas);
initCenteringGuidelines(canvas);
canvas.renderAll();
console.log("finished!!");
}
(function() {
canvas = new fabric.Canvas('c', {
allowTouchScrolling: true
});
WebFont.load({
google: {
families: ["Inter:200"]
},
active: function() {
canvas.loadFromJSON({
"height": "500",
"width": "500",
"edit": "yes",
"objects": [],
"backgroundImage": {
"crossOrigin": "anonymous"
}
}, function() {
fitCanvas(500, 500);
})
}
});
canvas.on('before:render', function(opt) {
canvas.getObjects().map(function(o, i) {
if (o.type.toLowerCase() == "textbox") {
var maxH = (o.maxHeight) ? (o.maxHeight) : (canvas.height);
o.set({
'maxHeight': maxH
});
if (o.fontSize > 0 && (maxH > o.fontSize)) {
while (o.height > maxH) {
o.set({
'fontSize': o.fontSize - 1
});
}
}
}
if (o.circleFrame) {
o.set({
clipPath: new fabric.Circle({
radius: o.width / 2,
originX: 'center',
originY: 'center'
})
});
}
if ((o.rx || o.ry) && o.type == "image") {
let rx = (o.rx || 0);
let ry = (o.ry || 0);
o.set({
clipPath: new fabric.Rect({
rx: rx,
ry: ry,
height: o.height,
width: o.width,
originX: 'center',
originY: 'center'
})
});
}
});
});
})();
</script>
<script>
fabric.Object.prototype.objectCaching = false;
function setCanvasBG(clr) {
canvas.backgroundColor = clr;
canvas.renderAll();
}
function changeDim() {
fitCanvas($("#widthC").val(), $("#heightC").val());
}
function setColor(clr, what = 'fill') {
canvas.getActiveObject().set(what, clr);
canvas.renderAll();
}
(function() {
$(document).on("mouseenter", "[data-label]", function() {
$("#font-search").val($(this).data("label"));
loadFont($(this).data("label"));
});
fabric.Canvas.prototype.getItemByAttr = function(attr, name) {
var object = null,
objects = this.getObjects();
for (var i = 0, len = this.size(); i < len; i++) {
if (objects[i][attr] && objects[i][attr] == name) {
object = objects[i];
break;
}
}
return object;
};
$("form#f").hide();
var activeObject;
$("#f input, #f select").on("input", function() {
if (["height", "width", "top", "left", "strokeWidth", "charSpacing"].includes(this.name)) {
canvas.getActiveObject().set(this.name, parseFloat(this.value)).setCoords();
} else {
canvas.getActiveObject().set(this.name, this.value).setCoords();
}
canvas.renderAll();
});
canvas.preserveObjectStacking = true;
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name,
text: this.text,
textAlign: this.textAlign,
fontSize: this.fontSize,
charSpacing: this.charSpacing,
lineHeight: this.lineHeight,
fontWeight: this.fontWeight,
fontFamily: this.fontFamily,
fontStyle: this.fontStyle,
textBackgroundColor: this.textBackgroundColor,
originX: this.originX,
originY: this.originY,
maxHeight: this.maxHeight,
height: this.height,
width: this.width,
radius: this.radius,
rx: this.rx,
ry: this.ry,
stroke: this.stroke,
padding: this.padding,
circleFrame: this.circleFrame
});
};
})(fabric.Object.prototype.toObject);
canvas.on('object:scaling', function(e) {
if (e.target.toObject().type != "image" && e.target.toObject().type != "circle") {
e.target.set({
width: e.target.width * e.target.scaleX,
height: e.target.height * e.target.scaleY,
scaleX: 1,
scaleY: 1
})
}
});
canvas.on('object:modified', function(opt) {
document.body.style.cursor = 'progress';
});
canvas.on("after:render", function() {
$("#sortable").empty();
canvas.includeDefaultValues = false;
canvas.toObject().objects.forEach(function(layer, id) {
if (typeof layer.name !== 'undefined') {
//console.log(id,layer.name);
//canvas.getItemByAttr(`name`, layer.name).set({ "name": String.fromCharCode(65 + id).toLowerCase() })
canvas.getItemByAttr(`name`, layer.name).set({
"name": layer.name.replace(/ /g, "_")
})
var actived = '';
if (canvas.getActiveObject()) {
actived = (canvas.getActiveObject().name == layer.name) ? " actived" : "";
}
$("#sortable").append('<li class="list-group-item ui-sortable-handle clearfix ' + actived + '" onClick="canvas.setActiveObject(canvas.getItemByAttr(`name`,`' + layer.name + '`)); canvas.renderAll();" id=' + layer.name + '>' + layer.name + ' (' + layer.type + ')' + '<span class="fr button-group"><a class="mx-2" title="Edit" href="#" onClick="RenameLayer(`' + layer.name + '`)"><i class="fa fa-pencil-alt" aria-hidden="true"></i></a><a class="mx-2" title="Delete" href="#" onClick="if(confirm(`Are you sure?`)){canvas.remove(canvas.getItemByAttr(`name`,`' + layer.name + '`)); canvas.renderAll();}"><i class="fa fa-trash-alt" aria-hidden="true"></i></a><a class="me-2" title="Duplicate this layer" href="#" onClick="Duplicate(`' + layer.name + '`); canvas.renderAll();"><i class="fa fa-clone" aria-hidden="true"></i></a></span></li>');
}
});
document.body.style.cursor = 'default'
});
canvas.on("selection:created", function(obj) {
if ("image" == obj.selected[0].type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
$("form#f input[type!='hidden'], #f select").parent().hide();
$("form#f").hide();
canvas.renderAll();
});
canvas.on("selection:updated", function(obj) {
if ("image" == obj.selected[0].type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'] , #f select, #f textarea").parent().hide();
});
canvas.on("selection:cleared", function() {
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'], #f select, #f textarea").parent().hide();
});
canvas.hoverCursor = 'default';
canvas.on('mouse:over', function(e) {
if (e.target) {
e.target._renderControls(canvas.contextTop, {
hasControls: false
})
}
});
canvas.on('mouse:out', function(e) {
canvas.clearContext(canvas.contextTop);
});
canvas.on('mouse:down', function(e) {
canvas.clearContext(canvas.contextTop);
});
addText = function() {
var text = new fabric.Textbox("Edit this Text", {
name: genNextName(),
left: canvas.getWidth() / canvas.getZoom() / 2,
top: canvas.getHeight() / canvas.getZoom() / 2,
width: (canvas.getWidth() / canvas.getZoom()) / 2,
fill: "#000000",
originX: "center",
originY: "center",
fontFamily: "Inter",
fontWeight: 400,
fontSize: 60,
padding: 20
});
text.setControlsVisibility({
mt: false,
mb: false,
ml: true,
mr: true,
tl: true,
tr: true,
bl: true,
br: true
});
canvas.add(text);
canvas.setActiveObject(text);
canvas.renderAll();
};
})();
function hide_mh_box() {
canvas.remove(canvas.getItemByAttr("isBB", true));
}
function show_mh_box() {
var h = parseInt($("[name=maxHeight]").val());
var n = new fabric.Rect({
top: canvas.getActiveObject().get('top'),
left: canvas.getActiveObject().get('left'),
width: canvas.getActiveObject().get('width'),
height: h,
originX: canvas.getActiveObject().get('originX'),
originY: canvas.getActiveObject().get('originY'),
angle: canvas.getActiveObject().get('angle'),
opacity: 1,
strokeWidth: 2,
stroke: "#FF00FF",
fill: "rgba(0,0,0,0)",
evented: !1,
isBB: true
});
canvas.add(n);
canvas.renderAll();
}
var visited = [];
$(document).ready(function() {
$("input[type=color]").on("input", function() {
$(this).parent().parent().find('input').first().val(this.value);
});
$("textarea, input").attr("autocomplete", "off");
if (window !== window.parent) {
const url = new URL(document.referrer);
$(".isIframe").removeClass('d-none');
$(".notIframe").hide();
}
});
</script>
<script>
function Duplicate(name) {
Copy(name);
}
function Copy(name) {
canvas.getItemByAttr("name", name).clone(function(cloned) {
cloned.set({
"name": genNextName()
})
_clipboard = cloned;
Paste(name);
canvas.renderAll();
});
}
function RenameLayer(name) {
let layerObj = canvas.getItemByAttr("name", name);
let newName = prompt("Rename Layer?", layerObj.name);
while (checkIfNameExists(newName)) {
alert("Your layer name: " + layerObj.name + " is NOT unique please rename your layer differently.")
newName = prompt("Rename Layer?", layerObj.name);
}
layerObj.name = newName;
canvas.renderAll();
}
function checkIfNameExists(newName) {
count = 0;
canvas.forEachObject(function(obj, i) {
if (obj.name == newName) {
count++;
}
});
if (count > 0) {
return true;
} else {
return false;
}
}
function Paste(name) {
_clipboard.clone(function(clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
clonedObj.canvas = canvas;
clonedObj.forEachObject(function(obj) {
canvas.add(obj);
});
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
_clipboard.top += 10;
_clipboard.left += 10;
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
}
function genNextName() {
canvas.renderAll();
var total = canvas.getObjects().length;
return String.fromCharCode(65 + total).toLowerCase()
}
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.borderColor = '#5cdce4';
fabric.Object.prototype.cornerColor = 'white';
fabric.Object.prototype.cornerStrokeColor = 'blue';
fabric.Object.prototype.cornerStyle = 'circle';
fabric.Object.prototype.cornerSize = 10;
fabric.Object.prototype.borderScaleFactor = 2;
</script>
</body>
</html>
Any suggestions what I am doing wrong?
I appreciate your replies!
I didn't do deep debugging of the code, but since in many places the layer "name" is used as a key value, you can try renaming the layer (and subsequent updating) in a separate macrotask, using setTimeout.
Instead of this code:
layerObj.name = newName;
canvas.renderAll();
try this code:
setTimeout(() => {
layerObj.name = newName;
canvas.renderAll();
});
Example of your code with setTimeout:
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.9.0/font/bootstrap-icons.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css">
<style>
html,
body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
body {
touch-action: none;
background-image: linear-gradient(to bottom left, rgb(214, 240, 201) 10%, rgba(255, 231, 191, 1) 80%);
-webkit-user-select: none;
-moz-user-select: -moz-none;
-ms-user-select: none;
user-select: none;
}
.input-group {
padding: 4px;
}
.canvas-container {
margin: 0 auto;
width: 100%;
overflow: hidden;
background: url(./transparent.png);
background-size: 15px 15px;
box-shadow: rgba(60, 64, 67, 0.3) 0px 1px 2px 0px, rgba(60, 64, 67, 0.15) 0px 1px 3px 1px;
}
.actived {
background: #fff9a8;
}
#sortable {
max-height: 200px;
overflow: scroll;
}
.list-group {
line-height: 35px;
}
.svg-icon {
width: 1em;
height: 1em;
}
.svg-icon path,
.svg-icon polygon,
.svg-icon rect {
fill: #4691f6;
}
.svg-icon circle {
stroke: #4691f6;
stroke-width: 1;
}
#bkboxXX {
background: url(transparent.png);
border: 1px solid rgba(0, 0, 0, 0.3);
display: inline-block;
height: 19px;
width: 20px;
}
.bk-btn {
background: url(/transparent.png);
}
.fl {
float: left;
}
.fr {
float: right;
}
.input-group-text {
background-color: #f4f4f4;
}
.input-group-sm>.input-group-text {
/*
padding: .2rem .3rem !important;
*/
}
.list-group-item {
padding: 2px 10px;
;
cursor: pointer;
}
.list-group {
border-radius: 0;
text-align: left;
}
</style>
</head>
<body>
<div class="container-fluid h-100">
<div class="row h-100">
<div class="col-sm-3 border-end text-center h-100 overflow-scroll bg-light py-3">
<div class="form-floating w-100 mb-3 tour5">
<h6 class="mb-3">Add Element</h6>
<button class="btn btn-outline-primary" onclick="addText();" data-toggle="tooltip" data-placement="top" title="" data-bs-original-title="Add Text" aria-label="Add Text"><i
class="fa fa-font"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Circle({ name: genNextName(), originX:'center', originY:'center', radius: 30, fill: 'green', top: 100, left: 100 }));" data-bs-original-title="Add Circle"
aria-label="Add Circle"><i
class="fa fa-circle"></i></button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick=" canvas.add(new fabric.Triangle({ name: genNextName(), originX:'center', originY:'center', height:100, width:100, fill: 'red', top: 100, left: 100 }));"
data-bs-original-title="Add Triangle">
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="triangle" role="img"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class=""
style="height: 16px;top: 9px;">
<path fill="currentColor"
d="M329.6 24c-18.4-32-64.7-32-83.2 0L6.5 440c-18.4 31.9 4.6 72 41.6 72H528c36.9 0 60-40 41.6-72l-240-416z"
class=""></path>
</svg>
</button>
<button class="btn btn-outline-primary" data-toggle="tooltip" data-placement="top" title="" onclick="canvas.add(new fabric.Rect({ name: genNextName(), originX:'center', originY:'center', left: 110, top: 110, fill: '#000', width: 50, height: 50 }))" data-bs-original-title="Add Rectangle"><i class="fa fa-square-full"></i> </button>
</div>
<hr>
<div class="w-100 tour7 Xd-none Xd-sm-block">
<h6 class="mb-3">Elements</h6>
<ul class="list-group" id="sortable"></ul>
</div>
</div>
<div class="col-sm-6 my-auto py-4 overflow-hidden">
<div class="canvas-container" style="width: 329px; height: 329px; position: relative; user-select: none;"><canvas id="c" class="lower-canvas" width="329" height="329" style="position: absolute; width: 329px; height: 329px; left: 0px; top: 0px; touch-action: none; user-select: none;"></canvas>
</div>
</div>
<div class="col-sm-3 border-start py-3 h-100 overflow-scroll bg-light text-center">
right map
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.0-beta1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script>
<script src="https://unpkg.com/fabric#5.2.1/dist/fabric.min.js"></script>
<script src="https://rawcdn.githack.com/lyzerk/fabric-history/8c223cbdc8305307b4a8f8710f97da54d9146ffa/src/index.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/centering_guidelines.js"></script>
<script src="https://rawgit.com/fabricjs/fabric.js/master/lib/aligning_guidelines.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
<script>
const rgba2hex = (rgba) => `#${rgba.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+\.{0,1}\d*))?\)$/).slice(1).map((n, i) => (i === 3 ? Math.round(parseFloat(n) * 255) : parseFloat(n)).toString(16).padStart(2, '0').replace('NaN', '')).join('')}`
function cn2h(cn) {
if (!cn) {
return 'transparent';
}
d = document.createElement("span");
d.style.display = "none";
d.style.color = cn
document.body.appendChild(d)
return rgba2hex(window.getComputedStyle(d).color);
}
</script>
<script>
var canvas;
var apiUrl;
var startedLoadingFamilies = false;
var to;
var scale;
fabric.Text.prototype.set({
_getNonTransformedDimensions() { // Object dimensions
return new fabric.Point(this.width, this.height).scalarAdd(this.padding);
},
_calculateCurrentDimensions() { // Controls dimensions
return fabric.util.transformPoint(this._getTransformedDimensions(), this.getViewportTransform(), true);
}
});
function fitCanvas(w, h) {
var scaleW = (document.querySelectorAll(".col-sm-6")[0].offsetWidth - 100) / w;
var scaleH = (document.querySelectorAll("body")[0].offsetHeight - 100) / h;
scale = Math.min(scaleH, scaleW);
if (scale > 1) {
scale = 1;
}
canvas.setZoom(scale);
canvas.setWidth(w * scale);
canvas.setHeight(h * scale);
initAligningGuidelines(canvas);
initCenteringGuidelines(canvas);
canvas.renderAll();
console.log("finished!!");
}
(function() {
canvas = new fabric.Canvas('c', {
allowTouchScrolling: true
});
WebFont.load({
google: {
families: ["Inter:200"]
},
active: function() {
canvas.loadFromJSON({
"height": "500",
"width": "500",
"edit": "yes",
"objects": [],
"backgroundImage": {
"crossOrigin": "anonymous"
}
}, function() {
fitCanvas(500, 500);
})
}
});
canvas.on('before:render', function(opt) {
canvas.getObjects().map(function(o, i) {
if (o.type.toLowerCase() == "textbox") {
var maxH = (o.maxHeight) ? (o.maxHeight) : (canvas.height);
o.set({
'maxHeight': maxH
});
if (o.fontSize > 0 && (maxH > o.fontSize)) {
while (o.height > maxH) {
o.set({
'fontSize': o.fontSize - 1
});
}
}
}
if (o.circleFrame) {
o.set({
clipPath: new fabric.Circle({
radius: o.width / 2,
originX: 'center',
originY: 'center'
})
});
}
if ((o.rx || o.ry) && o.type == "image") {
let rx = (o.rx || 0);
let ry = (o.ry || 0);
o.set({
clipPath: new fabric.Rect({
rx: rx,
ry: ry,
height: o.height,
width: o.width,
originX: 'center',
originY: 'center'
})
});
}
});
});
})();
</script>
<script>
fabric.Object.prototype.objectCaching = false;
function setCanvasBG(clr) {
canvas.backgroundColor = clr;
canvas.renderAll();
}
function changeDim() {
fitCanvas($("#widthC").val(), $("#heightC").val());
}
function setColor(clr, what = 'fill') {
canvas.getActiveObject().set(what, clr);
canvas.renderAll();
}
(function() {
$(document).on("mouseenter", "[data-label]", function() {
$("#font-search").val($(this).data("label"));
loadFont($(this).data("label"));
});
fabric.Canvas.prototype.getItemByAttr = function(attr, name) {
var object = null,
objects = this.getObjects();
for (var i = 0, len = this.size(); i < len; i++) {
if (objects[i][attr] && objects[i][attr] == name) {
object = objects[i];
break;
}
}
return object;
};
$("form#f").hide();
var activeObject;
$("#f input, #f select").on("input", function() {
if (["height", "width", "top", "left", "strokeWidth", "charSpacing"].includes(this.name)) {
canvas.getActiveObject().set(this.name, parseFloat(this.value)).setCoords();
} else {
canvas.getActiveObject().set(this.name, this.value).setCoords();
}
canvas.renderAll();
});
canvas.preserveObjectStacking = true;
fabric.Object.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
name: this.name,
text: this.text,
textAlign: this.textAlign,
fontSize: this.fontSize,
charSpacing: this.charSpacing,
lineHeight: this.lineHeight,
fontWeight: this.fontWeight,
fontFamily: this.fontFamily,
fontStyle: this.fontStyle,
textBackgroundColor: this.textBackgroundColor,
originX: this.originX,
originY: this.originY,
maxHeight: this.maxHeight,
height: this.height,
width: this.width,
radius: this.radius,
rx: this.rx,
ry: this.ry,
stroke: this.stroke,
padding: this.padding,
circleFrame: this.circleFrame
});
};
})(fabric.Object.prototype.toObject);
canvas.on('object:scaling', function(e) {
if (e.target.toObject().type != "image" && e.target.toObject().type != "circle") {
e.target.set({
width: e.target.width * e.target.scaleX,
height: e.target.height * e.target.scaleY,
scaleX: 1,
scaleY: 1
})
}
});
canvas.on('object:modified', function(opt) {
document.body.style.cursor = 'progress';
});
canvas.on("after:render", function() {
$("#sortable").empty();
canvas.includeDefaultValues = false;
canvas.toObject().objects.forEach(function(layer, id) {
if (typeof layer.name !== 'undefined') {
//console.log(id,layer.name);
//canvas.getItemByAttr(`name`, layer.name).set({ "name": String.fromCharCode(65 + id).toLowerCase() })
canvas.getItemByAttr(`name`, layer.name).set({
"name": layer.name.replace(/ /g, "_")
})
var actived = '';
if (canvas.getActiveObject()) {
actived = (canvas.getActiveObject().name == layer.name) ? " actived" : "";
}
$("#sortable").append('<li class="list-group-item ui-sortable-handle clearfix ' + actived + '" onClick="canvas.setActiveObject(canvas.getItemByAttr(`name`,`' + layer.name + '`)); canvas.renderAll();" id=' + layer.name + '>' + layer.name + ' (' + layer.type + ')' + '<span class="fr button-group"><a class="mx-2" title="Edit" href="#" onClick="RenameLayer(`' + layer.name + '`)"><i class="fa fa-pencil-alt" aria-hidden="true"></i></a><a class="mx-2" title="Delete" href="#" onClick="if(confirm(`Are you sure?`)){canvas.remove(canvas.getItemByAttr(`name`,`' + layer.name + '`)); canvas.renderAll();}"><i class="fa fa-trash-alt" aria-hidden="true"></i></a><a class="me-2" title="Duplicate this layer" href="#" onClick="Duplicate(`' + layer.name + '`); canvas.renderAll();"><i class="fa fa-clone" aria-hidden="true"></i></a></span></li>');
}
});
document.body.style.cursor = 'default'
});
canvas.on("selection:created", function(obj) {
if ("image" == obj.selected[0].type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
$("form#f input[type!='hidden'], #f select").parent().hide();
$("form#f").hide();
canvas.renderAll();
});
canvas.on("selection:updated", function(obj) {
if ("image" == obj.selected[0].type) {
canvas.getActiveObject().setControlsVisibility({
mb: false,
ml: false,
mt: false,
mr: false
});
}
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'] , #f select, #f textarea").parent().hide();
});
canvas.on("selection:cleared", function() {
canvas.renderAll();
$("form#f").hide();
$("form#f input[type!='hidden'], #f select, #f textarea").parent().hide();
});
canvas.hoverCursor = 'default';
canvas.on('mouse:over', function(e) {
if (e.target) {
e.target._renderControls(canvas.contextTop, {
hasControls: false
})
}
});
canvas.on('mouse:out', function(e) {
canvas.clearContext(canvas.contextTop);
});
canvas.on('mouse:down', function(e) {
canvas.clearContext(canvas.contextTop);
});
addText = function() {
var text = new fabric.Textbox("Edit this Text", {
name: genNextName(),
left: canvas.getWidth() / canvas.getZoom() / 2,
top: canvas.getHeight() / canvas.getZoom() / 2,
width: (canvas.getWidth() / canvas.getZoom()) / 2,
fill: "#000000",
originX: "center",
originY: "center",
fontFamily: "Inter",
fontWeight: 400,
fontSize: 60,
padding: 20
});
text.setControlsVisibility({
mt: false,
mb: false,
ml: true,
mr: true,
tl: true,
tr: true,
bl: true,
br: true
});
canvas.add(text);
canvas.setActiveObject(text);
canvas.renderAll();
};
})();
function hide_mh_box() {
canvas.remove(canvas.getItemByAttr("isBB", true));
}
function show_mh_box() {
var h = parseInt($("[name=maxHeight]").val());
var n = new fabric.Rect({
top: canvas.getActiveObject().get('top'),
left: canvas.getActiveObject().get('left'),
width: canvas.getActiveObject().get('width'),
height: h,
originX: canvas.getActiveObject().get('originX'),
originY: canvas.getActiveObject().get('originY'),
angle: canvas.getActiveObject().get('angle'),
opacity: 1,
strokeWidth: 2,
stroke: "#FF00FF",
fill: "rgba(0,0,0,0)",
evented: !1,
isBB: true
});
canvas.add(n);
canvas.renderAll();
}
var visited = [];
$(document).ready(function() {
$("input[type=color]").on("input", function() {
$(this).parent().parent().find('input').first().val(this.value);
});
$("textarea, input").attr("autocomplete", "off");
if (window !== window.parent) {
const url = new URL(document.referrer);
$(".isIframe").removeClass('d-none');
$(".notIframe").hide();
}
});
</script>
<script>
function Duplicate(name) {
Copy(name);
}
function Copy(name) {
canvas.getItemByAttr("name", name).clone(function(cloned) {
cloned.set({
"name": genNextName()
})
_clipboard = cloned;
Paste(name);
canvas.renderAll();
});
}
function RenameLayer(name) {
let layerObj = canvas.getItemByAttr("name", name);
let newName = prompt("Rename Layer?", layerObj.name);
while (checkIfNameExists(newName)) {
alert("Your layer name: " + layerObj.name + " is NOT unique please rename your layer differently.")
newName = prompt("Rename Layer?", layerObj.name);
}
setTimeout(() => {
layerObj.name = newName;
canvas.renderAll();
})
}
function checkIfNameExists(newName) {
count = 0;
canvas.forEachObject(function(obj, i) {
if (obj.name == newName) {
count++;
}
});
if (count > 0) {
return true;
} else {
return false;
}
}
function Paste(name) {
_clipboard.clone(function(clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
clonedObj.canvas = canvas;
clonedObj.forEachObject(function(obj) {
canvas.add(obj);
});
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
_clipboard.top += 10;
_clipboard.left += 10;
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
}
function genNextName() {
canvas.renderAll();
var total = canvas.getObjects().length;
return String.fromCharCode(65 + total).toLowerCase()
}
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.borderColor = '#5cdce4';
fabric.Object.prototype.cornerColor = 'white';
fabric.Object.prototype.cornerStrokeColor = 'blue';
fabric.Object.prototype.cornerStyle = 'circle';
fabric.Object.prototype.cornerSize = 10;
fabric.Object.prototype.borderScaleFactor = 2;
</script>
</body>
</html>
This solution is not optimal. But to be honest, the whole code needs serious refactoring. However, perhaps such a solution at the moment will be able to suit you.
This is a typing game that I am working on. I am pretty much done with it except for one problem that I am having. When the person finishes typing all of the words in the turboTypingArray, I call my gameWin() function which assigns the class game-over-win to the div with the id "board" and edits the innerHTML of "board". However, it is only adding the class but not the innerHTML. How can I fix this? I apologize in advance if my code is difficult to understand, I am new o this and still learning.
//CONSTANTS
let duplicate;
const easyWords = ["dog", "cat", "bat", "axe", "hat", "ant", "sat", "rug", "mug", "bet", "art", "can", "day", "box", "egg", "few", "bed", "job", "hot", "men", "use", "sun", "jar", "lip", "flu", "aim", "red", "lid", "ear", "tea", "ski", "oak", "gum", "ham", "mob", "nut", "shy", "van", "elk", "gem", "rap", "fur", "eve", "cry", "mad", "ore", "tax", "six", "pet", "old", "map", "gym", "leg", "bus", "app", "war", "yes", "mud", "rim", "duo"];
const mediumWords = ["house", "beach", "adult", "chief", "funny", "hello", "metal", "sauce", "cocoa", "flags", "upset", "pearl", "trash", "enemy", "pizza", "humor", "eagle", "flame", "cargo", "puppy", "retro", "spark", "bride", "straw", "inbox", "bored", "chalk", "fatal", "hobby", "melee", "bagel", "debug", "amaze", "witch", "stool", "thief", "acorn", "hover", "lever", "merge", "lunar", "debit", "cubic", "erase", "vivid", "waist", "yeast", "syrup", "trunk", "rebel", "lobby", "pasta", "grape", "choir", "jewel", "scoop", "rival", "yacht", "sushi", "bunny"];
const hardWords = ["ability", "battery", "compare", "illness", "weather", "speaker", "package", "organic", "quickly", "regular", "premium", "musical", "journal", "healthy", "economy", "connect", "gallery", "illegal", "parking", "roughly", "success", "accused", "chronic", "unusual", "version", "setting", "message", "removal", "several", "dispute", "tourist", "avocado", "witness", "soldier", "monster", "habitat", "crystal", "younger", "analyze", "nervous", "precise", "trailer", "satisfy", "minimal", "fortune", "genuine", "bizarre", "exhibit", "gesture", "nucleus", "pivotal", "rainbow", "mustard", "lottery", "address", "network", "legally", "cartoon", "horizon", "induced"];
for (var i = 0; i < hardWords.length; i++) {
for (var j = i+1; j < hardWords.length; j++) {
if (hardWords[i] == hardWords[j]) {
duplicate = hardWords[j]
console.log(duplicate)
}
}
}
//VARIABLES
let turboTypingArray = [];
let word
let score = 0;
let attempts = 0;
let correctAttempts = 0;
let answerStreak = 0;
let highestAnswerStreak = 0;
let timeRemaining;
let myTimer;
//EVENT LISTENERS
var input = document.getElementById("user-input");
input.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("input-word").click();
};
});
document.getElementById("easy").onclick = setEasy;
document.getElementById("medium").onclick = setMedium;
document.getElementById("hard").onclick = setHard;
//FUNCTIONS
function init() {
score = 0;
attempts = 0;
correctAttempts = 0;
answerStreak = 0;
highestAnswerStreak = 0;
timeRemaining = 120;
clearInterval(myTimer);
document.getElementById("timer").innerHTML = "2:00";
myTimer = setInterval(updateTimer, 1000);
if (document.getElementById("board").classList.contains("game-over-lose")) {
document.getElementById("board").classList.remove("game-over-lose");
}
if (document.getElementById("board").classList.contains("game-over-win")) {
document.getElementById("board").classList.remove("game-over-win");
}
}
function refresh() {
var newWordBoard = "";
turboTypingArray.forEach((item, i) => {
newWordBoard += "<div class='board-word'>" +item + "</div>"
});
document.getElementById("board").innerHTML = newWordBoard;
}
function setEasy() {
init();
turboTypingArray = easyWords.slice();
document.getElementById("user-input").focus();
refresh();
}
function setMedium() {
init();
turboTypingArray = mediumWords.slice();
turboTypingArray.forEach((item, i) => {
document.getElementById("board").innerHTML += "<div class='board-word'>" +item + "</div>"
});
document.getElementById("user-input").focus();
refresh();
}
function setHard() {
init();
turboTypingArray = hardWords.slice();
turboTypingArray.forEach((item, i) => {
document.getElementById("board").innerHTML += "<div class='board-word'>" +item + "</div>"
});
document.getElementById("user-input").focus();
refresh();
}
function CheckInput() {
word = document.getElementById("user-input").value;
if (turboTypingArray.includes(word)) {
correctWord()
}
else {
wrongWord();
}
document.getElementById("user-input").value = "";
refresh();
}
function correctWord() {
answerStreak = answerStreak + 1;
if (answerStreak > highestAnswerStreak) {
highestAnswerStreak = answerStreak
}
score = score + 10 + answerStreak;
attempts = attempts + 1;
correctAttempts = correctAttempts + 1;
for (var i = 0; i < turboTypingArray.length; i++) {
if(turboTypingArray[i] == word) {
turboTypingArray.splice(i, 1);
}
}
checkDone();
}
function wrongWord() {
attempts = attempts + 1;
answerStreak = 0;
alert("das wrong broke boi")
}
function checkDone() {
if (turboTypingArray.length < 1) {
score = score - (attempts - correctAttempts);
alert("kfdskn")
clearInterval(myTimer);
gameWin();
}
}
function gameOver() {
document.getElementById("board").classList.add("game-over-lose");
document.getElementById("board").innerHTML = "Score: " + score + "<br>Attempts: " + attempts + "<br>Correct Attempts: " + correctAttempts + "<br>Highest Answer Streak: " + highestAnswerStreak + "<br>Words Remaining: " + turboTypingArray.length + "/60";
}
function gameWin() {
console.log("win");
document.getElementById("board").classList.add("game-over-win");
document.getElementById("board").innerHTML = "Score: " + score + "<br>Attempts: " + attempts + "<br>Correct Attempts: " + correctAttempts + "<br>Highest Answer Streak: " + highestAnswerStreak + "<br>Words Remaining: " + turboTypingArray.length + "/60";
}
function updateTimer() {
timeRemaining--
if (timeRemaining > 60) {
timerSeconds = timeRemaining - 60;
timerDisplay = "1:" + timerSeconds;
}
if (timeRemaining < 70) {
timerSeconds = timeRemaining - 60
timerDisplay = "1:0" + timerSeconds;
}
if (timeRemaining < 60) {
timerDisplay = "0:" + timeRemaining;
}
if (timeRemaining < 10) {
timerDisplay = "0:0" + timeRemaining;
}
if (timeRemaining < 1) {
gameOver();
clearInterval(myTimer);
}
document.getElementById("timer").innerHTML = timerDisplay;
}
body {
text-align: center;
font-family: "Roboto", monospace;
color: white;
background-color: black;
}
h1 {
margin: 0 auto;
font-family: "Major Mono Display", monospace;
font-size: 48px;
margin: 2%;
}
input {
border-radius: 25px;
height: 50px;
width: 400px;
font-family: "Major Mono Display", monospace;
margin: auto;
font-size: 37px;
text-align: center;
}
button {
background-color: black;
color: white;
height: 50px;
width: 160px;
font-size: 37px;
}
.difficulty-level {
width: 100px;
padding: 3px 0;
margin: auto;;
margin-top: 5px;
margin-bottom: 5px;
text-align: center;
color: black;
}
.board {
height: 220px;
width: 60px;
margin-bottom: 10px;
}
.board-word {
border: 1px solid white;
height: 40px;
width: 130px;
margin: auto;
text-align: center;
font-size: 30px;
}
.user-input {
margin-top: 10px;
}
.container {
display: flex;
justify-content: center;
align-items: center;
}
.wrap {
flex-wrap: wrap;
height: 400px;
width: 1400px;
}
.game-over-lose {
background-color: rgb(255, 0, 0, 0.2);
font-size: 40px;
color: white;
}
.game-over-win {
background-color: lightgreen;
font-size: 40px;
color: white;
}
#difficulty {
margin-bottom: 10px;
margin: auto;
font-family: "Major Mono Display", monospace;
}
#easy {
color: lightgreen;
border: 1px solid lightgreen;
}
#medium {
color: yellow;
border: 1px solid yellow;
}
#hard {
color: red;
border: 1px solid red;
}
#board {
margin: auto;
}
#font-face {
font-family: "digital-clock";
src: url("../fonts/digital-7.ttf");
}
#timer {
font-size: 80px;
font-family: "digital-clock"
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link href="https://fonts.googleapis.com/css?family=Major+Mono+Display" rel="stylesheet" />
<link href="css/styles.css" rel="stylesheet" type="text/css" />
<script defer src="js/app.js"></script>
<title>Turbo Typing</title>
</head>
<body>
<h1>turbo typing</h1>
<h2>Select a Difficulty</h2>
<div id="difficulty" class="">
<div id="easy" class="difficulty-level" >easy</div>
<div id="medium" class="difficulty-level">medium</div>
<div id="hard" class="difficulty-level">hard</div>
</div>
<div id="timer"></div>
<div id="board" class="wrap container">
</div>
<div class='user-input'>
<input id = "user-input" type = "text" value = "" />
<button id="input-word" onclick="CheckInput()">Enter</button>
</div>
</body>
</html>
Must say, it was really hard to find the issue :D.
You are calling refresh() on every input check, it also gets called either on a gameOver() or gameWin(). I have set a flag, gameDone, if its true, I do not refresh. I set gameDone to true on gameWin() or gameOver() and reset it back in a refresh.
To test it out, select the "EASY" level and just enter "DOG".
//CONSTANTS
let duplicate;
const easyWords = ["dog"];
const mediumWords = ["house", "beach", "adult", "chief", "funny", "hello", "metal", "sauce", "cocoa", "flags", "upset", "pearl", "trash", "enemy", "pizza", "humor", "eagle", "flame", "cargo", "puppy", "retro", "spark", "bride", "straw", "inbox", "bored", "chalk", "fatal", "hobby", "melee", "bagel", "debug", "amaze", "witch", "stool", "thief", "acorn", "hover", "lever", "merge", "lunar", "debit", "cubic", "erase", "vivid", "waist", "yeast", "syrup", "trunk", "rebel", "lobby", "pasta", "grape", "choir", "jewel", "scoop", "rival", "yacht", "sushi", "bunny"];
const hardWords = ["ability", "battery", "compare", "illness", "weather", "speaker", "package", "organic", "quickly", "regular", "premium", "musical", "journal", "healthy", "economy", "connect", "gallery", "illegal", "parking", "roughly", "success", "accused", "chronic", "unusual", "version", "setting", "message", "removal", "several", "dispute", "tourist", "avocado", "witness", "soldier", "monster", "habitat", "crystal", "younger", "analyze", "nervous", "precise", "trailer", "satisfy", "minimal", "fortune", "genuine", "bizarre", "exhibit", "gesture", "nucleus", "pivotal", "rainbow", "mustard", "lottery", "address", "network", "legally", "cartoon", "horizon", "induced"];
for (var i = 0; i < hardWords.length; i++) {
for (var j = i+1; j < hardWords.length; j++) {
if (hardWords[i] == hardWords[j]) {
duplicate = hardWords[j]
console.log(duplicate)
}
}
}
//VARIABLES
let turboTypingArray = [];
let word
let score = 0;
let attempts = 0;
let correctAttempts = 0;
let answerStreak = 0;
let highestAnswerStreak = 0;
let timeRemaining;
let myTimer;
let gameDone = false;
//EVENT LISTENERS
var input = document.getElementById("user-input");
input.addEventListener("keyup", function(event) {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("input-word").click();
};
});
document.getElementById("easy").onclick = setEasy;
document.getElementById("medium").onclick = setMedium;
document.getElementById("hard").onclick = setHard;
//FUNCTIONS
function init() {
score = 0;
attempts = 0;
correctAttempts = 0;
answerStreak = 0;
highestAnswerStreak = 0;
timeRemaining = 120;
clearInterval(myTimer);
document.getElementById("timer").innerHTML = "2:00";
myTimer = setInterval(updateTimer, 1000);
if (document.getElementById("board").classList.contains("game-over-lose")) {
document.getElementById("board").classList.remove("game-over-lose");
}
if (document.getElementById("board").classList.contains("game-over-win")) {
document.getElementById("board").classList.remove("game-over-win");
}
}
function refresh() {
gameDone = false;
var newWordBoard = "";
turboTypingArray.forEach((item, i) => {
newWordBoard += "<div class='board-word'>" +item + "</div>"
});
document.getElementById("board").innerHTML = newWordBoard;
}
function setEasy() {
init();
turboTypingArray = easyWords.slice();
document.getElementById("user-input").focus();
refresh();
}
function setMedium() {
init();
turboTypingArray = mediumWords.slice();
turboTypingArray.forEach((item, i) => {
document.getElementById("board").innerHTML += "<div class='board-word'>" +item + "</div>"
});
document.getElementById("user-input").focus();
refresh();
}
function setHard() {
init();
turboTypingArray = hardWords.slice();
turboTypingArray.forEach((item, i) => {
document.getElementById("board").innerHTML += "<div class='board-word'>" +item + "</div>"
});
document.getElementById("user-input").focus();
refresh();
}
function CheckInput() {
word = document.getElementById("user-input").value;
if (turboTypingArray.includes(word)) {
correctWord()
}
else {
wrongWord();
}
document.getElementById("user-input").value = "";
if (gameDone === false) {
refresh();
}
}
function correctWord() {
answerStreak = answerStreak + 1;
if (answerStreak > highestAnswerStreak) {
highestAnswerStreak = answerStreak
}
score = score + 10 + answerStreak;
attempts = attempts + 1;
correctAttempts = correctAttempts + 1;
for (var i = 0; i < turboTypingArray.length; i++) {
if(turboTypingArray[i] == word) {
turboTypingArray.splice(i, 1);
}
}
checkDone();
}
function wrongWord() {
attempts = attempts + 1;
answerStreak = 0;
alert("das wrong broke boi")
}
function checkDone() {
if (turboTypingArray.length < 1) {
score = score - (attempts - correctAttempts);
alert("kfdskn")
clearInterval(myTimer);
gameWin();
}
}
function gameOver() {
document.getElementById("board").classList.add("game-over-lose");
document.getElementById("board").innerHTML = "Score: " + score + "<br>Attempts: " + attempts + "<br>Correct Attempts: " + correctAttempts + "<br>Highest Answer Streak: " + highestAnswerStreak + "<br>Words Remaining: " + turboTypingArray.length + "/60";
gameDone = true;
}
function gameWin() {
console.log("win");
document.getElementById("board").classList.add("game-over-win");
document.getElementById("board").innerHTML = "Score: " + score + "<br>Attempts: " + attempts + "<br>Correct Attempts: " + correctAttempts + "<br>Highest Answer Streak: " + highestAnswerStreak + "<br>Words Remaining: " + turboTypingArray.length + "/60";
gameDone = true;
}
function updateTimer() {
timeRemaining--
if (timeRemaining > 60) {
timerSeconds = timeRemaining - 60;
timerDisplay = "1:" + timerSeconds;
}
if (timeRemaining < 70) {
timerSeconds = timeRemaining - 60
timerDisplay = "1:0" + timerSeconds;
}
if (timeRemaining < 60) {
timerDisplay = "0:" + timeRemaining;
}
if (timeRemaining < 10) {
timerDisplay = "0:0" + timeRemaining;
}
if (timeRemaining < 1) {
gameOver();
clearInterval(myTimer);
}
document.getElementById("timer").innerHTML = timerDisplay;
}
body {
text-align: center;
font-family: "Roboto", monospace;
color: white;
background-color: black;
}
h1 {
margin: 0 auto;
font-family: "Major Mono Display", monospace;
font-size: 48px;
margin: 2%;
}
input {
border-radius: 25px;
height: 50px;
width: 400px;
font-family: "Major Mono Display", monospace;
margin: auto;
font-size: 37px;
text-align: center;
}
button {
background-color: black;
color: white;
height: 50px;
width: 160px;
font-size: 37px;
}
.difficulty-level {
width: 100px;
padding: 3px 0;
margin: auto;;
margin-top: 5px;
margin-bottom: 5px;
text-align: center;
color: black;
}
.board {
height: 220px;
width: 60px;
margin-bottom: 10px;
}
.board-word {
border: 1px solid white;
height: 40px;
width: 130px;
margin: auto;
text-align: center;
font-size: 30px;
}
.user-input {
margin-top: 10px;
}
.container {
display: flex;
justify-content: center;
align-items: center;
}
.wrap {
flex-wrap: wrap;
height: 400px;
width: 1400px;
}
.game-over-lose {
background-color: rgb(255, 0, 0, 0.2);
font-size: 40px;
color: white;
}
.game-over-win {
background-color: lightgreen;
font-size: 40px;
color: white;
}
#difficulty {
margin-bottom: 10px;
margin: auto;
font-family: "Major Mono Display", monospace;
}
#easy {
color: lightgreen;
border: 1px solid lightgreen;
}
#medium {
color: yellow;
border: 1px solid yellow;
}
#hard {
color: red;
border: 1px solid red;
}
#board {
margin: auto;
}
#font-face {
font-family: "digital-clock";
src: url("../fonts/digital-7.ttf");
}
#timer {
font-size: 80px;
font-family: "digital-clock"
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link href="https://fonts.googleapis.com/css?family=Major+Mono+Display" rel="stylesheet" />
<link href="css/styles.css" rel="stylesheet" type="text/css" />
<script defer src="js/app.js"></script>
<title>Turbo Typing</title>
</head>
<body>
<h1>turbo typing</h1>
<h2>Select a Difficulty</h2>
<div id="difficulty" class="">
<div id="easy" class="difficulty-level" >easy</div>
<div id="medium" class="difficulty-level">medium</div>
<div id="hard" class="difficulty-level">hard</div>
</div>
<div id="timer"></div>
<div id="board" class="wrap container">
</div>
<div class='user-input'>
<input id = "user-input" type = "text" value = "" />
<button id="input-word" onclick="CheckInput()">Enter</button>
</div>
</body>
</html>
I'm trying to create a code to show 5 buttons categories and the slider of the last products below. On mouseover effect on any category I'm expecting to see the relevant products of woocommerce. But it doesn't work: neither the buttons nor the product slider. I have an error in console "Cannot read property 'setAttribute' of undefined". How can it possible to solve the problem?
var carouseltopHtml = [];
jQuery(function($) {
var touchtimea = 0;
var touchtimeb = 0;
var touchtimec = 0;
var touchtimed = 0;
var touchtimee = 0;
$("#top_a_category_0").on("click", function() {
if (touchtimea == 0) {
onmuseoverslider(0);
touchtimea = new Date().getTime();
touchtimeb = 0;
touchtimec = 0;
touchtimed = 0;
touchtimee = 0;
if (window.innerWidth < 1024) {
return false;
}
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtimea) < 3000) {
window.location = this.href;
touchtimea = 0;
} else {
// not a double click so set as a new first click
touchtimea = new Date().getTime();
return false;
}
}
});
$("#top_a_category_1").on("click", function() {
if (touchtimeb == 0) {
onmuseoverslider(1);
touchtimeb = new Date().getTime();
touchtimea = 0;
touchtimec = 0;
touchtimed = 0;
touchtimee = 0;
if (window.innerWidth < 1024) {
return false;
}
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtimeb) < 3000) {
window.location = this.href;
touchtimeb = 0;
} else {
// not a double click so set as a new first click
touchtimeb = new Date().getTime();
return false;
}
}
});
$("#top_a_category_2").on("click", function() {
if (touchtimec == 0) {
onmuseoverslider(2);
touchtimea = 0;
touchtimeb = 0;
touchtimed = 0;
touchtimee = 0;
touchtimec = new Date().getTime();
if (window.innerWidth < 1024) {
return false;
}
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtimec) < 3000) {
window.location = this.href;
touchtimec = 0;
} else {
// not a double click so set as a new first click
touchtimec = new Date().getTime();
return false;
}
}
});
$("#top_a_category_3").on("click", function() {
if (touchtimed == 0) {
onmuseoverslider(3);
touchtimed = new Date().getTime();
touchtimea = 0;
touchtimeb = 0;
touchtimec = 0;
touchtimee = 0;
if (window.innerWidth < 1024) {
return false;
}
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtimed) < 3000) {
window.location = this.href;
touchtimed = 0;
} else {
// not a double click so set as a new first click
touchtimed = new Date().getTime();
return false;
}
}
});
$("#top_a_category_4").on("click", function() {
if (touchtimee == 0) {
onmuseoverslider(4);
touchtimee = new Date().getTime();
touchtimea = 0;
touchtimeb = 0;
touchtimec = 0;
touchtimed = 0;
if (window.innerWidth < 1024) {
return false;
}
} else {
// compare first click to this click and see if they occurred within double click threshold
if (((new Date().getTime()) - touchtimee) < 800) {
window.location = this.href;
touchtimee = 0;
} else {
// not a double click so set as a new first click
touchtimee = new Date().getTime();
return false;
}
}
});
});
jQuery(document).ready(function($) {
for (var i = 0; i < 5; i++) {
carouseltopHtml[i] = jQuery("#carrou0" + i).html();
if (i > 0) {
jQuery("#carrou0" + i).html('');
}
//jQuery("#carrou_bottom_" + i ).css('display','none');
}
});
for (var j = 0; j < 5; j++) {
if (window.innerWidth < 1024) {
if (j == 2)
document.getElementById('top_nav_category_' + j).setAttribute("style", "width:100%; height: 50px; min-height: 50px; background-image: url(); margin-bottom:0px");
else
document.getElementById('top_nav_category_' + j).setAttribute("style", "width:80%; height: fit-content; min-height: 50px; background-image: url(); margin-bottom:0px");
document.getElementById('top_a_category_' + j).setAttribute("style", "display: contents; margin-top: 0px; text-align: center;");
}
}
function onmuseoverslider(id) {
for (var i = 0; i < 5; i++) {
if (id == i)
jQuery("#carrou0" + i).html(carouseltopHtml[i]);
//jQuery("#carrou_bottom_" + i ).css('display','block');
else
jQuery("#carrou0" + i).html('');
// jQuery("#carrou_bottom_" + i ).css('display','none');
}
loadtopslider(id + 1);
/*for(var i = 1; i < 6; i ++){
if(i == id)
document.getElementById('carrou0'+id).className += ' mostrar';
else
document.getElementById('carrou0'+i).className =document.getElementById('carrou0'+i).className.replace(/(?:^|\s)mostrar(?!\S)/g,'');
}*/
}
function loadtopslider(index) {
//jQuery( '.wcpscwc-product-slider' ).each(function( index ) {
var item = jQuery('.wcpscwc-product-slider')[0];
var slider_id = jQuery(item).attr('id');
var slider_conf = jQuery.parseJSON(jQuery(item).closest('.wcpscwc-product-slider-wrap').find('.wcpscwc-slider-conf').attr('data-conf'));
var slider_cls = slider_conf.slider_cls ? slider_conf.slider_cls : 'products';
jQuery('#' + slider_id + ' .' + slider_cls).not('.slick-initialized').slick({
dots: (slider_conf.dots) == "true" ? true : false,
infinite: true,
arrows: (slider_conf.arrows) == "true" ? true : false,
speed: parseInt(slider_conf.speed),
autoplay: (slider_conf.autoplay) == "true" ? true : false,
autoplaySpeed: parseInt(slider_conf.autoplay_speed),
slidesToShow: parseInt(slider_conf.slide_to_show),
slidesToScroll: parseInt(slider_conf.slide_to_scroll),
rtl: (slider_conf.rtl) == "true" ? true : false,
responsive: [{
breakpoint: 1023,
settings: {
slidesToShow: 3,
slidesToScroll: 1,
infinite: true,
dots: false
}
}, {
breakpoint: 767,
settings: {
slidesToShow: 2,
slidesToScroll: 1
}
},
{
breakpoint: 479,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
dots: false
}
},
{
breakpoint: 319,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
dots: false
}
}
]
});
//});
}
.btnstop:hover,
.btnstop:focus {
background-color: #ebebeb;
transform: scale(1.1);
box-shadow: 2px 1px 2px 2px rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="carouselcattop01">
<ul class="ulbtncatcar">
<li class="btncatcar01 btnstop" id="top_nav_category_0" onmouseover="onmuseoverslider(0)" style="width: 15%; height: 20%;">
<a href="/categorie-produit/les-rouges/" title="Vins Rouges" class="titre" title="Les vins rouges" id="top_a_category_0">
<h3 style="color: #000000; font-size: 2vw; margin-bottom: 0px; font-family: Prata; ">Vins</h3>
<h2 style="color: #025F6D; font-family: Montserrat; font-size: 1.5vw;"> Rouges</h2>
</a>
</li>
<li class="btncatcar02 btnstop" id="top_nav_category_1" onmouseover="onmuseoverslider(1)" style="width: 15%; height: 20%;">
<a href="/categorie-produit/les-roses/" title="Vins Rosés" class="titre" title="Les vins rosés" id="top_a_category_1">
<h3 style="color: #000000; font-size: 2vw; margin-bottom: 0px; font-family: Prata;">Vins</h3>
<h2 style="color: #0092A7; font-family: Montserrat; font-size: 1.5vw; margin-bottom: 0px;"> Rosés</h2>
</a>
</li>
<li class="btncatcar03 btnstop" id="top_nav_category_2" onmouseover="onmuseoverslider(2)" style="width: 15%; height: 20%;">
<a href="/categorie-produit/les-blanc-liquoreux-et-secs/" title="Vins Blancs Secs et Liquoreux" class="titre" title="Les vins blancs" id="top_a_category_2">
<h3 style="color: #000000; font-size: 2vw; margin-bottom: 0px; font-family: Prata; padding-top: 10px;">Vins</h3>
<h2 style="color: #0092A7; font-family: Montserrat; font-size: 1.5vw;"> Blancs</h2>
<h5 style="color: #0092A7; font-family: Montserrat; font-size: 1vw;"> Secs et Liquoreux</h5>
</a>
</li>
<li class="btncatcar04 btnstop" id="top_nav_category_3" onmouseover="onmuseoverslider(3)" style="width: 15%; height: 20%;">
<a href="/categorie-produit/les-bulles/" title="Vins Pétillants" class="titre" title="Les vins pétillants" id="top_a_category_3">
<h3 style="color: #000000; font-size: 2vw; margin-bottom: 0px; font-family: Prata;">Vins</h3>
<h2 style="color: #9BD0D9; font-family: Montserrat; font-size: 1.5vw;"> Pétillants</h2>
</a>
</li>
<li class="btncatcar05 btnstop" id="top_nav_category_4" onmouseover="onmuseoverslider(4)" style="width: 15%; height: 20%;">
<a href="/categorie-produit/idees-cadeaux/" title="Idées Cadeaux" class="titre" title="Les idées cadeaux" id="top_a_category_4">
<h3 style="color: #000000; font-size: 2vw; margin-bottom: 0px; font-family: Prata;">Idées</h3>
<h2 style="color: #B1B3B4; font-family: Montserrat; font-size: 1.5vw;"> Cadeaux</h2>
</a>
</li>
<ul id="carrou00" class="ulcarrousel ocultar mostrar">
<li class="licarrousel">
<div class="dudomaine">Les <strong>vins rouges</strong> du Domaine</div>
[products_slider cats="21" slide_to_show="5" design="design-5" dots="false" slide_to_scroll="2"]
</li>
</ul>
<ul id="carrou01" class="ulcarrousel ocultar mostrar">
<li class="licarrousel">
<div class="dudomaine">Les <strong>vins rosés</strong> du Domaine</div>
[products_slider cats="22" slide_to_show="5" design="design-5" dots="false" slide_to_scroll="2"]
</li>
</ul>
<ul id="carrou02" class="ulcarrousel ocultar mostrar">
<li class="licarrousel">
<div class="dudomaine">Les <strong>vins blancs</strong> du Domaine</div>
[products_slider cats="23" slide_to_show="5" design="design-5" dots="false" slide_to_scroll="2"]
</li>
</ul>
<ul id="carrou03" class="ulcarrousel ocultar mostrar">
<li class="licarrousel">
<div class="dudomaine">Les <strong>vins pétillants</strong> du Domaine</div>
[products_slider cats="24" slide_to_show="5" design="design-5" dots="false" slide_to_scroll="2"]
</li>
</ul>
<ul id="carrou04" class="ulcarrousel ocultar mostrar">
<li class="licarrousel">
<div class="dudomaine">Les <strong>idées cadeaux</strong> du Domaine</div>
[products_slider cats="25" slide_to_show="5" design="design-5" dots="false" slide_to_scroll="2"]
</li>
</ul>
</ul>
</div>
I want to create/use an add-remove box like this in HTML using angularJS where you have a list of some objects on the left and you select the objects to put them on under the headings listed on the right. Any idea what do we call such tables/lists and can I create/find them?
I don't know what is the accurate title to call it :)
but I tried to implement a sample of 'add/remove box' to achieve the concept you want with AngularJS!
the main part consists of three sections:
left section which is going to be added
middle section which contains the buttons
right section which is going to be removed
The code below applies the above section which aforesaid:
<div class="box leftBox">
<div>
<div id="{{left.name}}" ng-click="clicked($event, 0)" data-ng-repeat="left in lefts">{{left.name}}</div>
</div>
</div>
<div class="box button_holder">
<button ng-click="add()" class="button button-blue">ADD ></button>
<button ng-click="remove()" class="button button-red">< REMOVE</button>
<button ng-click="addAll()" class="button button-blue button-dark">ADD ALL >></button>
<button ng-click="removeAll()" class="button button-red button-dark"><< REMOVE ALL</button>
<button ng-click="deleteChoice()" class="button delete">X</button>
</div>
<div class="box rightBox">
<div>
<div ng-click="clicked($event, 1)" data-ng-repeat="right in rights">{{right.name}}</div>
</div>
</div>
by using angularjs directives including data-ng-repeat you can control the procedure of adding or removing
here is the implemented overview.
here is the completed code on the "codepen".
you can also check my github.
try to run the snippet in a fullscreen window!
/**
* Created by ALIREZA on 8/30/2017.
*/
var app = angular.module('Add_Remove_Box', []);
app.controller('Ctrl', function($scope) {
var i;
var isRepeated = false;
var actionLicense = true;
var prevElement = null;
var currentElement = null;
var positionSide = null;
$scope.choices = ["left", "right"];
$scope.lefts = [{
id: 'left1'
}, {
id: 'left2'
}, {
id: 'left3'
}, {
id: 'left4'
}];
for (i = 0; i < $scope.lefts.length; i++) {
$scope.lefts[i].name = "left" + (i + 1).toString();
}
$scope.rights = [{
id: 'right1'
}, {
id: 'right2'
}];
for (i = 0; i < $scope.rights.length; i++) {
$scope.rights[i].name = "right" + (i + 1).toString();
}
$scope.insert = function($event) {
var side = $scope.selectedSide;
if (side == null || side == "left") {
var leftItemNo = $scope.lefts.length + 1;
$scope.lefts.push({
'id': 'left' + leftItemNo
});
$scope.lefts[leftItemNo - 1].name = $scope.choice.name;
} else {
var rightItemNo = $scope.rights.length + 1;
$scope.rights.push({
'id': 'right' + rightItemNo
});
$scope.rights[rightItemNo - 1].name = $scope.choice.name;
}
};
$scope.deleteChoice = function() {
if (positionSide === 0) {
var ItemNo = -1;
$scope.lefts.forEach(function(i, j) {
if (i.name === currentElement.textContent) {
ItemNo = j;
return;
}
});
$scope.lefts.splice(ItemNo, 1);
}
};
$scope.add = function() {
if (actionLicense && positionSide === 0) {
actionLicense = false;
var leftItemNo = -1;
$scope.lefts.forEach(function(i, j) {
if (i.name === currentElement.textContent) {
leftItemNo = j;
return;
}
});
$scope.lefts.splice(leftItemNo, 1);
var rightItemNo = $scope.rights.length + 1;
$scope.rights.push({
'id': 'right' + rightItemNo
});
$scope.rights[rightItemNo - 1].name = currentElement.textContent;
}
};
$scope.remove = function() {
if (actionLicense && positionSide === 1) {
actionLicense = false;
var rightItemNo = -1;
$scope.rights.forEach(function(i, j) {
if (i.name === currentElement.textContent) {
rightItemNo = j;
return;
}
});
$scope.rights.splice(rightItemNo, 1);
var leftItemNo = $scope.lefts.length + 1;
$scope.lefts.push({
'id': 'left' + leftItemNo
});
$scope.lefts[leftItemNo - 1].name = currentElement.textContent;
}
};
$scope.addAll = function() {
$scope.lefts.forEach(function(i) {
var rightItemNo = $scope.rights.length + 1;
$scope.rights.push({
'id': 'right' + rightItemNo
});
$scope.rights[rightItemNo - 1].name = i.name;
});
$scope.lefts.splice(0, $scope.lefts.length);
};
$scope.removeAll = function() {
$scope.rights.forEach(function(i) {
var leftItemNo = $scope.lefts.length + 1;
$scope.lefts.push({
'id': 'left' + leftItemNo
});
$scope.lefts[leftItemNo - 1].name = i.name;
});
$scope.rights.splice(0, $scope.rights.length);
};
$scope.clicked = function($event, pos) {
actionLicense = true;
positionSide = pos;
currentElement = $event.currentTarget;
var deleteButton = document.getElementsByClassName("delete")[0];
if (pos === 1) {
if (deleteButton.className.indexOf("button-deactive") === -1) {
deleteButton.className += " button-deactive";
}
} else {
deleteButton.className = deleteButton.className.replace(" button-deactive", "");
}
if (prevElement === null) {
prevElement = currentElement;
} else {
if (prevElement === currentElement) {
isRepeated = !isRepeated;
} else {
if (isRepeated) {
isRepeated = false;
}
}
}
if (prevElement.className.indexOf("active") !== -1) {
prevElement.className = prevElement.className.replace(" active", "");
}
if (!isRepeated && currentElement.className.indexOf("active") === -1) {
currentElement.className += " active";
}
prevElement = currentElement;
};
});
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
}
.container {
display: inline-block;
width: 100%;
padding: 10px;
height: 100vh;
border: #E64A19 inset .7vh;
background: #616161;
/* fallback for old browsers */
background: -webkit-linear-gradient(to left, #9bc5c3, #616161);
/* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to left, #9bc5c3, #616161);
/* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
.addItems {
height: 10vh;
margin-bottom: 5vh;
}
.box {
float: left;
display: inline-block;
margin: 0;
padding: 10px;
height: 80vh;
border: #cfcfcf outset 2px;
color: #eee;
font-size: medium;
}
.box>div {
border: #FFF59D ridge 2px;
border-bottom: none;
border-radius: 5px;
}
.box>div>div {
padding: 7px;
border-bottom: #FFF59D ridge 2px;
}
.box>div>div:hover {
background-color: rgba(100, 150, 220, .5);
transition: background-color .4s ease;
}
.box>button {
display: inline-block;
width: 70%;
margin: 5% 15%;
}
.button {
padding: 10px 24px;
border-radius: 3px;
border: none;
box-shadow: 2px 5px 10px rgba(22, 22, 22, .1);
}
.button:hover {
transition: all 60ms ease;
opacity: .95;
box-shadow: #444 0 3px 3px 0;
}
.button-blue {
color: #FFFFFF;
background: #416dea;
}
.button-red {
color: #FFFFFF;
background: #F32C52;
}
.button-dark {
filter: brightness(85%) contrast(110%);
}
.leftBox {
width: 40%;
}
.button_holder {
width: 20%;
}
.rightBox {
width: 40%;
}
input[type="text"],
select {
padding: 5px;
}
.active {
transition: all .1s ease;
background-color: #888;
color: #000;
;
border: dotted 1px black;
box-shadow: 0 2px 2px 0 rgba(97, 97, 97, .5);
margin-bottom: 1px;
}
.button-deactive {
opacity: .5;
box-shadow: none;
}
.button-deactive:hover {
opacity: .5;
box-shadow: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AddRemoveBox</title>
<link rel="stylesheet" href="index.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<!--include angularJs-->
<script src="index.js"></script>
</head>
<body>
<div class="container" ng-app="Add_Remove_Box" ng-controller="Ctrl">
<fieldset class="addItems">
<legend>Insert Items</legend>
<select ng-model="selectedSide">
<option ng-repeat="choice in choices">{{choice}}</option>
</select>
<input type="text" ng-model="choice.name" name="" placeholder="Enter The Item Name">
<button class="button insert" value="insert" ng-click="insert($event)">Insert</button>
</fieldset>
<div class="box leftBox">
<div>
<div id="{{left.name}}" ng-click="clicked($event, 0)" data-ng-repeat="left in lefts">{{left.name}}</div>
</div>
</div>
<div class="box button_holder">
<button ng-click="add()" class="button button-blue">ADD ></button>
<button ng-click="remove()" class="button button-red">< REMOVE</button>
<button ng-click="addAll()" class="button button-blue button-dark">ADD ALL >></button>
<button ng-click="removeAll()" class="button button-red button-dark"><< REMOVE ALL</button>
<button ng-click="deleteChoice()" class="button delete">X</button>
</div>
<div class="box rightBox">
<div>
<div ng-click="clicked($event, 1)" data-ng-repeat="right in rights">{{right.name}}</div>
</div>
</div>
</div>
</body>
</html>