简体   繁体   中英

Zooming and Brushing issues on D3 chart

I'm using d3.area() instead of d3.line() in below code. There are 2 groups "focus" and "context" . focus is the main chart while context is for selecting range by using brushed() and zoomed() .

Problem is circles of focus group are moving properly according to the selected range in context group while area is getting disappear.

I'm assuming area() is not returning proper values. JSFiddle

  var data = [ {xLabel: "02:01:00", LastMonday: 200, Today: 500}, {xLabel: "03:02:00", LastMonday: 620, Today: 600}, {xLabel: "10:03:20", LastMonday: 300, Today: 800}, {xLabel: "10:04:00", LastMonday: 440, Today: 700}, {xLabel: "10:05:00", LastMonday: 900, Today: 900}, {xLabel: "10:06:30", LastMonday: 300, Today: 500}, {xLabel: "10:07:00", LastMonday: 50, Today: 300}, {xLabel: "11:08:00", LastMonday: 350, Today: 70}, {xLabel: "12:09:50", LastMonday: 750, Today: 200} ]; var textRotation = true; var righttoleft = false; var category = ['LastMonday', 'Today']; var drawLine = ['Today'], drawArea = ['LastMonday']; function initLineChart(data, id) { var mainwidth = $(id).innerWidth(), mainheight = $(id).innerHeight(); function getPercent(actualval, perval) { return Math.round((actualval / 100) * perval); } var margin = { top: getPercent(mainheight,4), bottom: getPercent(mainheight,45), }, margin2 = { top: getPercent(mainheight,76), bottom: getPercent(mainheight,16), }; if(righttoleft) { margin.left = getPercent(mainwidth,4); margin.right = getPercent(mainwidth,8); margin2.left = getPercent(mainwidth,4); margin2.right = getPercent(mainwidth,8); }else { margin.left = getPercent(mainwidth,8); margin.right = getPercent(mainwidth,4); margin2.left = getPercent(mainwidth,8); margin2.right = getPercent(mainwidth,4); } var width = $(id).innerWidth() - margin.left - margin.right, height = $(id).innerHeight() - margin.bottom, height2 = $(id).innerHeight() - margin2.top - margin2.bottom ; var parseDate = d3.timeParse("%H:%M:%S"); var legendSize = 10, legendColor = {'LastMonday': 'rgba(255, 160, 233, 0.6)', 'Today': 'rgba(0, 160, 233, 0.2)'}; var x = d3.scaleTime().range([0, width]), x2 = d3.scaleTime().range([0, width]), y = d3.scaleLinear().range([height, 0]), y2 = d3.scaleLinear().range([height2, 0]); var xAxis = d3.axisBottom(x).tickFormat(d3.timeFormat("%H:%M:%S")) .tickPadding([6]).tickSize(-height), xAxis2 = d3.axisBottom(x2).tickFormat(d3.timeFormat("%H:%M:%S")), yAxis; if(righttoleft){ yAxis = d3.axisRight(y).ticks(10).tickSize(-width); }else { yAxis = d3.axisLeft(y).ticks(10).tickSize(-width); } var brush = d3.brushX() .extent([[0, 0], [width, height2]]) .on("brush end", brushed); var zoom = d3.zoom() .scaleExtent([1, Infinity]) .translateExtent([[0, 0], [width, height]]) .extent([[0, 0], [width, height]]) .on("zoom", zoomed); var ddata = (function() { var temp = {}, seriesArr = []; category.forEach(function (name) { temp[name] = {category: name, values:[]}; seriesArr.push(temp[name]); }); data.forEach(function (d) { category.map(function (name) { temp[name].values.push({'category': name, 'xLabel': parseDate(d.xLabel), 'num': d[name]}); }); }); return seriesArr; })(); var ldata = (function() { var temp = {}, seriesArr = []; temp[drawLine[0]] = {category: drawLine[0], values:[]}; seriesArr.push(temp[drawLine]); data.forEach(function (d) { drawLine.map(function (name) { temp[name].values.push({'category': name, 'xLabel': parseDate(d.xLabel), 'num': d[name]}); }); }); return seriesArr; })(); var adata = (function() { var temp = {}, seriesArr = []; temp[drawArea[0]] = {category: drawArea[0], values:[]}; seriesArr.push(temp[drawArea]); data.forEach(function (d) { drawArea.map(function (name) { temp[name].values.push({'category': name, 'xLabel': parseDate(d.xLabel), 'num': d[name]}); }); }); return seriesArr; })(); x.domain( d3.extent(data, function(d) { return parseDate(d.xLabel); }) ); y.domain([ 0, d3.max(ddata, function(c) { return d3.max(c.values, function(v) { return v['num']; }); })+100 ]); x2.domain(x.domain()); y2.domain(y.domain()); var area = d3.area().curve(d3.curveLinear) .x(function(d) { return x(d.xLabel); }) .y0(height) .y1(function(d) { return y(d['num']); }); var area2 = d3.area().curve(d3.curveLinear) .x(function(d) { return x2(d.xLabel); }) .y0(height2) .y1(function(d) { return y2(d['num']); }); d3.select('#svg-disk').remove(); var svg = d3.select(id).append("svg") .attr("id", "svg-disk") .attr("viewBox", "0 1 " + mainwidth + " " + mainheight) .attr("preserveAspectRatio", "xMinYMin"); svg.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); svg.append("rect") .attr("class", "zoom") .attr("width", width) .attr("height", height) .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(zoom); var focus = svg.append("g") .attr("class", "focus") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var context = svg.append("g") .attr("class", "context") .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); focus.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); context.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height2 + ")") .call(xAxis2); context.append("g") .attr("class", "brush") .call(brush) .call(brush.move, x.range()); focus.selectAll('.x .tick text').each(function(){ var dd = d3.select(this); if(textRotation) { dd.attr("dx", "-1em") .style("text-anchor", "end") .attr("transform", "rotate(-65)") .attr("dy", "1em"); }else { dd.attr("dx", "0em") .style("text-anchor", "middle"); } }); focus.append("g") .attr("class", "y axis") .call(yAxis); var path = focus.selectAll(".gPath") .data(adata) .enter().append("g") .attr("class", "gPath"); var path2 = context.selectAll(".gPath") .data(adata) .enter().append("g") .attr("class", "gPath"); path.append("path") .attr("d", function(d) { return area(d['values']); }) .attr("class", 'areaR'); path2.append("path") .attr("d", function(d) { return area2(d['values']); }) .attr("class", 'areaR'); var lpath = focus.selectAll(".lpath") .data(ldata) .enter().append("g") .attr("class", "lpath"); var lpath2 = context.selectAll(".lpath") .data(ldata) .enter().append("g") .attr("class", "lpath"); lpath.append("path") .attr("d", function(d) { return area(d['values']); }) .attr("class", "areaW"); lpath2.append("path") .attr("d", function(d) { return area2(d['values']); }) .attr("class", "areaW"); var points = focus.selectAll(".seriesPoints") .data(ddata) .enter().append("g") .attr("class", "seriesPoints"); points.selectAll(".tipPoints") .data(function (d) { return d['values']; }) .enter().append("circle") .attr("class", "tipPoints") .attr("cx", function (d) { return x(d.xLabel); }) .attr("cy", function (d) { return y(d['num']); }) .text(function (d) { return d['num']; }) .attr("r", "6px") .style("fill",function (d) { return legendColor[d['category']]; }) .style("stroke", "green") .on("mouseover", function (d) { var currentX = $(this)[0]['cx']['animVal']['value'], currentY = $(this)[0]['cy']['animVal']['value']; d3.select(this).transition().duration(100).style("opacity", 1); var ret = $('circle').filter(function(index) { return ($(this)[0]['cx']['animVal']['value'] === currentX && $(this)[0]['cy']['animVal']['value'] !== currentY); }); var jud = ret.length; var mainCate = (function() { if (jud === 0) return 'LastMonday/Today'; else return d['category']; })(); var viceCate = (function() { if (category[0] === d['category']) return category[1]; else return category[0]; })(); $.each(ret, function(index, val) { $(val).animate({ opacity: "1" }, 100); $(val).tooltip({ 'container': 'body', 'placement': 'left', 'title': viceCate + ' | ' + $(this)[0]['textContent'], 'trigger': 'hover' }).tooltip('show'); }); focus.append("g") .attr("class", "tipDot") .append("line") .attr("class", "tipDot") .transition() .duration(50) .attr("x1", x(d.xLabel)) .attr("x2", x(d.xLabel)) .attr("y2", height); focus.append("polyline") .attr("class", "tipDot") .style("fill", "black") .attr("points", (x(d.xLabel)-3.5)+","+(0-2.5)+","+x(d.xLabel)+","+(0+6)+","+(x(d.xLabel)+3.5)+","+(0-2.5)); focus.append("polyline") .attr("class", "tipDot") .style("fill", "black") .attr("points", (x(d.xLabel)-3.5)+","+(y(0)+2.5)+","+x(d.xLabel)+","+(y(0)-6)+","+(x(d.xLabel)+3.5)+","+(y(0)+2.5)); try{ $(this).tooltip({ 'container': 'body', 'placement': 'left', 'title': mainCate + ' | ' + d['num'], 'trigger': 'hover' }).tooltip('show'); }catch(e){} }) .on("mouseout", function (d) { var currentX = $(this)[0]['cx']['animVal']['value']; d3.select(this).transition().duration(100).style("opacity", 0); var ret = $('circle').filter(function(index) { return ($(this)[0]['cx']['animVal']['value'] === currentX); }); $.each(ret, function(index, val) { $(val).animate({ opacity: "0" }, 100); try{ $(val).tooltip('destroy'); }catch(e){} }); d3.selectAll('.tipDot').transition().duration(100).remove(); try{ $(this).tooltip('destroy'); }catch(e){} }); function brushed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom var s = d3.event.selection || x2.range(); x.domain(s.map(x2.invert, x2)); focus.select(".x").call(xAxis); focus.selectAll('.x .tick text').each(function(){ var dd = d3.select(this); if(textRotation) { dd.attr("dx", "-1em") .style("text-anchor", "end") .attr("transform", "rotate(-65)") .attr("dy", "1em"); }else { dd.attr("dx", "0em") .style("text-anchor", "middle"); } }); focus.select(".areaR").attr("d", area); focus.select(".areaW").attr("d", area); focus.selectAll('.tipPoints') .attr("cx", function (d) { return x(d.xLabel); }) .attr("cy", function (d) { return y(d['num']); }); svg.select(".zoom").call(zoom.transform, d3.zoomIdentity .scale(width / (s[1] - s[0])) .translate(-s[0], 0)); } function zoomed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush var t = d3.event.transform; x.domain(t.rescaleX(x2).domain()); focus.select(".x").call(xAxis); focus.selectAll('.x .tick text').each(function(){ var dd = d3.select(this); if(textRotation) { dd.attr("dx", "-1em") .style("text-anchor", "end") .attr("transform", "rotate(-65)") .attr("dy", "1em"); }else { dd.attr("dx", "0em") .style("text-anchor", "middle"); } }); focus.select(".areaR").attr("d", area); focus.select(".areaW").attr("d", area); focus.selectAll('.tipPoints') .attr("cx", function (d) { return x(d.xLabel); }) .attr("cy", function (d) { return y(d['num']); }); context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); } return this; } var sca = new initLineChart(data, "#linechart"); 
  html,body { width:100%; height:100%; margin:none; padding:none; } #linechart { width:99%; height:99%; margin:none; padding:none; background-color:#e3ecf3;} .axis path, .axis line { fill: none; stroke: #f3f3f3; shape-rendering: crispEdges; } .axis text { font-size: .7em; color: #a0a0a0; } .legendRect { stroke: #aaabb1; stroke-width: 1px; fill: none; } .focus .tipPoints { clip-path: url(#clip); } /* .tipPoints { stroke: white; stroke-width: 2px; opacity: 0; } .tipNetPoints { stroke: white; stroke-width: 2px; opacity: 0; } .tipDot { stroke: black; stroke-width: 0.5px; } */ .areaR { fill: rgba(255, 160, 233, 0.6); } .areaW { fill: rgba(0, 160, 233, 0.2); stroke-width: 2px; } .tick { font-family: serif; font-size: 18px; } .zoom { cursor: move; fill: none; pointer-events: all; } rect.selection { fill:green; opacity: 0.4; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="https://d3js.org/d3.v4.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"> <div id="linechart" ></div> 

Got it working, By replacing

focus.select(".areaR").attr("d", area);
focus.select(".areaW").attr("d", area);

with

focus.select(".areaR").attr("d", function(d) { return area(d['values']); });
focus.select(".areaW").attr("d", function(d) { return area(d['values']); });    

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM