Chart.js: Chart not resizing in iframe - javascript

I am trying to show multiple diagrams/charts at the same time using chart.js.
For my setup, I have one chart.html file which displays the diagram and a split.html file which creates multiple iframes (2 so far) and loads the chart.html in them.
When opening the chart.html directly, the resizing works, but when loaded in iframe it doesn't.
I could only imagine the error at chart.js since the sizing itself is already weird. It orients on the next "higher" element (div with fixed 100% width and height in my case) and setting width or height directly on the canvas doesnt change anything, see code below.
chart.html:
<html>
<head>
<script src="./node_modules/chart.js/dist/Chart.bundle.js"></script>
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./js/diagram.js"></script>
</head>
<body>
<div id="container" style="width:100%; height:100%;">
<canvas id="diagram"></canvas>
</div>
</body>
split.html:
<html>
<head>
<link rel="stylesheet" href="./css/splitter.css" />
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./js/splitter.js"></script>
</head>
<body>
<div id="content">
</div>
</body>
diagram.js:
$(document).ready(function() {
var ctx = document.getElementById("diagram");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: /** excluded (unimportance) **/
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
// Resize chart
$(window).resize(function() {
console.log("resize works!");
if(myChart) myChart.update();
});
});
splitter.js:
$(document).ready(function () {
const splits = 2;
switch (splits) {
case 2:
$("#content").append(
$('<iframe />')
.attr("id", "frame1")
.attr("src", "./chart.html")
.addClass("width50 height100")
);
$("#content").append(
$('<iframe />')
.attr("id", "frame2")
.attr("src", "./chart.html")
.addClass("width50 height100 left50")
);
break;
}
});
splitter.css:
iframe {
position: fixed;
border: none;
margin: 0;
padding: 0;
}
.width100 {
width: 100%;
}
.height100 {
height: 100%;
}
.width50 {
width: 50%;
}
.height50 {
height: 50%;
}
.left50 {
left: 50%;
}
.top50 {
top: 50%;
}

Change iframes to divs with modifiing your splitter.js:
$(document).ready(function () {
const splits = 2;
for(var i = 0; i < splits;i++){
var chartContainer = $('<div id="frame' + (i + 1) + '"></div>').appendTo("#content");
var canvas = $('<canvas class="diagram">').appendTo(chartContainer);
if(i === 0)
chartContainer.addClass('width50 height100');
else
chartContainer.addClass('width50 height100 left50');
}
});
It will add two divs to the content element instead of iframes and also put the canvases into the divs.
Than change your diagram.js to foreach over the canvases and make them work as a chart:
$('canvas.diagram').each(function(){
var ctx = $(this);
var myChart = new Chart(ctx, {
//here comes the chart configuration...
});
});
Change your css to align the two div next to each other with
.width50 {
width: 50%;
display: inline-block;
}
So the charts are now inside block elements and because of they're set to be responsive if you resize the window they will be resized automatically based on their parent elements' width (so you can remove the resizing part from your script too)

Related

Adding Text on the selected canvas in Fabric js

