media queries not working on dc.js chart - css

I want to set different width of dc.chart svg on different resolution,but media queries are not working.Is dc.chart supporting media queries or not?
please suggest me solution for it as soon as possible.
<!DOCTYPE html>
<html lang="en" style="overflow:hidden">
<head>
<title>DVH Graph</title>
<meta charset="UTF-8">
<!-- Stop this page from being cached -->
<meta http-Equiv="Cache-Control" Content="no-cache">
<meta http-Equiv="Pragma" Content="no-cache">
<meta http-Equiv="Expires" Content="0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/dc.css"/>
<script type="text/javascript" src="js/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="js/hash2Color.js"></script>
<script type="text/javascript" src="js/loadDVH.js"></script>
<script type="text/javascript" src="js/d3.js"></script>
<script type="text/javascript" src="js/crossfilter.js"></script>
<script type="text/javascript" src="js/dc.js"></script>
<style type="text/css">
#media(max-width:1280px) {
.dc-chart .axis path, .axis line { stroke:#000; }
.dc-chart .axis text { fill: #000; }
.dc-chart svg{width:350px;height:340px;margin-left:10px}
.dc-chart{margin-left:-7px;margin-top:-9px}
}
#media(max-width:1920px) {
.dc-chart .axis path, .axis line { stroke: #000; }
.dc-chart .axis text { fill: #000; }
.dc-chart svg{width:590px;height:340px;margin-left:10px}
.dc-chart{margin-left:-7px;margin-top:-9px}
}
</style>
</head>
<body style="background:#000000" border="0">
<div id="chartCumulativeDVH" style="background: #ffffff;"></div>
<script type="text/javascript">
var chart = dc.seriesChart("#chartCumulativeDVH");
var ndx, doseDimension, doseGroup;
function drawDVH(data) {
//
// The data returned from the DSS Data API isn't quite in the best format for dc graphs
// So, we need to reformat it slightly
//
var dvhColours = [];
var formatted = [];
for (var objCount = 0; objCount < data.length; objCount++) {
var contourID = objCount + 1;
for (var i = 0; i < data[objCount].NumberOfPoints; i++) {
data[objCount].Points[i].Contour = contourID;
formatted.push(data[objCount].Points[i]);
}
// Match the colour of the curve to the label.
var rgb = hash2Color(data[objCount].Contour);
dvhColours.push('rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')');
}
// Clear the existing chart
if(ndx) {
ndx.remove();
ndx.add(formatted);
dc.redrawAll();
}
ndx = crossfilter(formatted);
doseDimension = ndx.dimension(function(d) {
return [+d.Contour, +d.X];
});
doseDimension.filterFunction(function(d) {
return d;
});
doseGroup = doseDimension.group().reduceSum(function(d) {
return +d.Y;
});
chart
/* .width(347)
.height(280) */
.chart(function(c) { return dc.lineChart(c).interpolate('basis'); })
.x(d3.scale.linear().domain([0, 7500]))
.y(d3.scale.linear().domain([0, 100]))
.brushOn(false)
.yAxisLabel("% Volume")
.xAxisLabel("Dose mGy")
.clipPadding(10)
.dimension(doseDimension)
.group(doseGroup)
.mouseZoomable(true)
.seriesAccessor(function(d) { return "Contour: " + d.key[0]; })
.keyAccessor(function(d) { return +d.key[1]; })
.valueAccessor(function(d) { return +d.value; })
.ordinalColors(dvhColours);
chart.yAxis().tickFormat(function(d) {return d3.format(',d')(d + 0);});
chart.margins().left = 40;
dc.renderAll();
};
$(document).on("data-available", function (__e, __data) {
drawDVH(__data);
});
// Draw the default graph (e.g. no data)
drawDVH({});
</script>
</body>
</html>

The svg element is directly sized by dc.js, and since element-level styles override stylesheet-level styles, your media queries will have no effect.
What you want to do is set the size of the containing div (#chartCumulativeDVH or .dc-chart).
Then you have two at least three choices how to apply the size to the svg element that will be created:
Leave off the width and height as you show in your example. dc.js will automatically use the size of the container div if width and height are not specified. However, this will not work if anything else is in the div (or might show up there, like the filter and reset controls) because they will no longer be the same size, and the svg size can get out of control in these cases.
Set the size of the chart to match the div size, e.g. (using jQuery) something like
chart
.width($('#chartCumulativeDVH').innerWidth())
.height($('#chartCumulativeDVH').innerHeight())
Or, to base the width and height off the window size without using jQuery and without the media query, as we do in the resizing bar chart example:
chart
.width(window.innerWidth-20)
.height(window.innerHeight-20)

Related

take a screenshot of a web map

I am just starting out with javascript and I am trying to create an interactive web map....
I want to be able to position the map then press a button that will take a screenshot and save it to the computer.
Here is the code for my map.....
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Display a map on a webpage</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js"></script>
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = '[TOKEN]';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/charlie-enright/cl5b8bjil002y14o5u8xrssah', // style URL
center: [-4.369240916438415, 51.925803756014965], // starting position [lng, lat]
zoom: 8, // starting zoom
projection: 'globe' // display the map as a 3D globe
});
map.on('style.load', () => {
map.setFog({}); // Set the default atmosphere style
});
</script>
</body>
</html>
I have tried using html2canvas (https://codepen.io/samsammurphy/pen/VXdOPv) but the button seems to end up in a layer behind my map and I can not take a screenshot of the displayed map.
Any ideas how I could create a button that allows for a screenshot to be taken which saves to the computer will be greatly appreciated.
Thanks,
Here's an example of using map.getCanvas().toDataURL() and then injecting an img tag into the DOM. (This is not my example, I found it on this codepen by Sam Murphy https://codepen.io/samsammurphy/pen/VXdOPv)
$('button').click(function() {
var img = map.getCanvas().toDataURL();
var width = $('#screenshotPlaceholder').width()
var height = $('#screenshotPlaceholder').height()
var imgHTML = `<img src="${img}", width=${width}, height = ${height}/>`
$('#screenshotPlaceholder').empty();
$('#screenshotPlaceholder').append(imgHTML);
});
});
The codepen I found this on was not working due to an expired access token, so here's a fork that works if you want to try it out.
https://codepen.io/chriswhong/pen/YzapomG
Here's the code I use to take map screenshots using html2canvas
html2canvas(document.getElementById("map"), {useCORS:true}).then(canvas => {
var pseudolink = document.createElement('a');
pseudolink.download = 'myMapScreenshot.png';
pseudolink.href = canvas.toDataURL()
pseudolink.click();
})

