You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by GitBox <gi...@apache.org> on 2022/11/18 06:26:19 UTC

[GitHub] [echarts] DavidMarquezF commented on issue #13839: Is there a better way of handling data groupings (Hierarchical Data) and centering their category labels on xAxis

DavidMarquezF commented on issue #13839:
URL: https://github.com/apache/echarts/issues/13839#issuecomment-1319601929

   In my project I build the config dynamically so I don't have a single config for all available right now. However, the only important part you need is what i posted (the xAxis). The rest should be quite easy to lay down.  
   
   I actually improved the design a bit more so that the labels from the second groups are offset enough so that they don't overlap with the first row of categories. I will share my code but it's not copy paste material, you will need to figure it out a bit.
   
   ```typescript
   let groupCategrories: { caption: string, length: number }[] = // Here you should put the ordered list of the second level of categories. Caption is the name it should have and length is how many subcategories it holds;
    const labels: (string | number)[] = //Here put the list of labels from the first row of labels
   
    const longestLabel: string = labels.reduce<string>((a: string, b): string => {
           const strB = b?.toString();
           return a.length > strB?.length ? a : strB;
      }, "") ?? "";
   
   // We want to calculate the longest label in order to offset the second row of labels 
   const maxPixelLengthStr = getTextWidth(longestLabel, DEFAULT_FONT);
   const dummySeparator = "***";
   
   const xAxis: XAXisOption [] = [{
         name: this.xLabel,
         nameLocation: "middle",
         type: "category",
         axisLine: {
             show: false
          },
          axisTick: {
             show: false
          },
         axisLabel: {
           interval: 0,
           rotate: 90,
         },
         splitArea: {
             show: false
           },
       },
      {
           type: "category",
           position: "bottom",
           axisLine: {
             show: false,
             onZero: false
           },
           axisLabel: {
             inside: true,
             interval: (index, value) => {
               return value !== "" && value !== dummySeparator;
             },
           },
           offset: maxPixelLengthStr + 20,
           axisTick: {
             length: maxPixelLengthStr + 15,
             lineStyle: {
               color: "#CCC"
             },
             inside: true,
             interval: (index, value) => {
               return value === dummySeparator ||
                 (value !== "" && groupCategrories.find(c => c.caption === value).length <= 2);
             }
           },
           splitArea: {
             show: true,
             interval: (index, value) => {
               return value === dummySeparator;
             }
           },
           data: groupCategrories.flatMap(c => {
   
             const spaces: string[] = new Array<string>(c.length).fill("");
             spaces[0] = dummySeparator;
             spaces[Math.max(0, Math.trunc((spaces.length - 1) / 2))] = c.caption;
             return spaces;
           })
         }
   ];
      
   
   //The getTextWidth helper function
   function getTextWidth(text, font): number {
       // re-use canvas object for better performance
       const canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas"));
       const context = canvas.getContext("2d");
       context.font = font;
       const metrics = context.measureText(text);
       return metrics.width;
     }
   const DEFAULT_FONT = "400 14px \"Inter var\", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"";
   
   ```
   
   Then, for the rest of the config, just build a normal bar chart with a single series. You just use a single series and then the axis config is actually what does all of the work. 
   
   I'm sorry I can't share a full copy-paste example, I just don't have the time to do that right now. However, with this info it should be quite straight forward since the only complicated part about this is the xAxis itself and in the snippet I've shared that should work right of the bat.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org