cellmerged.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX files. Support reads and writes XLSX file generated by
  7. // Microsoft Excel™ 2007 and later. Support save file without losing original
  8. // charts of XLSX. This library needs Go version 1.10 or later.
  9. package excelize
  10. import (
  11. "fmt"
  12. "strings"
  13. )
  14. // MergeCell provides a function to merge cells by given coordinate area and
  15. // sheet name. For example create a merged cell of D3:E9 on Sheet1:
  16. //
  17. // err := f.MergeCell("Sheet1", "D3", "E9")
  18. //
  19. // If you create a merged cell that overlaps with another existing merged cell,
  20. // those merged cells that already exist will be removed.
  21. //
  22. // B1(x1,y1) D1(x2,y1)
  23. // +--------------------------------+
  24. // | |
  25. // | |
  26. // A4(x3,y3) | C4(x4,y3) |
  27. // +-----------------------------+ |
  28. // | | | |
  29. // | | | |
  30. // | |B5(x1,y2) | D5(x2,y2)|
  31. // | +--------------------------------+
  32. // | |
  33. // | |
  34. // |A8(x3,y4) C8(x4,y4)|
  35. // +-----------------------------+
  36. //
  37. func (f *File) MergeCell(sheet, hcell, vcell string) error {
  38. rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
  39. if err != nil {
  40. return err
  41. }
  42. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  43. _ = sortCoordinates(rect1)
  44. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  45. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  46. xlsx, err := f.workSheetReader(sheet)
  47. if err != nil {
  48. return err
  49. }
  50. ref := hcell + ":" + vcell
  51. if xlsx.MergeCells != nil {
  52. for i := 0; i < len(xlsx.MergeCells.Cells); i++ {
  53. cellData := xlsx.MergeCells.Cells[i]
  54. if cellData == nil {
  55. continue
  56. }
  57. cc := strings.Split(cellData.Ref, ":")
  58. if len(cc) != 2 {
  59. return fmt.Errorf("invalid area %q", cellData.Ref)
  60. }
  61. rect2, err := f.areaRefToCoordinates(cellData.Ref)
  62. if err != nil {
  63. return err
  64. }
  65. // Delete the merged cells of the overlapping area.
  66. if isOverlap(rect1, rect2) {
  67. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells[:i], xlsx.MergeCells.Cells[i+1:]...)
  68. i--
  69. if rect1[0] > rect2[0] {
  70. rect1[0], rect2[0] = rect2[0], rect1[0]
  71. }
  72. if rect1[2] < rect2[2] {
  73. rect1[2], rect2[2] = rect2[2], rect1[2]
  74. }
  75. if rect1[1] > rect2[1] {
  76. rect1[1], rect2[1] = rect2[1], rect1[1]
  77. }
  78. if rect1[3] < rect2[3] {
  79. rect1[3], rect2[3] = rect2[3], rect1[3]
  80. }
  81. hcell, _ = CoordinatesToCellName(rect1[0], rect1[1])
  82. vcell, _ = CoordinatesToCellName(rect1[2], rect1[3])
  83. ref = hcell + ":" + vcell
  84. }
  85. }
  86. xlsx.MergeCells.Cells = append(xlsx.MergeCells.Cells, &xlsxMergeCell{Ref: ref})
  87. } else {
  88. xlsx.MergeCells = &xlsxMergeCells{Cells: []*xlsxMergeCell{{Ref: ref}}}
  89. }
  90. return err
  91. }
  92. // UnmergeCell provides a function to unmerge a given coordinate area.
  93. // For example unmerge area D3:E9 on Sheet1:
  94. //
  95. // err := f.UnmergeCell("Sheet1", "D3", "E9")
  96. //
  97. // Attention: overlapped areas will also be unmerged.
  98. func (f *File) UnmergeCell(sheet string, hcell, vcell string) error {
  99. xlsx, err := f.workSheetReader(sheet)
  100. if err != nil {
  101. return err
  102. }
  103. rect1, err := f.areaRefToCoordinates(hcell + ":" + vcell)
  104. if err != nil {
  105. return err
  106. }
  107. // Correct the coordinate area, such correct C1:B3 to B1:C3.
  108. _ = sortCoordinates(rect1)
  109. // return nil since no MergeCells in the sheet
  110. if xlsx.MergeCells == nil {
  111. return nil
  112. }
  113. i := 0
  114. for _, cellData := range xlsx.MergeCells.Cells {
  115. if cellData == nil {
  116. continue
  117. }
  118. cc := strings.Split(cellData.Ref, ":")
  119. if len(cc) != 2 {
  120. return fmt.Errorf("invalid area %q", cellData.Ref)
  121. }
  122. rect2, err := f.areaRefToCoordinates(cellData.Ref)
  123. if err != nil {
  124. return err
  125. }
  126. if isOverlap(rect1, rect2) {
  127. continue
  128. }
  129. xlsx.MergeCells.Cells[i] = cellData
  130. i++
  131. }
  132. xlsx.MergeCells.Cells = xlsx.MergeCells.Cells[:i]
  133. return nil
  134. }
  135. // GetMergeCells provides a function to get all merged cells from a worksheet
  136. // currently.
  137. func (f *File) GetMergeCells(sheet string) ([]MergeCell, error) {
  138. var mergeCells []MergeCell
  139. xlsx, err := f.workSheetReader(sheet)
  140. if err != nil {
  141. return mergeCells, err
  142. }
  143. if xlsx.MergeCells != nil {
  144. mergeCells = make([]MergeCell, 0, len(xlsx.MergeCells.Cells))
  145. for i := range xlsx.MergeCells.Cells {
  146. ref := xlsx.MergeCells.Cells[i].Ref
  147. axis := strings.Split(ref, ":")[0]
  148. val, _ := f.GetCellValue(sheet, axis)
  149. mergeCells = append(mergeCells, []string{ref, val})
  150. }
  151. }
  152. return mergeCells, err
  153. }
  154. // MergeCell define a merged cell data.
  155. // It consists of the following structure.
  156. // example: []string{"D4:E10", "cell value"}
  157. type MergeCell []string
  158. // GetCellValue returns merged cell value.
  159. func (m *MergeCell) GetCellValue() string {
  160. return (*m)[1]
  161. }
  162. // GetStartAxis returns the merge start axis.
  163. // example: "C2"
  164. func (m *MergeCell) GetStartAxis() string {
  165. axis := strings.Split((*m)[0], ":")
  166. return axis[0]
  167. }
  168. // GetEndAxis returns the merge end axis.
  169. // example: "D4"
  170. func (m *MergeCell) GetEndAxis() string {
  171. axis := strings.Split((*m)[0], ":")
  172. return axis[1]
  173. }