
# Custom Renderer (Bar)

You can use a custom renderer to create a horizontal bar shape.  

This is an example of applying a custom renderer to the "Unit" column so that the renderer flows horizontally to other columns and is displayed.

### Note
* Using a custom renderer means that the developer directly controls the grid without using its functions. Therefore, it is not basically a technical support area.  
* However, if there is a problem with the code you wrote, you must send us the executable source code to receive `technical support`.  
* The custom renderer was developed for view purposes and is not suitable for input purposes.  
* Since it was not developed with the idea of being able to draw the entire thing using external components, there may be problems if you draw an area larger than the row height.  



```js
const fields = [
  { fieldName: 'mineral' },
  { fieldName: 'unit' },
  { fieldName: 'Gyeonggi', dataType: 'number' },
  { fieldName: 'Gangwon', dataType: 'number' },
  { fieldName: 'Chungbuk', dataType: 'number' },
  { fieldName: 'Chungnam', dataType: 'number' },
  { fieldName: 'Jeonbuk', dataType: 'number' },
  { fieldName: 'Jeonnam', dataType: 'number' },
  { fieldName: 'Gyeongbuk', dataType: 'number' },
  { fieldName: 'Gyeongnam', dataType: 'number' },
  { fieldName: 'Other', dataType: 'number' },
  { fieldName: 'Total', dataType: 'number' }
];

const columns = [
  { name: 'mineral', fieldName: 'mineral', width: 70, header: { text: 'Minerals' } },
  { name: 'unit', fieldName: 'unit', width: 90, header: { text: 'Unit' } },
  { name: 'Gyeonggi', fieldName: 'Gyeonggi', width: 60, header: { text: 'Gyeonggi' }, numberFormat: '#,##0' },
  { name: 'Gangwon', fieldName: 'Gangwon', width: 60, header: { text: 'Gangwon' }, numberFormat: '#,##0' },
  { name: 'Chungbuk', fieldName: 'Chungbuk', width: 60, header: { text: 'Chungbuk' }, numberFormat: '#,##0' },
  { name: 'Chungnam', fieldName: 'Chungnam', width: 60, header: { text: 'Chungnam' }, numberFormat: '#,##0' },
  { name: 'Jeonbuk', fieldName: 'Jeonbuk', width: 60, header: { text: 'Jeonbuk' }, numberFormat: '#,##0' },
  { name: 'Jeonnam', fieldName: 'Jeonnam', width: 60, header: { text: 'Jeonnam' }, numberFormat: '#,##0' },
  { name: 'Gyeongbuk', fieldName: 'Gyeongbuk', width: 60, header: { text: 'Gyeongbuk' }, numberFormat: '#,##0' },
  { name: 'Gyeongnam', fieldName: 'Gyeongnam', width: 60, header: { text: 'Gyeongnam' }, numberFormat: '#,##0' },
  { name: 'Other', fieldName: 'Other', width: 60, header: { text: 'Other' }, numberFormat: '#,##0' },
  { name: 'Total', fieldName: 'Total', width: 60, header: { text: 'Total' }, numberFormat: '#,##0' }
];

const datas = [
  {"mineral":"Gold","unit":"Au 99.9% ","Gyeonggi":17342,"Gangwon":24587,"Chungbuk":19845,"Chungnam":37612,"Jeonbuk":28453,"Jeonnam":29000,"Gyeongbuk":31421,"Gyeongnam":22134,"Other":30387,"Total":240781},
  {"mineral":"Silver","unit":"Ag 99.9% ","Gyeonggi":32541,"Gangwon":34800,"Chungbuk":28012,"Chungnam":31245,"Jeonbuk":27654,"Jeonnam":231400,"Gyeongbuk":34821,"Gyeongnam":25234,"Other":28987,"Total":440694},
  {"mineral":"Dong","unit":"Cu 25-29%","Gyeonggi":19423,"Gangwon":25412,"Chungbuk":31245,"Chungnam":20789,"Jeonbuk":18432,"Jeonnam":29654,"Gyeongbuk":31412,"Gyeongnam":22345,"Other":28721,"Total":227433},
  {"mineral":"Year","unit":"Pb 50%   ","Gyeonggi":28412,"Gangwon":25321,"Chungbuk":31245,"Chungnam":36789,"Jeonbuk":24567,"Jeonnam":27894,"Gyeongbuk":42600,"Gyeongnam":35789,"Other":30342,"Total":283459},
  {"mineral":"Zinc","unit":"Zn 50%   ","Gyeonggi":23781,"Gangwon":22300,"Chungbuk":28421,"Chungnam":29654,"Jeonbuk":25312,"Jeonnam":27543,"Gyeongbuk":129400,"Gyeongnam":31789,"Other":30512,"Total":352672},
  {"mineral":"Iron","unit":"Fe 56-65%","Gyeonggi":28421,"Gangwon":503648,"Chungbuk":31421,"Chungnam":32789,"Jeonbuk":30543,"Jeonnam":31245,"Gyeongbuk":32012,"Gyeongnam":29543,"Other":31789,"Total":669411},
  {"mineral":"Tungsten","unit":"WO3 70%  ","Gyeonggi":27891,"Gangwon":31421,"Chungbuk":30234,"Chungnam":29541,"Jeonbuk":28712,"Jeonnam":29643,"Gyeongbuk":30412,"Gyeongnam":31543,"Other":30321,"Total":270269},
  {"mineral":"Molybdenum","unit":"MoS2 90% ","Gyeonggi":30234,"Gangwon":28765,"Chungbuk":629,"Chungnam":31245,"Jeonbuk":29876,"Jeonnam":31789,"Gyeongbuk":30412,"Gyeongnam":30543,"Other":29654,"Total":214947},
  {"mineral":"Annotation","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":30234,"Chungbuk":31421,"Chungnam":29876,"Jeonbuk":30543,"Jeonnam":31789,"Gyeongbuk":30123,"Gyeongnam":29654,"Other":31245,"Total":267134},
  {"mineral":"Iron Sulfide","unit":"FeS 45%  ","Gyeonggi":31245,"Gangwon":30543,"Chungbuk":29781,"Chungnam":30678,"Jeonbuk":31421,"Jeonnam":31789,"Gyeongbuk":30123,"Gyeongnam":30543,"Other":31421,"Total":257463},
  {"mineral":"Titanium","unit":"Each Level     ","Gyeonggi":200214,"Gangwon":31789,"Chungbuk":30543,"Chungnam":31245,"Jeonbuk":29876,"Jeonnam":31789,"Gyeongbuk":30123,"Gyeongnam":31421,"Other":30543,"Total":367043},
  {"mineral":"Anthracite","unit":"         ","Gyeonggi":30543,"Gangwon":626299,"Chungbuk":31245,"Chungnam":30678,"Jeonbuk":29876,"Jeonnam":19650,"Gyeongbuk":30512,"Gyeongnam":31789,"Other":30543,"Total":841595},
  {"mineral":"Zircon","unit":"Each Level     ","Gyeonggi":31245,"Gangwon":30543,"Chungbuk":31421,"Chungnam":30412,"Jeonbuk":31789,"Jeonnam":30543,"Gyeongbuk":31245,"Gyeongnam":30543,"Other":31421,"Total":269622},
  {"mineral":"Rare Earth Metals","unit":"         ","Gyeonggi":31245,"Gangwon":30543,"Chungbuk":31421,"Chungnam":5355,"Jeonbuk":31789,"Jeonnam":30543,"Gyeongbuk":31245,"Gyeongnam":30543,"Other":31421,"Total":233605},
  {"mineral":"Flake Graphite","unit":"Each Level     ","Gyeonggi":31245,"Gangwon":30543,"Chungbuk":31421,"Chungnam":31234,"Jeonbuk":31789,"Jeonnam":30543,"Gyeongbuk":31245,"Gyeongnam":30543,"Other":31421,"Total":259444},
  {"mineral":"Amorphous Graphite","unit":"Each Level     ","Gyeonggi":29000,"Gangwon":30543,"Chungbuk":31245,"Chungnam":30678,"Jeonbuk":31421,"Jeonnam":31789,"Gyeongbuk":31245,"Gyeongnam":30543,"Other":31421,"Total":298385},
  {"mineral":"Talc","unit":"Each Level     ","Gyeonggi":31245,"Gangwon":30543,"Chungbuk":1329,"Chungnam":1569,"Jeonbuk":31789,"Jeonnam":30543,"Gyeongbuk":31421,"Gyeongnam":30512,"Other":30543,"Total":189494},
  {"mineral":"Pyrophyllite","unit":"Each Level     ","Gyeonggi":31245,"Gangwon":2304,"Chungbuk":4512,"Chungnam":31789,"Jeonbuk":30543,"Jeonnam":203700,"Gyeongbuk":42618,"Gyeongnam":30670,"Other":21055,"Total":391236},
  {"mineral":"Feldspar","unit":"Each Level     ","Gyeonggi":19645,"Gangwon":36720,"Chungbuk":3560,"Chungnam":165601,"Jeonbuk":1500,"Jeonnam":29560,"Gyeongbuk":509621,"Gyeongnam":2100,"Other":222507,"Total":990314},
  {"mineral":"Kaolin","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":351697,"Chungbuk":16773,"Chungnam":44162,"Jeonbuk":1276,"Jeonnam":52899,"Gyeongbuk":178283,"Gyeongnam":212985,"Other":26080,"Total":884144},
  {"mineral":"Limestone","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":60635450,"Chungbuk":23629029,"Chungnam":928102,"Jeonbuk":80222,"Jeonnam":168635,"Gyeongbuk":379284,"Gyeongnam":31789,"Other":31789,"Total":85820839},
  {"mineral":"Quartzite","unit":"Each Level     ","Gyeonggi":1400663,"Gangwon":930632,"Chungbuk":206479,"Chungnam":31789,"Jeonbuk":141,"Jeonnam":202087,"Gyeongbuk":201060,"Gyeongnam":60300,"Other":764737,"Total":3765888},
  {"mineral":"whenlica Sand","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":99496,"Chungbuk":11280,"Chungnam":264021,"Jeonbuk":31789,"Jeonnam":5200,"Gyeongbuk":653353,"Gyeongnam":31789,"Other":31789,"Total":1033416},
  {"mineral":"Diatomite","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":31789,"Chungbuk":31789,"Chungnam":31789,"Jeonbuk":31789,"Jeonnam":31789,"Gyeongbuk":120941,"Gyeongnam":31789,"Other":31789,"Total":301434},
  {"mineral":"Serpentine","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":31789,"Chungbuk":31789,"Chungnam":31789,"Jeonbuk":31789,"Jeonnam":31789,"Gyeongbuk":23432,"Gyeongnam":31789,"Other":31789,"Total":246452},
  {"mineral":"Mica","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":1886,"Chungbuk":1206,"Chungnam":353,"Jeonbuk":31789,"Jeonnam":31789,"Gyeongbuk":15932,"Gyeongnam":31789,"Other":31789,"Total":157622},
  {"mineral":"Fluorite","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":31789,"Chungbuk":31789,"Chungnam":31789,"Jeonbuk":31789,"Jeonnam":31789,"Gyeongbuk":177923,"Gyeongnam":31789,"Other":31789,"Total":370314},
  {"mineral":"Edit","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":31789,"Chungbuk":31789,"Chungnam":31789,"Jeonbuk":31789,"Jeonnam":31789,"Gyeongbuk":440,"Gyeongnam":31789,"Other":31789,"Total":225502},
  {"mineral":"Alunite","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":31789,"Chungbuk":31789,"Chungnam":31789,"Jeonbuk":31789,"Jeonnam":1400,"Gyeongbuk":31789,"Gyeongnam":31789,"Other":31789,"Total":194712},
  {"mineral":"Nephrite","unit":"Each Level     ","Gyeonggi":31789,"Gangwon":1337,"Chungbuk":31789,"Chungnam":31789,"Jeonbuk":31789,"Jeonnam":31789,"Gyeongbuk":654,"Gyeongnam":31789,"Other":31789,"Total":197724}
];

const colorCode = {
  "Gold": "#FFD700",
  "Silver": "#C0C0C0",
  "Dong": "#CD853F",
  "Year": "#A9A9A9",
  "Zinc": "#B0C4DE",
  "Iron": "#808080",
  "Tungsten": "#2F4F4F",
  "Molybdenum": "#4682B4",
  "Annotation": "#A9A9A9",
  "Iron Sulfide": "#8B4513",
  "Titanium": "#A9A9A9",
  "Anthracite": "#666C70",
  "Zircon": "#4682B4",
  "Rare Earth Metals": "#8A2BE2",
  "Flake Graphite": "#696969",
  "Amorphous Graphite": "#708090",
  "Talc": "#90EE90",
  "Pyrophyllite": "#9370DB",
  "Feldspar": "#CD853F",
  "Kaolin": "#DEB887",
  "Limestone": "#C2B280",
  "Quartzite": "#A9A9A9",
  "whenlica Sand": "#DAA520",
  "Diatomite": "#C0C080",
  "Serpentine": "#6B8E23",
  "Mica": "#BDB76B",
  "Fluorite": "#CD5C5C",
  "Edit": "#9370DB",
  "Alunite": "#4682B4",
  "Nephrite": "#3CB371"
};

const textColor = {
  "Gold": "#DAA520",
  "Silver": "#A9A9A9",
  "Dong": "#8B4513",
  "Year": "#696969",
  "Zinc": "#5F7A99",
  "Iron": "#808080",
  "Tungsten": "#2F4F4F",
  "Molybdenum": "#2E4A62",
  "Annotation": "#696969",
  "Iron Sulfide": "#5A2D0C",
  "Titanium": "#696969",
  "Anthracite": "#333333",
  "Zircon": "#2F4F7F",
  "Rare Earth Metals": "#4B0082",
  "Flake Graphite": "#404040",
  "Amorphous Graphite": "#2F3E4F",
  "Talc": "#556B2F",
  "Pyrophyllite": "#6A0DAD",
  "Feldspar": "#8B4513",
  "Kaolin": "#8B7355",
  "Limestone": "#7A6A3F",
  "Quartzite": "#555555",
  "whenlica Sand": "#B8860B",
  "Diatomite": "#666633",
  "Serpentine": "#556B2F",
  "Mica": "#8B8B00",
  "Fluorite": "#8B0000",
  "Edit": "#4B0082",
  "Alunite": "#004080",
  "Nephrite": "#2E8B57"
};

const { gridView, dataProvider } = RealGrid.createGrid('realgrid', {
  columns,
  header: {
    height: 40
  },
  display: {
    rowHeight: 40,
    emptyMessage: 'No data to display.',
    fitStyle: 'even',
    focusVisible: false
  },
  edit: {
    insertable: true,
    appendable: true,
    editable: false
  },
  footer: {
    visible: false
  },
  stateBar: {
    width: 16,
    visible: false
  },
  checkBar: {
    visible: false
  },
  onInitialized: (grid) => {
    grid.getDataSource().setRows(datas);
    grid.orderBy(['mineral'], ['ascending']);

    grid.columnByName('Total').styleCallback = function(grid, dataCell) {
      const ret = {};
      const mineral = grid.getValue(dataCell.index.itemIndex, 'mineral');
      ret.style = { color: textColor[mineral] };
      return ret;
    };

    grid.registerCustomRenderer('mineral', {
      initContent: function(dom) {
        let css = dom.style;
        css.display = 'flex';
        css.flexDirection = 'row';
        css.marginRight = '5px';
        css.alignItems = 'center';

        const textSpan = this._textSpan = document.createElement('span');
        css = textSpan.style;
        css.flex = '1 1 20px';
        const colorSpan = this._colorSpan = document.createElement('span');

        colorSpan.classList.add('dot');
        css = colorSpan.style;
        css.flex = '0 0 10px';

        dom.appendChild(this._textSpan);
        dom.appendChild(this._colorSpan);
      },
      canClick: function() {
        return true;
      },
      clearContent: function(dom) {},
      render: function(grid, model, width, height, info) {
        const itemIndex = model.item.index;
        const mineral = grid.getValue(itemIndex, 'mineral');
        this._textSpan.textContent = mineral;
        this._colorSpan.style.backgroundColor = colorCode[mineral];
      },
      click: function(event) {}
    });

    grid.registerCustomRenderer('mineralBar', {
      initContent: function(dom) {
        this._dom = dom;
        let css = dom.style;
        css.display = 'flex';
        css.height = '21px';
        css.alignItems = 'center';

        dom.style.removeProperty('overflow');
        const svg = this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
        css = svg.style;
        css.position = 'absolute';
        dom.appendChild(svg);

        const text = this.textSpan = document.createElement('span');
        css = text.style;
        css.flex = '1 1 20px';
        css.position = 'relative';
        dom.appendChild(text);
      },
      canClick: function() {
        return true;
      },
      clearContent: function(dom) {
        dom.removeChild(this.svg);
      },
      render: function(grid, model, colWidth, height, info) {
        const svg = this.svg;
        const widths = grid._view.activeCellLayout._cellWidths;
        let width = widths.reduce((a, b) => a + b, 0);
        width -= (grid.layoutByName('mineral').cellWidth + grid.layoutByName('Total').cellWidth);

        svg.setAttribute('width', `${width}`);
        svg.setAttribute('height', '16');
        svg.setAttribute('viewBox', `0 0 ${width} 16`);

        this.textSpan.textContent = model.value;

        const ds = grid.getDataSource();
        const mineral = ds.getValue(model.index.dataRow, 'mineral');
        const color = colorCode[mineral] || 'silver';
        const volume = ds.getValue(model.index.dataRow, 'Total') || 0;
        if (volume <= 0) {
          this.svg.innerHTML = '';
        } else if (volume <= 600000) {
          let barWidth = (volume / 500000) * 0.7 * width;
          this.svg.innerHTML = `<path d="M0 0 H${barWidth} A8 8 0 0 1 ${barWidth} 16 H0 Z" fill=${color} />`;
        } else {
          let barWidth = Math.min(0.7 * width + (((volume - 500000) / 3000000) * width), width - 10);
          let str = `
            <defs>
              <mask id="mask-transparent-stroke">
                <rect width=${width} height="16" fill="white" />
                <path d="M700 0 L695 5 L700 10 L695 15" stroke="black" stroke-width="2" fill="none" />
              </mask>
            </defs>
            <path d="M0 0 H${barWidth} A8 8 0 0 1 ${barWidth} 16 H0 Z" fill=${color} mask="url(#mask-transparent-stroke)"/>`;
          this.svg.innerHTML = str;
        }
      },
      click: function(event) {}
    });

    grid.columnByName('mineral').renderer = 'mineral';
    grid.columnByName('unit').renderer = 'mineralBar';
  }
}, {
  fields
});

window.gridView = gridView;
window.dataProvider = dataProvider;
```