I have fabric js multiple canvases and I would like to add Text on the selected canvas, instead of the last item of the array.
If a user creates multiple canvases then I need an option to add the text on the selected canvas.
Please run the code snippet or see the codepen demo of the current approach...
Thank you!
//================== Create Canvas start =================
var createCanvas = document.getElementById("createCanvas");
var canvasInstances = [];
createCanvas.addEventListener('click',function(){
var canvasContainer = document.getElementById("canvasContainer");
var newcanvas = document.createElement("canvas");
//newcanvas.classList.add("active");
canvasContainer.append(newcanvas);
var fabricCanvasObj = new fabric.Canvas(newcanvas, {
height: 400,
width: 400,
backgroundColor: '#ffffff',
});
canvasInstances.push(fabricCanvasObj);
console.log(canvasInstances);
})
//================== Create Canvas End =================
//================== Add Text ================
var addText = document.getElementById("addText");
addText.addEventListener('click',function(){
canvasInstances.forEach(function(current,id,array){
if(id === array.length - 1){
const converText = new fabric.IText(`Type Text`,{
type: 'text',
width: 200,
fontSize: 20,
left: 20,
top: 20,
fill: '#444'
});
current.add(converText);
current.renderAll();
return false;
}
})
})
//================== Add End =================
*{
box-sizing: border-box;
}
body{
background:#ccc;
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 200px;
}
.canvas-container{
margin-bottom:10px;
}
.add-text{
margin: 20px;
width: 400px;
text-align: center;
border:1px dashed red;
padding: 15px;
cursor:pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>
<div class="add-text" id="addText">Add Text</div>
<div id="canvasContainer">
</div>
<button id="createCanvas">Create Canvas</button>
Declare canvasobject globally, you can try below code
<script type="text/javascript">
var canvasobject;
window.onload = function () {
canvasobject = new fabric.Canvas('myCanvas');
canvasobject.backgroundColor = '#0056d6';
canvasobject.renderAll();
//
function addtext() {
var textvalue = "Type here";
var fontcolor = "#333";
var fontFamily = "Baloo 2";
var myfont = new FontFaceObserver(fontFamily);
myfont.load()
.then(function () {
// when font is loaded, use it.
var text = new fabric.Text(textvalue, {
left: 100,
top: 100,
fontFamily: fontFamily,
fill: fontcolor,
});
canvasobject.add(text);
canvasobject.renderAll();
}).catch(function (e) {
//console.log(e);
console.log('font loading failed ' + fontFamily);
});
}
}

Dygraphs: cannot set z-index for custom legend div

I am trying to implement a graph legend which will follow the mouse cursor. It works, but there is a problem: the legend div is drawn underneath the graph, which is not what I want.
See the following MWE:
<!DOCTYPE html>
<html>
<head>
<title>Testing</title>
<script src="static/dygraph.min.js"></script>
<link rel="stylesheet" href="static/dygraph.css" />
<style>
#graph {
height: 400px;
width: 640px;
}
#legend {
position: absolute;
background-color: red;
/* z-index: 99; */
}
</style>
</head>
<body>
<div id="legend"></div>
<div id="graph"></div>
<script>
document.onmousemove = function(e) {
var legend = document.getElementById("legend");
legend.style.left = e.pageX + "px";
legend.style.top = e.pageY + "px";
};
var data = [];
for(let i = 0; i < 100; i++) {
data.push([i, Math.random(), Math.random()]);
}
var g = new Dygraph(
"graph",
data,
{
fillGraph: true,
fillAlpha: 0.8,
labels: ["x", "y1", "y2"],
labelsDiv: legend,
legendFormatter: legendFormatter
}
);
function legendFormatter(data) {
if(data.x === null) return "";
return data.xHTML + "<br />" +
data.series.map(
v => "<span style='color:" + v.color + ";'>" +
v.labelHTML + "</span>: " + v.yHTML
).join("<br />");
}
</script>
</body>
</html>
The following screenshot shows the current behaviour (which is not what I want):
My natural instinct was to set the legend to have a higher z-index. However, doing so resulted in some weird behaviour.
In Firefox, the legend simply disappears.
In Chromium, the legend is not visible when the cursor is stationary (on the graph), and can be seen to flicker when the cursor is moving.
Why is this, and how do I make the legend appear correctly (on top of the graph)?
I still want the legend to be hidden when the cursor is off the graph, so setting #legend { display: block !important; } is not an option.
1) when the legend div is on top, and is moved to the position of the cursor,
this confuses the graph function that highlights the data point being hovered.
you'll notice when the legend div disappears, no point on the graph is highlighted.
this causes the flickering...
to correct this issue, add a few pixels to the x,y position,
so the legend div is not directly under the cursor.
legend.style.left = (e.pageX + 16) + "px";
legend.style.top = (e.pageY + 16) + "px";
plus, the mouse hides part of the info otherwise...
2) to place the legend div on top of the graph, without adding a z-index,
add the legend div later in the dom, after the graph div...
<div id="graph"></div>
<div id="legend"></div>
3) see following working snippet...
<!DOCTYPE html>
<html>
<head>
<title>Testing</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.css" />
<style>
#graph {
height: 400px;
width: 640px;
}
#legend {
position: absolute;
background-color: red;
}
</style>
</head>
<body>
<div id="graph"></div>
<div id="legend"></div>
<script>
var legend = document.getElementById("legend");
document.onmousemove = function(e) {
legend.style.left = (e.pageX + 16) + "px";
legend.style.top = (e.pageY + 16) + "px";
};
var data = [];
for(let i = 0; i < 100; i++) {
data.push([i, Math.random(), Math.random()]);
}
var g = new Dygraph(
"graph",
data,
{
fillGraph: true,
fillAlpha: 0.8,
labels: ["x", "y1", "y2"],
labelsDiv: legend,
legendFormatter: legendFormatter,
}
);
function legendFormatter(data) {
//if(data.x === null) return "";
return data.xHTML + "<br />" +
data.series.map(
v => "<span style='color:" + v.color + ";'>" +
v.labelHTML + "</span>: " + v.yHTML
).join("<br />");
}
</script>
</body>
</html>