How do I isolate floated content?

I am pulling blog posts in from the blogger JSON api into my page. The posts are HTML formatted. Some of the posts have floated content; an image, for instance, that is floated left with text to the right that is shorter than the image. The title and date of the post below it are pushed to the right as well. I remember there being an esoteric way within CSS to isolate float within a div. I can't remember how. And I don't remember what it is even called. I've been searching all day. Any ideas?
<!DOCTYPE html>
<html lang="en">
<head>
<title>Sandy Reads - News</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<style></style>
</head>
<body>
<div class="container-fluid">
<section id="posts">
<div class="page-header">
<h1>Sandy Reads <small>News</small></h1>
</div>
</section>
</div>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment-with-locales.min.js"></script>
<script>
$(function () {
var key = "Redacted";
var blogId = "Redacted";
var resource = "https://www.googleapis.com/blogger/v3/blogs/" + blogId + "/posts?maxResults=10&key=" + key;
$.getJSON(resource, function (data) {
var items = [];
$.each(data.items, function (key, val) {
var kind = val.kind;
if (kind !== 'blogger#post')
return;
var blogId = val.id;
var title = val.title;
var content = val.content;
var date = moment(val.updated);
items.push("<li id='" + blogId + "' class='post'>" +
"<a href='blog.html?id=" + blogId + "'><h3>" + title + "</h3></a>" +
"<i>" + date.format('MMMM Do YYYY') + "</i></div>" +
"<div>" + content + "</div>" +
"</li>");
});
$("<ul/>", {
"class": "list-group my-new-list",
html: items.join("")
}).appendTo("#posts");
});
});
</script>
</body>
</html>
You're probably thinking of overflow: hidden, but which element you apply it to depends on what your markup looks like. I can tell you to apply it to the parent of the float, but if the content that is being pushed aside appears in this same parent, then that's not going to help.
OK, so your script generates posts in a series of li.post elements. The content appears in a div following the title and date. You can either set li.post to clear floats, or apply overflow: hidden to the div. (There is a spurious </div> end tag after your post date that you may want to account for.)

Create columns in DOJO border container