```js
//mineral 광물컬럼
gridView.registerCustomRenderer("mineral", {
  initContent : function (dom) {
      let css = dom.style;
      css.display = "flex";
      css.flexDirection = "row";
      css.marginRight = "5px";
      css.alignItems = "center";

      const textSpan = this._textSpan = document.createElement("span");
      css = textSpan.style;
      css.flex = "1 1 20px";
      const colorSpan = this._colorSpan = document.createElement("span");
      
      colorSpan.classList.add("dot");
      css = colorSpan.style;
      css.flex = "0 0 10px";
      
      dom.appendChild(this._textSpan);
      dom.appendChild(this._colorSpan);
  },
  
  canClick : function() {
      return true;
  },
  
  clearContent : function(dom) {

  },
  
  render : function(grid, model, width, height, info) {
      const itemIndex = model.item.index
      const mineral = grid.getValue(itemIndex, "mineral");
      this._textSpan.textContent = mineral;
      this._colorSpan.style.backgroundColor = colorCode[mineral];
  },
  
  click : function(event) {
      
  }
});

//unit 단위컬럼
gridView.registerCustomRenderer("mineralBar", {
  initContent : function (dom) {
      this._dom = dom;
      let css = dom.style;
      css.display = "flex";
      css.height = "21px";
      css.alignItems = "center";

      dom.style.removeProperty("overflow");
      const svg = this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      css = svg.style;
      css.position = "absolute";
      dom.appendChild(svg);

      const text = this.textSpan = document.createElement("span");
      css = text.style;
      css.flex = "1 1 20px";
      css.position = "relative";
      dom.appendChild(text);
  },
  
  canClick : function() {
      return true;
  },
  
  clearContent : function(dom) {
      dom.removeChild(this.svg);
  },
  
  render : function(grid, model, colWidth, height, info) {
      const svg = this.svg;
    const widths = grid._view.activeCellLayout._cellWidths;
    let width = widths.reduce( (a, b) => a + b, 0);
    width -= (grid.layoutByName("mineral").cellWidth + grid.layoutByName("합계").cellWidth);

    svg.setAttribute("width", `${width}`);
    svg.setAttribute("height", "16");
    svg.setAttribute("viewBox", `0 0 ${width} 16`)

    this.textSpan.textContent = model.value;

    const ds = grid.getDataSource();
    //this.dom.style.removeProperty("overflow");
    const mineral = ds.getValue(model.index.dataRow, "mineral")
    const color = colorCode[mineral] || "silver";
    const volume = ds.getValue(model.index.dataRow, "합계") || 0;
    if (volume <= 0) {
        this.svg.innerHTML = "";
    } else if (volume <= 600000) { // 대략 70%
        let barWidth = (volume / 500000) * 0.7 * width;
        this.svg.innerHTML = `<path d="M0 0 H${barWidth} A8 8 0 0 1 ${barWidth} 16 H0 Z" fill=${color} />`;
    } else {
        let barWidth = Math.min( 0.7 * width + (((volume - 500000) / 3000000) * width), width - 10);
        // let barWidth = Math.min((volume / 500000) * width, width - 10);
        let str = `
            <defs>
                <!-- 마스크 정의: 전체는 보이게, 번개 선은 가리기 -->
                <mask id="mask-transparent-stroke">
                <!-- 전체 흰색 (보임) -->
                <rect width=${width} height="16" fill="white" />
                <!-- 번개 선 부분은 검정색 (가려짐 = 투명) -->
                <path d="M700 0 L695 5 L700 10 L695 15" stroke="black" stroke-width="2" fill="none" />
                </mask>
            </defs>
            <path d="M0 0 H${barWidth} A8 8 0 0 1 ${barWidth} 16 H0 Z" fill=${color} mask="url(#mask-transparent-stroke)"/>`;
        this.svg.innerHTML = str;
    }
  
  },
  
  click : function(event) {
      
  }
});

gridView.columnByName("mineral").renderer = "mineral";
gridView.columnByName("unit").renderer = "mineralBar";
```
