Forum Discussion
Overlapping Tick Marks on X-Axis
- 6 years ago
In case anyone runs into the same problem, this is how I solved the issue.
I put the creation of the X axis inside a do/while loop. The loop begins with creating the axis then loops through each text element and gets the width of the text. The width is added to an array from which the largest width is determined and multiplied by the total number of ticks to get an estimate of how much space all the labels would need. This is then compared to the plot width and if it is greater (i.e. the labels require more room than is available in the plot area and are overlapping) the whole loop is rerun (and the axis recreated) with one fewer ticks until there is no overlapping. Generally it only needs to run 5 or fewer times, but I put in an iteration counter and added it to the while condition to avoid an infinite loop.
I am pasting the code below in case it is helpful. It needs to be cleaned up considerably (I have a lot of console logs to help with debugging), but here it is for what it's worth.
If any one has a more efficient way I would love to hear it.
do { var xAxis = d3.axisBottom(xScale) .tickFormat((d) => valueFormatter.format(d)) .ticks(tickMarks); this.xAxisContainer .attr("class", "xAxis") .attr("transform", "translate(" + plotArea.x + "," + (plotArea.height + plotArea.y) + ")") .call(xAxis) .style("font-size", viewModel.XAxisFontSize) .style("font-family", viewModel.FontFamily) console.log("******************") console.log("iteration" + m) console.log("View Port Width:" + options.viewport.width) var gCounter = 0 var g = 0 var gArray = [] var labelWidth = 0 var gMax = 0 d3.select(".xAxis").selectAll("text") .each(function (d,i) { console.log("starting") let textProperties: TextProperties = { text: valueFormatter.format(d), fontFamily: viewModel.FontFamily, fontSize: "" + viewModel.XAxisFontSize } let h = textMeasurementService.measureSvgTextRect(textProperties).width gCounter++ g = h + g gArray.push(h) gMax = d3.max(gArray) labelWidth = ((gCounter - .5) * gMax) console.log("----------------------") console.log("Font Family: " + textProperties.fontFamily) console.log("Font Size: " + textProperties.fontSize) console.log("width of " + textProperties.text + ":" + h) console.log("Counter:" + gCounter) console.log("g:" + g) console.log("gArray: " + gArray) console.log("gMax: " + gMax) console.log("Label Width:" + labelWidth) console.log("Plot Width: " + plotArea.width) return(labelWidth) }); --tickMarks console.log("TickMarks:" + tickMarks) ++m console.log("Plot Width: " + plotArea.width) console.log("Label Width:" + labelWidth) console.log("Test: ", plotArea.width < labelWidth) } while (m<100 && plotArea.width < labelWidth)
You're welcome! Your visual is looking great BTW 🙂
If you want to use the MS-supported tooling for legend and data labels, you can find the doc in the same library (powerbi-visuals-utils-chartuilts):
I personally haven't used the data labels tooling, but the legend works just fine. I've messed with it too much in the visual I used above for it to be a reliable example for you, but you can see how I'm using it in this visual - specifically here (adding to DOM), here (rendering) and I've created a function here to hide the legend if the container gets too small. Hopefully these may save you some time when having a go yourself.
Good luck!
Daniel
The legend is giving me a lot more difficulty than I was expecting. I am trying to just get something, anything to show up and then I'll tweak it from there. A couple days into it and it's still not working. Quick question, for the LegendDataPoint that is require by drawLegend(), one of the required properties is "identity". If I just put null there for the time being, will the visual still display properly?
I might try downloading all your code from the visual you linked to and tweak that field to see what happens...
- cogsie6 years agoHelper I
I quickly tried changing the identity property in your populateLegend function to null on your small multiple line chart custom visual and sure enough that killed the visual. So I think that it probably my problem. Looks like I need to create a selection ID and use the SelectionIDBuilder to get it working. I'll see if that helps at all...
- dm-p6 years agoSuper UserYes - you'll need to provide a selectionId for legend items. Null used to work in older versions but stopped working when libraries got updated for latest SDK last year.