I want to use DOJO border container in my page. I have this sample.
<script>
require(["dijit/layout/BorderContainer", "dijit/layout/ContentPane","dojo/domReady!"],
function(BorderContainer, ContentPane){
// create a BorderContainer as the top widget in the hierarchy
var bc = new BorderContainer({
style: "height: 300px; width: 500px;"
});
// create a ContentPane as the center pane in the BorderContainer
var cp2 = new ContentPane({
region: "center",
content: "how are you?,this is a test content"
});
bc.addChild(cp2);
// put the top level widget into the document, and then call startup()
bc.placeAt(document.body);
bc.startup();
});
</script>
I want to create some columns so that it looks like a table. How can I do that??
Can someone help me
Based on your title, "create columns in Dojo BorderContainer" (emphasis mine), then I would think a dgrid, table container, or grid container inside the border container would suit, depending upon what you were trying to accomplish with the table.
If the table is for data, consider dgrid. If the table is for form layout, consider table container. If the table is for widget layout, consider a grid container.
Here's an example using grid container. nbZones is the number of columns.
<!DOCTYPE html>
<html>
<head>
<link href='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css' rel='stylesheet' type='text/css' />
<link href='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojox/widget/Portlet/Portlet.css' rel='stylesheet' type='text/css' />
<link href='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojox/layout/resources/GridContainer.css' rel='stylesheet' type='text/css' />
<script src='//ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js'></script>
<style type='text/css'>
html,body,#border { margin:0; width:100%; height:100%; }
</style>
</head>
<body class='claro'>
<div id='border' data-dojo-type='dijit/layout/BorderContainer'>
<div id='grid'></div>
</div>
<script type='text/javascript'>
require(
['dojo/ready', 'dojo/parser', 'dojox/layout/GridContainer', 'dojox/widget/Portlet'],
function (ready, Parser, GridContainer, Portlet) {
ready(function () {
Parser.parse().then(function () {
// create grid and put into border container
var grid = new GridContainer({nbZones:3}, 'grid');
// create cells and put into grid
for (var i = 0; i < 30; i++) {
grid.addChild(new Portlet({
closable:false,
content:'(' + Math.floor(i/3) + ', ' + (i%3) + ')'
}));
}
grid.startup();
});
});
}
);
</script>
</body>
</html>

dojo datagrid OnStyleRow not correct after sorting via header