jQuery photoResize function isn't working

I'm new to jQuery and i'm still in the process of learning HTML and CSS. I wanted to have a responsive image on the homepage of my website that scaled itself with the user's browser window. I found this at github: https://github.com/gutierrezalex/photo-resize.git
but i think i might be using it wrong, since i can't get it to work for me.
Here's my html:
<head>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js">
</script>
<reference path="jquery-1.5.1.min.js" />
<script src="jquery-photo-resize.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$("img").photoResize()
});
</script>
</head>
and here's the jquery-photo-resize.js file:
function photoResize($) {
"use strict";
$.fn.photoResize = function (options) {
var element = $(this),
defaults = {
bottomSpacing: 10
};
function updatePhotoHeight() {
var o = options,
photoHeight = $(window).height();
$(element).attr('height', photoHeight - o.bottomSpacing);
}
$(element).load(function () {
updatePhotoHeight();
$(window).bind('resize', function () {
updatePhotoHeight();
});
});
options = $.extend(defaults, options);
};
}
Like i said, i'm a novice, so please let me know what i'm doing wrong, and how i can achieve my desired effect.
You don't need jquery for this. Just set a class name and then in your style sheet use a width. If you only set a width it'll auto size the height to maintain the aspect ratio. Same goes for setting the height only. If you set both your aspect ratio may be off. The width can be a percentage of the current element. You could also use vw (view port width). Also calc is super helpful.
{ width:75%}
Update:
.cropper {
width: 75px;
height: 75px;
overflow: hidden;
position: relative;
}
.cropped {
width: 100px;
position: absolute;
left: -12.5px;
top: -12.5px;
}
<div class="cropper">
<img class="cropped" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/SIPI_Jelly_Beans_4.1.07.tiff/lossy-page1-256px-SIPI_Jelly_Beans_4.1.07.tiff.jpg"/>
</div>
Here is code :
CSS :
.featured { overflow:hidden;
border:2px solid #000;
position:relative;}
.featured img { width:100%; position:relative;}
#pos_1 { width:200px; height:190px; }
#pos_2 { width:150px; height:250px; }
#pos_3 { width:350px; height:150px; }
HTML :
<div id="topGallery">
<article class="featured" id="pos_1">
<img src="abc.jpd" class="attachment-post-thumbnail wp-post-image" alt="piano" />
</article>
</div>
Javascript :
jQuery(document).ready(function($) {
///HOME PAGE - image resizing
function imageLoaded() {
var w = $(this).width();
var h = $(this).height();
var parentW = $(this).parent().width();
var parentH = $(this).parent().height();
//console.log(w + '-' + h + '-' + parentW + '-' + parentH);
//if (w >= parentW){ //always true because of CSS
if (h > parentH){
$(this).css('top', -(h-parentH)/2);
} else if (h < parentH){
$(this).css('height', parentH).css('width', 'auto');
$(this).css('left', -($(this).width()-parentW)/2);
}
//}
}
$('#topGallery img').each(function() {
if( this.complete ) {
imageLoaded.call( this );
} else {
$(this).one('load', imageLoaded);
}
});
});

Add a border around the Google pie chart

I have created a Google Pie chart. I need to add a border around the Google pie chart can you guys help me to add this? I have added the code for the Google Chart and the image I want it to be done.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {
packages: ["corechart"]
});
google.setOnLoadCallback(drawChart);
var values = [];
$(document).ready(function() {
$.ajax({
type: "GET",
url: "ChartData.xml",
dataType: "xml",
success: function(xml) {
$(xml).find('Pie').each(function() {
var sTitle = $(this).find('Title').text();
var sValue = $(this).find('Value').text();
if (!isNaN(+sValue)) {
sValue = +sValue;
}
values.push([sTitle, sValue]);
});
drawChart(values);
},
error: function() {
alert("An error occurred while processing XML file.");
}
});
});
function drawChart(val) {
var data = google.visualization.arrayToDataTable(val);
var options = {'title':'Sample Charts', 'width':650, 'height':600, pieHole: 0.5, colors: ['#F6891F', '#A59B91', '#72C5EF', '#53585A', '#C8502B'], tooltip: {showColorCode: true}, is3D: false };
var chart = new google.visualization.PieChart(document.getElementById('piechart'));
chart.draw(data, options);
}
</script>
<title>My Read</title>
</head>
<body>
<div id="piechart"></div>
</body>
</html>
#piechart {
width:120px;
margin: 10px;
border:5px solid red;
border-radius: 100px;
-webkit-border-radius: 500px;
-moz-border-radius: 500px;
}
try giving this css style. It may Work. You can change dimensions accordingly.
I hope it works for you
Old question but maybe somebody could still use this:
function drawPieBorder(chart) {
var layout = chart.getChartLayoutInterface();
var chartArea = layout.getChartAreaBoundingBox();
var svg = chart.getContainer().getElementsByTagName('svg')[0];
var radius = chartArea.height/2;
var path = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
path.setAttribute('stroke', 'black');
path.setAttribute('stroke-width', 1);
path.setAttribute('fill', 'transparent');
path.setAttribute('cx', radius + chartArea.left);
path.setAttribute('cy', radius + chartArea.top);
path.setAttribute('r', radius);
svg.appendChild(path);
}

JavaScript/jQuery: Follow path over page

I need to make an animated gif 'fly over a page and follow a path. I'm thinking of using jQuery but would I be right in thinking the only way to do it is manually calculating the percentage of width/height where the shape layer should be placed, then using absolute positioning is the only way to do this? I know there are some amazing jQuery plugins available for this type of thing.
Absolute positioning is likely to be the best way to do it, yes. (I wouldn't put my hand on heart as saying it's the only way, I'm sure you could play other games to do something similar, but you probably don't want to.)
You don't have to do it as a percentage unless that's intrinsic to your problem. The following will happily make an element absolutely-positioned and then move it 5 pixels right and down every 10th of a second for up to 'count' iterations:
function moveDemo(element, count) {
element.style.position = "absolute";
moveit();
function moveit() {
element.style.left = ((parseInt(element.style.left) || 0) + 5) + "px";
element.style.top = ((parseInt(element.style.top) || 0) + 5) + "px";
if (count-- > 0) {
setTimeout(moveit, 100);
}
}
}
That's just raw JavaScript, but frameworks like jQuery, Prototype, Closure, YUI, etc. help you with a lot of things and are worth looking into. For instance, if you use the above, unless you make the element absolutely-positioned in advance and also specify the left and top styles on the element itself (via an inline style attribute), it'll jump to 0,0 at the outset and then start moving from there. Frameworks can help you with the fairly complex task of figuring out where an inline element is before making it absolutely-positioned.
Here's a complete example that doesn't rely on a framework (but probably should, at least for determining the starting position of 'myElement'):
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
<title>Move It Demo Page</title>
<style type='text/css'>
body {
font-family: sans-serif;
}
#myElement {
border: 1px solid black;
}
</style>
<script type='text/javascript'>
function startMoving() {
moveDemo(document.getElementById('myElement'), 10);
}
function moveDemo(element, count) {
element.style.position = "absolute";
moveit();
function moveit() {
element.style.left = ((parseInt(element.style.left) || 0) + 5) + "px";
element.style.top = ((parseInt(element.style.top) || 0) + 5) + "px";
if (count-- > 0) {
setTimeout(moveit, 100);
}
}
}
</script>
</head>
<body><div>
<input type='button' value='Start' onClick="startMoving();">
<div id='myElement'>I'm on the move</div>
</div></body>
</html>
jQuery seems to be the way to go, basic and more of a hack than a solution, but if you definitely need something with JS.
<style type="text/css">
#butterfly
{
display:block;
background: #f00;
width: 100px;
height: 100px;
left: 0;
top: 0;
position: fixed;
background: url(butterfly.gif) no-repeat;
}
</style>
<script type='text/javascript'>
function moveButterfly() {
//moveDemo(document.getElementById('butterfly'), 10);
var butterfly = $('#butterfly');
var positions = [
{ props: { left: '25%', top: '20%' }, time: 1000 },
{ props: { left: '40%', top: '18%' }, time: 610 },
{ props: { left: '58%', top: '38%'}, time: 400 },
{ props: { left: '81%', top: '52%' }, time: 520 },
{ props: { left: '150%', top: '67%'}, time: 440 },
];
jQuery.each(positions, function(i, e) {
butterfly.animate(e.props, e.time);
});
}
$().ready(function() {
moveButterfly();
});
</script>

Categories