|
|
@@ -0,0 +1,375 @@
|
|
|
+package excelize
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "encoding/xml"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+)
|
|
|
+
|
|
|
+// parseFormatShapeSet provides function to parse the format settings of the
|
|
|
+// shape with default value.
|
|
|
+func parseFormatShapeSet(formatSet string) *formatShape {
|
|
|
+ format := formatShape{
|
|
|
+ Width: 160,
|
|
|
+ Height: 160,
|
|
|
+ Format: formatPicture{
|
|
|
+ FPrintsWithSheet: true,
|
|
|
+ FLocksWithSheet: false,
|
|
|
+ NoChangeAspect: false,
|
|
|
+ OffsetX: 0,
|
|
|
+ OffsetY: 0,
|
|
|
+ XScale: 1.0,
|
|
|
+ YScale: 1.0,
|
|
|
+ },
|
|
|
+ Text: " ",
|
|
|
+ }
|
|
|
+ json.Unmarshal([]byte(formatSet), &format)
|
|
|
+ return &format
|
|
|
+}
|
|
|
+
|
|
|
+// AddShape provides the method to add shape in a sheet by given worksheet
|
|
|
+// index, shape format set (such as offset, scale, aspect ratio setting and
|
|
|
+// print settings) and properties set. For example, add text box (rect shape) in
|
|
|
+// Sheet1:
|
|
|
+//
|
|
|
+// xlsx.AddShape("Sheet1", "G6", `{"type":"rect", "text":"Rectangle Shape", "color":{"line":"#4286F4","fill":"#8eb9ff"}, "width": 180, "height": 90}`)
|
|
|
+//
|
|
|
+// The following shows the type of chart supported by excelize:
|
|
|
+//
|
|
|
+// accentBorderCallout1 (Callout 1 with Border and Accent Shape)
|
|
|
+// accentBorderCallout2 (Callout 2 with Border and Accent Shape)
|
|
|
+// accentBorderCallout3 (Callout 3 with Border and Accent Shape)
|
|
|
+// accentCallout1 (Callout 1 Shape)
|
|
|
+// accentCallout2 (Callout 2 Shape)
|
|
|
+// accentCallout3 (Callout 3 Shape)
|
|
|
+// actionButtonBackPrevious (Back or Previous Button Shape)
|
|
|
+// actionButtonBeginning (Beginning Button Shape)
|
|
|
+// actionButtonBlank (Blank Button Shape)
|
|
|
+// actionButtonDocument (Document Button Shape)
|
|
|
+// actionButtonEnd (End Button Shape)
|
|
|
+// actionButtonForwardNext (Forward or Next Button Shape)
|
|
|
+// actionButtonHelp (Help Button Shape)
|
|
|
+// actionButtonHome (Home Button Shape)
|
|
|
+// actionButtonInformation (Information Button Shape)
|
|
|
+// actionButtonMovie (Movie Button Shape)
|
|
|
+// actionButtonReturn (Return Button Shape)
|
|
|
+// actionButtonSound (Sound Button Shape)
|
|
|
+// arc (Curved Arc Shape)
|
|
|
+// bentArrow (Bent Arrow Shape)
|
|
|
+// bentConnector2 (Bent Connector 2 Shape)
|
|
|
+// bentConnector3 (Bent Connector 3 Shape)
|
|
|
+// bentConnector4 (Bent Connector 4 Shape)
|
|
|
+// bentConnector5 (Bent Connector 5 Shape)
|
|
|
+// bentUpArrow (Bent Up Arrow Shape)
|
|
|
+// bevel (Bevel Shape)
|
|
|
+// blockArc (Block Arc Shape)
|
|
|
+// borderCallout1 (Callout 1 with Border Shape)
|
|
|
+// borderCallout2 (Callout 2 with Border Shape)
|
|
|
+// borderCallout3 (Callout 3 with Border Shape)
|
|
|
+// bracePair (Brace Pair Shape)
|
|
|
+// bracketPair (Bracket Pair Shape)
|
|
|
+// callout1 (Callout 1 Shape)
|
|
|
+// callout2 (Callout 2 Shape)
|
|
|
+// callout3 (Callout 3 Shape)
|
|
|
+// can (Can Shape)
|
|
|
+// chartPlus (Chart Plus Shape)
|
|
|
+// chartStar (Chart Star Shape)
|
|
|
+// chartX (Chart X Shape)
|
|
|
+// chevron (Chevron Shape)
|
|
|
+// chord (Chord Shape)
|
|
|
+// circularArrow (Circular Arrow Shape)
|
|
|
+// cloud (Cloud Shape)
|
|
|
+// cloudCallout (Callout Cloud Shape)
|
|
|
+// corner (Corner Shape)
|
|
|
+// cornerTabs (Corner Tabs Shape)
|
|
|
+// cube (Cube Shape)
|
|
|
+// curvedConnector2 (Curved Connector 2 Shape)
|
|
|
+// curvedConnector3 (Curved Connector 3 Shape)
|
|
|
+// curvedConnector4 (Curved Connector 4 Shape)
|
|
|
+// curvedConnector5 (Curved Connector 5 Shape)
|
|
|
+// curvedDownArrow (Curved Down Arrow Shape)
|
|
|
+// curvedLeftArrow (Curved Left Arrow Shape)
|
|
|
+// curvedRightArrow (Curved Right Arrow Shape)
|
|
|
+// curvedUpArrow (Curved Up Arrow Shape)
|
|
|
+// decagon (Decagon Shape)
|
|
|
+// diagStripe (Diagonal Stripe Shape)
|
|
|
+// diamond (Diamond Shape)
|
|
|
+// dodecagon (Dodecagon Shape)
|
|
|
+// donut (Donut Shape)
|
|
|
+// doubleWave (Double Wave Shape)
|
|
|
+// downArrow (Down Arrow Shape)
|
|
|
+// downArrowCallout (Callout Down Arrow Shape)
|
|
|
+// ellipse (Ellipse Shape)
|
|
|
+// ellipseRibbon (Ellipse Ribbon Shape)
|
|
|
+// ellipseRibbon2 (Ellipse Ribbon 2 Shape)
|
|
|
+// flowChartAlternateProcess (Alternate Process Flow Shape)
|
|
|
+// flowChartCollate (Collate Flow Shape)
|
|
|
+// flowChartConnector (Connector Flow Shape)
|
|
|
+// flowChartDecision (Decision Flow Shape)
|
|
|
+// flowChartDelay (Delay Flow Shape)
|
|
|
+// flowChartDisplay (Display Flow Shape)
|
|
|
+// flowChartDocument (Document Flow Shape)
|
|
|
+// flowChartExtract (Extract Flow Shape)
|
|
|
+// flowChartInputOutput (Input Output Flow Shape)
|
|
|
+// flowChartInternalStorage (Internal Storage Flow Shape)
|
|
|
+// flowChartMagneticDisk (Magnetic Disk Flow Shape)
|
|
|
+// flowChartMagneticDrum (Magnetic Drum Flow Shape)
|
|
|
+// flowChartMagneticTape (Magnetic Tape Flow Shape)
|
|
|
+// flowChartManualInput (Manual Input Flow Shape)
|
|
|
+// flowChartManualOperation (Manual Operation Flow Shape)
|
|
|
+// flowChartMerge (Merge Flow Shape)
|
|
|
+// flowChartMultidocument (Multi-Document Flow Shape)
|
|
|
+// flowChartOfflineStorage (Offline Storage Flow Shape)
|
|
|
+// flowChartOffpageConnector (Off-Page Connector Flow Shape)
|
|
|
+// flowChartOnlineStorage (Online Storage Flow Shape)
|
|
|
+// flowChartOr (Or Flow Shape)
|
|
|
+// flowChartPredefinedProcess (Predefined Process Flow Shape)
|
|
|
+// flowChartPreparation (Preparation Flow Shape)
|
|
|
+// flowChartProcess (Process Flow Shape)
|
|
|
+// flowChartPunchedCard (Punched Card Flow Shape)
|
|
|
+// flowChartPunchedTape (Punched Tape Flow Shape)
|
|
|
+// flowChartSort (Sort Flow Shape)
|
|
|
+// flowChartSummingJunction (Summing Junction Flow Shape)
|
|
|
+// flowChartTerminator (Terminator Flow Shape)
|
|
|
+// foldedCorner (Folded Corner Shape)
|
|
|
+// frame (Frame Shape)
|
|
|
+// funnel (Funnel Shape)
|
|
|
+// gear6 (Gear 6 Shape)
|
|
|
+// gear9 (Gear 9 Shape)
|
|
|
+// halfFrame (Half Frame Shape)
|
|
|
+// heart (Heart Shape)
|
|
|
+// heptagon (Heptagon Shape)
|
|
|
+// hexagon (Hexagon Shape)
|
|
|
+// homePlate (Home Plate Shape)
|
|
|
+// horizontalScroll (Horizontal Scroll Shape)
|
|
|
+// irregularSeal1 (Irregular Seal 1 Shape)
|
|
|
+// irregularSeal2 (Irregular Seal 2 Shape)
|
|
|
+// leftArrow (Left Arrow Shape)
|
|
|
+// leftArrowCallout (Callout Left Arrow Shape)
|
|
|
+// leftBrace (Left Brace Shape)
|
|
|
+// leftBracket (Left Bracket Shape)
|
|
|
+// leftCircularArrow (Left Circular Arrow Shape)
|
|
|
+// leftRightArrow (Left Right Arrow Shape)
|
|
|
+// leftRightArrowCallout (Callout Left Right Arrow Shape)
|
|
|
+// leftRightCircularArrow (Left Right Circular Arrow Shape)
|
|
|
+// leftRightRibbon (Left Right Ribbon Shape)
|
|
|
+// leftRightUpArrow (Left Right Up Arrow Shape)
|
|
|
+// leftUpArrow (Left Up Arrow Shape)
|
|
|
+// lightningBolt (Lightning Bolt Shape)
|
|
|
+// line (Line Shape)
|
|
|
+// lineInv (Line Inverse Shape)
|
|
|
+// mathDivide (Divide Math Shape)
|
|
|
+// mathEqual (Equal Math Shape)
|
|
|
+// mathMinus (Minus Math Shape)
|
|
|
+// mathMultiply (Multiply Math Shape)
|
|
|
+// mathNotEqual (Not Equal Math Shape)
|
|
|
+// mathPlus (Plus Math Shape)
|
|
|
+// moon (Moon Shape)
|
|
|
+// nonIsoscelesTrapezoid (Non-Isosceles Trapezoid Shape)
|
|
|
+// noSmoking (No Smoking Shape)
|
|
|
+// notchedRightArrow (Notched Right Arrow Shape)
|
|
|
+// octagon (Octagon Shape)
|
|
|
+// parallelogram (Parallelogram Shape)
|
|
|
+// pentagon (Pentagon Shape)
|
|
|
+// pie (Pie Shape)
|
|
|
+// pieWedge (Pie Wedge Shape)
|
|
|
+// plaque (Plaque Shape)
|
|
|
+// plaqueTabs (Plaque Tabs Shape)
|
|
|
+// plus (Plus Shape)
|
|
|
+// quadArrow (Quad-Arrow Shape)
|
|
|
+// quadArrowCallout (Callout Quad-Arrow Shape)
|
|
|
+// rect (Rectangle Shape)
|
|
|
+// ribbon (Ribbon Shape)
|
|
|
+// ribbon2 (Ribbon 2 Shape)
|
|
|
+// rightArrow (Right Arrow Shape)
|
|
|
+// rightArrowCallout (Callout Right Arrow Shape)
|
|
|
+// rightBrace (Right Brace Shape)
|
|
|
+// rightBracket (Right Bracket Shape)
|
|
|
+// round1Rect (One Round Corner Rectangle Shape)
|
|
|
+// round2DiagRect (Two Diagonal Round Corner Rectangle Shape)
|
|
|
+// round2SameRect (Two Same-side Round Corner Rectangle Shape)
|
|
|
+// roundRect (Round Corner Rectangle Shape)
|
|
|
+// rtTriangle (Right Triangle Shape)
|
|
|
+// smileyFace (Smiley Face Shape)
|
|
|
+// snip1Rect (One Snip Corner Rectangle Shape)
|
|
|
+// snip2DiagRect (Two Diagonal Snip Corner Rectangle Shape)
|
|
|
+// snip2SameRect (Two Same-side Snip Corner Rectangle Shape)
|
|
|
+// snipRoundRect (One Snip One Round Corner Rectangle Shape)
|
|
|
+// squareTabs (Square Tabs Shape)
|
|
|
+// star10 (Ten Pointed Star Shape)
|
|
|
+// star12 (Twelve Pointed Star Shape)
|
|
|
+// star16 (Sixteen Pointed Star Shape)
|
|
|
+// star24 (Twenty Four Pointed Star Shape)
|
|
|
+// star32 (Thirty Two Pointed Star Shape)
|
|
|
+// star4 (Four Pointed Star Shape)
|
|
|
+// star5 (Five Pointed Star Shape)
|
|
|
+// star6 (Six Pointed Star Shape)
|
|
|
+// star7 (Seven Pointed Star Shape)
|
|
|
+// star8 (Eight Pointed Star Shape)
|
|
|
+// straightConnector1 (Straight Connector 1 Shape)
|
|
|
+// stripedRightArrow (Striped Right Arrow Shape)
|
|
|
+// sun (Sun Shape)
|
|
|
+// swooshArrow (Swoosh Arrow Shape)
|
|
|
+// teardrop (Teardrop Shape)
|
|
|
+// trapezoid (Trapezoid Shape)
|
|
|
+// triangle (Triangle Shape)
|
|
|
+// upArrow (Up Arrow Shape)
|
|
|
+// upArrowCallout (Callout Up Arrow Shape)
|
|
|
+// upDownArrow (Up Down Arrow Shape)
|
|
|
+// upDownArrowCallout (Callout Up Down Arrow Shape)
|
|
|
+// uturnArrow (U-Turn Arrow Shape)
|
|
|
+// verticalScroll (Vertical Scroll Shape)
|
|
|
+// wave (Wave Shape)
|
|
|
+// wedgeEllipseCallout (Callout Wedge Ellipse Shape)
|
|
|
+// wedgeRectCallout (Callout Wedge Rectangle Shape)
|
|
|
+// wedgeRoundRectCallout (Callout Wedge Round Rectangle Shape)
|
|
|
+//
|
|
|
+func (f *File) AddShape(sheet, cell, format string) {
|
|
|
+ formatSet := parseFormatShapeSet(format)
|
|
|
+ // Read sheet data.
|
|
|
+ xlsx := f.workSheetReader(sheet)
|
|
|
+ // Add first shape for given sheet, create xl/drawings/ and xl/drawings/_rels/ folder.
|
|
|
+ drawingID := f.countDrawings() + 1
|
|
|
+ drawingXML := "xl/drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
|
|
+ sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
|
|
+
|
|
|
+ if xlsx.Drawing != nil {
|
|
|
+ // The worksheet already has a shape or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
|
|
|
+ sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
|
|
|
+ drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
|
|
|
+ drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
|
|
|
+ } else {
|
|
|
+ // Add first shape for given sheet.
|
|
|
+ rID := f.addSheetRelationships(sheet, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
|
|
+ f.addSheetDrawing(sheet, rID)
|
|
|
+ }
|
|
|
+ f.addDrawingShape(sheet, drawingXML, cell, formatSet)
|
|
|
+ f.addDrawingContentTypePart(drawingID)
|
|
|
+}
|
|
|
+
|
|
|
+// addDrawingShape
|
|
|
+func (f *File) addDrawingShape(sheet, drawingXML, cell string, formatSet *formatShape) {
|
|
|
+ cell = strings.ToUpper(cell)
|
|
|
+ fromCol := string(strings.Map(letterOnlyMapF, cell))
|
|
|
+ fromRow, _ := strconv.Atoi(strings.Map(intOnlyMapF, cell))
|
|
|
+ row := fromRow - 1
|
|
|
+ col := titleToNumber(fromCol)
|
|
|
+ width := int(float64(formatSet.Width) * formatSet.Format.XScale)
|
|
|
+ height := int(float64(formatSet.Height) * formatSet.Format.YScale)
|
|
|
+ colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, col, row, formatSet.Format.OffsetX, formatSet.Format.OffsetY, width, height)
|
|
|
+ content := xlsxWsDr{}
|
|
|
+ content.A = NameSpaceDrawingML
|
|
|
+ content.Xdr = NameSpaceDrawingMLSpreadSheet
|
|
|
+ cNvPrID := 1
|
|
|
+ _, ok := f.XLSX[drawingXML]
|
|
|
+ if ok { // Append Model
|
|
|
+ decodeWsDr := decodeWsDr{}
|
|
|
+ xml.Unmarshal([]byte(f.readXML(drawingXML)), &decodeWsDr)
|
|
|
+ cNvPrID = len(decodeWsDr.OneCellAnchor) + len(decodeWsDr.TwoCellAnchor) + 1
|
|
|
+ for _, v := range decodeWsDr.OneCellAnchor {
|
|
|
+ content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
|
|
|
+ EditAs: v.EditAs,
|
|
|
+ GraphicFrame: v.Content,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ for _, v := range decodeWsDr.TwoCellAnchor {
|
|
|
+ content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
|
|
|
+ EditAs: v.EditAs,
|
|
|
+ GraphicFrame: v.Content,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ twoCellAnchor := xdrCellAnchor{}
|
|
|
+ twoCellAnchor.EditAs = "oneCell"
|
|
|
+ from := xlsxFrom{}
|
|
|
+ from.Col = colStart
|
|
|
+ from.ColOff = formatSet.Format.OffsetX * EMU
|
|
|
+ from.Row = rowStart
|
|
|
+ from.RowOff = formatSet.Format.OffsetY * EMU
|
|
|
+ to := xlsxTo{}
|
|
|
+ to.Col = colEnd
|
|
|
+ to.ColOff = x2 * EMU
|
|
|
+ to.Row = rowEnd
|
|
|
+ to.RowOff = y2 * EMU
|
|
|
+ twoCellAnchor.From = &from
|
|
|
+ twoCellAnchor.To = &to
|
|
|
+ shape := xdrSp{
|
|
|
+ NvSpPr: &xdrNvSpPr{
|
|
|
+ CNvPr: &xlsxCNvPr{
|
|
|
+ ID: cNvPrID,
|
|
|
+ Name: "Shape " + strconv.Itoa(cNvPrID),
|
|
|
+ },
|
|
|
+ CNvSpPr: &xdrCNvSpPr{
|
|
|
+ TxBox: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ SpPr: &xlsxSpPr{
|
|
|
+ PrstGeom: xlsxPrstGeom{
|
|
|
+ Prst: formatSet.Type,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ Style: &xdrStyle{
|
|
|
+ LnRef: setShapeRef(formatSet.Color.Line, 2),
|
|
|
+ FillRef: setShapeRef(formatSet.Color.Fill, 1),
|
|
|
+ EffectRef: setShapeRef(formatSet.Color.Effect, 0),
|
|
|
+ FontRef: &aFontRef{
|
|
|
+ Idx: "minor",
|
|
|
+ SchemeClr: &attrValString{
|
|
|
+ Val: "tx1",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ TxBody: &xdrTxBody{
|
|
|
+ BodyPr: &aBodyPr{
|
|
|
+ VertOverflow: "clip",
|
|
|
+ HorzOverflow: "clip",
|
|
|
+ Wrap: "none",
|
|
|
+ RtlCol: false,
|
|
|
+ Anchor: "t",
|
|
|
+ },
|
|
|
+ P: &aP{
|
|
|
+ R: &aR{
|
|
|
+ RPr: aRPr{
|
|
|
+ Lang: "en-US",
|
|
|
+ AltLang: "en-US",
|
|
|
+ Sz: 1100,
|
|
|
+ },
|
|
|
+ T: formatSet.Text,
|
|
|
+ },
|
|
|
+ EndParaRPr: &aEndParaRPr{
|
|
|
+ Lang: "en-US",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+ twoCellAnchor.Sp = &shape
|
|
|
+ twoCellAnchor.ClientData = &xdrClientData{
|
|
|
+ FLocksWithSheet: formatSet.Format.FLocksWithSheet,
|
|
|
+ FPrintsWithSheet: formatSet.Format.FPrintsWithSheet,
|
|
|
+ }
|
|
|
+ content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
|
|
+ output, _ := xml.Marshal(content)
|
|
|
+ f.saveFileList(drawingXML, string(output))
|
|
|
+}
|
|
|
+
|
|
|
+// setShapeRef provides function to set color with hex model by given actual
|
|
|
+// color value.
|
|
|
+func setShapeRef(color string, i int) *aRef {
|
|
|
+ if color == "" {
|
|
|
+ return &aRef{
|
|
|
+ Idx: 0,
|
|
|
+ ScrgbClr: &aScrgbClr{
|
|
|
+ R: 0,
|
|
|
+ G: 0,
|
|
|
+ B: 0,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return &aRef{
|
|
|
+ Idx: i,
|
|
|
+ SrgbClr: &attrValString{
|
|
|
+ Val: strings.Replace(strings.ToUpper(color), "#", "", -1),
|
|
|
+ },
|
|
|
+ }
|
|
|
+}
|