I am styling grid row based on a value in the column.
On initial load it looks ok, however, when I click on the header to sort, the styling follows the original style and does not reflect the value in the sorted list.
In the onStyleRow event that does the styling override, I can get the row object of the grid, But... how do I get the column data from the row so that I can style it properly.
I have gone through the two questions below and a few others in StackOverflow, Googled, checked Dojo API docs and reference, etc. So far no outcome...
dojox DataGrid onStyleRow works first time, then not again
dojo datagrid custom sorting server side
I attach working code below, you can cut and paste to a html file to run and see the problem I am facing (The //// comment in the code below is a key place to note).
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test</title>
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/resources/dojo.css">
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dijit/themes/tundra/tundra.css">
<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojox/grid/resources/tundraGrid.css">
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js" data-dojo-config="async:true,isDebug:true,parseOnLoad:true"></script>
<script>
var grid_report;
require([ 'dojo/parser', 'dojox/grid/DataGrid', 'dojox/data/CsvStore', 'dojo/domReady!' ], function(){
dojo.ready(function(){
var csvData = "id,val\n";
csvData += "1,10\n" + "2,20\n" + "3,30\n" + "4,40\n" + "5,50\n" + "6,60\n";
var csv_store = new dojox.data.CsvStore({identifier: "id", data: csvData});
grid_report = new dojox.grid.DataGrid({
style:'height:400px',
store: csv_store,
structure: [ { field: 'id', width: '80px', name: 'ID' }, { field: 'val', width: '80px', name: 'Value' }, ],
}, document.createElement('div'));
dojo.byId("gridDiv").appendChild(grid_report.domNode);
dojo.connect(grid_report, 'onStyleRow', function (row) {
var idx = row.index;
//// Below is not correct as index is the row index on the grid, but the data store is in a different order after sorting order change via clicking cell header
var _item = grid_report.getItem(idx);
if (!_item) return;
var val = parseInt( _item._csvStore._dataArray[ idx ][1] );
if (val <= 20) row.customStyles += 'background-color:#88f;';
else if (val > 40) row.customStyles += 'background-color:#f88;';
else row.customStyles += 'background-color:#ff8;';
dojox.grid.DataGrid.prototype.onStyleRow.apply(this, arguments);
});
grid_report.startup();
}); // end ready
}); // end require
</script>
</head>
<body class="tundra">
<div style="height:25px; width:100px; display:table-cell; text-align: center; vertical-align:middle; background-color:#88f;">Value 0-20</div>
<div style="height:25px; width:100px; display:table-cell; text-align: center; vertical-align:middle; background-color:#ff8;">Value 21-40 </div>
<div style="height:25px; width:100px; display:table-cell; text-align: center; vertical-align:middle; background-color:#f88;">Value 41 or more</div>
<div id="gridDiv" style="width:'800px';height:'600px';"></div>
</body>
</html>
I found a work around. It is not ideal as it may not work for all situations.
Change line with:
var idx = row.index;
to:
var idx = -1;
After the newly edit line above, add the following:
var _item = null;
grid_report.store.fetch({onComplete: function(items) {
dojo.forEach(items, function(item, index) {
// KLUDGE FOR finding item after sort
// use merged csv data AND row.node.textContent
var merged_csv_text = item._csvStore._dataArray[index].join('');
if (merged_csv_text == row.node.textContent) {
idx = index; // I finally get the correct index here!!!
return;
}
});
} });
if (idx == -1) return;
This works only if each data formed by merged_csv_text is unique.

setCenter within "center" event callback

I want to keep the map center coordinates into some limits. For this I call the setCenter method inside my "center" related callback function:
map.addObserver("center", function (obj, key, newValue, oldValue) {
var limits = {minLat: 47.4136, minLon: 5.9845, maxLat: 54.8073, maxLon: 14.3671};
if (newValue.latitude < limits.minLat || newValue.longitude < limits.minLon ||
newValue.latitude > limits.maxLat || newValue.longitude > limits.maxLon) {
var newLatLon = {latitude: Math.max(Math.min(newValue.latitude, limits.maxLat), limits.minLat),
longitude: Math.max(Math.min(newValue.longitude, limits.maxLon), limits.minLon)};
map.setCenter(nokia.maps.geo.Coordinate.fromObject(newLatLon));
console.log(newValue);
console.log(map.center);
}
});
If I drag the map outside the limits, I see in the console the map.center being correctly adjusted, but the newValue coordinates keep being outisde the limits.
Did I misunderstand the API ?
I am using http://api.maps.nokia.com/2.2.3/jsl.js?with=all
Adding an observer to a property and then altering that property within the observer function is not guaranteed to work for all properties. My understanding is that re-setting the center is not supported in order to avoid infinite loops. You would be better off using the event framework rather than observers in this case.
The code below restricts the centre of the map to remain within a rectangle centred on Germany. If you drag the map it will stop dead, if you flick the map it will bounce back. You will need to obtain your own free app id and token to get it to work.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9" />
<title>Nokia Maps API Example: Restricted Area</title>
<!-- KML support is required here. -->
<script type="text/javascript" charset="UTF-8" src="http://api.maps.nokia.com/2.2.3/jsl.js"></script>
</head>
<style type="text/css">
html {
overflow:hidden;
}
body {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
position: absolute;
}
#mapContainer {
width: 80%;
height: 80%;
}
</style>
</head>
<body>
<div id="mapContainer"></div>
<script type="text/javascript">
/////////////////////////////////////////////////////////////////////////////////////
// Don't forget to set your API credentials
//
// Replace with your appId and token which you can obtain when you
// register on http://api.developer.nokia.com/
//
nokia.Settings.set( "appId", "APP ID");
nokia.Settings.set( "authenticationToken", "TOKEN");
//
/////////////////////////////////////////////////////////////////////////////////////
</script>
<div id="uiContainer"></div>
<script>
var mapContainer = document.getElementById("mapContainer");
var map = new nokia.maps.map.Display(mapContainer, {
center: [51, 7],
zoomLevel: 6
});
map.addComponent(new nokia.maps.map.component.Behavior());
var dragger = map.getComponentById("panning.Drag");
// Set of initial geo coordinates to create the purple polyline
var points = [
new nokia.maps.geo.Coordinate(47.4136, 5.9845),
new nokia.maps.geo.Coordinate(47.4136, 14.3671),
new nokia.maps.geo.Coordinate(54.8073, 14.3671),
new nokia.maps.geo.Coordinate(54.8073, 5.9845),
new nokia.maps.geo.Coordinate(47.4136, 5.9845)
];
// Transparent purple polyline
map.objects.add(new nokia.maps.map.Polyline(
points,
{
pen: {
strokeColor: "#22CA",
lineWidth: 5
}
}
));
var restrict = function(evt) {
var limits = {minLat: 47.4136, minLon: 5.9845, maxLat: 54.8073, maxLon: 14.3671};
if (map.center.latitude < limits.minLat || map.center.longitude < limits.minLon ||
map.center.latitude > limits.maxLat || map.center.longitude > limits.maxLon) {
var latitude = Math.max(Math.min(map.center.latitude, limits.maxLat), limits.minLat);
var longitude = Math.max(Math.min(map.center.longitude, limits.maxLon), limits.minLon);
map.setCenter(new nokia.maps.geo.Coordinate(latitude,longitude));
evt.cancel();
}
}
map.addListener("dragend", restrict);
map.addListener("drag", restrict);
map.addListener("mapviewchange", restrict);
map.addListener("mapviewchangeend", restrict);
map.addListener("mapviewchangestart", restrict);
</script>
</body>
</html>
I have added event listeners to five events here, dragend, drag, mapviewchange, mapviewchangeend and mapviewchangestart - depending upon the effect you require, you may not need them all. The line evt.cancel(); stops the event from being processed.

Resources