From c0a3020886df623e76baedec04b97903573b6c0d Mon Sep 17 00:00:00 2001 From: Ri Xu Date: Wed, 25 Jan 2017 15:44:18 +0800 Subject: [PATCH] Support create merge cell. --- cell.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ excelize_test.go | 19 ++++++++++ 2 files changed, 111 insertions(+) diff --git a/cell.go b/cell.go index f20f05a..fc555b5 100644 --- a/cell.go +++ b/cell.go @@ -139,3 +139,95 @@ func (f *File) SetCellHyperLink(sheet, axis, link string) { output, _ := xml.Marshal(xlsx) f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) } + +// MergeCell provides function to merge cells by given axis and sheet name. +// For example create a merged cell of A1:B2 on Sheet1: +// +// xlsx.MergeCell("sheet1", "D9", "E9") +// +// If you create a merged cell that overlaps with another existing merged cell, +// those merged cells that already exist will be removed. +func (f *File) MergeCell(sheet, hcell, vcell string) { + if hcell == vcell { + return + } + + hcell = strings.ToUpper(hcell) + vcell = strings.ToUpper(vcell) + + // Coordinate conversion, convert C1:B3 to 2,0,1,2. + hcol := string(strings.Map(letterOnlyMapF, hcell)) + hrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, hcell)) + hyAxis := hrow - 1 + hxAxis := titleToNumber(hcol) + + vcol := string(strings.Map(letterOnlyMapF, vcell)) + vrow, _ := strconv.Atoi(strings.Map(intOnlyMapF, vcell)) + vyAxis := vrow - 1 + vxAxis := titleToNumber(vcol) + + if vxAxis < hxAxis { + hcell, vcell = vcell, hcell + vxAxis, hxAxis = hxAxis, vxAxis + } + + if vyAxis < hyAxis { + hcell, vcell = vcell, hcell + vyAxis, hyAxis = hyAxis, vyAxis + } + + var xlsx xlsxWorksheet + name := "xl/worksheets/" + strings.ToLower(sheet) + ".xml" + xml.Unmarshal([]byte(f.readXML(name)), &xlsx) + if xlsx.MergeCells != nil { + mergeCell := xlsxMergeCell{} + // Correct the coordinate area, such correct C1:B3 to B1:C3. + mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + // Delete the merged cells of the overlapping area. + for i := 0; i < len(xlsx.MergeCells.Cells); i++ { + if checkCellInArea(hcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[0], mergeCell.Ref) { + xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...) + } else if checkCellInArea(vcell, xlsx.MergeCells.Cells[i].Ref) || checkCellInArea(strings.Split(xlsx.MergeCells.Cells[i].Ref, ":")[1], mergeCell.Ref) { + xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...) + } + } + xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &mergeCell) + } else { + mergeCell := xlsxMergeCell{} + // Correct the coordinate area, such correct C1:B3 to B1:C3. + mergeCell.Ref = toAlphaString(hxAxis+1) + strconv.Itoa(hyAxis+1) + ":" + toAlphaString(vxAxis+1) + strconv.Itoa(vyAxis+1) + mergeCells := xlsxMergeCells{} + mergeCells.Cells = append(mergeCells.Cells, &mergeCell) + xlsx.MergeCells = &mergeCells + } + output, _ := xml.Marshal(xlsx) + f.saveFileList(name, replaceWorkSheetsRelationshipsNameSpace(string(output))) +} + +// checkCellInArea provides function to determine if a given coordinate is +// within an area. +func checkCellInArea(cell, area string) bool { + result := false + cell = strings.ToUpper(cell) + col := string(strings.Map(letterOnlyMapF, cell)) + row, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell)) + xAxis := row - 1 + yAxis := titleToNumber(col) + + ref := strings.Split(area, ":") + hCol := string(strings.Map(letterOnlyMapF, ref[0])) + hRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[0])) + hyAxis := hRow - 1 + hxAxis := titleToNumber(hCol) + + vCol := string(strings.Map(letterOnlyMapF, ref[1])) + vRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, ref[1])) + vyAxis := vRow - 1 + vxAxis := titleToNumber(vCol) + + if hxAxis <= yAxis && yAxis <= vxAxis && hyAxis <= xAxis && xAxis <= vyAxis { + result = true + } + + return result +} diff --git a/excelize_test.go b/excelize_test.go index 0ac4b9d..4a1c3fb 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -235,3 +235,22 @@ func TestSetSheetBackground(t *testing.T) { t.Log(err) } } + +func TestSMergeCell(t *testing.T) { + xlsx, err := OpenFile("./test/Workbook1.xlsx") + if err != nil { + t.Log(err) + } + xlsx.MergeCell("sheet1", "D9", "D9") + xlsx.MergeCell("sheet1", "D9", "E9") + xlsx.MergeCell("sheet1", "H14", "G13") + xlsx.MergeCell("sheet1", "C9", "D8") + xlsx.MergeCell("sheet1", "F11", "G13") + xlsx.MergeCell("sheet1", "H7", "B15") + xlsx.MergeCell("sheet1", "D11", "F13") + xlsx.MergeCell("sheet1", "G10", "I11") + err = xlsx.Save() + if err != nil { + t.Log(err) + } +}