Skip to content

Instantly share code, notes, and snippets.

@powersparks
Last active January 13, 2017 11:10
Show Gist options
  • Save powersparks/f7c042e2203c8bea6c5d35b958202b27 to your computer and use it in GitHub Desktop.
Save powersparks/f7c042e2203c8bea6c5d35b958202b27 to your computer and use it in GitHub Desktop.
D3.js Time Filter as a jQuery Plugin.
license: gpl-3.0
(function($){
api = {
register:function (context){
// api.renderGlobeCanvas(context.globeViewerId);
//api.renderGlobeSvg(context.globeViewerId);
},
renderGlobeSvg:function(globeDivId){
var diameter = 320,
radius = diameter/2,
velocity = .01,
then = Date.now();
// Width and height of the SVG element
var width = 600, height = 300;
// Store the rotation and scale of the projection
var state = {x: 0, y: -45, scale: height / 2};
var projection1 = d3.geoOrthographic()
.scale(radius - 2)
.translate([radius, radius])
.clipAngle(90)
.precision(0);
var projection = d3.geoOrthographic()
.scale(state.scale) //.scale(height / 2)
.translate([radius, radius]) //.translate([width / 2, height / 2])
.clipAngle(90)
.rotate([state.x, state.y]);
api.projection = projection;
var svg = d3.select("#" + globeDivId).append("svg")
.attr("width", diameter)
.attr("height", diameter);
var path = d3.geoPath()
.projection(projection);
var globe = {type: "Sphere"};
svg.append("path")
.datum(globe)
.attr("class", "foreground")
.attr("d", path);
d3.json("world-110m.json", function(error, world) {
if (error) throw error;
var land = topojson.feature(world, world.objects.land),
globe = {type: "Sphere"};
svg.insert("path")
.datum(topojson.feature(world, world.objects.land))
.attr("class", "land")
.attr("d", path);
d3.timer(function() {
var angle = velocity * (Date.now() - then);
projection.rotate([angle,0,0]);
svg.selectAll("path")
.attr("d", path.projection(projection));
});
});
$.coria.globe.svg = svg;
},
renderGlobeCanvas: function(canvasId){
var diameter = 960 / 3,
radius = diameter / 2,
velocity = 0.01;
var projection = d3.geoOrthographic()
.scale(radius - 2)
.translate([radius, radius])
.clipAngle(90)
.precision(0);
d3.select("#" + canvasId ).selectAll(".title")
.data(["λ", "φ", "γ"])
.enter().append("div")
.attr("class", "title")
.style("width", diameter + "px")
.text(function(d) { return d; });
var canvas = d3.select("#" + canvasId ).selectAll("canvas")
.data(d3.range(3))
.enter().append("canvas")
.datum(function() { return this.getContext("2d"); })
.attr("width", diameter)
.attr("height", diameter);
var path = d3.geoPath()
.projection(projection);
d3.json("world-110m.json", function(error, world) {
if (error) throw error;
var land = topojson.feature(world, world.objects.land),
globe = {type: "Sphere"};
d3.timer(function(elapsed) {
var angle = velocity * elapsed;
canvas.each(function(context, i) {
var rotate = [0, 0, 0];
rotate[i] = angle, projection.rotate(rotate);
context.clearRect(0, 0, diameter, diameter);
context.beginPath(), path.context(context)(land), context.fill();
context.beginPath(), path(globe), context.stroke();
});
});
});
}
};
$.coria = $.coria ? $.coria : {};
$.coria.globe = api;
})(jQuery);
/// <reference path="d3.js" />
/// <reference path="C:\Program Files\Telligent\9.2\Utility\JQuery\jquery.min.js" />
/// <reference path="C:\Program Files\Telligent\9.2\Utility\JQuery\evolution\telligent.evolution.js" />
var quakeResultsTemp ={
"type": "FeatureCollection",
"metadata": {
"generated": 1481433099000,
"url": "http://earthquake.usgs.gov/fdsnws/event/1/query?callback=quake321705&format=geojson&starttime=2014-01-01&endtime=2014-01-02",
"title": "USGS Earthquakes",
"status": 200,
"api": "1.5.2",
"count": 277
},
"features": [{
"type": "Feature",
"properties": {
"mag": 1.29,
"place": "10km SSW of Idyllwild, CA",
"time": 1388620296020,/****Times are reported in milliseconds since the epoch ( 1970-01-01T00:00:00.000Z)*/
"updated": 1457728844428,
"tz": -480,
"url": "http://earthquake.usgs.gov/earthquakes/eventpage/ci11408890",
"detail": "http://earthquake.usgs.gov/fdsnws/event/1/query?eventid=ci11408890&format=geojson",
"felt": null,
"cdi": null,
"mmi": null,
"alert": null,
"status": "reviewed",
"tsunami": 0,
"sig": 26,
"net": "ci",
"code": "11408890",
"ids": ",ci11408890,",
"sources": ",ci,",
"types": ",cap,focal-mechanism,general-link,geoserve,nearby-cities,origin,phase-data,scitech-link,",
"nst": 39,
"dmin": 0.06729,
"rms": 0.09,
"gap": 51,
"magType": "ml",
"type": "earthquake",
"title": "M 1.3 - 10km SSW of Idyllwild, CA"
},
"geometry": {
"type": "Point",
"coordinates": [-116.7776667, 33.6633333, 11.008]
},
"id": "ci11408890"
}],
"bbox": [-179.688, -56.1218, -0.653, 167.8106, 64.8073, 582.05]
};
(function ($) {
var date_dynField = "Date";
var y_dynField = "price";
var api = {
tfc_layout_array: [],
tfc_charts_array: [],
tfc_clipPath: function () {
var _id = "clip", _svg, _hgt, _wit, _shp = "rect";
function clipPath(svg, width, height) {
if (!arguments.length) {
return {
id: _id,
svg: _svg,
height: _hgt,
width: _wit,
shape: _shp
};
}
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
_id = "clip";
_svg = svg;
_hgt = height;
_wit = width;
_shp = "rect";
return clipPath();
}
clipPath.id = function (value) { if (!arguments.length) { return _id; } _id = value; return clipPath; };
clipPath.svg = function (value) { if (!arguments.length) { return _svg; } _svg = value; return clipPath; };
clipPath.height = function (value) { if (!arguments.length) { return _hgt; } _hgt = value; return clipPath; };
clipPath.width = function (value) { if (!arguments.length) { return _wit; } _wit = value; return clipPath; };
clipPath.shape = function (value) { if (!arguments.length) { return _shp; } _shp = value; return clipPath; };
return clipPath;
},
tfc_layout: function () {
var _svgSelector = "", _svg,
_cntrl_width = 600,
_cntrl_height = 80,
_margin = { top: 35, right: 10, bottom: 35, left: 10 },
_width = (_cntrl_width - _margin.left - _margin.right),
_height = (_cntrl_height - _margin.top - _margin.bottom),
_name = 'ChartName';
//x = d3.scaleTime().range([0, _width]),
//y = d3.scaleLinear().range([_height, 0]),
//_xAxis = d3.axisTop(x).tickSize([_height]),
// _yAxis = d3.axisRight(y).ticks(0).tickSize(_width);
//x.domain([new Date().setFullYear(2016, 01, 01), Date.now()]);
//y.domain([0, 100]);
function tfc_layout(opts) {
if (!arguments.length) {
return {
chartName: _name,
svgSelector: _svgSelector,
svg: _svg,
cntrl_width: _cntrl_width,
cntrl_height: _cntrl_height,
width: _width,
height: _height,
margin: _margin
};
}
_name = opts.name ? opts.name : _name;
_svgSelector = opts.svgSelector ? opts.svgSelector : _svgSelector;
_svg = opts.svg ? opts.svg : _svgSelector;
_cntrl_width = opts.width ? opts.width : _cntrl_width;
_cntrl_height = opts.height ? opts.height : _cntrl_height;
_margin = opts.margin ? opts.margin : _margin;
_margin.top = opts.margin ? opts.margin.top ? opts.margin.top : _margin.top : _margin.top;
_margin.bottom = opts.margin ? opts.margin.bottom ? opts.margin.bottom : _margin.bottom : _margin.bottom;
_margin.right = opts.margin ? opts.margin.right ?opts.margin.right : _margin.right : _margin.right ;
_margin.left = opts.margin ? opts.margin.left ? pts.margin.left : _margin.left : _margin.left;
}
tfc_layout.chartName = function (value) { if (!arguments.length) { return _name; } _name = value; return tfc_layout;};
tfc_layout.svgSelector = function (value) { if (!arguments.length) { return _svgSelector; } _svgSelector = value; return tfc_layout; };// gets or sets selection string
tfc_layout.svg = function (value) { if (!arguments.length) { return _svg; } _svg = value; return tfc_layout; };//gets svg if selector is defined or sets (using selector string)
tfc_layout.cntrl_width = function (value) { if (!arguments.length) { return _cntrl_width; } _cntrl_width = value; _width = (_cntrl_width - _margin.right - _margin.left); return tfc_layout; };//get or set control width
tfc_layout.cntrl_height = function (value) { if (!arguments.length) { return _cntrl_height; } _cntrl_height = value; _height = (_cntrl_height - _margin.top - _margin.bottom); return tfc_layout; };//get or set control height
tfc_layout.width = function (value) { if (!arguments.length) { return _width; } _width = value; _cntrl_width = (_width + _margin.left + _margin.right); return tfc_layout; };//gets width based on margins or sets width, as a number calculated base on margins /*if (checkNum(value)) tfc_layout({ "width" : value, "height": (value * 0.02) }); return tfc_layout; };
tfc_layout.height = function (value) { if (!arguments.length) { return _height; } _height = value; _cntrl_height = (_height + _margin.top + _margin.bottom); return tfc_layout; };//if (checkNum(value)) tfc_layout({ "height": value, "width" : (value / 0.02) }); return tfc_layout; };
tfc_layout.margin = function (value) { if (!arguments.length) { return _margin; } _margin = value; return tfc_layout; };//margin
tfc_layout.margin.top = function (value) { if (!arguments.length) { return _margin.top; } _margin.top = value; _height = (_cntrl_height - _margin.top - _margin.bottom); return tfc_layout; };//top margin
tfc_layout.margin.bottom = function (value) { if (!arguments.length) { return _margin.bottom; } _margin.bottom = value; _height = (_cntrl_height - _margin.top - _margin.bottom); return tfc_layout; };//bottom margin
tfc_layout.margin.right = function (value) { if (!arguments.length) { return _margin.right; } _margin.right = value; _width = (_cntrl_width - _margin.left - _margin.right); return tfc_layout; };//right margin
tfc_layout.margin.left = function (value) { if (!arguments.length) { return _margin.left; } _margin.left = value; _width = (_cntrl_width - _margin.left - _margin.right); return tfc_layout; };//left margin
// tfc_layout.x = function (value) { if (!arguments.length) { return x; } x = value; return tfc_layout; };// x scales or sets range
//tfc_layout.y = function (value) { if (!arguments.length) { return y; } y = value; return tfc_layout; };// y scales or sets range
// tfc_layout.xAxis = _xAxis ;//d3.axisTop(x).tickSize([_height]);//function (value) { if (!arguments.length) { return _xAxis; } _xAxis = value; return tfc_layout; };// xAxis setup
//tfc_layout.yAxis = _yAxis ;//d3.axisRight(y).ticks(0).tickSize(_width);//function (value) { if (!arguments.length) { return _yAxis; } _yAxis = value; return tfc_layout; };// yAxis setup
// var _xAxis = d3.axisTop(x).tickSize([height]),
// _yAxis = d3.axisRight(y).ticks(0).tickSize(width);
return tfc_layout;
},
tfc_chart: function () {
/**
* Class Name: Time Filter Control (servos)
* Description: TFC uses a paradigm of gears or virtual servo-mechanisms.
* using d3js, the objects consist of master and slave gear ratios,
* feedback, and adjustment surfaces( or pentiometers)
* to sense, move (rotate) and zoom on axis.
* 1) "Variable" - define layout dimensions (required as input)
* a) Height, width, margins required for svg control
* b) Use the default settings, or set your own
* c) Reusing and naming "tfc_layout" class
* d) Based on "Margin Convention" example:
* https://bl.ocks.org/mbostock/3019563
* e) other examples that helped form this:
brush and zoom
http://bl.ocks.org/tnightingale/4718717
*/
// var tfc_layout = new $.coria.timeFilterControl.tfc_layout();
var _timeFilterChart, _x, _y, _xAxis, _yAxis, X_MinFromDateExample, X_MaxToDateExample, Y_MinFromValueExample, Y_MinFromValueExample;
var _tfc_layout , _name;
function TimeFilterChart(tfc_layout,data) {
if (!arguments.length) {
return {
chartName: _name,
chart: _timeFilterChart,
x: _x,
y: _y,
xAxis: _xAxis,
yAxis: _yAxis,
settings: _tfc_layout
};
}
/*****
* 2) "Algebra" - group and assemble what is broken
* a) Select the html
* b) Append svg control (or chart)
* c) set svg control's class name, width, & height
* d) Append svg group ("g") orgin within the control
*/
_name = tfc_layout.chartName();
_tfc_layout = tfc_layout;
//_timeFilterChart = d3.select("svg.timeline-svg-filter2")
_timeFilterChart = api.svgMain
.append("svg")
.attr("class", "time-filter-control")
.attr("width", _tfc_layout.cntrl_width())
.attr("height", _tfc_layout.cntrl_height())
.append("g")
.attr("class", "timeline-axis-container layout")
.attr("transform", "translate(" + _tfc_layout.margin.left() + "," + _tfc_layout.margin.top() + ")");
/***
* 5) "Scaling" - arrange layout to domains
* a) Scale "time" range along layout's x-axis
* b) Scale "linear" range along the layout's y-axis
*/
_x = d3.scaleTime().range([0, _tfc_layout.width()]),
_y = d3.scaleLinear().range([_tfc_layout.height(), 0]);
/******
* c) Scaling axis' ticks and tick length to layout, use axis orienation methods, e.g., "axisTop" or "axisRight"
* d) Methods instantiate
*/
_xAxis = d3.axisTop(_x).tickSize(_tfc_layout.height()),
_yAxis = d3.axisRight(_y).ticks(0).tickSize(_tfc_layout.width());
/****
* f) Domain has Data Charateistics, EXAMPLES provided.
* e) Scaling Domain - overide d3 default domains on x and y axis
**/
var X_MinFromDateExample = new Date().setFullYear(2016, 01, 01), X_MaxToDateExample = Date.now();
var Y_MinFromValueExample = 0, Y_MaxToValueExample = 1000;
if (data == null) {
_x.domain([X_MinFromDateExample, X_MaxToDateExample]);
_y.domain([Y_MinFromValueExample, Y_MaxToValueExample]);
} else {
_x.domain(d3.extent(data, function (d) { return d[date_dynField]; }));
_y.domain([0, 100]);
// y.domain([0, d3.max(data, function (d) { return d.price; })]);
}
/****
* h) Append "g" x-axis, class, add xAxis' translate ticks to layout
* i) Append "g" y-axis, class, add yAxis'
*/
_timeFilterChart
.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + (_tfc_layout.height()) + ")")
.call(_xAxis);
_timeFilterChart
.append("g")
.attr("class", "axis axis--y")
.call(_yAxis);
/***
chart: _timeFilterChart,
x: _x,
y: _y,
xAxis: _xAxis,
yAxis: _yAxis,
settings: _tfc_layout
*/
//return TimeFilterChart;//_timeFilterChart;
}
TimeFilterChart.chart = function (value) { if (!arguments.length) { return TimeFilterChart; } _timeFilterChart = value; return TimeFilterChart; };
TimeFilterChart.settings = function (value) { if (!arguments.length) { return _tfc_layout; } _tfc_layout = value; return TimeFilterChart; };
TimeFilterChart.chartName = function (value) { if (!arguments.length) { return _name; } _name = value; return TimeFilterChart;};
TimeFilterChart.x = function (value) { if (!arguments.length) { return _x; } _x = value; return TimeFilterChart; };
TimeFilterChart.y = function (value) { if (!arguments.length) { return _y; } _y = value; return TimeFilterChart; };
TimeFilterChart.xAxis = function (value) { if (!arguments.length) { return _xAxis; } _xAxis = value; return TimeFilterChart; };
TimeFilterChart.yAxis = function (value) { if (!arguments.length) { return _yAxis; } _yAxis = value; return TimeFilterChart; };
TimeFilterChart.settings = function (value) { if (!arguments.length) { return _tfc_layout; } _tfc_layout = value; return TimeFilterChart; };
return TimeFilterChart;
},
tfc_data: function (d) {
opts.data = d;
api.tfc_setup(opts);
},
tfc_addEditIconBtn: function (opts) {
d3.selectAll('svg'+ ">*").remove();
var iconId = opts.timelineEditImgId, btnId = opts.timelineEditBtnId, url = opts.timelineEditSvgUrl;
$('#' + iconId).attr("src", url);
$("span.ui-loading").hide();
$('#' + btnId).on('click', function () {
$("span.ui-loading").show();
/*****
* <option value="internalSearch">REST API Search</option>
* <option value="earthquakes">GeoJson USGS Earthquakes</option>
**/
var DataChoice = $('#' +opts.tfc_sourceId).val();
switch (DataChoice) {
case "restApi":
//console.info("rest api");
tfc_dataRestApi(opts);
break;
case "csvFile":
tfc_dataCsvFie(opts);
break;
case "jsonUrl_earthquakes":
//console.info("case jsonUrl_earthquakes");
tfc_dataJsonUrl(opts);
break;
default:
tfc_dataRestApi(opts);
break;
}
function tfc_dataRestApi(opts) {
var search = api.tfc_data_SearchTelligentRestCall();
search(function (results) {
opts.data = results.SearchResults.map(function (d) {
return type(d, "Date", "Rating");
});
api.tfc_setup(opts );
$("span.ui-loading").hide();
});
}
function tfc_dataCsvFile(opts) { }
function tfc_dataJsonUrl(opts) {
var quakeRequest = api.tfc_data_UsgsEarthquake();
var startDateText= opts.tfc_fromDateId ? $('#' + opts.tfc_fromDateId).val() : "2014-01-01",
endDateText = opts.tfc_toDateId ? $('#' + opts.tfc_toDateId).val() : "2014-01-02";
quakeRequest(function (results, startDateTime, endDateTime ) {
opts.data = results.features.map(function (d) {
d.Date = new Date(d.properties.time);
d.price = d.properties.mag;
return d;
});
// console.info("quakeRequest");
// console.info(results);
opts.geoData = results;
api.tfc_setup(opts);
$("span.ui-loading").hide();
}, startDateText, endDateText);
}
});
},
tfc_setup: function (opts) {
var data = opts.data ? opts.data : null;
var svgMainHeight = 80;
d3.selectAll('svg' + ">*").remove();
d3.selectAll('#' + opts.globeViewerId + ">*").remove();
$.coria.globe.renderGlobeSvg(opts.globeViewerId);
// create path
var path = d3.geoPath()
.projection($.coria.globe.projection);
// Create the graticule lines and append them to the SVG container
//
//
var graticule = d3.geoGraticule();
// Add the graticule to the figure
$.coria.globe.svg.append('path').datum(graticule())
.attr('class', 'graticule')
.attr('d', path)
.style('fill','none')
.style('stroke','#aaa')
.style('stroke-width','1px')
.style('stroke-opacity','0.5')
.style('pointer-events','none');
// Magnitude extent of quakes
/****setup globe end**/
api.svgMain = d3.selectAll('#' + opts.tfcSvgId);
api.svgMain.attr("viewBox", "0 0 600 " + svgMainHeight);
//new layout and main time chart setup
var _tfc_layout_slave = new $.coria.timeFilterControl.tfc_layout()
.margin.top(10)
.margin.bottom(60)
.margin.left(30)
.margin.right(30);
_tfc_layout_slave.chartName("SlavedChart");
var _slaveChart = new $.coria.timeFilterControl.tfc_chart();
_slaveChart(_tfc_layout_slave, data);
var clipPath = api.tfc_clipPath();
var clipRect = clipPath(api.svgMain, _tfc_layout_slave.width(), _tfc_layout_slave.height());
api.clipRect = clipRect;
var line = d3.line()
.defined(function (d) { return d; })
.x(function (d) { return x(d[date_dynField]); })
//.y(y(100));
.y(function (d) { return y(d[y_dynField]); });
if (data != null) {
_slaveChart().chart.selectAll("circle")
.data(data).enter().append("circle")
.attr("clip-path", "url('#clip')")
.attr("d", line)
.attr("class", "dot")
.attr("r", 3.5)
.attr("opacity", 0.7)
.style("fill", "steelblue");
/* $.coria.globe.svg.selectAll("circle")
.data(data).enter().append("circle")
.attr("class", "quake")
.attr("r", 1.5)
.attr("opacity", 0.5)
.style("fill", "steelblue");
.insert("path")
.datum(topojson.feature(quake, quake.objects.land))
.attr("d", path);
*/
}
api.tfc_charts_array.push( _slaveChart );
var _dist_between_charts = _tfc_layout_slave.cntrl_height();
//new layout and master time chart setup
var _tfc_layout_master = new $.coria.timeFilterControl.tfc_layout()
.margin.top(35)
.margin.bottom(35)
.margin.left(30)
.margin.right(30);
_tfc_layout_master.chartName("MasteredChart");
api.tfc_layout_array.push(_tfc_layout_master);
var _masterChart = new $.coria.timeFilterControl.tfc_chart();
_masterChart(_tfc_layout_master,data);
api.tfc_charts_array.push( _masterChart );
var masterChart = _masterChart;
var slaveChart = _slaveChart;
/**
* 6) Brushes (master & slave) to interact between time filter charts
* a) Setup brush on X axis,
* b) extend of rendered brush
* c) event method on "brush" and "end"
*/
//Setup Brush for slave time filter
var brush_sensor_slave = d3.brushX()
.extent([[0, 0], [_tfc_layout_slave().width, _tfc_layout_slave().height]])
.on("brush end", slave_feedback);
//Append brush to slave chart
_slaveChart().chart
.append("g")
.attr("class", "brush brush-sensor brush-sensor-slave")
.call(brush_sensor_slave)
.call(brush_sensor_slave.move, [_tfc_layout_slave().width - Math.floor(_tfc_layout_slave().width / 2) - (_tfc_layout_slave().width / 5), _tfc_layout_slave().width - Math.floor(_tfc_layout_slave().width / 2) + (_tfc_layout_slave().width / 5)]);
/*
*[width - Math.floor(width / 2) - (width / 5), width - Math.floor(width / 2) + (width / 5)]
* Sets up a zoom servo as an adjustment surface for changing Gear(master/slave) Ratio
* uses a lazy setting, "Infinity" which assumes a level of precision in our data that is not realistic.
* realistic would calculate data resolution, e.g. date/time may only go to seconds, days, weeks, etc
* Spatial, temporal, or aspatial data resolutions need to be reported back to user in a meaningful anology
*/
var zoom_ratio = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [_tfc_layout_slave().width, _tfc_layout_slave().height]])
.extent([[0, 0], [_tfc_layout_slave().width, _tfc_layout_slave().height]])
.on("zoom", slave_feedback);
//append zoom servo
_slaveChart().chart
.append("rect")
.attr("class", "zoom servo ratio-adjustment-surface")
.attr("width", _tfc_layout_slave().width)
.attr("height", _tfc_layout_slave().height)
.attr("transform", "translate(" + 0 + "," + Math.floor(_tfc_layout_slave().margin.top / 2) + ")")
.call(zoom_ratio);
if(opts.geoData != null && opts.geoData.features != null )
{
var magExtent = d3.extent(opts.geoData.features, function(d) {
return d.properties.mag;
});
var rScale = d3.scaleLinear()
.domain(magExtent)
.range([d3.max(magExtent), d3.min(magExtent)]);
path.pointRadius(function(d) {
return d.properties ? rScale(d.properties.mag) : 1;
});
var s = [_tfc_layout_slave().width - Math.floor(_tfc_layout_slave().width / 2) - (_tfc_layout_slave().width / 5), _tfc_layout_slave().width - Math.floor(_tfc_layout_slave().width / 2) + (_tfc_layout_slave().width / 5)];
var slaveFeedbackRange = s.map(_slaveChart().x.invert, _slaveChart().x);
var filterData = opts.geoData.features.filter(function(d){ return d.Date > slaveFeedbackRange[0] && d.Date < slaveFeedbackRange[1]; });
$.coria.globe.svg.selectAll('path.quake-black').data(filterData)
.enter().append('path')
.attr('class', 'quake-black')
.attr('d', path);
}
//method for brushing event
function slave_feedback() {
if (d3.event.sourceEvent && (d3.event.sourceEvent.type === "wheel" || d3.event.sourceEvent.type === "zoom")) {
//change resolution of axis and data on slave chart, slave chart brush, and master chart brush
//console.info("zoom");
var transform = d3.event.transform;
_slaveChart().x.domain(transform.rescaleX(_masterChart().x).domain());
_slaveChart().chart.select(".axis--x").call(_slaveChart().xAxis);
_masterChart().chart.select(".brush").call(brush_sensor_master.move, _slaveChart().x.range().map(transform.invertX, transform));
/**/
}
if (d3.event.sourceEvent && (d3.event.sourceEvent.type === "wheel" || d3.event.sourceEvent.type === "zoom" || d3.event.sourceEvent.type === "mousemove" || d3.event.sourceEvent.type === "touchmove")) {
_slaveChart().chart.selectAll(".dot")
.attr('cx', function (d) { return _slaveChart().x(d[date_dynField]); })
.attr('cy', _tfc_layout_slave.height() * 0.5);
var s = d3.event.selection || _slaveChart().x.range();
var slaveFeedbackRange = s.map(_slaveChart().x.invert, _slaveChart().x);
// Draw the quakes on the map if data is not null
var filterData = opts.geoData.features.filter(function(d){
return d.Date > slaveFeedbackRange[0] && d.Date < slaveFeedbackRange[1];
});
$.coria.globe.svg.selectAll('path.quake-black')
.remove().exit();
$.coria.globe.svg.selectAll('path.quake-black')
.data(filterData)
.enter().append('path')
.attr('class', 'quake-black')
.attr('d', path);
}
}
//Setup Brush sensor for master chart's time filter
var brush_sensor_master = d3.brushX()
.extent([[0, 0], [_tfc_layout_master.width(), _tfc_layout_master.height()]])
.on("brush end", master_feedback);
// Append brush to master chart
_masterChart().chart
.append("g")
.attr("class", "brush brush-sensor brush-sensor-master")
.call(brush_sensor_master)
.call(brush_sensor_master.move, _masterChart().x.range());
//method for brushing event
function master_feedback() {
if (d3.event.sourceEvent && (d3.event.sourceEvent.type === "mousemove" || d3.event.sourceEvent.type === "touchmove")) {
//array from brush sensor or use default x-axis range
var sensor = d3.event.selection || _masterChart().x.range();
//provide feedback from master to slave
//drive domain mapping sensor output over master x-min and max values
_slaveChart().x.domain(sensor.map(_masterChart().x.invert, _masterChart().x));
//rescale the x axis after setting the domain.
_slaveChart().chart.select(".axis--x").call(_slaveChart().xAxis);
_slaveChart().chart.select(".zoom").call(zoom_ratio.transform, d3.zoomIdentity
.scale(_tfc_layout_slave().width / (sensor[1] - sensor[0]))
.translate(-sensor[0], 0));
}
_slaveChart().chart.selectAll(".dot")
.attr('cx', function (d) { return _slaveChart().x(d[date_dynField]); })
.attr('cy', _tfc_layout_slave.height() * 0.5);
}
},/****tfc_setup end**/
tfc_data_UsgsEarthquake: function () {
//https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2014-01-01&endtime=2014-01-02&callback=test
//https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&starttime=2014-01-01&endtime=2014-01-02&callback=quake558755&_=1481418159231
var _baseUrl = "https://earthquake.usgs.gov/fdsnws/event/1/query",
x3rand = Math.floor(Math.random() * 1000 + 0),
y3rand = Math.floor(Math.random() * 1000 + 0),
callbackname = "quake" + x3rand + y3rand,
startDateTime = "2014-01-01",
endDateTime = "2014-01-02";
function quakeResult(callback, startDate, endDate) {
//console.info("ajax");
$.ajax({
url: _baseUrl,
dataType: "jsonp",
jsonpCallback: callbackname,
data: {
format: "geojson",
starttime: startDate ? startDate : startDateTime,
endtime: endDate ? endDate : endDateTime
},
dataType: 'jsonp',
cache: true,
success: function (response) {
if (typeof callback !== 'undefined' && typeof callback === 'function') {
callback(response);
}
},
error: function (state, status, message) {
console.error("fail: ");
console.error(state);
console.error(status);
console.error(message);
}
});
};
return quakeResult;
},
tfc_data_SearchTelligentRestCall: function () {
var _baseUrl = $.telligent.evolution.site.getBaseUrl(true),
_searchRestApi = "api.ashx/v2/search.json",
x3rand = Math.floor(Math.random() * 1000 + 0),
y3rand = Math.floor(Math.random() * 1000 + 0),
callbackname = "search" + x3rand + y3rand;
//var loading = $.telligent.evolution.ui.components.loading = {
// setup: function () {
// // setup is called once per page if at least one element matches this component
// }, add: function (elm, options) {
// // add is called for each unique instance of an element matching the component
// // elm is the matching element
// // options is an object containing all data attributes defined on the element
// //$(elm).html('loading: ' + options.make + ' ' + options.model);
// }
//};
// Query: "{!geofilt pt=21.5,-158 sfield=GeoTagGeoHash d=10}"
var searchResult = function (callback) {
$.telligent.evolution.get({
url: _baseUrl + _searchRestApi,
callback: callbackname,
data: {
Query: "*:*"
},
cache: false
}).done(function (r) {
if (typeof callback !== 'undefined' && typeof callback === 'function') {
callback(r);
}
});
};
return searchResult;
},
getLayouts: function () { return api.tfc_layout_array; } ,
register: function (opts) {
if (typeof d3 === 'undefined') return;
opts.toDate = new Date(Date.now());
opts.fromDate = new Date(Date.now() - 1*24*60*60*1000);
var fromDate = TheDate();
fromDate(opts.fromDate);
var toDate = TheDate();
toDate(opts.toDate);
$('#' + opts.tfc_fromDateId).val(toDate.is());
$('#' + opts.tfc_toDateId).val(toDate.is());
$('#' + opts.tfc_fromDateId).val(fromDate.is());
api.tfc_addEditIconBtn(opts);
api.tfc_setup(opts);
},
TheDate: TheDate
};
$.coria = $.coria ? $.coria : {};
$.coria.timeFilterControl = api;
function checkMargins(margin) {
if (checkNum(margin.top) && checkNum(margin.bottom) && checkNum(margin.right) && checkNum(margin.left))
return true;
return false;
}
function checkNum(value) {
if (isNaN(value)) {
throw new Error("value must be a number not: " + value);
}
return true;
}
/**
*type: convert date
*/
function type(d, x_dynField, y_dynField) {
var parseDate = d3.utcParse("%Y-%m-%dT%H:%M:%S%Z");
var value_dynField = y_dynField ? y_dynField : "price";
var date_dynField = x_dynField ? x_dynField : "date";
d[date_dynField] = parseDate(d[date_dynField]);
//hard coded y value...
var num = isNaN(d[y_dynField]) ? Math.floor(Math.random() * 1000) : d[y_dynField] * 100;
d[y_dynField] = num <1000 ? num : 1000 ;//d.price;
return d;
}
function TheDate() {
var _now, _day, _month, _year, _theDate;
function TheDate(date) {
if (!arguments.length) {
return {
dd_text: _day,
mm_text: _month,
yyyy_text: _year,
is: _theDate
};
}
_now = new Date(date);
_day = ("0" + _now.getDate()).slice(-2);
_month = ("0" + (_now.getMonth() + 1)).slice(-2);
_year = _now.getFullYear() + "";
_theDate = _year + "-" + (_month) + "-" + (_day);
return TheDate;
}
TheDate.dd_text = function (value) { if (!arguments.length) { return _day; } _day = value; return TheDate; };
TheDate.mm_text = function (value) { if (!arguments.length) { return _month; } _month = value; return TheDate; };
TheDate.yyyy_text = function (value) { if (!arguments.length) { return _year; } _year = value; return TheDate; };
TheDate.is = function (value) { if (!arguments.length) { return _theDate; } _theDate = value; return TheDate; };
return TheDate;
}
})(jQuery);
.timeline-div svg{
/* these are settings important for mapping svgs
position: absolute;
-webkit-box-sizing: unset ;
-moz-box-sizing: unset;
box-sizing: unset ;
shape-rendering: crispEdges
*/
}
.axis--x .domain, .axis--grid .tick line {
stroke: #000;
}
.axis--x, .axis--y, .tick, .domain, .axis--grid .tick {
shape-rendering: crispEdges;
border: thin;
border-color:black;
}
.brush .brush-sensor {
shape-rendering: crispEdges;
border: thin;
border-color:black;
}
.brush .handle{
shape-rendering: crispEdges;
fill: steelblue;
}
.timeline-container{ margin: 10px;}
.timeline-container-toolbar {
/*border: 2px dashed #444;*/
height: 40px;
text-align: justify;
-ms-text-justify: distribute-all-lines;
text-justify: distribute-all-lines;
/* just for demo */
min-width: 300px;
}
.timeline-container-toolbar:after {
content: '';
width: 100%;
display: inline-block;
font-size: 0;
line-height: 0
}
.timeline-container-toolbar2 {
position:relative;
top:8px;
/*width:100%;*/
min-width: 300px;
height:40px;
padding:2px;
/***align example: //stackoverflow.com/questions/6865194/fluid-width-with-equally-spaced-divs/6880421#6880421*/
border: 2px dashed #444;
text-align: justify;
-ms-text-justify: distribute-all-lines;
text-justify: distribute-all-lines;
}
/***align example: //stackoverflow.com/questions/6865194/fluid-width-with-equally-spaced-divs/6880421#6880421*/
.timeline-container-toolbar > div {
/*width: 30px;*/
height: 40px;
vertical-align: top;
display: inline-block;
*display: inline;
zoom: 1 ;
padding:5px;
}
.graticule {
fill: none;
stroke: #aaa;
stroke-width: 1px;
stroke-opacity: 0.5;
pointer-events: none;
}
.foreground {
fill: #d8ffff;
stroke: #333;
stroke-width: 1.5px;
}
.land {
fill: #d7c7ad;
stroke: #766951;
}
/*#stretch {
width: 100%;
display: inline-block;
font-size: 0;
line-height: 0
}
#box1, #box3 {
background: #ccc
}
#box2, #box4 {
background: #0ff
}*/
.ui-loading{
/**float:right;*/
}
.timeline-edit {
width:20px;
/*float: right;*/
}
input.timeline-search {
border-radius:6px;
width:auto;
padding: 0 0 0 30px;
border:thin;
background-color:rgba(255, 255, 255, 0.3);
margin-left:4px;
}
input.timeline-search:hover{
background-color:rgba(255, 255, 255, 0.5);
transition: all 300ms;
}
input.timeline-search:focus{
background-color:rgba(255, 255, 255, 0.7);
transition: all 300ms;
}
.field-item-input.timeline-search::after {
font-size: 15px;
height: 15px;
width: 15px;
display:block;
font-family: Entypo;
content: "\e803";
position: absolute;
color: #bdc3c7;
top: .1em;
left: 8px;
}
.timeline-div{
background-color:rgba(130, 130, 130, 0.3);
border-radius: 12px;
border:none;
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3);
margin:3px;
/*
font-size: 50px;
text-align: center;
line-height: 100px;*/
/* height:100px;
width: 820px;
min-height:20px;
min-width:400px;
*/
}
.line{
border: solid 1px steelblue;
margin: 4px;
padding: 4px;
background-color: #eeeeec;
fill: none;
/* clip-path: url("/~powersparks/bz.html#clip");
*/
}
/**
g .brush > .overlay{
stroke: #000 !important;
border: solid 1px #000;
}
***/
/**
.brush .overlay{
border: solid 1px steelblue;
fill:rgba(70,130,180,0.5);
}
*/
.area {
fill: steelblue;
/* clip-path: url("/~powersparks/bz.html#clip");*/
}
rect.zoom{
cursor:ns-resize;
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
}
.context {
}
.axis--grid .domain {
fill: #ddd;
stroke: none;
}
.axis--x .domain,
.axis--grid .tick line {
stroke: #fff;
}
.axis--grid .tick--minor line {
stroke-opacity: .5;
}
.quake-black{
stroke:red;
fill:red;
opacity: .3;
}
/*
<div id="container-glass-id">
<img id="img-glass-id" src="http://lorempixel.com/450/300/sports" />
<div id="overlay-glass-id">chipChocolate.py</div>
<svg id="svg-glass-id" width="450" height="100" viewBox="0 0 450 100" style="position: absolute; left:0;top: 0;">
<defs>
<filter id="blur-glass-id">
<feGaussianBlur in="SourceGraphic" stdDeviation="3" />
</filter>
</defs>
<image id="image-glass-id" filter="url(#blur)" xlink:href="http://lorempixel.com/450/300/sports" x="0" y="0" height="300px" width="450px" />
</svg>
</div>
*/
/*
#svg-glass-id{}
#blur-glass-id{}
#container-glass-id {
position: relative;
width: 450px;
margin: 0 auto;
}
#img-glass-id {
height: 300px;
}
#overlay-glass-id {
position: absolute;
left: 0;
top: 0;
width: 100%;
z-index: 1;
color: rgba(188, 143, 143, 0.2);
font-size: 50px;
text-align: center;
line-height: 100px;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.3);
}
.container{
width:auto;;
height:auto;
background-color: papayawhip;
box-sizing: border-box;
}
svg .responsive-graph
{
width:960px;
height:500px;
}
.axis--grid .domain {
fill: #ddd;
stroke: none;
}
.axis--x .domain,
.axis--grid .tick line {
stroke: #fff;
}
.axis--grid .tick--minor line {
stroke-opacity: .5;
}
*/
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Coria Timeline - Time Filter</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js" ></script>
<script type="text/javascript" src='https://d3js.org/d3.v4.js' charset="utf-8"></script>
<script type="text/javascript" src="https://d3js.org/topojson.v1.min.js" ></script>
</head>
<body>
<link href='CoriaTimeline.css' rel='stylesheet' type='text/css'>
<div id="timelineContainerDivId" class="timeline-container">
<div id="timelineId" class="timeline-div" >
<div id="timelineContainerToolBar" style="{display:none;}" class="timeline-container-toolbar">
<div>
<input id="timelineSearch" style="{display:none;}" class="ui-tourtip timeline-search " autocomplete="off" placeholder="Search" value="" data-tourtipkey="1234" data-tourtipmessage="Add text to filter timeline posts" type="search">
</div>
<div>
<select id="sourceId">
<option value="jsonUrl_earthquakes">GeoJson USGS Earthquakes</option>
<option value="restApi">custom REST API Search</option>
</select>
</div>
<div>
<span class="ui-loading" style="{display:none; }" data-width="30" data-height="30"></span>
</div>
<div >
<span style="{ white-space:nowrap}"> <label for="fromDateId">From:</label>
<input id="fromDateId" type="date" /> </span>
</div>
<div>
<span style="{ white-space:nowrap}"><label for="toDateId">To:</label>
<input id="toDateId" type="date" /> </span>
</div>
<div>
<a href="#" id="timelineEditBtnId" style="{display:none;}" class="timeline-edit-btn">
<img id="timelineEditImgId" src="" style="{display:none;}" class="timeline-edit" alt="timeline edit tool"/>
</a>
</div>
</div>
<div>
<svg id="tfcSvgId" class="timeline-svg-filter2" viewBox="0 0 600 80" preserveAspectRatio="xMidYMid"></svg>
</div>
</div>
</div>
<div id="globeViewerId" height="300" width="600"></div>
<script type="text/javascript" src="CoriaTimeFilter.js"></script>
<script type="text/javascript" src="CoriaGlobe.js"></script>
<script type="text/javascript">
jQuery(function (j){
j.coria.timeFilterControl.register({
tfc_toDateId: "toDateId",
tfc_fromDateId: "fromDateId" ,
tfc_sourceId: "sourceId",
tfc_clipPathId: "clip",
tfcSvgId: "tfcSvgId",
timelineEditBtnId:"timelineEditBtnId",
timelineEditSvgUrl: "edit.svg",
timelineEditImgId:"timelineEditImgId",
globeViewerId:"globeViewerId"
});
});
jQuery(function (j){
j.coria.globe.register({
globeViewerId:"globeViewerId"
});
});
</script>
</body>
</html>
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment