Skip to content

Instantly share code, notes, and snippets.

@powersparks
Last active April 6, 2017 00:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save powersparks/baa3446d737713ce25b938b3fcddced0 to your computer and use it in GitHub Desktop.
Save powersparks/baa3446d737713ce25b938b3fcddced0 to your computer and use it in GitHub Desktop.
The brush is over the data area, instead of the labels, while zoom and pan are over the labels, and over zoom bar area too.
/// <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';
var _tickSizeInner = 10 , _tickSizeOuter = 10, _tickPadding = 3;
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,
tickSizeInner: _tickSizeInner,
tickSizeOuter: _tickSizeOuter,
tickPadding: _tickPadding
};
}
_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 ? opts.margin.left : _margin.left : _margin.left;
_tickSizeInner = opts.tickSizeInner ? opts.tickSizeInner : _tickSizeInner;
_tickSizeOuter = opts.tickSizeOuter ? opts.tickSizeOuter : _tickSizeOuter;
_tickPadding = opts.tickPadding ? opts.tickPadding : _tickPadding;
}
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.tickSizeInner = function (value) { if (!arguments.length) { return _tickSizeInner; } _tickSizeInner = value; return tfc_layout; };
tfc_layout.tickSizeOuter = function (value) { if (!arguments.length) { return _tickSizeOuter; } _tickSizeOuter = value; return tfc_layout; };
tfc_layout.tickPadding = function (value) { if (!arguments.length) { return _tickPadding; } _tickPadding = value; return tfc_layout; };
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 " + _name)
.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
* var xAxis = d3.axisTop(x).tickSizeInner(height-5).tickSizeOuter( height).tickPadding(-height *0.2),
* _xAxis = d3.axisTop(_x).tickSizeInner(_tfc_layout.height() -5).tickSizeOuter(_tfc_layout.height() -5).tickPadding(- _tfc_layout.height() * 0.2),
* */
_xAxis = d3.axisTop(_x).tickSizeInner(_tfc_layout.tickSizeInner()).tickSizeOuter(_tfc_layout.tickSizeOuter()).tickPadding(_tfc_layout.tickPadding()),
_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 _svgMainWidth = document.getElementById(opts.svgTimelineContainerId).clientWidth;
var data = opts.data ? opts.data : null;
var _svgMainHeight = 80;
d3.selectAll('svg' + ">*").remove();
d3.selectAll('#' + opts.globeViewerId + ">*").remove();
api.svgMain = d3.selectAll('#' + opts.tfcSvgId);
api.svgMain.attr("viewBox", "0 0 " + _svgMainWidth + " " + _svgMainHeight);
var tickSize = 25;
//new layout and main time chart setup
var _tfc_layout_slave = new $.coria.timeFilterControl.tfc_layout()
.cntrl_width(_svgMainWidth)
.margin.top(10)
.margin.bottom(40)
.margin.left(30)
.margin.right(30)
.tickSizeInner( tickSize )
.tickSizeOuter( 30 )
.tickPadding(- 10);
_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(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");
}
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()
.cntrl_width(_svgMainWidth)
.margin.top(55)
.margin.bottom(15)
.margin.left(30)
.margin.right(30)
.tickSizeInner( 0 )
.tickSizeOuter( 10 )
.tickPadding(0);
//master chart, use css to modify the lables
//
_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"
*/
/*
*[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, 50])
.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 zoom-pan-slave")
.attr("width", _tfc_layout_slave().width)
.attr("height", _tfc_layout_slave().height * 2)
.attr("transform", "translate(" + 0 + "," + Math.floor(_tfc_layout_slave().margin.top - 10) + ")")
.call(zoom_ratio)
.on("wheel",function() { d3.event.preventDefault(); });
//Setup Brush for slave time filter
var brush_sensor_slave = d3.brushX()
.extent([[0, 0], [_tfc_layout_slave().width, _tfc_layout_slave().height/2]])
.on("brush end", slave_feedback);
//Append brush to slave chart
_slaveChart().chart
.append("g")
.attr("class", "brush brush-sensor brush-sensor-slave")
.attr("transform", "translate(" + 0 + "," + Math.floor(_tfc_layout_slave().margin.top + 5) + ")")
// .attr("cursor", "default !important")
.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)])
.on("wheel",function() { d3.event.preventDefault(); })
.selectAll('.overlay')
.attr('pointer-events','none');
_slaveChart().chart.selectAll('.tick line')
.attr("y1", function(d){
return - _slaveChart().settings().height;
});
if(opts.geoData != null && typeof opts.geoData.features !== 'undefined' && 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" || d3.event.sourceEvent.type === 'mousemove' || d3.event.sourceEvent.type === 'mousedown' )) {
//change resolution of axis and data on slave chart, slave chart brush, and master chart brush
//console.info("zoom");
var transform = d3.event.transform;
if(typeof transform !== 'undefined'){
_slaveChart().x.domain(transform.rescaleX(_masterChart().x).domain());
_masterChart().chart.select(".brush").call(brush_sensor_master.move, _slaveChart().x.range().map(transform.invertX, transform));
/**/
}
_slaveChart().chart.select(".axis--x").call(_slaveChart().xAxis);
_slaveChart().chart.selectAll('.tick line')
.attr("y1", function(d){
return - _slaveChart().settings().height;
});
}
if (d3.event.sourceEvent && (d3.event.sourceEvent.type === "wheel" || d3.event.sourceEvent.type === "zoom" || d3.event.sourceEvent.type === "mousedown" || 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.7);
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
if(typeof opts.geoData !== 'undefined' && typeof opts.geoData.features !== 'undefined' )
{
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")
// .attr("rx": "20")
//.attr("ry": "20")
.call(brush_sensor_master)
.call(brush_sensor_master.move, _masterChart().x.range());
var handles_chart = _masterChart().chart.selectAll(".handle");
handles_chart
.attr("width",20)
.attr("height",20)
.attr("y",-4)
.attr("rx", 20)
.attr("ry", 20);
//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.7);
_slaveChart().chart.selectAll('.tick line')
.attr("y1", function(d){
return - _slaveChart().settings().height;
});
_masterChart().chart.selectAll(".handle")
.attr("width",20)
.attr("height",20)
.attr("y",-4)
.attr("rx", 20)
.attr("ry", 20);
}
},/****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);
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>
<style>
.MasteredChart .axis--x .tick text {opacity:0;}
.MateredChart > rect.handle {border-radius: 10;}
.MasteredChart .selection {stroke: rgba(0,0,0,0);}
.SlavedChart .selection {stroke: rgba(0,0,0,0);}
.SlavedChart { }
.area { fill: steelblue; /* clip-path: url("/~powersparks/bz.html#clip");*/ }
.axis--grid .domain { fill: #ddd; stroke: none;}
.axis--grid .tick--minor line { stroke-opacity: .5;}
.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; }
rect .MasteredChart .brush .brush-sensor {stroke: #000; shape-rendering: crispEdges; border: thin; border-color:black; }
.MasteredChart .brush .handle{ cursor:col-reszie; shape-rendering: crispEdges; fill: steelblue; }
.SlavedChart .brush .brush-sensor { stroke: #000; shape-rendering: crispEdges; border: thin; border-color:black; }
.SlavedChart .selection {cursor: ew-resize; }
.SlavedChart .handle{cursor: col-resize; }
/* use only to see the zoom area // .SlavedChart .zoom { border: thin; stroke: #000; border-top-color: black}*/
.context { }
.coria-div-table{ float:right;width:300px;max-width:400px;border-color:red;border:2px;}
.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;}
.foreground { fill: #d8ffff; stroke: #333; stroke-width: 1.5px;}
.graticule { fill: none; stroke: #aaa; stroke-width: 1px; stroke-opacity: 0.5; pointer-events: none;}
.land { fill: #d7c7ad; stroke: #766951; opacity: .5;}
.line{ border: solid 1px steelblue; margin: 4px; padding: 4px; background-color: #eeeeec; fill: none; /* clip-path: url("/~powersparks/bz.html#clip");*/ }
.quake-black{ stroke:red;fill:red;opacity: .3;}
.svg-timeline-container{ width:100%; height: 80px; margin: 0px;}
.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 > div { /*width: 30px;*/ height: 40px; vertical-align: top; display: inline-block; *display: inline; zoom: 1 ; padding:5px;}
.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;}
.timeline-container{ margin: 10px;}
.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; */ }
.timeline-edit { width:20px;/*float: right;*/ }
.ui-loading { /**float:right;*/ }
.zoom { cursor: move !important; fill: none; pointer-events: all;}
/*.zoom { cursor: move; fill: none; pointer-events: all;}*/
/** .brush .overlay{ border: solid 1px steelblue; fill:rgba(70,130,180,0.5);} */
/** g .brush > .overlay{ stroke: #000 !important; border: solid 1px #000;} ***/
/***align example: //stackoverflow.com/questions/6865194/fluid-width-with-equally-spaced-divs/6880421#6880421*/
/*#stretch { width: 100%; display: inline-block; font-size: 0; line-height: 0 } #box1, #box3 { background: #ccc } #box2, #box4 { background: #0ff }*/
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:focus{ background-color:rgba(255, 255, 255, 0.7); transition: all 300ms;}
input.timeline-search:hover{ background-color:rgba(255, 255, 255, 0.5); transition: all 300ms;}
/*rect.zoom{ cursor:ns-resize;}*/
</style>
</head>
<body>
<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 id="svg_timeline_container_id" class="svg-timeline-container">
<svg id="tfcSvgId" class="timeline-svg-filter2" viewBox="0 0 600 80" preserveAspectRatio="xMinYMin"></svg>
</div>
</div>
</div>
<!--div id="globeViewerId" height="300" width="600"></div-->
<script type="text/javascript" src="CoriaTimeFilter4.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",
svgTimelineContainerId: "svg_timeline_container_id"
});
});
/*
jQuery(function (j){
j.coria.globe.register({
globeViewerId:"globeViewerId"
});
});
*/
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment